diff --git a/.agents/GEMINI.md b/.agents/GEMINI.md index 5bf834d6..7a77eb8e 100644 --- a/.agents/GEMINI.md +++ b/.agents/GEMINI.md @@ -1,23 +1,17 @@ # Antigravity Workspace Instructions -MANDATORY FIRST ACTION for this workspace: +**Agents Remember — session start.** -You are not allowed to read, write, or execute code on any repository until you -read `/ar-coordination/AGENTS.md` and started its -`l-01` procedure. +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** -Read and follow `/ar-coordination/AGENTS.md` -before working in any sibling project. -Treat those rules as workspace instructions. - -Until the build/job decision is made, read managed-repo source with the -`read_ar_files` MCP tool — not the harness's native read tool. One call returns -each file paired with its onboarding plus the repository and governing route -overviews. Native read is reserved as the edit precondition once building begins. - -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent), and -keep a running count of your `read_ar_files` calls. Include the onboarding files -inspected and every CGC, GrepAI, and `read_ar_files` call made as evidence. +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`/ar-coordination/AGENTS.md` and treat those rules +as workspace instructions, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. @/ar-coordination/AGENTS.md diff --git a/.agents/skills/c-01-findings-capture/SKILL.md b/.agents/skills/c-01-findings-capture/SKILL.md index e145d7ee..d413e8fe 100644 --- a/.agents/skills/c-01-findings-capture/SKILL.md +++ b/.agents/skills/c-01-findings-capture/SKILL.md @@ -13,7 +13,7 @@ Companion file: ## Operating Modes -1. Inside a task workflow (an `l-01-session-job-lifecycle` build job or a `w-02-light-task-workflow` task, including a master + light sub-task series). +1. Inside a task workflow (an `l-01-agent-lifecycles` orchestrator build phase or a `w-02-light-task-workflow` task, including a master + light sub-task series). 2. Standalone during direct clarification. ## Durable Destinations diff --git a/.agents/skills/c-03-repo-bootstrap/SKILL.md b/.agents/skills/c-03-repo-bootstrap/SKILL.md index 40148918..44f14f78 100644 --- a/.agents/skills/c-03-repo-bootstrap/SKILL.md +++ b/.agents/skills/c-03-repo-bootstrap/SKILL.md @@ -1240,7 +1240,7 @@ The orchestrator remains thin throughout. | `c-05-create-or-update-onboarding-files` | Owns final file-level onboarding semantics and routes structural slice maintenance back to the `c-03-repo-bootstrap` skill. The `c-03-repo-bootstrap` skill creates cards/waves and delegates file output rules to the `c-05-create-or-update-onboarding-files` skill. | | `c-04-retrieval-strategy-router` | Consumes bootstrapped overviews and file maps as the Intent substrate and can route to semantic/relationship providers first. | | `c-02-memory-quality-control` | Becomes relevant after bootstrap; touched files can be promoted from deferred to covered. | -| `l-01-session-job-lifecycle` | May trigger targeted bootstrap when an active job enters an uncovered area. | +| `l-01-agent-lifecycles` | May trigger targeted bootstrap when an active job enters an uncovered area. | | `confluence-search` / documentation search skills | Feed the docs evidence pass through approved sources from the input ledger. | --- diff --git a/.agents/skills/c-04-retrieval-strategy-router/SKILL.md b/.agents/skills/c-04-retrieval-strategy-router/SKILL.md index 01434c77..e226f8c0 100644 --- a/.agents/skills/c-04-retrieval-strategy-router/SKILL.md +++ b/.agents/skills/c-04-retrieval-strategy-router/SKILL.md @@ -160,7 +160,7 @@ names an unresolved source question. ### Rules: -- During the research phase (the lifecycle up to the build/job decision), read managed-repo +- During the research phase (the lifecycle up to the build decision), read managed-repo source with `read_ar_files`, not the native read tool — one call returns each file paired with its onboarding plus the repository and governing route overviews (the recipe above, batched and observable). diff --git a/.agents/skills/c-09-git-worktree-manager/SKILL.md b/.agents/skills/c-09-git-worktree-manager/SKILL.md index e19c7902..692dec19 100644 --- a/.agents/skills/c-09-git-worktree-manager/SKILL.md +++ b/.agents/skills/c-09-git-worktree-manager/SKILL.md @@ -7,7 +7,7 @@ description: "Create, attach to, report on, integrate, finalize, and clean up Ag Use this skill when a task should run through an explicit code/memory worktree wrapper. -The `c-09-git-worktree-manager` skill wraps the existing chat-build, light-task, or external workflow. It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. +The `c-09-git-worktree-manager` skill wraps the existing light-task or external workflow (a build that fits one session still rides a THIN `w-02-light-task-workflow` doc — chat is never a build route, per the `l-01-agent-lifecycles` invariant). It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. For closeout, use the `c-12-closeout` skill. The `c-09-git-worktree-manager` skill only supplies the worktree-specific contract path and integration/finalization follow-up rules. @@ -67,7 +67,7 @@ The intended order is: 1. run the `c-08-ar-coordination-context-resolver` skill for the target repository 2. run the `c-02-memory-quality-control` skill's task-start drift check and follow the existing AGENTS Gate 3/4 choice point 3. when onboarding is refreshed, commit the memory content and ledger before starting any worktree -4. decide whether the work is a chat build, a `w-02-light-task-workflow` light task (or master + light sub-task series), or external workflow +4. decide whether the work is a `w-02-light-task-workflow` light task — possibly a THIN one for single-session work; chat never builds — a master + light sub-task series, or external workflow 5. read the repository's `system/git-workflow.md` and identify the parent branch edge. For a standalone task, the leaf worktree branches from the approved source branch. For a master series, the master owns a root `series-contract.md` @@ -198,7 +198,9 @@ moved since task start. ## Integration -Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. +Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. Orchestrated-run carve-out (ruled 2026-07-06): dependency-ordered leaf→master and master→super integrations ride the series' standing approval (the developer's portfolio-gate approval recorded in the planner master) — the developer hand-off concentrates at the super PR/carry-over gate per the `l-01-agent-lifecycles` loop/orchestrator doctrine; a raised durable `integration-approval` gate still awaits the developer. + +On an orchestrated master's exit (master → super integration) the integrate step additionally enforces the delegated `master-handover-approval` seam: an undecided or policy-invalid handover gate addressed to the master (by `enclosure` = master task name) returns `handover-gate-blocked` instead of landing — decide the gate per the `l-01-agent-lifecycles` seam doctrine, then rerun. When no gate addresses the integrating master but open `master-handover-approval` gates exist elsewhere, integrate still proceeds and its result carries a `handover_gate_warning` naming them — treat it as a spelling check on the raised gate's `enclosure`. Run `worktree_integrate(..., dry_run=true)` first, then **hand off**: call `lifecycle_turn_end_notification(summary={…the integration plan…})` as the **last tool call**, then diff --git a/.agents/skills/c-12-closeout/SKILL.md b/.agents/skills/c-12-closeout/SKILL.md index f83071d9..2c7fe3ff 100644 --- a/.agents/skills/c-12-closeout/SKILL.md +++ b/.agents/skills/c-12-closeout/SKILL.md @@ -40,7 +40,7 @@ records the developer's explicit commit approval. Agents must not treat implementation approval, a previous "looks good", or their own judgment as commit approval. -The relay follows the `l-01-session-job-lifecycle` skill hand-off protocol: run the +The relay follows the `l-01-agent-lifecycles` orchestrator hand-off protocol: run the preview/dry-run first, then call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the **last tool call**, then deliver the preview facts and proposed messages as plain diff --git a/.agents/skills/c-13-install-and-onboard/SKILL.md b/.agents/skills/c-13-install-and-onboard/SKILL.md index 6515ae46..d583fd13 100644 --- a/.agents/skills/c-13-install-and-onboard/SKILL.md +++ b/.agents/skills/c-13-install-and-onboard/SKILL.md @@ -52,10 +52,12 @@ Run this sequence in order: 0. Preflight: verify the copied package and MCP setup are usable enough to continue. 1. Runtime scaffold: run or verify `runtime_install()`. -2. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. -3. Bootstrap: when a new memory repo was scaffolded, hand off to +2. Agentic settings: walk the developer through the orchestration defaults in + the seeded global settings file. +3. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. +4. Bootstrap: when a new memory repo was scaffolded, hand off to `c-03-repo-bootstrap`. -4. Providers: when providers are enabled, start/refresh indexing and verify +5. Providers: when providers are enabled, start/refresh indexing and verify readiness. This skill orchestrates and delegates. It does not reimplement @@ -79,7 +81,9 @@ Check, in order: 3. **Settings sane.** Confirm `server_info` reports the expected `coordinationRoot`, `workspaceRoot`, allowed repositories, and providers. Surface the resolved absolute paths because wrong paths are the common cause - of resolver failures. + of resolver failures. Also report whether the global agentic settings file + (`/system/settings.json`) exists yet; Stage 1 seeds it + when missing and Stage 2 configures it. 4. **Runtime state.** Check whether the coordinator scaffold already exists under `coordinationRoot` (`AGENTS.md`, `skills/`, `tasks/`, `memory-repos/`, `system/` as applicable). If it is missing or stale, Stage 1 will run @@ -118,7 +122,61 @@ Do not run `skills_install()` as part of first-run setup. The harness starter package already carries the skills. `skills_install()` remains available for manual maintenance or non-package setups, but it is not the default path. -## Stage 2 - Memory Repo: Ask Scaffold Vs Existing +## Stage 2 - Agentic Settings: Interview The Developer + +`runtime_install()` seeds the GLOBAL agentic settings file at +`/system/settings.json` copy-if-missing, with every knob at +its documented default: all-human gate delegation, the standard three-party-loop +defaults, no concurrency caps, no spawn harness preference. This stage turns +those defaults into the developer's actual posture so the intended workflows +run on ANY harness. The schema reference is `docs/reference/settings-json.md` +(Agentic Settings); unknown `orchestration.*` keys fail loud, so write only +documented keys. + +Walk the developer through the four knob families and edit the global file with +their answers (leave a family at its seeded default when they have no +preference): + +1. **Gate delegation posture** (`orchestration.gateDelegation`; GLOBAL file only - the + loader refuses it repo-locally and the boot snapshot reads the coordinator file) - keep every + gate human (`all-human`, the default), or delegate leaf gates with the + `manager-decides-leaf-gates` policy, optional per-kind `kinds` overrides, + and `requireReviewerVerdictAtSeams`. Say explicitly that this one key is + boot-snapshot: a change needs an MCP/harness restart. +2. **Loop defaults** (`orchestration.loops`) - the review-round cap + (`defaults.maxRounds`), reviewer reuse (`defaults.reviewerReuse`), + complexity thresholds (`defaults.complexity`), and per-level loop postures + (`perLevel`). Read per-use; edits apply on the next use, no restart. +3. **Concurrency caps** (`orchestration.concurrency`) - `maxParallelMasters`, + `maxParallelLeaves`, `maxSubAgents`. Default: uncapped. +4. **Harness preference + role knobs** (`orchestration.spawn.harness`, + per-role `orchestration.roles.`, per-level + `orchestration.rolesPerLevel..`) - which installed harness + `spawn_agent_session` uses when the spawning seat passes none, per-role + harness/model/effort overrides, and per-LEVEL overrides + (leaf|master|portfolio) for tiered economics (e.g. a cheap leaf reviewer, + a smarter master-seam reviewer). Harness values must be known ids: the + builtin registry (`claude`, `codex`, `pi`) or an `orchestration.harnesses` + entry the developer defines (new TUIs, or a pre-customized launch argv for + a builtin). `effort` is validated per-harness at dispatch (claude: + `low|medium|high|xhigh|max` on the `--effort` flag plus the session-level + `ultracode`); mention the FREE-FORM escape hatch for anything outside the + vocabularies - `launchArgs` (verbatim argv), `sessionCommands` (pasted + before the brief), `promptKeywords` (prepended to the brief) - never + validated, recorded in spawn provenance. Default: detection-gated (the + first detected harness). The full spawn-surface manual is + `docs/reference/harnesses.md`. + +If the developer wants to skip the interview, confirm the seeded defaults +apply and continue; tell them the file can be edited any time (picked up +per-use, except the gateDelegation restart note above). + +Per-repo overrides: a code repo may carry its own `/system/settings.json` +with the same `orchestration.*` shape; repo-local leaf values override the +global file (arrays replace). Offer this only when the developer asks for +repo-specific behavior; do not create the file unprompted. + +## Stage 3 - Memory Repo: Ask Scaffold Vs Existing Do not assume the developer wants a fresh memory repo. Ask which case applies, unless a memory repo is already present and resolvable: @@ -126,10 +184,10 @@ unless a memory repo is already present and resolvable: 1. **Scaffold a new memory repo** - they have no existing memory for this code repo. Run `c-00-initialize-memory-repo` (internal by default; external only if the developer asks or the configured topology requires it). Continue to Stage - 3. + 4. 2. **Use an existing memory repo** - they already have one. Clone or checkout it to the resolved memory location, then adopt it as the ledgered baseline with - `c-10-adopt-memory-baseline`. Skip Stage 3 because its onboarding already + `c-10-adopt-memory-baseline`. Skip Stage 4 because its onboarding already exists. Internal-memory note: pre-existing internal memory lives inside the code repo @@ -137,9 +195,9 @@ Internal-memory note: pre-existing internal memory lives inside the code repo `c-08-ar-coordination-context-resolver` and skip the question when the memory layer is already there. -## Stage 3 - Bootstrap +## Stage 4 - Bootstrap -Run this stage only when Stage 2 scaffolded a new memory repo. +Run this stage only when Stage 3 scaffolded a new memory repo. Hand off to `c-03-repo-bootstrap` to generate initial onboarding. A thin `overview.md` is enough to start; deeper route-local overviews and file-level @@ -147,7 +205,7 @@ onboarding should grow as work touches new areas. Skip this stage when an existing memory repo was adopted. -## Stage 4 - Configure Providers To Index +## Stage 5 - Configure Providers To Index If providers are enabled, make them index the configured code and memory: @@ -177,10 +235,12 @@ Summarize: step the developer must perform; 2. runtime scaffold: `runtime_install()` run or already current, with the resolved coordination root; -3. memory repo: scaffolded, existing-adopted, or already present, with the +3. agentic settings: interviewed and written, or left at the seeded defaults, + with the global file path; +4. memory repo: scaffolded, existing-adopted, or already present, with the resolved memory root; -4. bootstrap: run via `c-03-repo-bootstrap` or skipped; -5. providers: indexing status and any deferred/degraded state. +5. bootstrap: run via `c-03-repo-bootstrap` or skipped; +6. providers: indexing status and any deferred/degraded state. End by telling the developer whether the project is ready for normal work. Do not tell them to restart for hooks installed by this skill, because this skill no diff --git a/.agents/skills/l-01-agent-lifecycles/SKILL.md b/.agents/skills/l-01-agent-lifecycles/SKILL.md new file mode 100644 index 00000000..1d390618 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/SKILL.md @@ -0,0 +1,259 @@ +--- +name: l-01-agent-lifecycles +description: "The agent lifecycles: one lifecycle per agent type, under one roof. Routes every session by exactly three conditions (spawn-role env -> role brief -> otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator, designer, strategist, manager, worker, adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. A developer-facing session IS the orchestrator; solo work is the degenerate portfolio. Supersedes and replaces both l-01-session-job-lifecycle and l-02-agent-orchestration." +--- + +# l-01-agent-lifecycles — The Agent Lifecycles + +Lifecycle and job are **one entity**: each agent type runs its own, self-contained lifecycle. This +skill is the single roof over all of them — a thin router, the minimal frame every session shares, +and the role lifecycles as the payload files. No role is defined by reference to another role's +lifecycle, and no role reads another role's file. + +## Which Lifecycle Am I? (the router — exactly three conditions, in order) + +1. **`AR_SPAWN_ROLE` is set** (spawn env, injected by `spawn_agent_session`) → run + `roles/.md`. Nothing else in this file's "developer session" material applies to you. + (`designer` here means the same design hat in a separate chair — see `roles/designer.md`.) +2. **Else: the first user message is a role brief** — a `templates/*-brief.md`-shaped dispatch or + a first line of the form `ROLE BRIEF — ` from an orchestrating agent → run that role's + lifecycle. The brief is your session start; a workspace session-start notice is not addressed + to you. +3. **Else** (a developer opened this session) → you are the **orchestrator**: run + `roles/orchestrator.md`. Solo work is the degenerate portfolio — the same three jobs with hats + collapsed (the orchestrator wears the manager hat in flat runs and builds hands-on at session + scale); the task doc still comes first. + +There is no fourth entry, and the edge cases are decided: an **unresolvable `AR_SPAWN_ROLE` +value** (no matching `roles/.md`) falls through to condition 2 (the brief); a role-env +session **whose brief never arrives** announces itself on the inbox and waits — it never +improvises a task; `AR_SPAWN_ROLE=orchestrator` is valid only as a takeover chair (the Profile +check (takeover) in `roles/orchestrator.md`, The Event Loop) — the developer still talks to **one** orchestrator. Orchestrated +fan-out (spawning managers/workers at scale) begins only on an explicit developer request (e.g. +*"orchestrate these masters"*) — no agent promotes itself into a spawning seat. + +One exception to the no-cross-reading rule above: **a seat that WEARS a hat runs that hat's file +as its own** — the orchestrator always for `roles/designer.md`, and in flat runs for +`roles/manager.md` (the hat-collapse rule). + +## The Role Registry + +| Role | Seat | Lifecycle file | +| --- | --- | --- | +| **orchestrator** | the developer-facing session; first coordination leaf of an orchestrated series | `roles/orchestrator.md` | +| **designer** | a HAT the orchestrator pulls inline (front of the pipeline or mid-flight; separate chair optional) | `roles/designer.md` | +| **strategist** | the sprint planner, SPAWN-FIRST; a strategist run is a **mandatory precondition for any orchestrated run** — its deliverable is the orchestration task (sprint plan + scope); spawn value `strategist` | `roles/strategist.md` | +| **manager** | one coordination leaf per master; drives that master's leaf loop | `roles/manager.md` | +| **worker** | one leaf worktree, short-lived, fresh session | `roles/worker.md` | +| **adversarial reviewer** | short-lived, spawned at the two seams (master-exit, super-exit) and as any three-party loop's reviewer seat (criteria catalogs bound per review type); spawn value `reviewer` | `roles/reviewer.md` | + +The **lenses** (bug · feature · triage · research — `lenses.md`) are how the scoping seats +(orchestrator, designer) read a piece of work; a dispatched role never picks a lens — its brief +already carries the flavor. + +## The Minimal Frame (the only machinery every session shares) + +Every session in a managed repo may be a **lifecycle**: six signals — `lifecycle_start` · +`lifecycle_phase` · `lifecycle_turn_end_notification` · `worktree_attach` · `switch_lifecycle` · +`lifecycle_end` (plus the automatic `worktree_start` promotion) — record where it +is and what it waits on, so work is observable and resumable across chat deaths. The model **never +handles a lifecycle id** — identity is server-side, anchored in the worktree contract. + +| When | Signal | Effect | +| --- | --- | --- | +| Trust checkpoint passes (managed repo) | `lifecycle_start` | begin a **fleeting** lifecycle (guarded: one per session; no id) | +| Entering a phase | `lifecycle_phase` | move the phase axis (`request` / `trust-checkpoint` / `reframe-research` / `decide` / `build` / `close`) | +| A developer hand-off | `lifecycle_turn_end_notification(summary=…)` | set `awaiting-developer`, surface the attention item, return immediately; the **next turn's first AR call auto-resumes** — never resume by hand | +| `worktree_start` | *(automatic promotion)* | the fleeting lifecycle becomes **persistent**, anchored in the contract | +| Resuming an existing task | `worktree_attach` | re-adopts the contract's lifecycle (contract-resolved) | +| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | the save gate — never dropped silently | +| Close | `lifecycle_end` (`completed`\|`abandoned`) | the terminal record | + +Rules: a tool call outside any lifecycle is **dropped, never misattributed**; `paused` is +system-owned. **A spawned role that never touches mutating AR tools simply never instantiates a +lifecycle — that is correct, not a violation.** A spawned role runs its **own** lifecycle when it +runs one; it never adopts its spawner's. The session↔leaf association is the catalog binding made +at spawn (the **qualified** leaf key `//`), not lifecycle adoption. + +## Shared Invariants (every role can count on these) + +- **Continuity lives in the `task_doc` + durable artifacts, never in transcripts** — which is why + short-lived workers and reviewers are safe, and why every seat writes its artifact of record. +- **Escalation ladder: worker → manager → orchestrator → developer.** No rung is skipped, ever. + Each role file states only its own rung. +- **Observability:** coordination seats are `task_doc` leaves with attached chats; the developer + can walk into any seat at any level. +- **Decision-needing questions land in the task doc's `openQuestions`** — the rendered decision + surface; `notes/` carries the analysis behind them. + +## The Three-Party Loop (one home — this section owns the loop doctrine) + +**OWNER → BUILDER → REVIEWER → owner, at every level that owns work.** The owner never +self-approves; the builder never lands; the reviewer never decides — verdicts are evidence. The +owner checks the verdict and either redispatches a builder or escalates. Role files reference this +section; they do not restate it. + +| Level | Owner (holds the deliverable, rules, lands) | Builder | Reviewer | +| --- | --- | --- | --- | +| Leaf | the leaf's owning seat (manager; orchestrator in tight/flat mode) | spawned worker (no-commit contract) | spawned reviewer, criteria catalog + liberty | +| Master | the manager | the leaf workers | the master-exit seam reviewer (verdict rides `master-handover-approval`) | +| Portfolio | the orchestrator | the STRATEGIST (spawn-first) | reviewer with the plan-review catalog | + +**Complexity-scored tiers (per leaf, at dispatch).** The owning seat scores three axes — blast +radius (doctrine/enforcement/public surface vs leaf-local) · novelty (new subsystem vs +pattern-following) · size (files × steps) — into three tiers: **direct** (no loop +machinery — the level's ordinary build channel implements: hands-on at session scale, the leaf's +worker under a manager; self-check + checks ladder only), **builder-verified** (builder +implements; owner verifies report-vs-artifact; no reviewer), **full loop** (builder + independent +reviewer rounds). The +strategist's blast-radius register is the scoring input when an orchestration task exists. A +leaf's loop mark (tier + scope: manager | orchestrator — the owning level runs the loop with ITS +agent set) is recorded on the leaf doc with a decision-log entry. **A master whose leaves all +score `direct` is a workflow-free manager** — no loop machinery; the knobs make every loop +optional per level, never mandatory ceremony. + +**Rounds and the HARD cap.** A round = implement → review. **Hard cap: 3 rounds per loop — and +ONLY full end-to-end rounds count against it.** Residuals of a passing round are landed and +**delta-verified by the SAME reviewer via a follow-up message** (it retains everything it already +verified, at a fraction of a fresh round's cost); **fix rounds resume the SAME builder**. A fresh +reviewer is spawned only for a full round or when new scope opens. Delta-verifies close rounds; +they do not open them. + +**The convergence rule (the real control; the cap is the backstop).** Every round must SHRINK the +open finding set. A round that does not shrink it escalates immediately, regardless of the count; +a monotonically converging loop may never hit the cap at all. At the cap, or on non-convergence, +the owner does not spin another round — it **escalates one seat up the ladder (worker → manager → +orchestrator → developer) with the full round history attached**; the escalation packet IS the +upper seat's visibility. + +**Quo-vadis (the written developer-escalation criterion).** A question is developer-worthy when it +is a **high-blast-radius truth** — answered wrong it means big rewrites later (architecture +direction, security posture, doctrine contradictions, irreversible data/branch operations, where +agent settings live). Quo-vadis questions escalate IMMEDIATELY, regardless of round count. +Presentation-grade choices (2px vs 3px) never do — the owner rules and logs. + +**Criteria catalogs (the reviewer as test bench).** Criteria are never made up on the spot: every +review runs its type's standing catalog from `criteria/` (code-seam · doctrine · +onboarding-memory · report-verification · plan-review) plus an exploratory mandate, under the +promotion ratchet (each catalog carries it). `roles/reviewer.md` binds them. + +**Per-level agent sets.** Each level runs its loop with its own harness/model/effort set — the +orchestrator-level set (the strongest models) and the manager-level set (cheaper, possibly +workflow-free) are configured per level in the `orchestration.loops` settings block (schema in +`docs/reference/settings-json.md`; stored in the global agentic settings file with repo-local +override, parsed by the kernel agentic-settings loader — L13, landed). The strategist's mandatory +pre-run is doctrine, not a knob — it is unconditional. + +## Knob Block & Capability Doctrine (no per-harness files) + +Role files are **model-interpreted markdown, never an executor**. Each carries a portable **knob +block** (harness / model / effort / tools) — the defaults the terminal host injects at spawn. +Resolution: **role-file defaults < settings.json orchestration block.** There are deliberately +**no per-harness role files** (developer decision 2026-07-05): harness-specific ABILITIES — +sub-agent fan-out and the like — are covered inside the portable files as capability-conditional +doctrine any coding agent can apply, and harness PREFERENCE is deployment configuration +(settings), not doctrine. Hard-coding a vendor would fork the doctrine per harness. For spawning +seats, `spawn_agent_session` is itself the harness-independent fan-out: a harness with no +sub-agent facility still dispatches seats through the framework (a chat, no leaf attachment +required) — the DBMS principle: one behavior, any engine. + +## settings.json Orchestration Block + +Machine/user overrides layer over the role-file defaults, in the **global agentic settings file** +(`/system/settings.json`), with `/system/settings.json` as the +repo-local override layer (leaf-key deep merge, arrays replace, unknown `orchestration.*` keys +fail loud — schema in `docs/reference/settings-json.md`, Agentic Settings). Precedence: role-file +defaults < global settings < repo-local settings. + +```jsonc +{ + "orchestration": { + "roles": { // role → knob override; validated: harness/model/effort · free-form: launchArgs/promptKeywords/sessionCommands + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { // per-LEVEL agent sets (leaf|master|portfolio), deep-merged over roles + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" }, // spawn_agent_session default when the seat passes none + "gateDelegation": { + "policy": "manager-decides-leaf-gates", + "requireReviewerVerdictAtSeams": true + } + } +} +``` + +**As-built (L13 + L16):** the whole block is parsed by the kernel agentic-settings loader +(`kernel/agentic_settings.py`) — typed models for `roles` / `rolesPerLevel` / `concurrency` / +`spawn` / `harnesses` / `loops`, +read PER-USE (an edit applies on the next use, no restart). `orchestration.gateDelegation` is +parsed and **enforced** (`controlplane/gate_policy.py` — all-human default, opt-in delegation, +human-pinned kinds `integration-approval` / `push-approval` / `cleanup-approval`, owner never +self-approves); it is the ONE boot-snapshot key — read from the global file at MCP boot, a change +needs a restart (an authority-file value is a one-cycle legacy fallback with a boot warning). +`requireReviewerVerdictAtSeams` **binds delegated seam decisions** (`master-handover-approval`) to +attached reviewer-verdict evidence; the named policy `manager-decides-leaf-gates` routes leaf gates +to the manager and the master-exit handover to the **orchestrator** (human review concentrates at +the super gate). `spawn_agent_session` resolves its knobs (260703-L16) as explicit args > +repo-local level override > global level override > repo-local role default > global role default +> detection-gated default — the dispatcher declares its `level` (leaf|master|portfolio, default +leaf) and the resolved level rides spawn provenance — and **applies** them at the harness +boundary: model/effort ride as `AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` env AND map onto the launch argv +per-harness via the effective registry (claude `--model`/`--effort`; a mapping-less harness stays +env-only; a session-vocabulary effort like claude's `ultracode` is delivered as a post-launch +`/effort` paste). Unknown effort values REFUSE at dispatch naming the harness's vocabulary — the +CLI would warn-and-silently-degrade. The free-form escape hatch (`launchArgs` verbatim argv, +`promptKeywords` riding the brief paste, `sessionCommands` pasted before the brief) is never +validated, only recorded in spawn provenance; `orchestration.harnesses` teaches the framework new +TUIs or pre-customizes builtin launches (manual: `docs/reference/harnesses.md`). +`orchestration.loops` (the three-party-loop knobs: per-level loop sets, round cap, reviewer +reuse, complexity thresholds) lives in the same block — meaning in +`docs/reference/settings-json.md`; no knob touches the master-exit seam gate. + +## Companion Files + +- `lenses.md` — the four job lenses for the scoping seats. +- `roles/…` — the six self-contained role lifecycles (the registry above). +- `templates/…` — turn-report · worker-brief · manager-brief (`ROLE BRIEF — manager`; the + orchestrator compiles a manager's session start from it) · master-handover-packet · + conversation-handover-packet · verdict · impact-analysis · onboarding-coherency · + deep-research-report · orchestration-task (the strategist's sprint plan). Spawning seats compile + briefs FROM these; sub-agents fan out and fill them, so analysis survives compaction. +- `criteria/…` — the reviewer criteria catalogs (code-seam · doctrine · onboarding-memory · + report-verification · plan-review), the review test bench the three-party loop binds; maintained + through the promotion ratchet, never made up on the spot. + +## The Super Integration Branch (orientation only — the doctrine lives with its owner) + +``` +main + └── super-integration (orchestrator-owned, off main) + ├── master-A branch (off super) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, C-11) + ├── master-B branch (off the moved super — sees A) + └── … final: super → main PR + memory carry-over + push +``` + +The full topology — dependency-ordered dispatch, the integration-duty procedure, the two +conflict-resolution modes, leaf moves — lives in **`roles/orchestrator.md`** and only there. + +## Credits + +This skill absorbs and supersedes `l-01-session-job-lifecycle` and `l-02-agent-orchestration` +(converged 2026-07-05: lifecycle and job are one entity — one lifecycle per agent type). The +orchestration vocabulary adopts the parked `260619_agentic-control-plane` spec — jobs as +model-interpreted markdown (D6), the knob block (D7), role + lens in one file (D10), the +ambient-singleton rule (D11), per-harness variants (D12), the judge rung, short-lived workers with +structured handoff, dev-talks-to-one-orchestrator (D15) — which in turn credits **Archon** and the +**agent-control-plane** project (D14); that credit carries forward. + +## Relationship To Other Instructions + +This skill extends — never replaces — the coordinator `AGENTS.md`, the `w-02-light-task-workflow` +task format, and the memory layer (`c-…` skills). Each `roles/.md` is self-contained for its +seat; read exactly the one the router selects. diff --git a/.agents/skills/l-01-agent-lifecycles/criteria/code-seam.md b/.agents/skills/l-01-agent-lifecycles/criteria/code-seam.md new file mode 100644 index 00000000..053feb1b --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/criteria/code-seam.md @@ -0,0 +1,85 @@ +# Criteria Catalog — Code-Seam Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review wires code seams: consumers, enforcement points, gates, addresses, tool contracts. +Binds at the master-exit and super-exit seams and in any loop review whose change set touches code +(see the binding table in `../roles/reviewer.md`). Criteria are never made up on the spot: the +standing list below is the regression floor, run every time; the exploratory mandate and the +promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### CS-1 — Production-wiring walk + +**Trace the real call path, never a hand-aligned harness.** A claim that a consumer or an +enforcement point exists must be walked through the PRODUCTION call path — the controller, the +tool registration, the store fold — not through a test that hand-assembles the pieces into +alignment. A test can pass while the production consumer is inert. + +- Catching evidence: 260703-L8 review 3 (AR3-1) — the integrate consumer was proven **inert**: the + policy was omitted at the controller and the gate was looked up on the wrong lifecycle, while a + hand-aligned test passed (L8 decision log, cycle-6 entry). + +### CS-2 — Fail-open hunt + +**What happens when the address/config is absent or mistyped?** For every identity, address, key, +or config the seam matches on: feed it nothing, feed it a near-miss, and confirm the seam fails +CLOSED (refuses) rather than open (silently proceeds unmatched). + +- Catching evidence: 260703-L8 review 4 (AR4-1) — the seam's `enclosure` address had to be pinned + as an exact-string contract and the enclosure-less raise made a refusal (L8 decision log, + cycle-7 entry). + +### CS-3 — Validate-then-mutate + +**Every raise/write validates before it mutates.** A call that records state (a gate raise, a +store append, a contract write) must perform its refusal checks before any durable effect; a +mutation that precedes validation leaves half-states behind on refusal. + +- Catching evidence: 260703-L8 cycle 6 — the `wait=false` raise was reworked to be + validate-then-mutate and seam-kind-restricted (L8 decision log, cycle-6 entry). + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### CS-4 — Reused-primitive affordance parity *(candidate — 1 catch)* + +**When a screen reuses a shared content primitive, verify every branch of the ORIGINAL's +affordances (banners, status chips, truncation notices, error states) still fires on the reuse +path.** A dropped affordance is a silent regression the reuse's own tests won't catch — they +assert the new screen's happy paths, not the primitive's full surface. + +- Catching evidence (single engagement): 260703-L17 review (L17R-2) — the notes reader's + `DualPane` reuse drops the "first 2 MiB" truncation banner on the markdown path (the banner + lives in `CodeSide`, which markdown never reaches); text and binary keep it. + +### CS-5 — Cross-repo side-effect safety *(candidate — seeded from a clean exemplar, 0 catches)* + +**Any step that writes to a repository OTHER than the one it operates in gets the full +validate-then-mutate treatment plus partial-failure and dirty-target analysis.** Check the order +of validation vs the foreign write, the state left behind when the write lands but the caller +fails afterward, behavior against a dirty target repo, and an exact format round-trip with the +foreign artifact's consumer. + +- Seeding evidence: 260703-L18 finding 7 (`_reconcile_missing_mapping` writing the official + memory repo's ledger mid-`worktree_start`) PASSED all four lenses under this analysis — the + clean exemplar that defined the class. A catch in a later engagement promotes. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS change set the catalog does not name yet. Every novel finding-class that survives +refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.agents/skills/l-01-agent-lifecycles/criteria/doctrine.md b/.agents/skills/l-01-agent-lifecycles/criteria/doctrine.md new file mode 100644 index 00000000..9b9ccae1 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/criteria/doctrine.md @@ -0,0 +1,58 @@ +# Criteria Catalog — Doctrine Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review is doctrine: skill files, role lifecycles, templates, instruction surfaces, docs +that agents obey. Binds whenever doctrine/skill files are in the change set (see the binding table +in `../roles/reviewer.md`). Criteria are never made up on the spot: the standing list below is the +regression floor, run every time; the exploratory mandate and the promotion ratchet keep the +catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### D-1 — Doctrine-vs-code anchoring + +**Every "X enforces Y" needs a code anchor.** A doctrine sentence claiming enforcement, refusal, +or automatic behavior must resolve to the code that does it (file + mechanism). Doctrine that +narrates enforcement which does not exist is a defect, not an aspiration. + +- Catching evidence: 260703-L8 review 1 (AR-5) — `requireReviewerVerdictAtSeams` was documented as + binding while the flag was **inert**; the finding forced the wiring (L8 decision log, AR-1 + entry: "closing AR-5's inert flag"). + +### D-2 — Cross-file contradiction sweep + +**Sweep sibling doctrine for statements the change set now contradicts.** A doctrine change is +reviewed against the whole doctrine surface (skills, role files, templates, docs, hooks, canvas +prose), not just the edited files — one file's new invariant is another file's stale sentence. + +- Catching evidence: 260703-L10 — the landed "chat is never a build route" invariant contradicted + surviving chat-build wording inside `c-09` / `w-02` (builder escalation 1, owner-sanctioned + sweep; L10 builder report). + +### D-3 — Stuck-state walk + +**Can an agent following the prose deadlock?** Walk the doctrine as the obeying agent: at every +wait, gate, and handover, ask who unblocks it and through which channel. Prose in which two seats +each wait on the other — or a seat waits on a channel nobody is told to serve — is a blocking +finding. + +- Catching evidence: 260703-L8 review 2 — the seam deadlock: the manager's blocking raise and the + orchestrator's decide path could not meet as written; the ruled `wait=false` + + packet-carried-gateId channel resolved it (L8 rounds 2/4b history). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS doctrine change the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.agents/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md b/.agents/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md new file mode 100644 index 00000000..e47783e3 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md @@ -0,0 +1,67 @@ +# Criteria Catalog — Onboarding/Memory Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run over the +memory side of a change set: sidecars, route overviews, route indexes, update histories. Binds at +the master-exit and super-exit seams (the onboarding-vs-code lens) and in loop reviews whose change +set carries onboarding (see the binding table in `../roles/reviewer.md`). Criteria are never made +up on the spot: the standing list below is the regression floor, run every time; the exploratory +mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### OM-1 — Staleness diff vs as-landed code + +**Diff every body claim about current behavior against the as-landed code.** A sidecar or overview +body that describes the present tense is checked against what the branch actually ships — deleted +things still described, renamed things under old names, duplicated rows. + +- Catching evidence, two separate engagements: 260703-L8 cycle 6 (owner follow-up pass) — route + overview bodies still described **deleted canvas models** (the panels overview's build-job/frame + tail) and carried **duplicated table rows** (the tools and controlplane overviews' Layout + tables), durably recorded in those overviews' own 2026-07-05T19:25 Update History entries; + 260703-L10 — the flowModels sidecar body was still the pre-convergence 8-model census and its + references row still said "8 models" (the sidecar's 2026-07-06T12:05 history entry + L10R-3). + +### OM-2 — History-only-update detection + +**"Refreshed" must mean a genuine body edit.** An onboarding file whose only change is a new +Update History line has NOT been refreshed — the body still asserts the old truth. Check that +every claimed refresh touched body sentences, not just the history list. + +- Catching evidence: 260703-L8 cycle 6 — the builder reported route overviews as refreshed when + they were **history-only**; the closeout body gate caught it (L8 decision log, cycle-6 entry: + "report-vs-artifact verification belongs in the reviewer criteria catalog"). + +## Candidate Criteria (seeded exploratory — one catching engagement; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### OM-3 — Newest-first with the checker's own semantics *(candidate — 1 catch)* + +**Update History sorts newest-first under the CHECKER's datetime parse, not lexicographically.** +The quality checker compares naive timestamps as-is and folds tz-aware stamps to UTC; a merge or +mechanical insert that sorts by string can pass the eye and fail the gate (or worse, pass the gate +in the wrong order). Verify ordering with the checker's semantics. + +- Catching evidence (single engagement): 260703-L11 — four onboarding history collisions from the + parallel wave had to be re-sorted **with the checker's own datetime semantics** (naive compare + as-is, tz-aware folds to UTC); the quality gates caught the owner's wrong sort key (L11 decision + log). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS memory delta the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate is the working example, and it is THIS catalog's own OM-2 mechanized: the gate catches + history-only "refreshes" at commit time, where prose requests did not. diff --git a/.agents/skills/l-01-agent-lifecycles/criteria/plan-review.md b/.agents/skills/l-01-agent-lifecycles/criteria/plan-review.md new file mode 100644 index 00000000..ef4d2d90 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/criteria/plan-review.md @@ -0,0 +1,69 @@ +# Criteria Catalog — Plan Review (the strategist loop) + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run against an +**orchestration task** (`../templates/orchestration-task.md`) — the strategist's sprint plan — +before the developer's drawing board. This is the portfolio loop's review type: owner = +orchestrator, builder = strategist, reviewer = this catalog. The reviewer holds the same read-only +analysis tools the strategist used (`cgc_*`, `grepai_*`, `read_ar_files`), so the plan's mechanical +claims are re-derivable, not just readable. Criteria are never made up on the spot: the standing +list below is the regression floor, run every time; the exploratory mandate and the promotion +ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### PR-1 — Refute uncited edges + +**An uncited dependency edge is refutable by default.** Every edge in the dependency graph must +carry evidence — a cgc/grepai query, a file, a decision-log entry, a design-section citation, or +(for new surfaces) a declaration cross-reference naming both leaf declarations. An edge with no +evidence is challenged as a finding; so is evidence that does not actually support the edge's +direction or kind. + +### PR-2 — Missed-shared-surface hunt (class-completeness on intersections) + +**Re-intersect the surface lists independently.** Take the plan's per-leaf touch surfaces (both +existing and declared-new), recompute the pairwise intersections, and hunt pairs the edge list +omits — including CONFLICT-risk at a shared parent route where two leaves declare additions +(wiring points, shared registries). A plan that lists surfaces but misses one of their +intersections has a hole exactly where collisions happen. + +### PR-3 — Blast-radius re-derivation + +**Re-derive at least the HIGH-blast-radius entries with the cgc tools** (`cgc_dependencies` / +`cgc_callers` / `cgc_callees`, capped depth) — and spot-check a sample of the low/medium entries. +A register entry whose derivation cannot be reproduced, or whose classification drops the doctrine +propagation / migration / user-visible unions, is a finding; the register parameterizes every +downstream loop tier, so an understated radius under-reviews a leaf. + +### PR-4 — Order-respects-edges + +**Check the sprint order/waves against the edge list, mechanically.** No ORDER edge may run +backwards across the proposed sequence; every CONFLICT edge must be resolved by serialization or a +recorded leaf move (from→to + rationale); parallel waves may contain only INDEPENDENT pairs, and +the wave plan must acknowledge the landing-reconciliation cost. + +### PR-5 — Honesty of the findings section + +**Verify the plan's failure claims both ways.** Every "unplannable as scoped" finding must be +genuine (the leaf can name neither existing surfaces nor the parent anchoring of its additions — +a merely not-yet-existing surface is NOT unplannable); and thin leaf scopes the plan silently +guessed around instead of flagging are themselves findings. Quo-vadis contradictions must be +flagged at the top of the coherence findings, not buried. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS plan could be wrong that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example; PR-4 is this catalog's mechanization candidate (a topological check over + a structured edge list). diff --git a/.agents/skills/l-01-agent-lifecycles/criteria/report-verification.md b/.agents/skills/l-01-agent-lifecycles/criteria/report-verification.md new file mode 100644 index 00000000..fb3bdda8 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/criteria/report-verification.md @@ -0,0 +1,95 @@ +# Criteria Catalog — Report Verification + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) — and the loop OWNER +verifying a builder round — MUST run over every report, claim, and summary in the change set: +builder reports, owner claims, handover packets. **Standing from day one** in every review type: +report-vs-artifact caught real defects in three separate engagements before this catalog existed. +Criteria are never made up on the spot: the standing list below is the regression floor, run every +time; the exploratory mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### RV-1 — Report-vs-artifact on EVERY claim + +**Open the artifact behind every claim.** A report sentence asserting "X was done / is green / +was refreshed" is verified against the artifact itself, not trusted — claim by claim, no sampling +of the load-bearing ones. + +- Catching evidence, three separate engagements (260703-L8): review 3 caught a **hand-aligned + test** behind a wiring claim; cycle 6's closeout gate caught **"refreshed" overviews that were + history-only**; review 4 caught the **OWNER's own canvas overclaim** (L8 decision log, cycle-7 + entry) — builder reports and owner claims fail the same way. + +### RV-2 — CLASS-completeness *(promoted to standing at 260703-L18 — 2 catches)* + +**Hunt the siblings of every found instance.** A finding or a fix names an instance of a CLASS +(a directive surface, a census count, a vocabulary token). Enumerate the class — every sibling +surface, not just the instances the report names — and check each one. + +- Catching evidence: (1) 260703-L10 round 1 — the reviewer's completeness sweep found **six of + ten first-action surfaces** still shipping the retired directive when the report claimed the + flip done (L10 decision log). (2) 260703-L18 review (L18R-3) — the fix for + advertised-but-unimplemented recovery choices named the `cli.py` `custom` residual but missed + the SIBLING `_load_memory_ledger` block still advertising an inert `reconciliation`; the + sibling hunt found it. + +### RV-4 — Decision-log completeness for scope-expanding disclosures *(promoted to standing at 260703-L18 — 2 catches)* + +**A scope-expanding owner supplement or load-bearing builder disclosure must be verifiable in +the task-doc decision log, not only the builder report.** Continuity lives in the task_doc + +durable artifacts, never in transcripts; a ruling or environment finding that exists only in a +report is one lost file away from unrecoverable. Cross-check every supplement and disclosure the +builder report carries against the decision log. + +- Catching evidence: (1) 260703-L17 review (L17R-1) — supplement 2 (the wait-loop-era remnant + sweep with per-hit verdicts and two named follow-ups) was recorded only in the builder report. + (2) 260703-L18 review (L18R-4) — the load-bearing editable-install/PYTHONPATH environment + finding + named follow-ups lived only in the builder report; the leaf's `decisions[]` was + empty. Both folded by the owner at closeout. + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### RV-3 — Partial-fix-creates-falsehoods *(candidate — 1 catch)* + +**Verify claims ABOUT the changed artifacts, not only the artifacts.** A partial fix can turn +previously-true sentences elsewhere false (docs describing the artifact, install guides quoting +it, counts referencing it). Sweep for statements about what changed and re-verify their truth +after the change. + +- Catching evidence (single engagement): 260703-L10 round 1 — the partial hook flip made **two + install-doc claims false** ("injects the same startup directive" no longer held); round 2 + restored byte-identity so the claims became true again (L10 decision log + builder report). + +### RV-5 — Worktree-shadowed regression pins *(candidate — 1 catch)* + +**A regression test must bite under the invocation the owner actually runs.** An editable +install pointing at another checkout can shadow the worktree's sources, making a mutation-tested +pin pass vacuously under the canonical invocation while failing only under a hand-set +`PYTHONPATH`. Verify sensitivity by mutating the target and running the CANONICAL invocation; +a pin that only bites under a nonstandard environment is not yet a pin. + +- Catching evidence (single engagement): 260703-L18 review (L18R-1) — the inbox + delivered/unconfirmed pin failed its mutation check only under `PYTHONPATH=src`; under the + canonical `pytest mcp/tests` the main-repo editable install shadowed the worktree and the + mutated code still passed. Remedy: the `sys.path` pin idiom the sibling suites carry. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS report could mislead that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests (RV-1 is itself the precedent: promoted on three catches). Promotion is proposed in the + verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.codex/skills/l-01-session-job-lifecycle/job-variants.md b/.agents/skills/l-01-agent-lifecycles/lenses.md similarity index 82% rename from .codex/skills/l-01-session-job-lifecycle/job-variants.md rename to .agents/skills/l-01-agent-lifecycles/lenses.md index 48f032c6..0f277b06 100644 --- a/.codex/skills/l-01-session-job-lifecycle/job-variants.md +++ b/.agents/skills/l-01-agent-lifecycles/lenses.md @@ -1,7 +1,9 @@ -# l-01-session-job-lifecycle Job Variants — The Lenses +# Lenses — How the Scoping Seats Read a Job -The job type is a **lens**, picked during `reframe-research` and re-pickable at any time. It is not a gate and it -never changes the spine (`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three +Read by the **scoping seats** (orchestrator, designer); a dispatched role never picks a lens — its +brief already carries the flavor. The job type is a **lens**, picked during `reframe-research` and +re-pickable at any time. It is not a gate and it never changes the orchestrator phase axis +(`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three things only: - **Opening move** — the first concrete thing `reframe-research` does for this kind of job. @@ -25,8 +27,8 @@ invariant the bug violates. Defaults to a build; the fix lands through `decide - Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the -contracts the feature must respect. Defaults to a build; size decides chat vs durable `w-02-light-task-workflow` task at -`decide`. +contracts the feature must respect. Defaults to a build; size decides the minimal `w-02-light-task-workflow` artifact vs a master + +sub-task series at `decide`. ## triage diff --git a/.agents/skills/l-01-agent-lifecycles/roles/designer.md b/.agents/skills/l-01-agent-lifecycles/roles/designer.md new file mode 100644 index 00000000..c67cec40 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/roles/designer.md @@ -0,0 +1,91 @@ +# Lifecycle — Designer (the hat) + +> The design lifecycle the **orchestrator pulls inline** whenever design is needed — front of the +> pipeline or mid-flight. **A hat, not a seat**: it cannot sit in a coordination leaf because the +> task is what it exists to create — no leaf, no worktree, no branch, no spawn required. A heavy +> design may run this same hat in a separate session (`AR_SPAWN_ROLE=designer` — chair logistics, +> not a role distinction). +> +> Drawn as the **DESIGNER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Hat Is + +Task design is **its own job** (developer decision 2026-07-04). Before orchestration one implicit +do-it-all role did design, features, and fixes; the roles now diversify, and design routes +**through the orchestrator, which wears this hat** — at the front of the pipeline AND mid-flight +(most leaves of a live series are designed mid-flight). It is the `tasks/AGENTS.md` collaboration +doctrine (meta-questioning, reframe-before-execution, evidence-first) given a distinct, optimized +shape as a job. Nothing here assumes a master exists yet — producing one is the point. + +The designer shares the orchestrator's **bird's-eye toolkit** — route indexes, onboarding, the +`grepai_search` MCP tool, the code-graph (`cgc_*`) MCP tools, blast-radius analysis — but is **scoped +to one master**. Collisions with *other* — especially **future** — masters can slip past a +single-master view. That residual risk is **owned downstream, not here**: at portfolio streamlining the +**orchestrator doubles as the designer's adversarial reviewer** (planned-vs-planned and +planned-vs-past). The designer's duty is to *declare* the limit, not to close it. + +## Lens + +- **Opening move:** meta-question the ask. Surface the request, the deeper objective, and the + highest-leverage framing before any structure exists — do not jump from the developer's first + phrasing to a plan. +- **Retrieval lean:** evidence-first, within the master's scope. Route indexes and onboarding for the + map; `grepai_search` for semantics; `cgc_*` for relationships/impact; bounded `read_ar_files` for + intent confirmation. Sub-agents fan out and write durable reports. +- **Decide default:** a `w-02-light-task-workflow`-shaped master + leaf task_doc, handed into the + portfolio — **not** a build. The designer designs; it does not implement. + +## Duties + +1. **Reframe with `tasks/AGENTS.md`.** Distinguish surface request · deeper objective · highest-leverage + framing · assumptions · boundaries · invariants · truth gaps. Material scope/intent/sequencing + changes are **played back and wait for confirmation**; a pure clarification may be presented and + continued. +2. **Evidence-first, master-scoped.** Make the evidence model visible before or alongside the plan + (external · repo-internal · cross-repo · executable). Gather it through the + `c-04-retrieval-strategy-router` skill, not ad-hoc reads. +3. **Blast-radius WITHIN the master.** Routes touched · invariants at risk · regressions — bounded to + this master's scope. Cross-master and future-master reasoning is explicitly out of the designer's + reach. +4. **Author the task_doc.** Master + leaves (requirements · steps · code examples per distinct change, + the `w-02-light-task-workflow` shape), leaves scoped around routes/areas, via the `task_doc` MCP + tool. Include a **code example for every distinct change** when code is in scope. + Decision-needing questions land in the task doc's `openQuestions` — the rendered decision + surface; `notes/` carries the analysis behind them. +5. **Declare the designer limit.** Record on the doc that this is a **master-scoped bird's-eye**: + cross-master and future-master collisions can slip and are owned downstream at streamlining. Never + hide the limit. +6. **Ask, never fill silently.** Assumptions and truth gaps only the developer can resolve are asked as + a short, high-leverage list — never filled silently. + +## Artifact Obligations + +- The **task_doc** (master + leaves) is the durable artifact of the designer job. +- A **designer-limits note** on the doc — the declared master-scoped blind spot, for the orchestrator's + later adversarial pass. +- Evidence reports from fan-out sub-agents (durable), so the framing survives into streamlining. + +## Comms Protocol + +- **Primary channel:** the developer, directly, in the designer's attached chat — this seat is a + co-thinking loop, so the developer is the standing interlocutor here (unlike the deeper seats, which + relay through the ladder). +- **Handover:** the finished design **joins the portfolio**. At streamlining the orchestrator + adversarially reviews it; hand the task_doc + the designer-limits note over via the inbox + (`operator_inbox_post`) and, for a hosted orchestrator, stdin push. +- **Escalation:** the hat's "escalation" is simply the handover into the portfolio job — the + orchestrator that wears it is already the last resolver before the developer. + +## Knobs + +| Knob | Default | Notes | +| ------- | ------------------ | --------------------------------------------------------------------- | +| harness | (the wearer's) | the hat runs inside the orchestrator session, or a spawned design chair | +| model | high-reasoning | reframe + blast-radius reasoning wants a strong model | +| effort | high | design leverage justifies the thinking budget | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | bird's-eye toolkit | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · inbox | + +Settings.json `orchestration.roles.designer` overrides these, and `orchestration.rolesPerLevel..designer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.agents/skills/l-01-agent-lifecycles/roles/manager.md b/.agents/skills/l-01-agent-lifecycles/roles/manager.md new file mode 100644 index 00000000..0b42124a --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/roles/manager.md @@ -0,0 +1,168 @@ +# Lifecycle — Manager + +> One master, one seat, self-contained. The manager lifecycle drives exactly one master series: +> spawn a fresh worker per leaf, review turn reports, decide the delegated leaf gates, close out and +> integrate each leaf, hand the completed master to the orchestrator through the master-exit seam. +> Your **brief is your session start**. +> +> Drawn as the **MANAGER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**One per master task.** Spawned by the orchestrator with the master's context packet. It owns its own +coordination leaf + chat (**no worktree**) and drives exactly one master series: spawns/respawns a fresh +worker per leaf, reviews turn-report artifacts, decides **delegated** leaf gates, integrates leaves into +the master integration branch via the `c-11-memory-carryover-from-branch` skill, and hands the completed +master to the orchestrator through the master-exit adversarial seam. + +The manager owns the leaf lifecycle machinery **end-to-end**: `worktree_start` → (the worker +builds) → closeout preview/apply (deciding the delegated gates per the gate policy) → +`worktree_integrate` → finalize — task-doc statuses via the finalizer, **steps checked by this +seat by hand** (the tool does not reconcile checkboxes). The worker's terminal +state is checks-green + turn report; everything after that is this seat's. + +**Flat-run note:** in a flat series (no managers spawned) the **orchestrator wears this hat** — +same duties, same artifacts, one chair. + +A manager has **no bird's-eye view** — it sees one master, not the portfolio. That boundary shapes +everything below. + +## Lens + +- **Opening move:** read the master `task_doc` + its leaf docs; order the leaves (parallel where safe — + the C-11 reconcile absorbs a moved base). +- **Retrieval lean:** intent-confirmation on the master's own routes (paired `read_ar_files`); the + breadth/blast-radius reasoning belongs to the orchestrator, not here. +- **Decide default:** dispatch the next ready leaf; the master exits through the master-exit seam. + +## The Default-Behavior Rule (read this before anything else) + +The **default agent behavior stands**: **fulfill the task, fill small blanks.** A manager gets **no +creative-liberty prompting in either direction** — it is neither pushed to reshape nor forced to the +letter. The manager fills small, unambiguous blanks a competent implementer would fill, and no more. + +> **The spirit test does NOT apply to this seat.** It is orchestrator-only. A manager's changes can +> collide with what it cannot see, so a **plan delta beyond blank-filling escalates to the +> orchestrator** — the manager does not reshape plans. This is not a licence to be timid and it is not a +> licence to be creative; it is the ordinary "do the task well, ask when the task itself is in +> question" default, with the ask routed **up the ladder to the orchestrator**, never to the developer. + +## Duties + +### 1 — Seat & intake + +Take the master's own coordination leaf (`task_doc`, no enclosure); the chat is attached so the +developer can walk in any time. Read the master + leaf docs; order the leaves. + +### 2 — Leaf dispatch loop (per leaf) + +- **Score the leaf's loop tier at dispatch** (loop doctrine: `../SKILL.md`, The Three-Party Loop): + blast radius · novelty · size → **direct** (NO loop machinery: the leaf's worker implements as + usual — worker self-check + checks ladder + this seat's ordinary artifact review; this seat + still dispatches per leaf and never grows a build surface) | **builder-verified** (the worker + implements; this seat additionally verifies its report claim-by-claim against the artifacts; no + reviewer) | **full loop** (worker + independent reviewer rounds). When an orchestration task + exists, its **blast-radius register is the scoring input**. Record the mark (tier + scope: + manager | orchestrator — the owning level runs the loop with ITS agent set) on the leaf doc with + a decision-log entry. **A master whose leaves all score `direct` is a workflow-free manager** — + no loop machinery, just the dispatch-review-integrate spine below. +- On a full-loop leaf, run the loop with this level's controls: a round = implement → review; + **hard cap 3 full rounds** (delta-verifies by the SAME reviewer close rounds, they do not count; + fix rounds resume the SAME builder); **every round must shrink the finding set** — a + non-shrinking round escalates to the orchestrator immediately, with the full round history + attached, regardless of the count. +- `spawn_agent_session(worker)` — a **fresh session** on the leaf: the brief (compiled from + `../templates/worker-brief.md`) is pasted + submitted, with `env={"AR_SPAWN_ROLE": "worker"}` and + the **qualified** leaf key `//`; the worker edits inside the leaf + worktrees the brief names. +- **Monitor the worker** — a turn-report artifact is expected at **every** hand-off. Inactivity or a + missing artifact → a **rate-limited stdin nudge** (logged as an event, never spammy). Escalation + intake via the inbox. +- **Review artifact vs `task_doc`** — completion vs requirements/steps · checks green · + onboarding refreshed in the same pass (the manager's own leaf-level review; **this is not an + adversarial seam**). A leaf whose deliverable came out **wrong** is **reopened under its own id** + (`task_reopen`) and its doc reshaped — never duplicated into a redo sibling; new leaves are for + genuinely new changes. +- **Delegated leaf gates (plan · closeout)** — decide the leaf's delegated gates, **attributed** + (`decidedBy: `, `decidedVia: orchestration`), appended and dashboard-visible. The + **owning agent never self-approves; a distinct configured role may** — that configured role is the + manager. (Enforced as-built by the gate policy: `orchestration.gateDelegation` in settings, + `controlplane/gate_policy.py` — human-pinned kinds stay human, decisions attributed.) + Your own hand-off idiom, this seat only: durable gates + inbox posts — you never call the + developer-facing notification; your counterparty is the orchestrator. +- **Integrate leaf → master branch** via the `c-11-memory-carryover-from-branch` skill (ff-only / replay + per the `c-09-git-worktree-manager` skill). Know the human-pinned gate kinds by name: + `integration-approval`, `push-approval`, `cleanup-approval` — none is ever delegable. When a + durable `integration-approval` gate is raised on this step it awaits the **developer** (via the + dashboard GateResponder or your attached chat — you do not relay; if the wait blocks the loop, + escalate to the orchestrator). Absent a durable gate, the **series' standing approval** governs: + the developer's portfolio-gate approval of this series, recorded in the planner master's + decision log, covers dependency-ordered leaf integrations. Loop until the master's leaves are + done. + +### 3 — Master-exit seam + +When all leaves have landed on the master integration branch, spawn the **adversarial reviewer** +(master-exit) via `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "reviewer"}` and the reviewer +role file (`roles/reviewer.md`), passing the master branch ref, +master/leaf task docs, worker turn reports, decision logs, changed paths, resolved +`system/tools.md` evidence, and carry-over state. The verdict lands at +`notes/reports/-master-exit-verdict.md` and attaches to the handover gate as +`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"pass|pass-with-notes|block"}]` +— a verdict over completion vs task docs · `system/tools.md` quality · onboarding-vs-code. **Blocked? → the verdict decomposes into fix leaves** the manager dispatches (loop +back to the leaf loop). Verdicts are **evidence, not decisions**. The seam channel, exactly: +**raise without blocking** — `lifecycle_gate(kind="master-handover-approval", +enclosure="", evidence_refs=[], wait=false)` (raise-and-continue +is allowed precisely because the kind is a delegated seam kind; the `enclosure` MUST carry the +master's identity — it is the address integration enforcement matches the gate by, and the match +is exact-string: pass the EXACT master task name as the contracts carry it (`worktree_start`'s +`task_name`) — the raise refuses without an enclosure; the call +returns the **gateId**); then **carry that gateId in the handover +packet** (§4) — the packet is the orchestrator's trigger AND its address for the gate. Under an +all-human policy the raise blocks and the developer decides — do not pass wait=false. Identity +truth, as-built: the gate pins to your ambient lifecycle when you raise it; the deciding +orchestrator resolves the gate **by the packet-carried gate id** (gate ids are model-visible — +only LIFECYCLE ids stay server-side) and its own ambient identity becomes `decidedBy`; +owner-never-self-approves holds by construction. A handover carrying serious issues the +orchestrator cannot answer on its own escalates up the ladder (orchestrator → developer). + +### 4 — Handover to the orchestrator + +Post the **master-handover packet** (`../templates/master-handover-packet.md`) — inbox (durable) + stdin +push — integration branch ref · change-set summary · verdict ref · **handover gateId** · +carry-over state. The seat (chat + coordination leaf) **stays reachable** until the series +retires; your raised gate stays open until the orchestrator decides it (poll `gate_list` on your +own lifecycle if you need its state). + +## Artifact Obligations + +- The **master-handover packet** at master exit (the manager's primary durable artifact). +- Leaf-review notes (completion vs task_doc) — lightweight, on the master's coordination leaf. +- Delegated-gate decision records (attributed). + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down to workers, escalation + intake up from workers, handover up to the orchestrator; all durable + dashboard-visible. +- **Stdin push** — nudges and messages delivered into hosted worker sessions; poll is the fallback. +- **Escalation** — **up to the orchestrator, never straight to the developer.** A stumped manager, and + any plan delta beyond blank-filling, raises to the orchestrator. The manager resolves within its own + master's view first. A loop that hits the 3-round cap or stops converging escalates **with the + full round history attached**. **Quo-vadis test:** a question that is a **high-blast-radius + truth** — answered wrong it means big rewrites later, not a cosmetic choice — is flagged as + quo-vadis when raised, so the orchestrator relays it to the developer immediately instead of + absorbing it; presentation-grade choices are never escalated — decide and log. + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ---------------------------------------------------------------- | +| harness | claude | default preference only — settings picks the actual harness | +| model | mid-reasoning | leaf review + coordination; strong but below the orchestrator | +| effort | medium | one master's scope, not the portfolio | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | coordination + review + leaf lifecycle | `task_doc` · `read_ar_files` · gates · `spawn_agent_session` · worktree lifecycle (start · closeout · integrate · finalize) · C-11/`c-09` · inbox | + +Settings.json `orchestration.roles.manager` overrides these, and `orchestration.rolesPerLevel..manager` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.agents/skills/l-01-agent-lifecycles/roles/orchestrator.md b/.agents/skills/l-01-agent-lifecycles/roles/orchestrator.md new file mode 100644 index 00000000..90a5e06a --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/roles/orchestrator.md @@ -0,0 +1,377 @@ +# Lifecycle — Orchestrator + +> The developer-facing lifecycle: an **event loop over durable portfolio state**, not a +> request-to-close pipeline. Each turn routes the incoming event — a developer message, a worker +> report, a verdict, the orchestrator's own finding — into one of **three jobs** (Design · +> Portfolio · Orchestrate) under one roof, with solo work as the same jobs run with hats collapsed. + +## What This Seat Is + +The developer's single point of contact and the only seat with a standing developer relay +(managers/workers stay reachable via their attached chats). It owns the design conversation, the +portfolio bird's-eye, dependency-ordered dispatch, the super integration branch, the **spirit +test**, and the **integrity bulwark** against "fixed one thing, broke two others." + +Its real state is the **task tree** — masters, leaves, statuses, decision logs, `openQuestions`, +contracts — never the transcript. That is why sessions can die, compact, and resume without losing +the run. Its analysis substrate is the **memory system** (route indexes, onboarding, +`grepai_search`, `cgc_*`); **orchestrator quality ∝ memory-repo quality**. Its durable notes and +reports are the most important artifacts in the system: only this seat sees the whole picture. + +## The Event Loop + +**Opening move, every session — new or resumed** (resumption is the common case, not the +exception): + +1. **Trust checkpoint** (below), then `lifecycle_start` (the frame's fleeting lifecycle). +2. **Portfolio orientation:** read the portfolio state — what exists, what is in flight, what is + blocked on whom, what awaits the developer — and **say it back**. +3. **Route the event** by what exists and what is asked: + +| Condition | Job | +| --- | --- | +| No task doc exists for the ask (or a planning-status doc needs reshaping before work) | **D — Design** | +| Designed masters exist; coherence/conflicts/order in question, or "orchestrate these" | **P — Portfolio** | +| An approved task/series is ready for implementation | **O — Orchestrate** | +| The ask changes no code (a question, an investigation) | **research-only exit** — deliver the answer; chat is the right medium; no worktree, no task artifact | + +**Profile check (takeover).** Before heavy work in any job: if this session's harness/model/ +effort is wrong for the run (resolved: role file < settings), spawn the right chair — +`spawn_agent_session` with `AR_SPAWN_ROLE=orchestrator` + a conversation-handover packet +(`../templates/conversation-handover-packet.md`) — and hand over; the developer still talks to +ONE orchestrator at a time. + +Several jobs can be active across a day; the loop routes per event. The frame's phase axis stays +the observable `lifecycle_phase` vocabulary (`reframe-research` ≈ D, `decide` ≈ P, `build`/`close` +≈ O); the jobs are the decision structure. + +## The Invariant Ladder + +``` +task doc (approved) → branch (intent) → worktree (only where something is built) +``` + +- **Design and Portfolio never touch git.** Nothing is being built there. +- **Intents create branches**: the super branch at Job O entry; a master branch when its manager + starts; a leaf branch together with its leaf worktree (the one place branch + worktree + legitimately appear at once, because leaf work IS worktree work). +- **Worktrees exist per build/integration edge** and are reclaimed after. +- **Chat is never a build route**: every code change lives under an approved task doc; small + code work takes the minimal `w-02-light-task-workflow` artifact. Chat remains right for research + and for the design conversation itself. + +## Trust Checkpoint (shared opening detail) + +1. `context_packet(repo_id="", include_providers=true, include_drift=true, + include_freshness=true)`. +2. Report the packet facts before relying on memory or providers: repository/branch/dirty state; + memory + onboarding roots; provider state; drift status and actionable count; branch freshness + (`behind`/`diverged` → fast-forward the local official line first; + `ledgerMapsCodeHead=false` → carryover or the right memory branch first). +3. Drifted/missing/orphaned onboarding on committed, non-dirty source: **ask the developer** before + refreshing via `c-05-create-or-update-onboarding-files` — drift handling is approval-gated. + Drift tied to dirty source is active work-in-progress, not maintenance. +4. Providers stopped/degraded: run the matching provider/runtime operations, re-check, report; + `indexing` means healthy-but-busy (partial results). + +When this seat spawns a role it compiles the trust facts into the brief — a spawned role does not +repeat this checkpoint. + +## Hand-Off Protocol — Dry-Run → Notify-And-Stop → Report + +Every developer hand-off (design acceptance, portfolio plan, worktree intent, commit, push, +integration, cleanup/finalization, any dev-wait) is three actions, never one. Carve-out (ruled +2026-07-06): in an orchestrated run, leaf→master and master→super integrations ride the series' +**standing approval** — no per-edge developer hand-off; the developer hand-off concentrates at the +super PR/carry-over gate (see Super exit & landing tail). The table's integration row governs when +a hand-off DOES happen (solo runs; a raised durable gate): + +1. **Dry-run** the pending mutation and self-fix failures before reporting. +2. **Notify:** `lifecycle_turn_end_notification(summary=…)` as the **last tool call**. +3. **Report:** the complete packet as final prose, the decision handed over as the last line — + then STOP. The next turn's first AR call auto-resumes. + +| Junction | Parked durable gate `kind` | Hands off via | +| --- | --- | --- | +| design acceptance / plan gate | `plan-approval` | this lifecycle | +| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | +| commit / closeout | `closeout-approval` | `c-12-closeout` | +| push | `push-approval` | this lifecycle / `c-09` | +| integration | `integration-approval` | `c-09` / `c-12` | +| cleanup / finalization | `cleanup-approval` | `c-09` / `c-12` | +| any other dev-wait | `agent-question` | this lifecycle | + +`closeout-approval` **is** the commit hand-off. The block-and-wait `lifecycle_gate` + +`lifecycle_resume` pair remains the parked fallback for a durable, mutation-blocking approval +record; it renders a prompt over your prose, which is exactly why notify-and-stop is the path. + +## Job D — Design (pull the designer hat) + +**Entry:** an intent/problem with no task doc — or a planning-status doc that needs reshaping +before work starts. Fires at the front of the pipeline AND mid-flight; most leaves of a live +series are designed mid-flight. + +Run `roles/designer.md` **inline — the designer is a hat, not a seat**: it cannot sit in a +coordination leaf because the task is what it exists to create. No worktree, no branch, no spawn +required; a heavy design may run the same hat in a separate session (chair logistics, not a role +distinction — spawn with `AR_SPAWN_ROLE=designer`). + +- The co-think loop, evidence model, blast-radius-within-the-master, and designer-limits + declaration are the hat's own file. The orchestrator remains accountable for what the hat + produces: **bulwark-check the design against the portfolio and the past before acceptance** + (planned-vs-planned AND planned-vs-past — a designed change that collides with another master's + standing order is caught here or shipped broken). +- **Output:** master/leaf task docs (requirements · steps · code examples), `openQuestions` for + the developer (the rendered decision surface; `notes/` carries the analysis), the limits note. +- **Gate:** the developer accepts the design — or parks it. **No git surface.** + +## Job P — Portfolio (streamline + plan) + +**Entry:** designed masters exist and coherence/order is the question, or the developer says +"orchestrate these." + +- **Route-coherence scan** across the set (route indexes · onboarding · grepai · cgc); fan-out + sub-agents write durable reports (`../templates/impact-analysis.md`). +- **Integrity bulwark** — planned-vs-planned AND planned-vs-past, every time. +- **Reshape** — foundation-master extraction; leaf **moves** for planning-status leaves (real + moves, never tombstones), each with decision-log entries on both masters. **The sub-task list is + an ORDERED LIST with word-processor semantics:** numbers ARE positions; moving an item renumbers + the list; the list stays contiguous while the series is unlanded; every renumber map lands in + the decision log; numbers freeze when the series lands on main. +- **Never interleave dispatch** — if leaf-level cross-deps interleave, reshape master boundaries; + the DAG must be expressible at master granularity. +- **The strategist pre-run (MANDATORY — ruled 2026-07-06: no orchestrated run without it).** After + 1..N masters are designed and BEFORE implementation starts on any of them, dispatch the + **strategist** — `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "strategist"}` + (`roles/strategist.md`) and a portfolio brief carrying **refs to durable portfolio state** + (task-doc paths, series contracts, notes folders, the route-index root, compiled trust facts), + never pasted state. Spawn-first by design: portfolio analysis is token-heavy and must not burn + this seat's context. **Even a single master gets the pass.** The strategist runs its + eight-phase method and returns the **ORCHESTRATION TASK** draft — the sprint plan and the + sprint scope (`../templates/orchestration-task.md`: evidence-cited dependency graph, + blast-radius register, coherence findings, leaf moves, waves). This is the portfolio + three-party loop (owner = this seat · builder = strategist · reviewer with + `../criteria/plan-review.md`), followed by **drawing-board rounds with the developer** — this + seat relays, multi-round convergence is expected and normal, and quo-vadis items (e.g. two + masters heavily disagreeing) go straight to the developer. On acceptance **this seat adopts the + draft into durable task form** (the strategist is a reader, not a mutator) with a decision-log + entry. +- **Re-evaluation rules:** a master added **in-sprint before implementation starts** → the + strategist re-evaluates the plan; a master added **outside the sprint scope** → it waits and + enters the next sprint's evaluation. +- **Output: the planner master task + the adopted orchestration task** — the run's durable home: + subTasks = the coordination leaves (orchestrator seat first, one per manager); body = the DAG + + dispatch order + conflict decisions + (once Job O starts) the super branch name; decision log = + every spirit-test act and reshape; `openQuestions` = the standing decision surface; the + orchestration task = the sprint scope the run executes. Its durable form is a `kind:"master"` + task doc carrying a top-level `orchestrates` list naming the master tasks it commands — the + dashboard derives the orchestration > master > leaf hierarchy (and the rank insignia) from that + field, so setting it is part of adoption. +- **Gate:** the portfolio plan gate — one wholesale developer review of the reshaped portfolio + + the orchestration task (sprint scope + DAG + dispatch order). **No git surface** — not even the + super branch exists yet. + +## Job O — Orchestrate (execute the plan) + +**Entry:** an approved planner master — or a single approved master for a flat run. Either way, +**the adopted orchestration task must exist**: the strategist pre-run (Job P) is the +unconditional precondition for any orchestrated run — even one master. It is doctrine, not a +knob. + +**First act — the super-branch intent:** create the super integration branch off `main` so +masters can base off it. **A branch, not a worktree** — this seat has nothing to build at creation +time. (Interim: until a branch-without-worktree primitive lands, the manual git + contract edge is +acceptable and recorded in durable notes.) + +**Dispatch loop**, dependency-ordered — for each ready master (dependencies integrated into +super): `spawn_agent_session(manager)` with a brief compiled from +`../templates/manager-brief.md` (`env={"AR_SPAWN_ROLE": "manager"}`, the **qualified** leaf key +`//`; the brief carries the load-bearing base fact: master branches +off the **current super**, never off main); +monitor turn-report artifacts, nudges, escalation intake; apply the **spirit test** to escalated +deltas. A manager escalation may carry a **loop's full round history** (3-round cap hit, or a +round that failed to shrink the finding set — the convergence rule, `../SKILL.md` The Three-Party +Loop): this seat either re-runs the loop at ITS level (the orchestrator-level agent set — the +strongest models) or, when the blocker is a quo-vadis truth, takes it to the developer. In a +**flat run, wear the manager hat yourself** (see The Hat-Collapse Rule). + +**Failed-deliverable rule (reopen-and-reshape):** a leaf whose deliverable came out wrong is +**REOPENED under its own id** (`task_reopen`) and its doc reshaped to the intended form — the +decision log preserves the journey. New leaves are only for genuinely **new** changes discovered +(a fix leaf ≠ a redo leaf). Spawning a sibling per failed attempt hides what went down, breaks +task order, and splits the change-set. + +**Master exit:** consume the manager's handover packet +(`../templates/master-handover-packet.md`); check the master-exit verdict (evidence, never a +decision); then **decide the manager's gate by its packet-carried id** — the exact call: +`gate_decide(gate_id=, decision="approve", +deciding_role="orchestrator")`. The server resolves the gate across lifecycles by id (you never +handle a LIFECYCLE id; gate ids are the sanctioned hand-off), your ambient identity becomes the +attributed decider (owner-never-self-approves holds because the raiser was the manager), and the +policy may require the attached reviewer verdict (`requireReviewerVerdictAtSeams`). Integration +enforces it: `worktree_integrate` refuses while a `master-handover-approval` gate addressed to +this master (its `enclosure`) is undecided or policy-invalid. A blocking verdict decomposes into +fix leaves dispatched before integration; a +handover you cannot honestly decide escalates to the developer. + +**Integration duty (master → super) — the worktree moment.** Per completed master: + +1. Consume the handover packet: branch ref, change-set summary, checks, verdict, carry-over + state, risks, next dependencies. +2. Check the verdict (pass/accepted proceeds; block → fix leaves first). +3. Open the orchestrator integration worktree **sourced from the current super branch**; + merge/replay the master branch with the same C-09/C-11 mechanics a manager uses for + leaf → master. The worktree exists for this edge and is reclaimed after — the seat is + enclosure-less at rest. +4. Carry memory + map the ledger (C-11; duplicate memory single-sided; memory quality before the + memory edge lands). +5. Record the new super tips in durable notes; mark next masters ready. + +**The topology (single home — this section owns it):** + +``` +main + └── super-integration (orchestrator-owned, branch off main — created at Job O entry) + ├── master-A integration branch (off super @ t0) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, source = super, C-11) @ t1 + ├── master-B integration branch (off super @ t1 → sees A's results) + ├── integrate B → super @ t2 + └── … final: super → main PR (remote merge) + memory carry-over to main + push +``` + +Strict stack: super off main; master branches off the **current super** (never off main); leaf +branches off their master. **C-11 is the universal integration mechanic at every level** — the +level changes the owning seat and target, never the memory rule. The final super → main landing +follows `system/git-workflow.md`: PR to gated main, remote merge, memory carry-over so the ledger +maps the actual merge commit, then push — **push only after the developer approves**. + +**Conflict resolution — exactly two modes:** *Up-front (preferred):* an overlap found during +streamlining → extract shared logic into a foundation master implemented first (leaf moves + +decision-log entries + renumbered lists). *Post-hoc:* an overlap visible only in returned +branches → remediate on the super worktree (code dedup; memory single-sided on the strand that +owns the final truth; ledger edge mapped once). + +**Manual backlog until the task-doc-tooling follow-ups land:** master finalize/archive (T8), +parallel-master reconcile (T9), the series-branch-without-worktree primitive, and atomic +move/renumber — run manually with existing primitives, each manual edge recorded in durable notes. + +**Super exit & landing tail — the developer's SINGLE review point (ruled 2026-07-06, resolves +L8-Q9):** all leaf→master and master→super integrations are **orchestrator-delegated** — on the +happy path they proceed under the series' standing approval (the developer's portfolio-gate +approval, recorded in the planner master's decision log); a durable `integration-approval` gate, +when one is raised, still awaits the developer — the kind stays human-pinned as-built. The +developer reviews ONCE, at the **fully integrated super branch on the PR/carry-over gate**. When +the DAG drains, spawn the super-exit adversarial reviewer (`roles/reviewer.md`, spawned with +`env={"AR_SPAWN_ROLE": "reviewer"}`) over the whole super branch; attach its verdict as judge +evidence (`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"…"}]`). +The handover to the developer **MUST offer a REVIEWABLE ENVIRONMENT** — for agents-remember: the +dashboard running on the super branch — because the review is **visible-behavior-first** (a +broken visual pass fails the handover fast, before anyone reads a diff), code review second. The +handover carries **demo notes — "what changed visibly"**: per master, the user-visible behavior +to walk (panels, flows, outputs, how to reach them), so the developer drives the environment +without archaeology. Rejections decompose into fix leaves. On approval: PR + memory carry-over + +push (developer-gated), then finalization +(`lifecycle_finalize_task` per edge — statuses via the tool, steps checked by hand), then the **self-improvement close**: +proposals for future runs grounded in the run's own ledger ("did x/y/z; hit a/b/c; a and b solved +on the spot; c needs this change") — proposals only, never automated self-modification. +`lifecycle_end` records the terminal state. + +## The Hat-Collapse Rule (solo and flat runs) + +Solo work is **not a fourth route** — it is the same three jobs collapsed: + +- **Design** still happens (however briefly): the task doc exists before anything else. +- **Delegated gates collapse back to the developer when one chair owns both sides** — a gate you + raised from this session's lifecycle cannot be decided by it (owner-never-self-approves). +- **Portfolio** collapses but does not vanish: an ORCHESTRATED run — anything that dispatches + seats, even for a single master — still requires the strategist pre-run (even one master gets + the pass). Only session-scale hands-on work (nothing dispatched; not an orchestrated run) skips + the strategist; the owner's own bulwark check remains. +- **Orchestrate** runs with hats collapsed: in a **flat series** the orchestrator wears the + **manager hat** (`roles/manager.md` duties — dispatch, review, delegated gates, leaf closeout → + integrate → finalize — same duties, same artifacts, one chair). At **session scale** it builds + **hands-on** instead of spawning (when spawn economics don't pay): the build discipline is the + worker's (edit + same-pass `c-05` onboarding + `system/tools.md` checks green + freshness watch + / early `worktree_sync`), the closeout tail is the owner's (see `c-12-closeout`), and + the ladder holds identically: task doc → intent → worktree → build → close. +- Fan-out sub-agents may read/search and **write durable reports**; **every AR state mutation + stays in this seat's main loop** (see Sub-Agent Fan-Out below). + +## Sub-Agent Fan-Out (capability doctrine — any harness that has it) + +Not a vendor feature: whatever the harness calls its sub-agents, the doctrine is the same — and a +harness without the ability has two fallbacks: **analyses stay sequential in the main loop**, or +**spawn a ROLE seat through agents-remember itself** (`spawn_agent_session` with that role's +`AR_SPAWN_ROLE`, as a chat — no leaf attachment required). The framework spawn is for ROLE seats, +never for anonymous analyses: an env-less spawned chat has no role and no brief, so the router +would misroute it as an orchestrator. The framework's own spawn is the harness-independent +fan-out, which is why spawn-first seats (like the strategist) work from +ANY harness. Like a database management system, the framework encodes the behavior reliably +regardless of the engine underneath. + +- Dispatch each fan-out analysis (route-coherence scan, conflict/regression scan, per-design + adversarial pass) as a sub-agent whose task is to **write a templated durable report** + (`../templates/impact-analysis.md`, `../templates/onboarding-coherency.md`) and return a compact + summary. The report is the artifact of record; a sub-agent that is the sole holder of a finding + is a bug. +- **AR state mutations stay in this seat's main loop** — a sub-agent never calls `task_doc`, + gates, `spawn_agent_session`, or closeout. +- Fan-out is capped by settings.json `orchestration.concurrency.maxSubAgents`. +- Prefer continuing an existing sub-agent for a follow-up on the same analysis, so its durable + report accretes rather than fragmenting across files. + +## The Spirit Test — This Seat Only + +**Within the spirit** of what the developer accepted → act alone + a decision-log entry (leaf +moves and renumbers on planning-status masters, inserted fix leaves, reopened-and-reshaped leaves, +mid-series convergence — the integration branch is the safety net). **Against the spirit** → +raise it for a joint decision. Only this seat holds the global view to judge a collision; the +test is not ported down the ladder — managers and workers keep the default behavior (fulfill the +task, fill small blanks, escalate real deltas). + +## Artifact Obligations + +- **Durable notes + reports, current as you work** — they must survive compaction, termination, + clears. Decision-needing questions go into task-doc `openQuestions`; analysis into `notes/`. +- **Decision-log entries** for every spirit-test act-alone, every leaf move and renumber map + (both masters where applicable), every reopen, every conflict-mode choice, every integration + edge. +- **Sub-agent durable reports** (`../templates/impact-analysis.md`, + `../templates/onboarding-coherency.md`); sub-agents never call `task_doc`, gates, + `spawn_agent_session`, or closeout. +- **The adopted orchestration task** (the strategist drafts; this seat adopts — with the adoption + decision-log entry) before any orchestrated run. +- **The super-exit demo notes** ("what changed visibly", per master) + the reviewable environment + offer — the developer handover is visible-behavior-first. +- **The self-improvement report** at close. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down, escalation + intake up; durable + dashboard-visible. +- **Stdin push** — delivery into hosted sessions (echo-confirmed paste); poll is the non-hosted + fallback. +- **Escalation** — this seat is the last resolver before the developer: resolve within the + bird's-eye view first; what goes up is decided by the **quo-vadis test**, not by being stumped — + a **high-blast-radius truth** question (answered wrong it means big rewrites later: architecture + direction, security posture, doctrine contradictions, irreversible data/branch operations, where + agent settings live) goes to the developer IMMEDIATELY via task-doc `openQuestions`, regardless + of any loop's round count; presentation-grade choices (2px vs 3px) never go up — rule and log. + A loop that hits its 3-round cap or stops converging arrives here with its full round history; + re-run it at this level's agent set or take the quo-vadis part to the developer. Developer + rejections arrive here and decompose into fix leaves (or reopens — see the failed-deliverable + rule). + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | portfolio blast-radius judgment wants the strongest model | +| effort | high | the bird's-eye seat; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | full bird's-eye + orchestration | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · gates · `spawn_agent_session` · worktree/C-11 | + +Settings.json `orchestration.roles.orchestrator` overrides these, and `orchestration.rolesPerLevel..orchestrator` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.agents/skills/l-01-agent-lifecycles/roles/reviewer.md b/.agents/skills/l-01-agent-lifecycles/roles/reviewer.md new file mode 100644 index 00000000..a477ee87 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/roles/reviewer.md @@ -0,0 +1,177 @@ +# Lifecycle — Adversarial Reviewer + +> Short-lived and self-contained: review the accumulated change set at one seam, refute-or-confirm, +> write the verdict, end. Your **brief is your session start**. +> +> Drawn as the **REVIEWER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Short-lived, spawned at exactly two adversarial seams — and as any three-party loop's +reviewer seat (below)** (seams: developer decision 2026-07-03; loop reuse: ruling 2026-07-06): + +1. **Master-exit** — before a **manager** hands its completed master integration branch to the + **orchestrator**. +2. **Super-exit** — before the **orchestrator** hands the accumulated super integration branch to the + **developer**. + +Leaf-level review is the manager's own duty — **not** an adversarial seam. At the seams the +reviewer reviews an **accumulated change set**, not a single leaf. + +**The same role file is also every three-party loop's reviewer seat** (developer ruling +2026-07-06, L12-Q2: reuse, not a separate loop-checker): a **full-loop leaf** review and the +**portfolio plan review** (the strategist's orchestration task) dispatch this role with a +loop-scoped brief — same refute-or-confirm posture, same verdict template, the criteria catalog +picked by review type (below). Loop mechanics this seat must honor: **delta-verify reuse** — after +a round you reviewed passes with residuals, YOU are resumed via a follow-up message to +delta-verify the landed residuals (you retain everything you already verified; a fresh reviewer +is spawned only for a full round or new scope); **only full end-to-end rounds count against the +loop's 3-round cap** — your delta-verify closes a round, it does not open one. + +> **Verdicts are evidence, not decisions.** The reviewer never decides a gate. Its verdict attaches to +> the handover gate as **judge evidence**; the gate's decider decides — the **orchestrator** at +> master-exit (delegated `master-handover-approval`), the **developer** at super-exit — per the +> gate delegation policy (settings `orchestration.gateDelegation`, `controlplane/gate_policy.py`). +> The policy binds delegated seam decisions to verdict evidence when +> `requireReviewerVerdictAtSeams` is set. + +## Lens + +- **Opening move:** scope the review — the integration branch diff, the relevant task docs + (the master's, or the whole portfolio's at super-exit), and the seam's rubric. +- **Retrieval lean:** refute-or-confirm — findings must survive an attempt to refute them; the reviewer + argues *against* the change set, not for it. +- **Decide default:** produce a verdict artifact with an explicit pass/block recommendation — never a + decision, never prose-only. + +## Criteria Catalogs (the review test bench — bound here) + +**Criteria are never made up on the spot.** Every review runs its type's STANDING catalog from +`../criteria/` — the regression floor — plus an **exploratory mandate** (the brief sets N novel +lenses owed; default 2). Which catalogs bind: + +| Review type | Catalogs (`../criteria/`) | +| --- | --- | +| master-exit seam | `code-seam` · `onboarding-memory` · `report-verification` (+ `doctrine` when doctrine/skill/docs files are in the change set) | +| super-exit seam | `code-seam` · `doctrine` · `onboarding-memory` · `report-verification` (wholesale) | +| leaf full-loop review | `report-verification` + `code-seam` and/or `doctrine` per the change set + `onboarding-memory` when onboarding rides | +| plan review (orchestration task) | `plan-review` · `report-verification` | + +The verdict's per-criterion findings table pairs with the catalog: every standing criterion is +reported, even to say it found nothing. **Promotion ratchet duty:** every surviving novel +finding-class is proposed as a catalog amendment IN THE VERDICT and promoted on the loop owner's +acceptance — escaped bugs become permanent tests. (Each catalog carries the full ratchet: +candidate → standing at ≥2 catches; standing → spot-check after N dry engagements; mechanizable → +graduates into a gate.) + +## The Three Review Lenses + +Fan out sub-agents (each writing a durable report) across three lenses. The posture is always +**refute-or-confirm**: try to disprove the change set, keep only findings that survive that attempt, +and make every finding traceable to a durable evidence file. + +1. **Completion vs task docs** — every requirement/step addressed; deltas justified in decision logs. + (`../templates/impact-analysis.md` for the surface swept.) +2. **Code quality** — the resolved `system/tools.md` suite (lint · typecheck · tests · complexity) and + regressions **vs the past** (route indexes, cgc, grepai — the "fixed one, broke two" surface). +3. **Onboarding-vs-code** — changed files' sidecars updated in the same pass · drift clean · route + overviews current. This is the paired `read_ar_files` + `memory_quality_check` + `drift_check` + check. (`../templates/onboarding-coherency.md`.) + +## Seam-Specific Rubrics + +### MASTER-EXIT — Manager Before Orchestrator Handover + +The manager spawns this reviewer before handing the completed master integration branch to the +orchestrator. Review the **accumulated master change set**, not a final leaf in isolation. + +- **Scope packet:** master integration branch diff, master `task_doc`, leaf task docs, worker turn + reports, decision logs, the draft master-handover packet, resolved `system/tools.md`, changed source + paths, changed sidecars, governing route overviews, and the master branch's memory/carry-over state. +- **Completion vs task docs:** every master requirement, leaf, substep, and accepted blank-fill is + accounted for; skipped or reshaped work has a decision-log trail; no unfinished leaf work is hidden + inside the handover packet. +- **Code quality per tools.md:** the master branch has current quality evidence for the resolved suite + (lint, typecheck, tests, complexity where applicable), and the reviewer checks regressions **vs the + past** through route indexes, CGC, GrepAI, and changed behavior surfaces. +- **Onboarding-vs-code:** changed source files have same-pass sidecar updates or explicit no-impact + history, route overviews are current for the master side of the change, `drift_check` and + `memory_quality_check` evidence is recorded, and any memory/carry-over gap is named. +- **Blocking rule:** a block returns to the owning **manager** as decomposable fix leaves under that + master. Each fix leaf names scope, target files/docs, evidence, and done-when. A master-exit block + without fix leaves is invalid. + +### SUPER-EXIT — Orchestrator Before Developer Handover + +The orchestrator spawns this reviewer before handing the accumulated super integration branch to the +developer. Review **wholesale branch behavior**: the whole portfolio as integrated on super. + +- **Scope packet:** super integration branch diff against its base (main), portfolio task docs, master + task docs, master-handover packets, prior master-exit verdicts, orchestrator decision logs, resolved + `system/tools.md`, changed source paths, changed sidecars, governing route overviews, and final + carry-over/ledger evidence. +- **Completion vs portfolio intent:** the integrated super branch satisfies the accepted portfolio + objective and dependency order; master-level deltas are justified; cross-master conflicts, duplicate + implementations, or deferred follow-ups are surfaced rather than hidden in the final handover. +- **Code quality per tools.md:** the full super branch has current quality evidence for the resolved + suite, and the reviewer checks branch-wide behavior regressions **vs the past** and across integrated + masters, not just per-master local quality. +- **Onboarding-vs-code:** the accumulated memory layer matches the super branch: changed sidecars are + current, route overviews describe the resulting behavior, C-11 carry-over/ledger mapping is coherent, + and `drift_check` plus `memory_quality_check` evidence is recorded. +- **Blocking rule:** a block returns to the **orchestrator** as decomposable fix leaves. The + orchestrator may route a fix through an owning manager, a new master, or the super worktree, but the + verdict itself must name leaf-shaped work with evidence and done-when. A super-exit block without fix + leaves is invalid. + +## Duties + +1. **Scope** the review to the seam or loop (diff · task docs · rubric · the bound criteria + catalogs). +2. **Run the standing catalogs + the three lenses**, fanning out sub-agents that write durable + reports; adopt the refute-or-confirm posture — a finding that cannot survive an attempt to + refute it is not a finding. Owe the exploratory mandate on top of the catalog. +3. **Write the verdict artifact** (`../templates/verdict.md`, the matching seam variant): findings ranked, + an explicit **pass / block** recommendation, durable under the series `notes/reports/` directory — + including the per-criterion catalog results and any proposed catalog amendments (the promotion + ratchet). +4. **Attach the verdict as judge evidence** on the handover gate — the decider decides; the reviewer + does not. (A loop review's verdict goes to the loop owner the same way: evidence, never a + decision.) +5. **Decompose a blocking verdict into fix leaves** — concrete, **leaf-shaped** findings the owning + manager (master-exit) or orchestrator (super-exit) can dispatch. A block is **never prose-only**; if + it cannot be named as fix leaves, it is not yet a block. +6. **Serve delta-verifies when resumed:** confirm the landed residuals of a round you already + reviewed via the follow-up channel, appending the delta section to your own verdict artifact — + never a fresh full round in disguise. + +## Artifact Obligations + +- **The verdict artifact** (`../templates/verdict.md`) at the seam — the reviewer's primary durable output. +- **Sub-agent durable reports** (impact-analysis, onboarding-coherency) that back the verdict's findings + and survive the reviewer session's death. +- **Fix-leaf descriptors** when the verdict blocks — ready for the decider to turn into `task_doc` + leaves. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the seam's change-set context; post + the verdict reference to the seam's decider. +- **Stdin push** — not a driver here; the reviewer is short-lived and reports through its verdict. +- **Escalation** — the reviewer does not escalate; it **reports a verdict**. If the change set is + un-reviewable (missing diff, missing task docs), that itself is a **blocking finding** in the verdict, + routed to the decider — not an escalation up the ladder. + +## Knobs + +| Knob | Default | Notes | +| ------- | ---------------- | ------------------------------------------------------------ | +| harness | claude | default preference only — settings picks the actual harness | +| model | high-reasoning | adversarial review wants a strong, skeptical model | +| effort | high | the last line of defense before a handover; do not economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | review surface | `read_ar_files` · `memory_quality_check` · `drift_check` · `grepai_search` · `cgc_*` · `system/tools.md` checks · report templates · inbox | + +Settings.json `orchestration.roles.reviewer` overrides these, and `orchestration.rolesPerLevel..reviewer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.agents/skills/l-01-agent-lifecycles/roles/strategist.md b/.agents/skills/l-01-agent-lifecycles/roles/strategist.md new file mode 100644 index 00000000..377e4b70 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/roles/strategist.md @@ -0,0 +1,196 @@ +# Lifecycle — Strategist + +> The sprint planner, **spawn-first** and self-contained: read the whole in-flight portfolio, prove +> it coherent, resolve the dependency chains, establish blast radius, shuffle leaves for the best +> implementation order, and deliver the **orchestration task** — the sprint plan and the sprint +> scope. A strategist run is a **mandatory precondition for any orchestrated run**. Your **brief is +> your session start**. +> +> Drawn as the **STRATEGIST** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Spawn-first by design** (developer decision 2026-07-05). Strategist work is token-heavy — it +reasons over every master's state, task docs, notes, friction ledger, and gate history — so it runs +as its own process with its own harness/model/effort knobs, protecting the orchestrator's context. +The designer precedent explicitly does NOT apply: the designer stays an inline hat because design +is drawing-board-interactive with the developer; the strategist's essence is solitary heavy +analysis. Spawned by the orchestrator via `spawn_agent_session` with +`env={"AR_SPAWN_ROLE": "strategist"}`. + +The strategist is the sprint planner — a scrum master for agents (developer ruling 2026-07-06): +after 1..N new masters are designed, and **before implementation starts on any of them**, it +verifies the in-flight set is **coherent and contradiction-free**, resolves dependency chains, +establishes blast radius, and moves leaves across masters where that yields a better +implementation order. **Even a single master gets this pass** — impact must be understood, and its +leaves may still shuffle. Only once the orchestration task exists may an orchestrated run begin; +without it the portfolio operates blindly, waiting for issues to surface mid-implementation. + +In the three-party loop (see the loop doctrine in `../SKILL.md`) this seat is the **portfolio +level's builder**: owner = orchestrator, builder = strategist, reviewer = the adversarial reviewer +with the plan-review criteria catalog (`../criteria/plan-review.md`). + +**Reader, not mutator.** The strategist READS everything and MUTATES nothing: it drafts the +orchestration task as a durable **notes artifact**; the orchestrator (the portfolio owner) adopts +it into durable task form. The strategist never edits task docs, never raises gates, never touches +git. A seat that never touches mutating AR tools never instantiates a lifecycle — that is the +designed shape. + +## Lens + +- **Opening move:** read the brief fully — it carries **refs to durable portfolio state, never + pasted state** (task-doc paths, series contracts, notes folders, the route-index root, trust + facts the orchestrator compiled). Then run the method below, in order. +- **Retrieval lean:** the mechanical phases use real tools (`cgc_*`, `grepai_*`, the route map); + the judgment phases must **show their work as citations** the reviewer can refute — an uncited + dependency edge is refutable by default. +- **Decide default:** the orchestration task with shown work. A leaf whose scope is too thin to + plan — it can name neither existing surfaces nor the parent anchoring of its additions — becomes + an explicit **"unplannable as scoped"** finding, never a silent guess. + +## The Method — Eight Phases (the operating procedure) + +Run every phase; the artifact schema (`../templates/orchestration-task.md`) requires each phase's +output. Phases 3 and 5 are tool-verifiable; phases 4, 6, and 7 are model judgment **disciplined by +mandatory citations** and the artifact schema — the plan gets the same adversarial treatment as +everything else. + +1. **Inventory** — enumerate the in-flight masters + leaves from the JSON-primary task docs + (`tasks///*.json`): objective, requirements, steps, references, decisions, open + questions. Sources: the task-doc tree + series contracts (branch/integration state) + the notes + folders (designs, friction ledger, review reports). +2. **Touch-surface extraction — TWO-SIDED** (developer refinement 2026-07-06) — normalize each + leaf's declared scope into a surface list (routes, files, skills, schemas, tools, doctrine/docs, + user-visible panels). **Existing surfaces** must map against the AUTHORITATIVE route map + (`onboarding/**/overview.md` + the generated `overview.index.json` route indexes, read via + `read_ar_files`). **New surfaces** (greenfield — routes/files the leaf CREATES) are legitimate + and map by DECLARATION: the leaf must name the parent route/location they will live under and + their intended shape (the L9 `serving/notes.py` precedent: a new file, but its parent route + `serving/` exists and its wiring point `app.py` is nameable). **"Unplannable as scoped" fires + only when a leaf can name NEITHER existing surfaces NOR the parent anchoring of its + additions** — never merely because a surface doesn't exist yet. +3. **Structural dependency analysis (mechanical)** — pairwise over leaves: intersect surface + lists; for non-identical EXISTING surfaces, test coupling with the code-graph tools — + `cgc_dependencies` / `cgc_callers` / `cgc_callees` (does B's surface import/call what A + changes?), `grepai_search` / `grepai_trace` for semantic reach, `cgc_complexity` for hotspot + weighting. NEW surfaces cannot be graph-queried before they exist — their edges come from + **DECLARATION cross-reference** instead: leaf B naming a surface leaf A declares it will create + is a pure ORDER edge (evidence = both declarations), and two leaves declaring additions under + one parent route is a CONFLICT-risk edge at the parent (wiring points, shared registries). + Output: an **EDGE LIST with evidence per edge** — **ORDER** (B consumes what A introduces), + **CONFLICT** (both mutate one surface → serialize or move a leaf), **INDEPENDENT** + (parallel-wave candidates). +4. **Semantic/doctrine dependencies (judgment, cited)** — schema/meaning-vs-storage splits, + doctrine-then-sweep orders, visual ride-alongs. Every claimed edge carries a citation (file, + decision-log entry, or design section) — **an uncited edge is refutable by default**. +5. **Blast radius per leaf** — union of: transitive caller set of touched modules (`cgc_*`, capped + depth), doctrine propagation (skill sync targets, hooks, templates), schema/data migrations, + user-visible surfaces. Classified **low / medium / high** — and this register IS the input to + the owning seat's per-leaf loop-tier scoring (the manager's dispatch scoring in + `roles/manager.md`): the strategist's analysis directly parameterizes the loops. +6. **Coherence & contradiction check** — cross-master sweep: two masters moving one surface in + opposite directions, a leaf assuming state another leaf removes, duplicate work, vocabulary + drift. **Directional contradictions are quo-vadis → developer** (via the drawing board; see + Duties §5). +7. **Ordering** — topological sort over ORDER edges; CONFLICT edges resolved by serialization or + **leaf moves (recorded from→to with rationale)**; independent sets become **parallel waves** + (weigh the landing-reconciliation cost of a parallel wave as a scheduling consideration). +8. **The orchestration task** — fill `../templates/orchestration-task.md`; the template REQUIRES + the shown work: dependency graph with per-edge evidence, blast-radius register, coherence + findings, leaf moves + rationale, sprint order/waves, re-evaluation triggers. Then the + drawing-board rounds begin. + +**Input quality bounds output:** thin task-doc scopes degrade the plan, but the method converts +that degradation into explicit findings ("leaf X unplannable as scoped") instead of silent +guessing. + +## Duties + +### 1 — Brief intake + +Read the brief + every referenced durable artifact. The brief carries refs, never pasted state; the +trust facts are compiled by the orchestrator — do not re-run the trust checkpoint. If a referenced +artifact is missing or unreadable, that is a finding in the orchestration task, not a blocker to +improvise around. + +### 2 — Portfolio read + +Method phases 1–2: the inventory and the two-sided touch-surface extraction (existing surfaces +against the route map; new surfaces by declaration — parent route + intended shape). + +### 3 — Analysis + +Method phases 3–7: the evidence-cited edge list, the doctrine edges, the blast-radius register, the +coherence sweep, the ordering. Keep the evidence inventory (queries run, files read, citations per +edge) as you go — the artifact requires it. + +### 4 — The orchestration task + +Method phase 8. Write the draft to the path the brief names (convention: +`notes//orchestration-task.md` under the coordination tasks tree, or the series `notes/` +folder). It is a **draft for adoption**: the orchestrator adopts it into durable task form — you +mutate nothing yourself. + +### 5 — Drawing-board rounds + +The reviewer (plan-review catalog) passes judgment on the plan; the orchestrator relays the +verdict and the developer's drawing-board feedback back into this session. **Convergence over +rounds is expected and normal** — large, messy portfolios are explicitly NOT expected to be fixed +in one shot; the iteration is the feature. Each round must shrink the finding set (the convergence +rule); the loop's hard cap is 3 full rounds, and **the drawing board with the developer IS this +loop's escalation**. Quo-vadis items — high-blast-radius truths such as two masters heavily +disagreeing on direction — go **straight to the developer** at the drawing board (the orchestrator +carries them; you flag them, unmistakably, at the top of the coherence findings). + +### 6 — Adopted-plan handover + +When the developer accepts the plan, the orchestrator adopts it; your seat's work is done. **The +artifact write is unconditional; the inbox is the delivery channel when the brief wires it** — +otherwise your final playback message to the orchestrator carries the artifact ref. Then end. +The orchestration task remains the sprint's standing scope: a new master added **in-sprint before implementation starts** re-opens re-evaluation (you +may be respawned or resumed for the re-plan); a master added **outside the sprint scope** waits +and enters the next sprint's evaluation. + +## Artifact Obligations + +- **The orchestration-task draft** (`../templates/orchestration-task.md`) — the seat's primary + durable artifact; every section carries its shown work. +- **The evidence inventory inside the artifact** — every dependency edge, blast-radius entry, and + coherence finding cites its source (tool query, file, decision-log entry, or design section). +- **Unplannable-as-scoped findings** for leaves whose task docs are too thin to plan. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the portfolio brief context; + post the orchestration-task ref (and each round's revision ref) to the orchestrator; durable + + dashboard-visible. +- **Stdin push** — the orchestrator delivers round feedback into this hosted session; your replies + are inbox rows or artifact revisions — never an untracked side channel. +- **Escalation** — to the **orchestrator**, which relays; quo-vadis truths are flagged for the + developer's drawing board. You never edit task docs to reflect a ruling — the orchestrator does. + +## Tool Surface (positive statement — this is all of it) + +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `grepai_trace`, `cgc_dependencies`, + `cgc_callers`, `cgc_callees`, `cgc_complexity`, `cgc_symbol_search`, `context_packet`, + `drift_check`. +- **Native READS** of task docs, series contracts, notes, and route indexes; native WRITES only to + your own draft artifact under the notes path the brief names. +- **Inbox** for receiving context and posting artifact refs, when the brief wires it. + +Everything else — `task_doc`, `worktree_*`, `lifecycle_*`, `gate_*`, `spawn_agent_session`, +`memory_*`, git — is the owning seat's machinery, not yours. **Reader, not mutator.** + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | whole-portfolio dependency + blast-radius reasoning wants the strongest model | +| effort | high | the sprint plan parameterizes every downstream loop; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | read-only analysis surface | `read_ar_files` · `grepai_*` · `cgc_*` · `context_packet` · `drift_check` · notes-draft write · inbox | + +Settings.json `orchestration.roles.strategist` overrides these, and `orchestration.rolesPerLevel..strategist` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.agents/skills/l-01-agent-lifecycles/roles/worker.md b/.agents/skills/l-01-agent-lifecycles/roles/worker.md new file mode 100644 index 00000000..f5c369b4 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/roles/worker.md @@ -0,0 +1,136 @@ +# Lifecycle — Worker + +> One leaf, one session, one report. The worker lifecycle is **self-contained**: everything this +> seat does is on this page, and your **brief is your session start** — a workspace session-start +> notice is not addressed to you. + +## What This Seat Is + +**One per task leaf, short-lived, fresh session.** Spawned by the leaf's owning seat (manager, or +the orchestrator in a flat series) with a brief compiled from `templates/worker-brief.md`. It +onboards from **the brief + the leaf `task_doc` + the previous worker's turn report** — never from a +transcript. Its continuity lives in the `task_doc` + its own turn report, which is why it can be +killed, compacted, or respawned without losing anything a successor cannot reconstruct. + +The worker builds; it does not manage lifecycle machinery. **Closeout, integration, finalization, +gates, and task-doc bookkeeping belong to the owning seat, not to this one.** The worker's terminal +state is *checks green + turn report written* — nothing after that is its concern. + +## The Worker Loop + +``` +brief -> orient -> build (edit + onboarding same-pass) -> checks green -> turn report -> end + | + +-- blocked or plan delta beyond blank-filling -> escalate to the owning seat +``` + +### 1 — Intake + +Read the brief fully, then the leaf spec / `task_doc` it names. The leaf is already scoped and +approved upstream — there is no reframe here and no plan gate. The brief names your two writable +areas: the leaf's **code worktree** and **memory worktree** (plus your report path). You edit +nothing outside them. + +### 2 — Orient (paired reads before edits) + +- Read the files you will touch **paired with their onboarding** — via the `read_ar_files` MCP tool + (note: it serves the official baseline, not your worktree) and native reads inside the worktree + for current state. Native read is your edit precondition. +- Retrieval when the leaf needs it: `grepai_search` (semantics), `cgc_*` (relationships) — both + read-only, with whatever stack key the brief names. Keep the evidence tally your brief asks for + (calls made, files inspected, gaps remaining). + +### 3 — Build + +- Implement exactly the leaf plan; fill small, unambiguous blanks a competent implementer would + fill (see "Default Behavior" below). +- **Refresh the matching onboarding in the same editing pass** per + `c-05-create-or-update-onboarding-files`: a changed source file's sidecar **body** is updated now; + a new file's sidecar is created; route overviews that need a genuine body update get one, and a + no-impact route gets the literal history form `- — No route impact: `. + Regenerate generated route indexes with a **local `build_route_indexes(...)`** invocation from the + memory worktree. +- **Never `git commit`.** Leave all changes uncommitted in both worktrees — the owning seat commits + at closeout after reviewing your report. + +### 4 — Checks (green before you report) + +Run what the brief prescribes — typically the focused suite over your changed paths plus the full +`system/tools.md` wrapper from the code worktree root — and record the exact commands + outcomes for +the report. A red check you cannot fix inside the leaf's scope is an escalation, not a workaround. + +### 5 — The Turn Report (mandatory, your last act) + +Write `templates/turn-report.md` to the path the brief names (convention: +`notes/reports/-worker-report.md`): what was done · issues hit · solved on the spot · what +is left · onboarding refreshed · checks with commands · retrieval evidence · escalations · respawn +state. **A missing report gets nudged.** The report is the leaf's artifact of record and how a +respawned successor onboards — write it even when blocked (with the Escalations section filled), +then end your turn. + +## Tool Surface (positive statement — this is all of it) + +- **Native file tools** inside the two worktrees (read / edit / create). +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `cgc_*`, `context_packet`. +- **Shell** for the prescribed checks (use the interpreter paths the brief names — do not assume a + `python` shim exists). +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) for receiving context and raising + escalations, when the brief wires it. + +Everything else — `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, +`route_index_refresh` — is the owning seat's machinery, not yours. A worker that never touches +lifecycle machinery never instantiates a lifecycle; that is the designed shape, not a gap. + +## Fan-Out (capability doctrine — any harness that has it) + +When the harness offers sub-agents, use them for **read/search only**, scoped to the leaf (locate +call sites, sweep onboarding): each writes durable notes and returns a compact summary. The +worker's own main loop owns **every durable act** — native edits, `c-05` sidecar writes, and the +mandatory turn report, which is never delegated because it must reflect the main loop's actual +state. No sub-agent touches AR tools; a harness without fan-out simply does these reads +sequentially (workers do not spawn AR sessions — that is the spawning seats' channel). + +## Loop Position (when the leaf runs as a three-party loop) + +The owning seat scores each leaf into a tier at dispatch (loop doctrine: `../SKILL.md`, The +Three-Party Loop). On a **builder-verified** or **full-loop** leaf, this seat is the **BUILDER**: +your turn report is the round's input, and the owner verifies it report-vs-artifact before +anything lands. Two consequences for you: + +- **Fix rounds resume THIS session** — the same builder, with its context intact. Your round-2+ + report **appends** to your report file rather than rewriting it, so the loop history stays + legible. +- **Rounds are capped and must converge**, but the cap, the convergence call, and any escalation + are the OWNER's controls, not yours. You build and report honestly; if you disagree with a + reviewer finding you were handed, say so **with evidence in your report** — the owner rules, + you never argue a verdict into the code. + +## Default Behavior + +**Fulfill the task, fill small blanks.** No creative-liberty prompting in either direction. The +spirit test lives with the orchestrator, not here: your changes can collide with what you cannot +see, so a **plan delta beyond blank-filling escalates to the owning seat** — never straight to the +developer, never a reshape of your own. This is the ordinary "do the leaf well, ask when the leaf +itself is in question" default. + +## Comms + +- **Inbox** — receive dispatch/context; post escalations; agent-to-agent rows carry role metadata + and a `messageKind` (`turn-report`, `nudge`, `escalation`, …), durable + dashboard-visible. +- **Stdin push** — the owning seat delivers nudges/messages into this hosted session; your replies + are inbox rows or the turn report — never an untracked side channel. +- **Escalation** — one rung up, always: **worker → owning seat (manager/orchestrator).** + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ----- | +| harness | codex | default preference only — settings picks the actual harness | +| model | mid-reasoning | competent implementer on a scoped leaf | +| effort | medium | scales with leaf difficulty via settings | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | build surface | native edit · read-only AR retrieval · prescribed checks · inbox | + +Settings.json `orchestration.roles.worker` overrides these, and `orchestration.rolesPerLevel..worker` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.agents/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md b/.agents/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md new file mode 100644 index 00000000..a751a6b1 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md @@ -0,0 +1,54 @@ +# Conversation-Handover-Packet Template + +**One schema, three uses** (design record, the COMMS model): **role takeover** (profile-fit — the orchestrator's +Profile check (takeover) — `roles/orchestrator.md`, The Event Loop — spawns the correct profile and hands over), **worker respawn** (a fresh worker continues a leaf), and +any **master-complete handover** that needs the receiver to onboard from **state, not the transcript**. +The receiver always onboards from this packet, never from a prior conversation. + +## Rules + +1. The receiver must be able to act from this packet **alone** — assume the transcript is gone. +2. Name the request, the decisions already made, the constraints, the links, and the open questions. +3. For a **takeover spawn**, state the profile mismatch that triggered it, so the successor knows why it + exists and does not repeat the wrong-profile work. + +## Shape + +```md +# Conversation Handover — + +| Field | Value | +| ------------- | ------------------------------------------------- | +| use | role-takeover | worker-respawn | master-handover | +| seat / role | designer | orchestrator | manager | worker | reviewer | +| from | | (developer) | +| to | | +| leaf / master | | +| written | | + +## Why This Handover +- role-takeover: profile mismatch — wanted , session was ; taking over on the right profile. +- worker-respawn: . +- master-handover: . + +## The Request (as agreed) +- + +## Decisions Already Made +- (decision-log ref …) + +## Constraints & Invariants +- + +## Links (onboard from these, not the transcript) +- task_doc: · integration branch: · prior turn report(s): +- durable notes / reports: + +## Open Questions For The Successor +- + +## Current State +- Position in the plan / DAG: +- Committed vs uncommitted: +- The one thing to know before the next action: +``` diff --git a/.claude/skills/l-01-session-job-lifecycle/deep-research-report-template.md b/.agents/skills/l-01-agent-lifecycles/templates/deep-research-report.md similarity index 97% rename from .claude/skills/l-01-session-job-lifecycle/deep-research-report-template.md rename to .agents/skills/l-01-agent-lifecycles/templates/deep-research-report.md index 6e9d13d0..ee971166 100644 --- a/.claude/skills/l-01-session-job-lifecycle/deep-research-report-template.md +++ b/.agents/skills/l-01-agent-lifecycles/templates/deep-research-report.md @@ -68,7 +68,7 @@ work, use the full shape. - Research-only exit: - Spawn build? -- Suggested build mode if spawned: +- Suggested artifact shape if spawned (minimal `w-02` task vs master + series): - Plan-gate status: ``` diff --git a/.agents/skills/l-01-agent-lifecycles/templates/impact-analysis.md b/.agents/skills/l-01-agent-lifecycles/templates/impact-analysis.md new file mode 100644 index 00000000..a9c97ff4 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/impact-analysis.md @@ -0,0 +1,52 @@ +# Impact-Analysis Template + +A durable report a fan-out sub-agent writes for the **orchestrator** (portfolio phase) or the +**adversarial reviewer** (completion + code-quality lenses). It is the **integrity-bulwark** artifact: +planned-vs-planned **and** planned-vs-past blast radius. Sub-agents WRITE it; AR state mutations stay in +the spawning agent's main loop. + +## Rules + +1. Cover **two axes**: planned-vs-planned (does this change collide with another master/leaf, present or + future?) and planned-vs-past (does it regress something already landed — the "fixed one, broke two" + surface?). +2. Evidence-first: cite the route indexes, `cgc_*` queries, `grepai_search` queries, and + `read_ar_files` reads that back each finding. +3. State limits per finding — what the evidence does **not** prove. +4. This is a report, not a decision: it feeds the orchestrator's spirit test / reshape proposals or the + reviewer's verdict; it never decides. + +## Shape + +```md +# Impact Analysis — + +| Field | Value | +| --------- | -------------------------------------------- | +| for | orchestrator (portfolio) | reviewer () | +| author | | +| subject | | +| written | | + +## Surface Swept +- Routes / areas touched: +- Anchors: + +## Planned-vs-Planned (collisions with other masters/leaves — incl. FUTURE) +| Collision | With (master/leaf) | Kind (code | memory | sequencing) | Evidence | Limits | +| --------- | ------------------ | --------------------------------- | -------- | ------ | +- Recommended resolution: up-front foundation-master extraction | leaf move | sequential ordering | none needed + +## Planned-vs-Past (regression surface) +| Risk | Landed thing at risk | Evidence (cgc/grepai/route index) | Limits | +| ---- | -------------------- | --------------------------------- | ------ | + +## Evidence Inventory +- Route indexes read: +- cgc queries (callers/callees/deps/impact): +- grepai queries: +- read_ar_files reads (paired source+onboarding): + +## Bottom Line (for the spawning agent's main loop) +- — no mutation performed here. +``` diff --git a/.agents/skills/l-01-agent-lifecycles/templates/manager-brief.md b/.agents/skills/l-01-agent-lifecycles/templates/manager-brief.md new file mode 100644 index 00000000..10c37922 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/manager-brief.md @@ -0,0 +1,62 @@ +# Template — Manager Brief + +The dispatch packet the orchestrator compiles for a manager taking one master. Like the worker +brief, **this brief is the manager's entire session start** — it replaces the front half the +orchestrator already ran. Spawn with `env={"AR_SPAWN_ROLE": "manager"}` and the **qualified** leaf +key of the master's coordination leaf (`//`). + +--- + +```md +ROLE BRIEF — manager + +# MANAGER BRIEF — · + +You are the MANAGER for master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/manager.md`; this brief is your session start. Drive this +master's leaf loop to the master-exit seam, then hand over. + +## The master +- Task doc: `` (read it + every leaf doc first). +- Planner master: +- Leaves, in order: . +- Trust facts (compiled by the orchestrator — do not re-run the checkpoint): providers , drift , freshness . + +## The branch base (load-bearing) +- Your master integration branch: ``, based off the CURRENT super branch + `` @ `` — master branches base off super, never off main. +- Leaf worktrees base off your master branch (normal `worktree_start` per leaf). + +## Dispatch defaults +- Worker spawns: `templates/worker-brief.md`, `env={"AR_SPAWN_ROLE": "worker"}`, qualified leaf + keys; knob overrides: . +- Concurrency: . + +## The exit +- When all leaves have landed on your branch: spawn the master-exit reviewer + (`env={"AR_SPAWN_ROLE": "reviewer"}`, `roles/reviewer.md`) with the scope packet your role file + enumerates; then RAISE the gate without blocking — + `lifecycle_gate(kind="master-handover-approval", enclosure="", + evidence_refs=[], wait=false)` — the `enclosure` MUST carry the master's identity: + the EXACT master task name as the contracts carry it (the raise refuses without one) — + and post the master-handover packet **carrying the returned gateId**: the ORCHESTRATOR decides + the gate by that id. Under an all-human policy the raise blocks and the developer decides — do + not pass wait=false. +- Escalation: to the orchestrator, never the developer. Human-pinned kinds you may meet: + `integration-approval`, `push-approval`, `cleanup-approval`. + +## Reports +- Your handover packet: `../templates/master-handover-packet.md`. +- Leaf-review notes on your coordination leaf; decision-log entries for every delegated gate you + decide and every reopen. +``` + +--- + +**Compiler notes for the orchestrator.** + +- Fill every ``; an unresolved placeholder is not dispatchable. +- The super-tip commit you write here is the reconciliation anchor if a sibling master lands + first — state it explicitly. +- Deliver as an echo-confirmed paste; only count delivery on a post-boot echo. diff --git a/.agents/skills/l-01-agent-lifecycles/templates/master-handover-packet.md b/.agents/skills/l-01-agent-lifecycles/templates/master-handover-packet.md new file mode 100644 index 00000000..c8f5cb5c --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/master-handover-packet.md @@ -0,0 +1,49 @@ +# Master-Handover-Packet Template + +The artifact a **manager** posts to the **orchestrator** at master exit (`roles/manager.md`), after the +master-exit adversarial seam. Delivered via the inbox (durable) + stdin push. It is what the +orchestrator integrates a completed master into the super branch from. + +## Rules + +1. Post it only **after** the master-exit verdict exists — the verdict reference is a required slot. +2. Name the integration branch precisely; the orchestrator bases its C-11 integration on it. +3. The carry-over state must let the orchestrator's `c-11-memory-carryover-from-branch` integration run + without re-deriving what landed. +4. Post the packet as an `operator_inbox_post` row with `messageKind="master-handover"` and push + delivery enabled so the durable inbox row and stdin notification agree. + +## Shape + +```md +# Master Handover — · + +| Field | Value | +| ------------------ | -------------------------------------------- | +| master | | +| manager seat | | +| integration branch | | +| handover gateId | | +| base | | +| verdict | | +| verdict outcome | pass | pass-with-notes | +| written | | + +## Change-Set Summary +- +- Leaves landed: , … + +## Requirements / Steps Completion +- All master requirements addressed: yes | with justified deltas (decision-log refs: …) + +## Carry-Over State (for the orchestrator's master → super C-11) +- Memory rows parked / carried: +- Ledger maps every leaf commit: yes | +- Single-siding notes (if this master overlaps another strand): + +## Known Follow-Ups +- | none + +## Reachability +- Manager seat (chat + coordination leaf) stays reachable until the series retires. +``` diff --git a/.agents/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md b/.agents/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md new file mode 100644 index 00000000..81c2466b --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md @@ -0,0 +1,48 @@ +# Onboarding-Coherency Template + +A durable report a fan-out sub-agent writes for the **adversarial reviewer's** third lens +(onboarding-vs-code) and for the **orchestrator's** memory-quality checks. It is the paired +`read_ar_files` + `memory_quality_check` + `drift_check` review made durable — the check that the +memory repo stayed in lockstep with the code, since **orchestrator quality ∝ memory-repo quality**. + +## Rules + +1. Every **changed** source file must have its sidecar body updated **in the same pass** — a refreshed + `lastVerifiedCommitHash` over stale content silently defeats the drift check and is a finding. +2. Every **new** source file must have a created sidecar (`check_missing_onboarding` clean). +3. Route/repository overviews must reflect the change set; a moved/added/deleted slice must be + reflected in the governing overview. +4. This is a report; the reviewer's verdict or the orchestrator's main loop acts on it. + +## Shape + +```md +# Onboarding Coherency — + +| Field | Value | +| --------- | --------------------------------------- | +| for | reviewer () | orchestrator | +| author | | +| scope | | +| written | | + +## Changed Files — Sidecar Refresh +| Source file | Sidecar updated same pass? | Body reflects change? | Finding | +| ----------- | -------------------------- | --------------------- | ------- | + +## New Files — Missing Onboarding +| New source file | Sidecar created? | check_missing_onboarding clean? | Finding | +| --------------- | ---------------- | ------------------------------- | ------- | + +## Drift & Quality +- drift_check: clean | actionable (list) +- memory_quality_check: pass | +- Ledger maps code HEAD: yes | + +## Overviews +- Route/repository overviews current for touched routes: yes | +- Moved/added/deleted slices reflected in governing overviews: yes | + +## Bottom Line +- Onboarding-vs-code coherent: yes | NO — +``` diff --git a/.agents/skills/l-01-agent-lifecycles/templates/orchestration-task.md b/.agents/skills/l-01-agent-lifecycles/templates/orchestration-task.md new file mode 100644 index 00000000..c3d4bb08 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/orchestration-task.md @@ -0,0 +1,89 @@ +# Orchestration-Task Template + +The artifact a **strategist** drafts for the **orchestrator** (`roles/strategist.md`) — the sprint +plan and the sprint scope. A strategist run producing this artifact is a **mandatory precondition +for any orchestrated run**; the orchestrator adopts the accepted draft into durable task form (the +strategist is a reader, not a mutator). It is written under the series/coordination `notes/` path +the brief names and revised across drawing-board rounds. + +## Rules + +1. **Shown work is required per section.** Every dependency edge carries evidence (a tool query, a + file, a decision-log entry, a design-section citation, or — for new surfaces — a **declaration + cross-reference**: the two leaf declarations that couple) — an uncited edge is refutable by + default. Every blast-radius entry names its derivation (caller-set / doctrine-propagation / + migration / user-visible). Every leaf move carries from→to + rationale. +2. **Surfaces are two-sided:** the surface lists distinguish **existing** surfaces (mapped against + the route map) from **new** surfaces (greenfield, mapped by declaration: parent route/location + + intended shape). New-surface edges come from declaration cross-reference — leaf B naming a + surface leaf A creates is a pure ORDER edge; two leaves declaring additions under one parent + route is a CONFLICT-risk edge at the parent. +3. **Coherence findings include the honest failures:** a leaf that can name neither existing + surfaces nor the parent anchoring of its additions is recorded as **"unplannable as scoped"** — + never silently guessed around (a merely not-yet-existing surface is NOT unplannable). Directional + cross-master contradictions are flagged quo-vadis at the top of that section. +4. This is a **draft for adoption**, not a mutation: the strategist never edits task docs; the + orchestrator (the portfolio owner) adopts the plan and records the adoption in the decision log. +5. The plan is reviewed adversarially (the plan-review criteria catalog, + `../criteria/plan-review.md`) before the developer's drawing board; revisions append round + sections rather than rewriting history. +6. Once adopted, this artifact is the sprint's standing scope: in-sprint additions before + implementation starts trigger re-evaluation; out-of-sprint additions wait for the next sprint. + +## Shape + +```md +# Orchestration Task — · + +| Field | Value | +| ---------------- | ------------------------------------------------ | +| strategist | | +| masters in scope | | +| status | draft | in-review | round- | adopted | +| round | (3-round cap; the drawing board is the escalation) | +| written | | + +## Sprint Scope +- IN: +- OUT: + +## Touch Surfaces (per leaf — two-sided) +| Leaf | Existing surfaces (route-map-mapped) | New surfaces (declared: parent route/location + intended shape) | +| ---- | ------------------------------------ | ---------------------------------------------------------------- | + +## Dependency Graph (every edge cited — an uncited edge is refutable by default) +| From (leaf/master) | To | Kind (ORDER | CONFLICT | INDEPENDENT) | Evidence (cgc/grepai query · file · decision-log · design § · declaration cross-reference) | +| ------------------ | -- | ------------------------------------ | ------------------------------------------------------------------------------------------ | + +## Blast-Radius Register (feeds the owning seat's loop-tier scoring) +| Leaf | Radius (low | medium | high) | Derivation (caller-set | doctrine-propagation | migration | user-visible) | Evidence | +| ---- | ---------------------------- | ------------------------------------------------------------------------- | -------- | + +## Leaf Moves +| Leaf | From (master) | To (master) | Rationale | +| ---- | ------------- | ----------- | --------- | + +## Coherence Findings +- ⟁ QUO-VADIS (developer decision required): | none +- +- Unplannable as scoped: | none + +## Sprint Order / Waves +1. (note the + landing-reconciliation cost of parallel waves as a scheduling consideration) +2. + +## Open Risks +- + +## Re-Evaluation Triggers +- In-sprint master added before implementation starts → re-plan (strategist re-evaluates). +- Master added outside the sprint scope → next sprint's evaluation. +- + +## Evidence Inventory +- cgc queries (dependencies/callers/callees/complexity): +- grepai queries (search/trace): +- read_ar_files reads (paired source+onboarding) / route indexes read: +- task docs, decision logs, and design sections cited: +``` diff --git a/.agents/skills/l-01-agent-lifecycles/templates/turn-report.md b/.agents/skills/l-01-agent-lifecycles/templates/turn-report.md new file mode 100644 index 00000000..b771ada4 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/turn-report.md @@ -0,0 +1,57 @@ +# Turn-Report Template + +The **mandatory** artifact a worker writes at **every** hand-off (`roles/worker.md`). It is how the +leaf's work survives the session's death and how a respawned successor onboards from **state, not the +transcript**. A missing turn report is nudged by the manager. + +## Rules + +1. Write it in the **main loop**, from your own work plus any sub-agent summaries — never delegate it to + a sub-agent (it is the leaf's single artifact of record). +2. State facts, not a narrative: what changed, what broke, what is proven green, what remains. +3. The **Respawn State** section must let a fresh successor continue **without reading any transcript**. +4. Keep it durable and in the series notes; reference it from the leaf `task_doc`. +5. Default path: `notes/reports/-worker-report.md`. The control-plane helper exposes this + convention so manager nudges and respawn onboarding can point at the same artifact. + +## Shape + +```md +# Turn Report — · + +| Field | Value | +| ------------ | --------------------------------------- | +| leaf | | +| master | | +| worker | | +| worktree | | +| status | in-progress | leaf-complete | blocked | +| checks | green | failing: | not-yet-run | +| written | | +| inbox | | + +## What Was Done +- (files: ``, …) + +## Issues Hit +- → resolved: | still open: + +## Solved On The Spot +- (a plan delta beyond blank-filling is NOT here — it was + escalated to the manager; see Escalations) + +## What Is Left +- [ ] + +## Onboarding Refreshed +- in this pass (c-05) + +## Escalations +- | none + +## Respawn State (onboard a successor from this — no transcript needed) +- Current position in the leaf plan: +- Files touched so far: +- The one thing a successor must know before editing: +- Uncommitted vs committed state: +``` diff --git a/.agents/skills/l-01-agent-lifecycles/templates/verdict.md b/.agents/skills/l-01-agent-lifecycles/templates/verdict.md new file mode 100644 index 00000000..3f292443 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/verdict.md @@ -0,0 +1,142 @@ +# Verdict Template (adversarial reviewer) + +The artifact an **adversarial reviewer** writes at a seam (`roles/reviewer.md`). It lands +under the series `notes/reports/` directory and attaches to the handover gate as **judge evidence**. +There are two variants: **master-exit** (before a manager hands over to the orchestrator) and +**super-exit** (before the orchestrator hands over to the developer) — plus a loop-review +adaptation of the master-exit shape (see Loop-Review Adaptation below). + +## Rules + +1. **A verdict is evidence, not a decision.** State an explicit pass/block **recommendation**; the gate's + decider decides. Never write the verdict as if it were the gate outcome. +2. **A block must decompose into fix leaves** — concrete, leaf-shaped findings the owning + manager/orchestrator can dispatch. A block that cannot be named as fix leaves is not yet a block. +3. **Refute-or-confirm:** every finding must survive an attempt to refute it. Rank findings and cite + the backing evidence file. +4. Cover all three lenses (completion · code quality · onboarding-vs-code) explicitly, even to say a + lens is clean. +5. Record the gate evidence reference exactly: `kind=reviewer-verdict`, `ref=`, and + `verdict=`. +6. **Report every bound catalog criterion** in the Criteria Catalog Results table (the catalogs the + binding table in `roles/reviewer.md` assigns this review type, `../criteria/`) — one row per + standing criterion even when it found nothing, candidate rows when run — and carry any proposed + catalog amendments (the promotion ratchet) in that section. + +## Master-Exit Variant + +```md +# Adversarial Verdict — master-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | master-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | orchestrator (delegated `master-handover-approval`; serious issues escalate → developer) | +| artifact path | notes/reports/-master-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Task Docs +- Master requirement/substep coverage: addressed | delta justified | MISSING +- Leaf task docs and worker reports reconcile with the master task_doc: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite: green | failing: +- regressions vs the past (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- master-side route overviews current: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Manager Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the master-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Super-Exit Variant + +```md +# Adversarial Verdict — super-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | super-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | developer (human review concentrates at the super gate) | +| artifact path | notes/reports/-super-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Portfolio Task Docs +- Portfolio objective and dependency order satisfied: yes | +- Master handover packets and prior master-exit verdicts reconciled: yes | +- Cross-master conflicts, duplicate implementations, and deferred follow-ups surfaced: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite for the accumulated super branch: green | failing: +- branch-wide regressions vs the past and across masters (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- route overviews describe the accumulated behavior: yes | +- C-11 carry-over and ledger mapping coherent for the final super branch: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Orchestrator Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the super-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Loop-Review Adaptation (leaf full-loop · plan review) + +A three-party-loop review (a full-loop leaf round, or the plan review over an orchestration task) +uses the **master-exit variant's shape minus the gate machinery**: drop the `gate evidence` header +row and the Judge-Evidence Note (a loop review attaches to no gate), set `decider` to the **loop +owner** (the leaf's owning seat, or the orchestrator for the plan review), scope to the round's +change set (or the orchestration-task draft), and keep everything else — recommendation, Criteria +Catalog Results (the loop's bound catalogs, e.g. `plan-review` + `report-verification` for a plan +review), ranked refute-tested findings, and fix decomposition. The verdict remains **evidence to +the loop owner, never a decision**; a delta-verify appends a dated delta section to this same +artifact rather than opening a new one. diff --git a/.agents/skills/l-01-agent-lifecycles/templates/worker-brief.md b/.agents/skills/l-01-agent-lifecycles/templates/worker-brief.md new file mode 100644 index 00000000..db8f44d0 --- /dev/null +++ b/.agents/skills/l-01-agent-lifecycles/templates/worker-brief.md @@ -0,0 +1,72 @@ +# Template — Worker Brief + +The dispatch packet a spawning seat (manager / orchestrator) compiles for a worker. **The brief is +the worker's entire session start** — it replaces the front half the spawner already ran (trust +checkpoint, reframe, plan). Compile it fresh per leaf from this shape; the proven form below +absorbed a series of real dispatch frictions (route-index leaks, attestation format, provider-stack +keying, missing `python` shim), so deviate knowingly or not at all. + +Spawn with `env={"AR_SPAWN_ROLE": "worker"}` and the **qualified** leaf key +`//` so the session-start router and the dashboard leaf rail both engage. + +--- + +```md +ROLE BRIEF — worker + +# WORKER BRIEF — · + +You are a WORKER for leaf `` of master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/worker.md`; this brief is your session start. Execute the leaf +completely, write your turn report, then stop. + +## Worktrees (your ONLY writable areas) +- Code: `` (branch ``, base ``) +- Memory: `` +- Plus your turn report at the path below. Nothing else. NEVER `git commit` — the owning seat + closes out after reviewing your report. + +## Tool surface +- Native file tools inside the two worktrees; shell for the checks below. +- Read-only AR retrieval: `read_ar_files` (serves the OFFICIAL baseline, never your worktree — + final verification uses native reads), `grepai_search` / `cgc_*` (provider stack key: + ``), `context_packet`. +- No `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, or `route_index_refresh` — + generated route indexes are regenerated with a local `build_route_indexes(...)` from the memory + worktree. +- Interpreter: `` with `PYTHONPATH=/mcp/src` — there is no + `python` shim in this environment. + +## The task +Leaf spec: `` (read it first). + +## Checks (green before you report) +- Focused: . +- Full: — must exit 0. +- `git diff --check` in both worktrees. + +## Onboarding (same editing pass, per c-05) +- Changed source files: update the sidecar BODY now; new files: create the sidecar. +- Route overviews: genuine body update where routes changed; otherwise the newest history entry + uses the LITERAL form `- — No route impact: ` (timestamp first). +- Pin idiom for verification metadata: "Verification metadata pinned until closeout stamps the + commit." + +## Turn report (mandatory, last act) +Write `/-worker-report.md` following +`skills/l-01-agent-lifecycles/templates/turn-report.md` — including exact check commands + +outcomes, the retrieval-evidence tally, and the respawn state. If blocked: fill Escalations and +stop — escalate to , never to the developer. +``` + +--- + +**Compiler notes for the spawning seat.** + +- Fill every ``; a brief with an unresolved placeholder is not dispatchable. +- Verify the provider stack actually answers before naming it; write `NONE (native reads only)` + when it does not — a worker discovering dead providers mid-leaf wastes its turn. +- Deliver as an echo-confirmed paste; verify the harness's paste chip (`[Pasted Content N chars]`) + before submitting, and only count delivery on a post-boot echo. +- The report path lives under the series `notes/reports/` — the same folder the seam verdicts use. diff --git a/.agents/skills/l-01-session-job-lifecycle/SKILL.md b/.agents/skills/l-01-session-job-lifecycle/SKILL.md deleted file mode 100644 index 9b3cc6d6..00000000 --- a/.agents/skills/l-01-session-job-lifecycle/SKILL.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -name: l-01-session-job-lifecycle -description: "The session job lifecycle the coordinator routes every session into: request -> context/trust checkpoint -> developer-agreed reframe -> deeper research -> decide build mode -> build -> close. Owns research-only exits, the build-mode decision (chat build vs durable w-02-light-task-workflow task), and the job lens (bug/feature/triage/research). Supersedes the retired chat workflow by migrating and modernizing its doctrine." ---- - -# l-01-session-job-lifecycle Session Job Lifecycle - -The `l-01-session-job-lifecycle` skill is the **canvas** the coordinator routes into at the start of every session. -It is not a task format. A task format is one outcome of a single step inside it. - -The lifecycle is one shared spine with thin per-job lenses. Its front half is a -developer/model collaboration loop: the developer states the request, the model -runs mandatory MCP grounding checks, the model presents an evidence-backed -reframe, and the developer agrees or revises that reframe before deeper research -or build-mode decisions proceed. - -## Companion Files - -1. `job-variants.md` — the four thin job lenses (bug / feature / triage / research). -2. `deep-research-report-template.md` — the reusable report and evidence-ledger shape for deeper research. - -``` -0 Request -> 1 Trust Checkpoint -> 2 Reframe + Research -> 3 Decide -> 4 Build -> 5 Close - | - +-- research-only (e.g. investigation, code questions...) -``` - -## Hand-off Protocol — Dry-run action => "Notify-and-stop" Action => "Report" Action - -Every developer hand-off / gate moment — reframe agreement, plan gate, worktree intent, commit -approval, push approval, integration, cleanup/finalization, regular turn-end — is **notify-and-continue**: -surface an attention item, present the result, and **end your turn**; the developer responds and your -**next** turn picks up automatically. It is **three actions, never one**: - -1. **Dry-run action.** Run applicable MCP tools in `dry-run` for the hand-off. If dry run succeeds, - proceed with the notify-and-stop action. If dry run fails, try to ammend the issue first before reporting failure. -2. **Notify-and-stop action.** Call `lifecycle_turn_end_notification(summary=…)`. It sets the new - **`awaiting-developer`** lifecycle state, surfaces a dashboard attention item, and **returns - immediately — no wait, no inbox.** This is the **last tool call of the turn** — the report prose - still follows it; do not STOP here. The developer responds on the - dashboard or in the leaf's attached chat, and the **first AR tool call of your next turn** - automatically resumes the lifecycle (`running`) and clears the attention item — you send **no** - explicit resume. -3. **Report action.** Deliver the complete hand-off report as plain assistant output - (the reframe, the plan, the intent packet, or the closeout relay with - preview facts, quality results, proposed commit messages, and - attestations), and make the decision you are handing to the developer the last - line of prose. **The report is the last thing in the turn — then STOP / end your turn.** - -Use the `dry-run` step to verify that the planned tool call (for example the closeout apply) will -succeed before you hand off, and self-fix any failure before reporting it. - -`lifecycle_turn_end_notification` returns immediately and does **not** render a prompt over your prose, -so the report you deliver after it is exactly what the developer sees — call the -notification, then deliver the report as your final prose, then stop. Keep the report turn free of any mutating or permission-triggering operation so -nothing obscures the report. - -Junction → Dry-run → notify (`lifecycle_turn_end_notification`) → Report. Every junction below now hands -off through that one notification; the named `kind` is the **parked** durable-gate label the fallback -would use (see "Parked fallback" below), kept so the dashboard can still classify each hand-off: - -| Junction | Parked durable gate `kind` | Skill that hands off | -| -------------------------------- | -------------------------- | ---------------------------------------------------------- | -| plan gate | `plan-approval` | `l-01-session-job-lifecycle` | -| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | -| commit / closeout | `closeout-approval` | `c-12-closeout` | -| push | `push-approval` | `l-01-session-job-lifecycle` / `c-09-git-worktree-manager` | -| integration | `integration-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| cleanup / lifecycle finalization | `cleanup-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| any other dev-wait | `agent-question` | `l-01-session-job-lifecycle` | - -`closeout-approval` **is** the commit hand-off — there is no separate -`commit-approval`. Closeout is the single commit-of-record for code, memory, and -ledger, so every commit (including a singular one) routes through the closeout -hand-off. `agent-question` is the non-exhaustive catch-all so any dev-wait that is -not a structured junction is still observable. - -### Parked fallback — block-and-wait `lifecycle_gate` - -The block-and-wait `lifecycle_gate(kind=…)` junction (which creates a durable gate and waits for a -developer decision), the operator inbox, and the dashboard GateResponder **still exist and still work** -when explicitly raised — but they are **no longer the active path**, and nothing routes toward them: -`next_step.py` repoints every gate moment to `lifecycle_turn_end_notification`. Reach for the -server-enforced `lifecycle_gate` (followed by `lifecycle_resume` after the developer decides) only when -you deliberately need a durable, developer-attributed, mutation-blocking approval record; its `kind` -values are the table above. If you ever do raise it, it renders an approval prompt **over** your prose, -so the report must land in an earlier turn — which is exactly why notify-and-stop is preferred. - -## Lifecycle Signals — Making The Session Observable - -Every session in a managed repo is a **lifecycle**: the six `lifecycle_*` signals -record where it is and what it is waiting on, so the work is observable and -resumable across chat deaths (design `docs/design/observable-lifecycle.md`). The -model **never handles a lifecycle id** — identity is server-side, anchored in the -worktree contract. - -| When (phase) | Signal | Why | -| ---------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Trust Checkpoint passes (managed repo) | `lifecycle_start` | Begin a **fleeting** lifecycle (guarded: one per session; takes no id). | -| Entering each phase | `lifecycle_phase` | Move the orthogonal phase axis (`request`/`trust-checkpoint`/`reframe-research`/`decide`/`build`/`close`). | -| At a hand-off (reframe, plan, commit, …) | `lifecycle_turn_end_notification(summary=…)` (last tool call), then the report prose, then **STOP** | Set `awaiting-developer`, surface the dashboard attention item, and return immediately (no wait, no inbox); the next turn's first AR tool call auto-resumes (`running`) and clears the item. Block-and-wait `lifecycle_gate(kind=, ask=…, packet=…)` + `lifecycle_resume` is the parked fallback. | -| `worktree_start` (Decide → Build) | _(promotion — automatic)_ | The fleeting lifecycle becomes **persistent**, anchored in the contract; no separate signal. | -| Resuming an existing task | `worktree_attach` | Re-adopts the contract's lifecycle (contract-resolved); the model passes no id. | -| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | The save gate: promote it or abandon it — never dropped silently. | -| Close | `lifecycle_end` (`completed`\|`abandoned`) | The terminal record. | - -Rules: `lifecycle_start` is guarded (one active lifecycle, no id). `paused` is -**system-owned** — there is no pause signal. `awaiting-developer` is set by -`lifecycle_turn_end_notification` and auto-cleared back to `running` by the next -turn's first AR tool call — you never resume it by hand. A tool call outside any -lifecycle is **dropped, never misattributed**. `worktree_start` **promotes** the current -lifecycle (fleeting → persistent); `worktree_attach` **resumes** the contract's -lifecycle; both keep identity server-side. - -## 0 — Request - -Receive the developer's raw request and identify the active repository. - -1. Treat the developer's statement as raw input, not yet as an implementation plan. -2. Infer the target code repository from the request and local context. Ask the - developer if the target is unclear. - -Request intake changes nothing. It only establishes which repository the next -checkpoint must inspect. - -The upcoming `Trust Checkpoint` reveals whether or not the request is related to repositories managed by Agents Remember. If not, then the lifecycle exits early and the agent can work as usual. - -However, if later work is to enter the boundary of repositories being managed by Agents Remember, -the lifecycle must be re-entered. - ---- - -## 1 — Trust Checkpoint - -Establish whether memory and providers are trustworthy enough to use. - -1. For the target repository, resolve coordination/memory context with - the MCP tool call: - - ```text - context_packet(repo_id="", include_providers=true, include_drift=true, include_freshness=true) - ``` - -2. Report the packet facts before relying on memory or providers: - - repository, branch, and dirty state - - memory root and onboarding root - - provider state - - drift status and actionable drift count - - branch freshness: whether the code and memory checkouts are current with - their upstreams (`behind`/`diverged` means the local official line is - stale — fast-forward it before trusting analysis or basing work on it) - and whether the ledger maps code HEAD (`ledgerMapsCodeHead=false` means - the memory checkout does not match the code state; run carryover or - check out the right memory branch first) -3. If onboarding for committed source is drifted, missing verification, or - orphaned, and the corresponding source file is not dirty in the code - worktree, stop and ask the developer whether or not to refresh it through - `c-05-create-or-update-onboarding-files`. Drift handling is approval-gated! -4. If drift is tied to dirty source, report it as active work-in-progress. Do - not adopt it as maintenance or silently trust it as current state unless the - developer explicitly says this job owns it. -5. If providers are stopped or degraded, use the matching MCP provider/runtime - operations, then re-run the provider check. If providers are ready, report - readiness and continue. If issues persist, report it to the developer and - wait for instructions. If the packet's providers summary lists `indexing` - targets, report them to the developer: those providers are healthy but - busy, and their results may be partial until the scan completes. -6. After the trust checkpoint passes, read committed-state onboarding for the - in-scope anchors as needed. A file dirty in another chat is still valid for - HEAD and worth comparing, but its dirty-source drift remains active work. - ---- - -## 2 — Reframe And Research - -Turn the developer's raw request into an agreed piece of work, then perform the -deeper research that the agreed frame requires. The `tasks/AGENTS.md` -collaboration doctrine applies here in plain chat, before any task file or task -format exists. - -**Read tool for this phase.** Until the build-mode decision (Phase 3), read managed-repo source -through the `read_ar_files` MCP tool, not the harness's native read — it returns paired -source+onboarding plus the repository/route overviews in one observable, lifecycle-attributed -call, and you keep a running count of those calls as evidence. Native read is the edit -precondition in Phase 4. - -1. **Gather evidence for the reframe** through reading the - `c-04-retrieval-strategy-router` skill. Pick the strategy by the question: - - _Semantics_ (grepai over onboarding) — "where does X live / what handles Y." - - _Relationship_ (cgc) — callers/callees/dependencies/impact. - - _Intent_ (onboarding + bounded source confirmation) — hidden contracts, invariants, - branch-valid truths, behavioral expectations. This is a workflow of paired - source+onboarding reads via the `read_ar_files` MCP tool: one call pairs each source - file with its verified onboarding and auto-attaches the repository overview + governing - route-overview chain (the bird's-eye view). -2. **Reframe** the request through `tasks/AGENTS.md`: distinguish the surface - request, deeper objective, highest-leverage framing, assumptions, boundaries, - invariants, and truth gaps. Do not rush a statement into a plan. -3. Present the reframe to the developer. If the developer disagrees, discuss and - revise the reframe. If the developer agrees, proceed to deeper research. -4. **Perform deeper research** for the agreed frame. This research still uses - `c-04-retrieval-strategy-router`, but it is now scoped by the developer-agreed - frame rather than by the model's first guess. Use - `deep-research-report-template.md` for the report shape; the lifecycle owns - the required proof categories, while the template owns evidence formatting. -5. The deeper research report must list its proof and tie evidence to the claim it supports: - - `read_ar_files` calls (paired source+onboarding reads — the running count) - - onboarding docs read - - semantic queries performed - - code graph queries performed - - source files inspected - - remaining truth gaps -6. Run the **job opening move** for the job lens (see `job-variants.md`) and use - the deeper research to name the truth gaps that remain. -7. Continue until the developer agrees the design is defined well enough to write - down, then produce the **plan**: the steps, and a **code example for every - distinct change** you intend to make. - -**Plan gate:** **hand off** before changing any code. No implementation begins -before the developer approves. Call -`lifecycle_turn_end_notification(summary={…the plan + the developer-facing approval ask…})` as the -**last tool call**, then present the plan as your final prose and **STOP**; -the developer approves on the dashboard or in chat and your next turn auto-resumes to begin -implementation. (Parked fallback: the server-enforced -`lifecycle_gate(kind="plan-approval", ask=…, packet=…)` + `lifecycle_resume` still exist if you -deliberately need a mutation-blocking approval record.) - ---- - -## 3 — Decide (build mode) - -One decision: does this job change code? - -- **No -> research-only exit.** Deliver the answer/assessment. No worktree, no task artifact, no closeout. - A research-only job may recommend or spawn a follow-up build job; it does not perform one itself. -- **Yes -> worktree intent hand-off, then always a worktree.** Read `c-09-git-worktree-manager` - and `system/git-workflow.md`, call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the worktree - intent packet as your final prose and **STOP**. The developer approves and your next turn - auto-resumes to `worktree_start`. Then open it with - `c-09-git-worktree-manager` and pick the build mode: - - **Chat build** — small enough to carry inline this session: worktree-backed, **no** `task.md`. - - **Durable task build** — hand off to `w-02-light-task-workflow`: `task.md`, checklist, decision - log, proposed code examples. Escalate to a master + light sub-task series when the work outgrows a - single-page plan. - -The worktree intent packet names the target repo, build mode, discovered branch policy, proposed -`source_branch`, proposed work branch/worktree name, memory mode, landing path, and material risks. -On PR-gated repos, the packet must prove that the recorded `source_branch` is pushable and that -protected targets are reached later through the repo's PR flow. - -Worktree granularity = the leaf task unit. A single task gets its own leaf enclosure/worktree. A -master multi-task owns a root `series-contract.md` and integration branch, while each active leaf -sub-task gets its own `enclosures//series-contract.md`, branch, and worktree. A chat build -gets its own leaf worktree without a task artifact. The git-landing decision (direct vs PR-gated) is -deferred to the repo's `system/git-workflow.md` — read it before landing on a gated branch. - ---- - -## 4 — Build - -Implement inside the worktree, keeping memory and tests in lockstep with the code. - -1. Apply the approved code changes. -2. **Refresh the matching onboarding in the same editing pass**, per completed plan-section — never - deferred to the end of the job. When a change affects durable current-state knowledge, the sidecar - is updated alongside it through `c-05-create-or-update-onboarding-files`. - - For **changed** (already-onboarded) source files, update the sidecar **body** now: the closeout - gate rejects a changed source file whose existing sidecar was not modified this job, because - refreshing `lastVerifiedCommitHash` over stale content silently defeats the drift check. - - For **new** source files, run `check_missing_onboarding` before the commit and create the - reported missing sidecars through the `c-05-create-or-update-onboarding-files` skill; the post-code-commit memory refresh stamps them with - the real code commit hash and date. -3. Run the checks from the `c-08-ar-coordination-context-resolver` resolved `system/tools.md` (lint, typecheck, complexity, tests) and - get them **green before each incremental commit**. Testing is never deferred to a final task; the - pre-commit/pre-push hooks enforce it. -4. **Watch the official line and sync early.** `worktree_status`'s `freshness` block reports when the - recorded base pair fell behind the local source branch tips (a parallel cycle landed). Pull the - moved official line in with `worktree_sync` — preferably **before memories are written**: with - parked memory the sync is a pure fast-forward, the other cycle's sidecars and ledger rows end up - beneath this task's future work, and end-of-series integration stays `ff-only` with no carryover - reconciliation. - -Incremental, pushable commits keep the work-loss window small. Each closeout below is one such commit. - ---- - -## 5 — Close - -Land the work. **Implementation approval is not commit approval.** - -1. Run the `c-09-git-worktree-manager` closeout **preview** for the worktree (`worktree_closeout_preview`). - Every build closes through its worktree — there is no direct-checkout closeout. - Relay the proposed code, memory, and ledger commit messages. -2. **Commit gate:** run the closeout **preview** (dry-run), then **hand off** before any real commit or closeout - apply. If required onboarding is missing, run the `c-05-create-or-update-onboarding-files` skill for the affected file and re-run the preview. - Call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the - **last tool call**, then deliver the preview facts as your final prose and **STOP**; - the developer approves on the dashboard or in chat and your next turn auto-resumes to - `worktree_closeout_apply`. The `c-12-closeout` skill owns this hand-off. Parked fallback: when you - deliberately raise the durable `closeout-approval` `lifecycle_gate`, it is enforced **server-side** — - `worktree_closeout_apply` refuses unless it is approved by the developer, and an agent self-approval - never satisfies it. -3. On approval, the `c-09-git-worktree-manager` skill owns the external-memory invariant in order: commit code → refresh affected - onboarding metadata to the new code commit → run memory quality control → commit memory content → - update and commit the ledger. -4. **Integrate + land** per `c-09-git-worktree-manager` and `system/git-workflow.md`: integrate the - worktree branch into the approved source/integration branch, then on a PR-gated repo push that - source branch, open the PR, wait for green checks, and merge per the repo convention. Never push a - protected branch directly. The agent does not push on its own authority — call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the push intent - as your final prose, and **STOP**; push only after the developer - approves and your next turn auto-resumes. The `c-09-git-worktree-manager` skill makes the matching - integration and cleanup/finalization hand-offs at its landing tail (parked durable kinds - `integration-approval` / `cleanup-approval`). -5. **Map the ledger to the landed commit.** A PR merge usually lands a **merge commit** on top of the - work — tree-identical to the verified tip but a new SHA the ledger does not yet map. Ensure the - ledger maps that merge commit so the next worktree can base off the merged branch without a manual - reconciliation. `system/git-workflow.md` owns this step. -6. **Finalize the lifecycle:** run `lifecycle_finalize_task(..., dry_run=true)` once the local parent - branch contains the landed commit and memory carryover is done. Call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then relay its landed-commit - proof, cleanup plan, and task-document updates as your final prose, and - **STOP**. The developer approves cleanup/finalization and your next turn auto-resumes to run the real - finalizer. The tool proves one parent-child branch edge, - reclaims the worktrees, and marks the leaf task plus immediate parent row `Completed` when those - task-doc paths are supplied. It does not recursively complete ancestors; repeat the edge at the next - parent level when that parent task lands. -7. **Keep squash out of the normal path.** A PR-gated edge is structurally the same as a direct edge - after the model finishes the PR merge and pulls the target branch locally. Do not use squash-merge - equivalence as a default finalization proof; squash is an emergency/manual recovery path because it - erases commit lineage and can make memory lookup history wrong. - -A research-only exit skips this phase entirely. - -## Relationship To Other Instructions - -This skill extends the coordinator `AGENTS.md` and the repository memory layer; it does not replace -them. Read `job-variants.md` for the per-job lenses, and `deep-research-report-template.md` for the -deeper research report shape. diff --git a/.agents/skills/w-02-light-task-workflow/SKILL.md b/.agents/skills/w-02-light-task-workflow/SKILL.md index 248e6f3c..b34f3017 100644 --- a/.agents/skills/w-02-light-task-workflow/SKILL.md +++ b/.agents/skills/w-02-light-task-workflow/SKILL.md @@ -40,7 +40,7 @@ Light-task artifacts use minute-precision timestamps in `YYYY-MM-DDTHH:MM` forma The task document is **JSON-primary**: an `ar-task-document/v1` JSON file is the source of truth, and the `task.md` (or `.md` for a sub-task) is a deterministic **render** of it. Author and update it with the `task_doc` MCP tool — `create`, `set_status`, `set_step`, `append_decision`, `set_field` — which writes the JSON and re-renders the markdown on every write. Do not hand-edit a tool-managed `task.md`; edit through the tool and let it re-render. `template.md` and `master-template.md` document the **render spec** (the shape the renderer produces), not a separate hand-authored format. When a planning slice defers its code examples to the plan gate, record that with `codeExamplesNote` (a `set_field` value, e.g. "Drafted at the plan gate.") so the rendered "Proposed Code Examples" section reads as *deferred* rather than as if none are needed. A leaf doc may also carry a descriptive `statusNote` (a suffix beside the strict status enum), `headerNotes` (extra `**Key:** value` header lines such as Verified/Source), and freeform `sections` appended after References — the escape hatch for bespoke prose (e.g. a Status history) while the standard template sections stay the backbone. Pass `dry_run=true` to any op to **preview** — it builds + validates and returns the rendered markdown, a unified `diff` vs the on-disk `.md`, and a `wouldLose` flag, **without writing**; use it before adopting a hand-authored `.md` into JSON-primary (author the JSON → dry-run → confirm `wouldLose` is false → then write). -Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for a chat build (a thin doc: title plus a few steps, so even a no-`task.md` session is legible) and a *full* one for a durable task; the difference is content completeness, not a separate format. +Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for the smallest single-session build (a THIN doc: title plus a few steps — chat is never a build route, so even micro-work gets this thin doc and stays legible on the dashboard) and a *full* one for a durable task; the difference is content completeness, not a separate format. Scope and transition: the tool manages **`light` and `subTask`** documents, and the format also covers a series **master** (`kind:"master"`: a structured `subTasks` index + ordered `sections` that preserve a master's bespoke prose, so a re-render is lossless). Masters and existing markdown task files stay hand-authored markdown until the runtime ships `task_doc` and they are intentionally migrated — new tasks adopt the JSON-primary format going forward. diff --git a/.agents/skills/w-02-light-task-workflow/master-template.md b/.agents/skills/w-02-light-task-workflow/master-template.md index 7cb4e85a..42738c16 100644 --- a/.agents/skills/w-02-light-task-workflow/master-template.md +++ b/.agents/skills/w-02-light-task-workflow/master-template.md @@ -7,7 +7,7 @@ built to grow as the work unfolds. ## When to escalate to a series -The `l-01-session-job-lifecycle` skill's `decide` build-mode step escalates a single task to a series once its size is apparent — the +The `l-01-agent-lifecycles` orchestrator lifecycle's `decide` step escalates a single task to a series once its size is apparent — the implementation plan no longer fits on a single page, or the work splits into distinct slices that each deserve their own checklist and commit. You can also start single and escalate later: drop in the master `task.md` and move the existing plan into the first `NN_.md`. diff --git a/.claude/hooks/agents-remember-session-start.md b/.claude/hooks/agents-remember-session-start.md index 427c30f3..cd999a73 100644 --- a/.claude/hooks/agents-remember-session-start.md +++ b/.claude/hooks/agents-remember-session-start.md @@ -1,14 +1,12 @@ -MANDATORY FIRST ACTION for this workspace +**Agents Remember — session start.** -You are not allowed to read, write, or execute code on any repository -until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure! +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** -Until the build/job decision is made, read managed-repo source with the -`read_ar_files` MCP tool — not the harness's native read tool. One call returns -each file paired with its onboarding plus the repository and governing route -overviews. Native read is reserved as the edit precondition once building begins. - -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent), and -keep a running count of your `read_ar_files` calls. Include the onboarding files -inspected and every CGC, GrepAI, and `read_ar_files` call made as evidence. +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`ar-coordination/AGENTS.md`, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. diff --git a/.claude/skills/c-01-findings-capture/SKILL.md b/.claude/skills/c-01-findings-capture/SKILL.md index e145d7ee..d413e8fe 100644 --- a/.claude/skills/c-01-findings-capture/SKILL.md +++ b/.claude/skills/c-01-findings-capture/SKILL.md @@ -13,7 +13,7 @@ Companion file: ## Operating Modes -1. Inside a task workflow (an `l-01-session-job-lifecycle` build job or a `w-02-light-task-workflow` task, including a master + light sub-task series). +1. Inside a task workflow (an `l-01-agent-lifecycles` orchestrator build phase or a `w-02-light-task-workflow` task, including a master + light sub-task series). 2. Standalone during direct clarification. ## Durable Destinations diff --git a/.claude/skills/c-03-repo-bootstrap/SKILL.md b/.claude/skills/c-03-repo-bootstrap/SKILL.md index 40148918..44f14f78 100644 --- a/.claude/skills/c-03-repo-bootstrap/SKILL.md +++ b/.claude/skills/c-03-repo-bootstrap/SKILL.md @@ -1240,7 +1240,7 @@ The orchestrator remains thin throughout. | `c-05-create-or-update-onboarding-files` | Owns final file-level onboarding semantics and routes structural slice maintenance back to the `c-03-repo-bootstrap` skill. The `c-03-repo-bootstrap` skill creates cards/waves and delegates file output rules to the `c-05-create-or-update-onboarding-files` skill. | | `c-04-retrieval-strategy-router` | Consumes bootstrapped overviews and file maps as the Intent substrate and can route to semantic/relationship providers first. | | `c-02-memory-quality-control` | Becomes relevant after bootstrap; touched files can be promoted from deferred to covered. | -| `l-01-session-job-lifecycle` | May trigger targeted bootstrap when an active job enters an uncovered area. | +| `l-01-agent-lifecycles` | May trigger targeted bootstrap when an active job enters an uncovered area. | | `confluence-search` / documentation search skills | Feed the docs evidence pass through approved sources from the input ledger. | --- diff --git a/.claude/skills/c-04-retrieval-strategy-router/SKILL.md b/.claude/skills/c-04-retrieval-strategy-router/SKILL.md index 01434c77..e226f8c0 100644 --- a/.claude/skills/c-04-retrieval-strategy-router/SKILL.md +++ b/.claude/skills/c-04-retrieval-strategy-router/SKILL.md @@ -160,7 +160,7 @@ names an unresolved source question. ### Rules: -- During the research phase (the lifecycle up to the build/job decision), read managed-repo +- During the research phase (the lifecycle up to the build decision), read managed-repo source with `read_ar_files`, not the native read tool — one call returns each file paired with its onboarding plus the repository and governing route overviews (the recipe above, batched and observable). diff --git a/.claude/skills/c-09-git-worktree-manager/SKILL.md b/.claude/skills/c-09-git-worktree-manager/SKILL.md index e19c7902..692dec19 100644 --- a/.claude/skills/c-09-git-worktree-manager/SKILL.md +++ b/.claude/skills/c-09-git-worktree-manager/SKILL.md @@ -7,7 +7,7 @@ description: "Create, attach to, report on, integrate, finalize, and clean up Ag Use this skill when a task should run through an explicit code/memory worktree wrapper. -The `c-09-git-worktree-manager` skill wraps the existing chat-build, light-task, or external workflow. It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. +The `c-09-git-worktree-manager` skill wraps the existing light-task or external workflow (a build that fits one session still rides a THIN `w-02-light-task-workflow` doc — chat is never a build route, per the `l-01-agent-lifecycles` invariant). It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. For closeout, use the `c-12-closeout` skill. The `c-09-git-worktree-manager` skill only supplies the worktree-specific contract path and integration/finalization follow-up rules. @@ -67,7 +67,7 @@ The intended order is: 1. run the `c-08-ar-coordination-context-resolver` skill for the target repository 2. run the `c-02-memory-quality-control` skill's task-start drift check and follow the existing AGENTS Gate 3/4 choice point 3. when onboarding is refreshed, commit the memory content and ledger before starting any worktree -4. decide whether the work is a chat build, a `w-02-light-task-workflow` light task (or master + light sub-task series), or external workflow +4. decide whether the work is a `w-02-light-task-workflow` light task — possibly a THIN one for single-session work; chat never builds — a master + light sub-task series, or external workflow 5. read the repository's `system/git-workflow.md` and identify the parent branch edge. For a standalone task, the leaf worktree branches from the approved source branch. For a master series, the master owns a root `series-contract.md` @@ -198,7 +198,9 @@ moved since task start. ## Integration -Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. +Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. Orchestrated-run carve-out (ruled 2026-07-06): dependency-ordered leaf→master and master→super integrations ride the series' standing approval (the developer's portfolio-gate approval recorded in the planner master) — the developer hand-off concentrates at the super PR/carry-over gate per the `l-01-agent-lifecycles` loop/orchestrator doctrine; a raised durable `integration-approval` gate still awaits the developer. + +On an orchestrated master's exit (master → super integration) the integrate step additionally enforces the delegated `master-handover-approval` seam: an undecided or policy-invalid handover gate addressed to the master (by `enclosure` = master task name) returns `handover-gate-blocked` instead of landing — decide the gate per the `l-01-agent-lifecycles` seam doctrine, then rerun. When no gate addresses the integrating master but open `master-handover-approval` gates exist elsewhere, integrate still proceeds and its result carries a `handover_gate_warning` naming them — treat it as a spelling check on the raised gate's `enclosure`. Run `worktree_integrate(..., dry_run=true)` first, then **hand off**: call `lifecycle_turn_end_notification(summary={…the integration plan…})` as the **last tool call**, then diff --git a/.claude/skills/c-12-closeout/SKILL.md b/.claude/skills/c-12-closeout/SKILL.md index f83071d9..2c7fe3ff 100644 --- a/.claude/skills/c-12-closeout/SKILL.md +++ b/.claude/skills/c-12-closeout/SKILL.md @@ -40,7 +40,7 @@ records the developer's explicit commit approval. Agents must not treat implementation approval, a previous "looks good", or their own judgment as commit approval. -The relay follows the `l-01-session-job-lifecycle` skill hand-off protocol: run the +The relay follows the `l-01-agent-lifecycles` orchestrator hand-off protocol: run the preview/dry-run first, then call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the **last tool call**, then deliver the preview facts and proposed messages as plain diff --git a/.claude/skills/c-13-install-and-onboard/SKILL.md b/.claude/skills/c-13-install-and-onboard/SKILL.md index 6515ae46..d583fd13 100644 --- a/.claude/skills/c-13-install-and-onboard/SKILL.md +++ b/.claude/skills/c-13-install-and-onboard/SKILL.md @@ -52,10 +52,12 @@ Run this sequence in order: 0. Preflight: verify the copied package and MCP setup are usable enough to continue. 1. Runtime scaffold: run or verify `runtime_install()`. -2. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. -3. Bootstrap: when a new memory repo was scaffolded, hand off to +2. Agentic settings: walk the developer through the orchestration defaults in + the seeded global settings file. +3. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. +4. Bootstrap: when a new memory repo was scaffolded, hand off to `c-03-repo-bootstrap`. -4. Providers: when providers are enabled, start/refresh indexing and verify +5. Providers: when providers are enabled, start/refresh indexing and verify readiness. This skill orchestrates and delegates. It does not reimplement @@ -79,7 +81,9 @@ Check, in order: 3. **Settings sane.** Confirm `server_info` reports the expected `coordinationRoot`, `workspaceRoot`, allowed repositories, and providers. Surface the resolved absolute paths because wrong paths are the common cause - of resolver failures. + of resolver failures. Also report whether the global agentic settings file + (`/system/settings.json`) exists yet; Stage 1 seeds it + when missing and Stage 2 configures it. 4. **Runtime state.** Check whether the coordinator scaffold already exists under `coordinationRoot` (`AGENTS.md`, `skills/`, `tasks/`, `memory-repos/`, `system/` as applicable). If it is missing or stale, Stage 1 will run @@ -118,7 +122,61 @@ Do not run `skills_install()` as part of first-run setup. The harness starter package already carries the skills. `skills_install()` remains available for manual maintenance or non-package setups, but it is not the default path. -## Stage 2 - Memory Repo: Ask Scaffold Vs Existing +## Stage 2 - Agentic Settings: Interview The Developer + +`runtime_install()` seeds the GLOBAL agentic settings file at +`/system/settings.json` copy-if-missing, with every knob at +its documented default: all-human gate delegation, the standard three-party-loop +defaults, no concurrency caps, no spawn harness preference. This stage turns +those defaults into the developer's actual posture so the intended workflows +run on ANY harness. The schema reference is `docs/reference/settings-json.md` +(Agentic Settings); unknown `orchestration.*` keys fail loud, so write only +documented keys. + +Walk the developer through the four knob families and edit the global file with +their answers (leave a family at its seeded default when they have no +preference): + +1. **Gate delegation posture** (`orchestration.gateDelegation`; GLOBAL file only - the + loader refuses it repo-locally and the boot snapshot reads the coordinator file) - keep every + gate human (`all-human`, the default), or delegate leaf gates with the + `manager-decides-leaf-gates` policy, optional per-kind `kinds` overrides, + and `requireReviewerVerdictAtSeams`. Say explicitly that this one key is + boot-snapshot: a change needs an MCP/harness restart. +2. **Loop defaults** (`orchestration.loops`) - the review-round cap + (`defaults.maxRounds`), reviewer reuse (`defaults.reviewerReuse`), + complexity thresholds (`defaults.complexity`), and per-level loop postures + (`perLevel`). Read per-use; edits apply on the next use, no restart. +3. **Concurrency caps** (`orchestration.concurrency`) - `maxParallelMasters`, + `maxParallelLeaves`, `maxSubAgents`. Default: uncapped. +4. **Harness preference + role knobs** (`orchestration.spawn.harness`, + per-role `orchestration.roles.`, per-level + `orchestration.rolesPerLevel..`) - which installed harness + `spawn_agent_session` uses when the spawning seat passes none, per-role + harness/model/effort overrides, and per-LEVEL overrides + (leaf|master|portfolio) for tiered economics (e.g. a cheap leaf reviewer, + a smarter master-seam reviewer). Harness values must be known ids: the + builtin registry (`claude`, `codex`, `pi`) or an `orchestration.harnesses` + entry the developer defines (new TUIs, or a pre-customized launch argv for + a builtin). `effort` is validated per-harness at dispatch (claude: + `low|medium|high|xhigh|max` on the `--effort` flag plus the session-level + `ultracode`); mention the FREE-FORM escape hatch for anything outside the + vocabularies - `launchArgs` (verbatim argv), `sessionCommands` (pasted + before the brief), `promptKeywords` (prepended to the brief) - never + validated, recorded in spawn provenance. Default: detection-gated (the + first detected harness). The full spawn-surface manual is + `docs/reference/harnesses.md`. + +If the developer wants to skip the interview, confirm the seeded defaults +apply and continue; tell them the file can be edited any time (picked up +per-use, except the gateDelegation restart note above). + +Per-repo overrides: a code repo may carry its own `/system/settings.json` +with the same `orchestration.*` shape; repo-local leaf values override the +global file (arrays replace). Offer this only when the developer asks for +repo-specific behavior; do not create the file unprompted. + +## Stage 3 - Memory Repo: Ask Scaffold Vs Existing Do not assume the developer wants a fresh memory repo. Ask which case applies, unless a memory repo is already present and resolvable: @@ -126,10 +184,10 @@ unless a memory repo is already present and resolvable: 1. **Scaffold a new memory repo** - they have no existing memory for this code repo. Run `c-00-initialize-memory-repo` (internal by default; external only if the developer asks or the configured topology requires it). Continue to Stage - 3. + 4. 2. **Use an existing memory repo** - they already have one. Clone or checkout it to the resolved memory location, then adopt it as the ledgered baseline with - `c-10-adopt-memory-baseline`. Skip Stage 3 because its onboarding already + `c-10-adopt-memory-baseline`. Skip Stage 4 because its onboarding already exists. Internal-memory note: pre-existing internal memory lives inside the code repo @@ -137,9 +195,9 @@ Internal-memory note: pre-existing internal memory lives inside the code repo `c-08-ar-coordination-context-resolver` and skip the question when the memory layer is already there. -## Stage 3 - Bootstrap +## Stage 4 - Bootstrap -Run this stage only when Stage 2 scaffolded a new memory repo. +Run this stage only when Stage 3 scaffolded a new memory repo. Hand off to `c-03-repo-bootstrap` to generate initial onboarding. A thin `overview.md` is enough to start; deeper route-local overviews and file-level @@ -147,7 +205,7 @@ onboarding should grow as work touches new areas. Skip this stage when an existing memory repo was adopted. -## Stage 4 - Configure Providers To Index +## Stage 5 - Configure Providers To Index If providers are enabled, make them index the configured code and memory: @@ -177,10 +235,12 @@ Summarize: step the developer must perform; 2. runtime scaffold: `runtime_install()` run or already current, with the resolved coordination root; -3. memory repo: scaffolded, existing-adopted, or already present, with the +3. agentic settings: interviewed and written, or left at the seeded defaults, + with the global file path; +4. memory repo: scaffolded, existing-adopted, or already present, with the resolved memory root; -4. bootstrap: run via `c-03-repo-bootstrap` or skipped; -5. providers: indexing status and any deferred/degraded state. +5. bootstrap: run via `c-03-repo-bootstrap` or skipped; +6. providers: indexing status and any deferred/degraded state. End by telling the developer whether the project is ready for normal work. Do not tell them to restart for hooks installed by this skill, because this skill no diff --git a/.claude/skills/l-01-agent-lifecycles/SKILL.md b/.claude/skills/l-01-agent-lifecycles/SKILL.md new file mode 100644 index 00000000..1d390618 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/SKILL.md @@ -0,0 +1,259 @@ +--- +name: l-01-agent-lifecycles +description: "The agent lifecycles: one lifecycle per agent type, under one roof. Routes every session by exactly three conditions (spawn-role env -> role brief -> otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator, designer, strategist, manager, worker, adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. A developer-facing session IS the orchestrator; solo work is the degenerate portfolio. Supersedes and replaces both l-01-session-job-lifecycle and l-02-agent-orchestration." +--- + +# l-01-agent-lifecycles — The Agent Lifecycles + +Lifecycle and job are **one entity**: each agent type runs its own, self-contained lifecycle. This +skill is the single roof over all of them — a thin router, the minimal frame every session shares, +and the role lifecycles as the payload files. No role is defined by reference to another role's +lifecycle, and no role reads another role's file. + +## Which Lifecycle Am I? (the router — exactly three conditions, in order) + +1. **`AR_SPAWN_ROLE` is set** (spawn env, injected by `spawn_agent_session`) → run + `roles/.md`. Nothing else in this file's "developer session" material applies to you. + (`designer` here means the same design hat in a separate chair — see `roles/designer.md`.) +2. **Else: the first user message is a role brief** — a `templates/*-brief.md`-shaped dispatch or + a first line of the form `ROLE BRIEF — ` from an orchestrating agent → run that role's + lifecycle. The brief is your session start; a workspace session-start notice is not addressed + to you. +3. **Else** (a developer opened this session) → you are the **orchestrator**: run + `roles/orchestrator.md`. Solo work is the degenerate portfolio — the same three jobs with hats + collapsed (the orchestrator wears the manager hat in flat runs and builds hands-on at session + scale); the task doc still comes first. + +There is no fourth entry, and the edge cases are decided: an **unresolvable `AR_SPAWN_ROLE` +value** (no matching `roles/.md`) falls through to condition 2 (the brief); a role-env +session **whose brief never arrives** announces itself on the inbox and waits — it never +improvises a task; `AR_SPAWN_ROLE=orchestrator` is valid only as a takeover chair (the Profile +check (takeover) in `roles/orchestrator.md`, The Event Loop) — the developer still talks to **one** orchestrator. Orchestrated +fan-out (spawning managers/workers at scale) begins only on an explicit developer request (e.g. +*"orchestrate these masters"*) — no agent promotes itself into a spawning seat. + +One exception to the no-cross-reading rule above: **a seat that WEARS a hat runs that hat's file +as its own** — the orchestrator always for `roles/designer.md`, and in flat runs for +`roles/manager.md` (the hat-collapse rule). + +## The Role Registry + +| Role | Seat | Lifecycle file | +| --- | --- | --- | +| **orchestrator** | the developer-facing session; first coordination leaf of an orchestrated series | `roles/orchestrator.md` | +| **designer** | a HAT the orchestrator pulls inline (front of the pipeline or mid-flight; separate chair optional) | `roles/designer.md` | +| **strategist** | the sprint planner, SPAWN-FIRST; a strategist run is a **mandatory precondition for any orchestrated run** — its deliverable is the orchestration task (sprint plan + scope); spawn value `strategist` | `roles/strategist.md` | +| **manager** | one coordination leaf per master; drives that master's leaf loop | `roles/manager.md` | +| **worker** | one leaf worktree, short-lived, fresh session | `roles/worker.md` | +| **adversarial reviewer** | short-lived, spawned at the two seams (master-exit, super-exit) and as any three-party loop's reviewer seat (criteria catalogs bound per review type); spawn value `reviewer` | `roles/reviewer.md` | + +The **lenses** (bug · feature · triage · research — `lenses.md`) are how the scoping seats +(orchestrator, designer) read a piece of work; a dispatched role never picks a lens — its brief +already carries the flavor. + +## The Minimal Frame (the only machinery every session shares) + +Every session in a managed repo may be a **lifecycle**: six signals — `lifecycle_start` · +`lifecycle_phase` · `lifecycle_turn_end_notification` · `worktree_attach` · `switch_lifecycle` · +`lifecycle_end` (plus the automatic `worktree_start` promotion) — record where it +is and what it waits on, so work is observable and resumable across chat deaths. The model **never +handles a lifecycle id** — identity is server-side, anchored in the worktree contract. + +| When | Signal | Effect | +| --- | --- | --- | +| Trust checkpoint passes (managed repo) | `lifecycle_start` | begin a **fleeting** lifecycle (guarded: one per session; no id) | +| Entering a phase | `lifecycle_phase` | move the phase axis (`request` / `trust-checkpoint` / `reframe-research` / `decide` / `build` / `close`) | +| A developer hand-off | `lifecycle_turn_end_notification(summary=…)` | set `awaiting-developer`, surface the attention item, return immediately; the **next turn's first AR call auto-resumes** — never resume by hand | +| `worktree_start` | *(automatic promotion)* | the fleeting lifecycle becomes **persistent**, anchored in the contract | +| Resuming an existing task | `worktree_attach` | re-adopts the contract's lifecycle (contract-resolved) | +| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | the save gate — never dropped silently | +| Close | `lifecycle_end` (`completed`\|`abandoned`) | the terminal record | + +Rules: a tool call outside any lifecycle is **dropped, never misattributed**; `paused` is +system-owned. **A spawned role that never touches mutating AR tools simply never instantiates a +lifecycle — that is correct, not a violation.** A spawned role runs its **own** lifecycle when it +runs one; it never adopts its spawner's. The session↔leaf association is the catalog binding made +at spawn (the **qualified** leaf key `//`), not lifecycle adoption. + +## Shared Invariants (every role can count on these) + +- **Continuity lives in the `task_doc` + durable artifacts, never in transcripts** — which is why + short-lived workers and reviewers are safe, and why every seat writes its artifact of record. +- **Escalation ladder: worker → manager → orchestrator → developer.** No rung is skipped, ever. + Each role file states only its own rung. +- **Observability:** coordination seats are `task_doc` leaves with attached chats; the developer + can walk into any seat at any level. +- **Decision-needing questions land in the task doc's `openQuestions`** — the rendered decision + surface; `notes/` carries the analysis behind them. + +## The Three-Party Loop (one home — this section owns the loop doctrine) + +**OWNER → BUILDER → REVIEWER → owner, at every level that owns work.** The owner never +self-approves; the builder never lands; the reviewer never decides — verdicts are evidence. The +owner checks the verdict and either redispatches a builder or escalates. Role files reference this +section; they do not restate it. + +| Level | Owner (holds the deliverable, rules, lands) | Builder | Reviewer | +| --- | --- | --- | --- | +| Leaf | the leaf's owning seat (manager; orchestrator in tight/flat mode) | spawned worker (no-commit contract) | spawned reviewer, criteria catalog + liberty | +| Master | the manager | the leaf workers | the master-exit seam reviewer (verdict rides `master-handover-approval`) | +| Portfolio | the orchestrator | the STRATEGIST (spawn-first) | reviewer with the plan-review catalog | + +**Complexity-scored tiers (per leaf, at dispatch).** The owning seat scores three axes — blast +radius (doctrine/enforcement/public surface vs leaf-local) · novelty (new subsystem vs +pattern-following) · size (files × steps) — into three tiers: **direct** (no loop +machinery — the level's ordinary build channel implements: hands-on at session scale, the leaf's +worker under a manager; self-check + checks ladder only), **builder-verified** (builder +implements; owner verifies report-vs-artifact; no reviewer), **full loop** (builder + independent +reviewer rounds). The +strategist's blast-radius register is the scoring input when an orchestration task exists. A +leaf's loop mark (tier + scope: manager | orchestrator — the owning level runs the loop with ITS +agent set) is recorded on the leaf doc with a decision-log entry. **A master whose leaves all +score `direct` is a workflow-free manager** — no loop machinery; the knobs make every loop +optional per level, never mandatory ceremony. + +**Rounds and the HARD cap.** A round = implement → review. **Hard cap: 3 rounds per loop — and +ONLY full end-to-end rounds count against it.** Residuals of a passing round are landed and +**delta-verified by the SAME reviewer via a follow-up message** (it retains everything it already +verified, at a fraction of a fresh round's cost); **fix rounds resume the SAME builder**. A fresh +reviewer is spawned only for a full round or when new scope opens. Delta-verifies close rounds; +they do not open them. + +**The convergence rule (the real control; the cap is the backstop).** Every round must SHRINK the +open finding set. A round that does not shrink it escalates immediately, regardless of the count; +a monotonically converging loop may never hit the cap at all. At the cap, or on non-convergence, +the owner does not spin another round — it **escalates one seat up the ladder (worker → manager → +orchestrator → developer) with the full round history attached**; the escalation packet IS the +upper seat's visibility. + +**Quo-vadis (the written developer-escalation criterion).** A question is developer-worthy when it +is a **high-blast-radius truth** — answered wrong it means big rewrites later (architecture +direction, security posture, doctrine contradictions, irreversible data/branch operations, where +agent settings live). Quo-vadis questions escalate IMMEDIATELY, regardless of round count. +Presentation-grade choices (2px vs 3px) never do — the owner rules and logs. + +**Criteria catalogs (the reviewer as test bench).** Criteria are never made up on the spot: every +review runs its type's standing catalog from `criteria/` (code-seam · doctrine · +onboarding-memory · report-verification · plan-review) plus an exploratory mandate, under the +promotion ratchet (each catalog carries it). `roles/reviewer.md` binds them. + +**Per-level agent sets.** Each level runs its loop with its own harness/model/effort set — the +orchestrator-level set (the strongest models) and the manager-level set (cheaper, possibly +workflow-free) are configured per level in the `orchestration.loops` settings block (schema in +`docs/reference/settings-json.md`; stored in the global agentic settings file with repo-local +override, parsed by the kernel agentic-settings loader — L13, landed). The strategist's mandatory +pre-run is doctrine, not a knob — it is unconditional. + +## Knob Block & Capability Doctrine (no per-harness files) + +Role files are **model-interpreted markdown, never an executor**. Each carries a portable **knob +block** (harness / model / effort / tools) — the defaults the terminal host injects at spawn. +Resolution: **role-file defaults < settings.json orchestration block.** There are deliberately +**no per-harness role files** (developer decision 2026-07-05): harness-specific ABILITIES — +sub-agent fan-out and the like — are covered inside the portable files as capability-conditional +doctrine any coding agent can apply, and harness PREFERENCE is deployment configuration +(settings), not doctrine. Hard-coding a vendor would fork the doctrine per harness. For spawning +seats, `spawn_agent_session` is itself the harness-independent fan-out: a harness with no +sub-agent facility still dispatches seats through the framework (a chat, no leaf attachment +required) — the DBMS principle: one behavior, any engine. + +## settings.json Orchestration Block + +Machine/user overrides layer over the role-file defaults, in the **global agentic settings file** +(`/system/settings.json`), with `/system/settings.json` as the +repo-local override layer (leaf-key deep merge, arrays replace, unknown `orchestration.*` keys +fail loud — schema in `docs/reference/settings-json.md`, Agentic Settings). Precedence: role-file +defaults < global settings < repo-local settings. + +```jsonc +{ + "orchestration": { + "roles": { // role → knob override; validated: harness/model/effort · free-form: launchArgs/promptKeywords/sessionCommands + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { // per-LEVEL agent sets (leaf|master|portfolio), deep-merged over roles + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" }, // spawn_agent_session default when the seat passes none + "gateDelegation": { + "policy": "manager-decides-leaf-gates", + "requireReviewerVerdictAtSeams": true + } + } +} +``` + +**As-built (L13 + L16):** the whole block is parsed by the kernel agentic-settings loader +(`kernel/agentic_settings.py`) — typed models for `roles` / `rolesPerLevel` / `concurrency` / +`spawn` / `harnesses` / `loops`, +read PER-USE (an edit applies on the next use, no restart). `orchestration.gateDelegation` is +parsed and **enforced** (`controlplane/gate_policy.py` — all-human default, opt-in delegation, +human-pinned kinds `integration-approval` / `push-approval` / `cleanup-approval`, owner never +self-approves); it is the ONE boot-snapshot key — read from the global file at MCP boot, a change +needs a restart (an authority-file value is a one-cycle legacy fallback with a boot warning). +`requireReviewerVerdictAtSeams` **binds delegated seam decisions** (`master-handover-approval`) to +attached reviewer-verdict evidence; the named policy `manager-decides-leaf-gates` routes leaf gates +to the manager and the master-exit handover to the **orchestrator** (human review concentrates at +the super gate). `spawn_agent_session` resolves its knobs (260703-L16) as explicit args > +repo-local level override > global level override > repo-local role default > global role default +> detection-gated default — the dispatcher declares its `level` (leaf|master|portfolio, default +leaf) and the resolved level rides spawn provenance — and **applies** them at the harness +boundary: model/effort ride as `AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` env AND map onto the launch argv +per-harness via the effective registry (claude `--model`/`--effort`; a mapping-less harness stays +env-only; a session-vocabulary effort like claude's `ultracode` is delivered as a post-launch +`/effort` paste). Unknown effort values REFUSE at dispatch naming the harness's vocabulary — the +CLI would warn-and-silently-degrade. The free-form escape hatch (`launchArgs` verbatim argv, +`promptKeywords` riding the brief paste, `sessionCommands` pasted before the brief) is never +validated, only recorded in spawn provenance; `orchestration.harnesses` teaches the framework new +TUIs or pre-customizes builtin launches (manual: `docs/reference/harnesses.md`). +`orchestration.loops` (the three-party-loop knobs: per-level loop sets, round cap, reviewer +reuse, complexity thresholds) lives in the same block — meaning in +`docs/reference/settings-json.md`; no knob touches the master-exit seam gate. + +## Companion Files + +- `lenses.md` — the four job lenses for the scoping seats. +- `roles/…` — the six self-contained role lifecycles (the registry above). +- `templates/…` — turn-report · worker-brief · manager-brief (`ROLE BRIEF — manager`; the + orchestrator compiles a manager's session start from it) · master-handover-packet · + conversation-handover-packet · verdict · impact-analysis · onboarding-coherency · + deep-research-report · orchestration-task (the strategist's sprint plan). Spawning seats compile + briefs FROM these; sub-agents fan out and fill them, so analysis survives compaction. +- `criteria/…` — the reviewer criteria catalogs (code-seam · doctrine · onboarding-memory · + report-verification · plan-review), the review test bench the three-party loop binds; maintained + through the promotion ratchet, never made up on the spot. + +## The Super Integration Branch (orientation only — the doctrine lives with its owner) + +``` +main + └── super-integration (orchestrator-owned, off main) + ├── master-A branch (off super) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, C-11) + ├── master-B branch (off the moved super — sees A) + └── … final: super → main PR + memory carry-over + push +``` + +The full topology — dependency-ordered dispatch, the integration-duty procedure, the two +conflict-resolution modes, leaf moves — lives in **`roles/orchestrator.md`** and only there. + +## Credits + +This skill absorbs and supersedes `l-01-session-job-lifecycle` and `l-02-agent-orchestration` +(converged 2026-07-05: lifecycle and job are one entity — one lifecycle per agent type). The +orchestration vocabulary adopts the parked `260619_agentic-control-plane` spec — jobs as +model-interpreted markdown (D6), the knob block (D7), role + lens in one file (D10), the +ambient-singleton rule (D11), per-harness variants (D12), the judge rung, short-lived workers with +structured handoff, dev-talks-to-one-orchestrator (D15) — which in turn credits **Archon** and the +**agent-control-plane** project (D14); that credit carries forward. + +## Relationship To Other Instructions + +This skill extends — never replaces — the coordinator `AGENTS.md`, the `w-02-light-task-workflow` +task format, and the memory layer (`c-…` skills). Each `roles/.md` is self-contained for its +seat; read exactly the one the router selects. diff --git a/.claude/skills/l-01-agent-lifecycles/criteria/code-seam.md b/.claude/skills/l-01-agent-lifecycles/criteria/code-seam.md new file mode 100644 index 00000000..053feb1b --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/criteria/code-seam.md @@ -0,0 +1,85 @@ +# Criteria Catalog — Code-Seam Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review wires code seams: consumers, enforcement points, gates, addresses, tool contracts. +Binds at the master-exit and super-exit seams and in any loop review whose change set touches code +(see the binding table in `../roles/reviewer.md`). Criteria are never made up on the spot: the +standing list below is the regression floor, run every time; the exploratory mandate and the +promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### CS-1 — Production-wiring walk + +**Trace the real call path, never a hand-aligned harness.** A claim that a consumer or an +enforcement point exists must be walked through the PRODUCTION call path — the controller, the +tool registration, the store fold — not through a test that hand-assembles the pieces into +alignment. A test can pass while the production consumer is inert. + +- Catching evidence: 260703-L8 review 3 (AR3-1) — the integrate consumer was proven **inert**: the + policy was omitted at the controller and the gate was looked up on the wrong lifecycle, while a + hand-aligned test passed (L8 decision log, cycle-6 entry). + +### CS-2 — Fail-open hunt + +**What happens when the address/config is absent or mistyped?** For every identity, address, key, +or config the seam matches on: feed it nothing, feed it a near-miss, and confirm the seam fails +CLOSED (refuses) rather than open (silently proceeds unmatched). + +- Catching evidence: 260703-L8 review 4 (AR4-1) — the seam's `enclosure` address had to be pinned + as an exact-string contract and the enclosure-less raise made a refusal (L8 decision log, + cycle-7 entry). + +### CS-3 — Validate-then-mutate + +**Every raise/write validates before it mutates.** A call that records state (a gate raise, a +store append, a contract write) must perform its refusal checks before any durable effect; a +mutation that precedes validation leaves half-states behind on refusal. + +- Catching evidence: 260703-L8 cycle 6 — the `wait=false` raise was reworked to be + validate-then-mutate and seam-kind-restricted (L8 decision log, cycle-6 entry). + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### CS-4 — Reused-primitive affordance parity *(candidate — 1 catch)* + +**When a screen reuses a shared content primitive, verify every branch of the ORIGINAL's +affordances (banners, status chips, truncation notices, error states) still fires on the reuse +path.** A dropped affordance is a silent regression the reuse's own tests won't catch — they +assert the new screen's happy paths, not the primitive's full surface. + +- Catching evidence (single engagement): 260703-L17 review (L17R-2) — the notes reader's + `DualPane` reuse drops the "first 2 MiB" truncation banner on the markdown path (the banner + lives in `CodeSide`, which markdown never reaches); text and binary keep it. + +### CS-5 — Cross-repo side-effect safety *(candidate — seeded from a clean exemplar, 0 catches)* + +**Any step that writes to a repository OTHER than the one it operates in gets the full +validate-then-mutate treatment plus partial-failure and dirty-target analysis.** Check the order +of validation vs the foreign write, the state left behind when the write lands but the caller +fails afterward, behavior against a dirty target repo, and an exact format round-trip with the +foreign artifact's consumer. + +- Seeding evidence: 260703-L18 finding 7 (`_reconcile_missing_mapping` writing the official + memory repo's ledger mid-`worktree_start`) PASSED all four lenses under this analysis — the + clean exemplar that defined the class. A catch in a later engagement promotes. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS change set the catalog does not name yet. Every novel finding-class that survives +refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.claude/skills/l-01-agent-lifecycles/criteria/doctrine.md b/.claude/skills/l-01-agent-lifecycles/criteria/doctrine.md new file mode 100644 index 00000000..9b9ccae1 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/criteria/doctrine.md @@ -0,0 +1,58 @@ +# Criteria Catalog — Doctrine Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review is doctrine: skill files, role lifecycles, templates, instruction surfaces, docs +that agents obey. Binds whenever doctrine/skill files are in the change set (see the binding table +in `../roles/reviewer.md`). Criteria are never made up on the spot: the standing list below is the +regression floor, run every time; the exploratory mandate and the promotion ratchet keep the +catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### D-1 — Doctrine-vs-code anchoring + +**Every "X enforces Y" needs a code anchor.** A doctrine sentence claiming enforcement, refusal, +or automatic behavior must resolve to the code that does it (file + mechanism). Doctrine that +narrates enforcement which does not exist is a defect, not an aspiration. + +- Catching evidence: 260703-L8 review 1 (AR-5) — `requireReviewerVerdictAtSeams` was documented as + binding while the flag was **inert**; the finding forced the wiring (L8 decision log, AR-1 + entry: "closing AR-5's inert flag"). + +### D-2 — Cross-file contradiction sweep + +**Sweep sibling doctrine for statements the change set now contradicts.** A doctrine change is +reviewed against the whole doctrine surface (skills, role files, templates, docs, hooks, canvas +prose), not just the edited files — one file's new invariant is another file's stale sentence. + +- Catching evidence: 260703-L10 — the landed "chat is never a build route" invariant contradicted + surviving chat-build wording inside `c-09` / `w-02` (builder escalation 1, owner-sanctioned + sweep; L10 builder report). + +### D-3 — Stuck-state walk + +**Can an agent following the prose deadlock?** Walk the doctrine as the obeying agent: at every +wait, gate, and handover, ask who unblocks it and through which channel. Prose in which two seats +each wait on the other — or a seat waits on a channel nobody is told to serve — is a blocking +finding. + +- Catching evidence: 260703-L8 review 2 — the seam deadlock: the manager's blocking raise and the + orchestrator's decide path could not meet as written; the ruled `wait=false` + + packet-carried-gateId channel resolved it (L8 rounds 2/4b history). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS doctrine change the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.claude/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md b/.claude/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md new file mode 100644 index 00000000..e47783e3 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md @@ -0,0 +1,67 @@ +# Criteria Catalog — Onboarding/Memory Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run over the +memory side of a change set: sidecars, route overviews, route indexes, update histories. Binds at +the master-exit and super-exit seams (the onboarding-vs-code lens) and in loop reviews whose change +set carries onboarding (see the binding table in `../roles/reviewer.md`). Criteria are never made +up on the spot: the standing list below is the regression floor, run every time; the exploratory +mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### OM-1 — Staleness diff vs as-landed code + +**Diff every body claim about current behavior against the as-landed code.** A sidecar or overview +body that describes the present tense is checked against what the branch actually ships — deleted +things still described, renamed things under old names, duplicated rows. + +- Catching evidence, two separate engagements: 260703-L8 cycle 6 (owner follow-up pass) — route + overview bodies still described **deleted canvas models** (the panels overview's build-job/frame + tail) and carried **duplicated table rows** (the tools and controlplane overviews' Layout + tables), durably recorded in those overviews' own 2026-07-05T19:25 Update History entries; + 260703-L10 — the flowModels sidecar body was still the pre-convergence 8-model census and its + references row still said "8 models" (the sidecar's 2026-07-06T12:05 history entry + L10R-3). + +### OM-2 — History-only-update detection + +**"Refreshed" must mean a genuine body edit.** An onboarding file whose only change is a new +Update History line has NOT been refreshed — the body still asserts the old truth. Check that +every claimed refresh touched body sentences, not just the history list. + +- Catching evidence: 260703-L8 cycle 6 — the builder reported route overviews as refreshed when + they were **history-only**; the closeout body gate caught it (L8 decision log, cycle-6 entry: + "report-vs-artifact verification belongs in the reviewer criteria catalog"). + +## Candidate Criteria (seeded exploratory — one catching engagement; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### OM-3 — Newest-first with the checker's own semantics *(candidate — 1 catch)* + +**Update History sorts newest-first under the CHECKER's datetime parse, not lexicographically.** +The quality checker compares naive timestamps as-is and folds tz-aware stamps to UTC; a merge or +mechanical insert that sorts by string can pass the eye and fail the gate (or worse, pass the gate +in the wrong order). Verify ordering with the checker's semantics. + +- Catching evidence (single engagement): 260703-L11 — four onboarding history collisions from the + parallel wave had to be re-sorted **with the checker's own datetime semantics** (naive compare + as-is, tz-aware folds to UTC); the quality gates caught the owner's wrong sort key (L11 decision + log). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS memory delta the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate is the working example, and it is THIS catalog's own OM-2 mechanized: the gate catches + history-only "refreshes" at commit time, where prose requests did not. diff --git a/.claude/skills/l-01-agent-lifecycles/criteria/plan-review.md b/.claude/skills/l-01-agent-lifecycles/criteria/plan-review.md new file mode 100644 index 00000000..ef4d2d90 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/criteria/plan-review.md @@ -0,0 +1,69 @@ +# Criteria Catalog — Plan Review (the strategist loop) + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run against an +**orchestration task** (`../templates/orchestration-task.md`) — the strategist's sprint plan — +before the developer's drawing board. This is the portfolio loop's review type: owner = +orchestrator, builder = strategist, reviewer = this catalog. The reviewer holds the same read-only +analysis tools the strategist used (`cgc_*`, `grepai_*`, `read_ar_files`), so the plan's mechanical +claims are re-derivable, not just readable. Criteria are never made up on the spot: the standing +list below is the regression floor, run every time; the exploratory mandate and the promotion +ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### PR-1 — Refute uncited edges + +**An uncited dependency edge is refutable by default.** Every edge in the dependency graph must +carry evidence — a cgc/grepai query, a file, a decision-log entry, a design-section citation, or +(for new surfaces) a declaration cross-reference naming both leaf declarations. An edge with no +evidence is challenged as a finding; so is evidence that does not actually support the edge's +direction or kind. + +### PR-2 — Missed-shared-surface hunt (class-completeness on intersections) + +**Re-intersect the surface lists independently.** Take the plan's per-leaf touch surfaces (both +existing and declared-new), recompute the pairwise intersections, and hunt pairs the edge list +omits — including CONFLICT-risk at a shared parent route where two leaves declare additions +(wiring points, shared registries). A plan that lists surfaces but misses one of their +intersections has a hole exactly where collisions happen. + +### PR-3 — Blast-radius re-derivation + +**Re-derive at least the HIGH-blast-radius entries with the cgc tools** (`cgc_dependencies` / +`cgc_callers` / `cgc_callees`, capped depth) — and spot-check a sample of the low/medium entries. +A register entry whose derivation cannot be reproduced, or whose classification drops the doctrine +propagation / migration / user-visible unions, is a finding; the register parameterizes every +downstream loop tier, so an understated radius under-reviews a leaf. + +### PR-4 — Order-respects-edges + +**Check the sprint order/waves against the edge list, mechanically.** No ORDER edge may run +backwards across the proposed sequence; every CONFLICT edge must be resolved by serialization or a +recorded leaf move (from→to + rationale); parallel waves may contain only INDEPENDENT pairs, and +the wave plan must acknowledge the landing-reconciliation cost. + +### PR-5 — Honesty of the findings section + +**Verify the plan's failure claims both ways.** Every "unplannable as scoped" finding must be +genuine (the leaf can name neither existing surfaces nor the parent anchoring of its additions — +a merely not-yet-existing surface is NOT unplannable); and thin leaf scopes the plan silently +guessed around instead of flagging are themselves findings. Quo-vadis contradictions must be +flagged at the top of the coherence findings, not buried. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS plan could be wrong that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example; PR-4 is this catalog's mechanization candidate (a topological check over + a structured edge list). diff --git a/.claude/skills/l-01-agent-lifecycles/criteria/report-verification.md b/.claude/skills/l-01-agent-lifecycles/criteria/report-verification.md new file mode 100644 index 00000000..fb3bdda8 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/criteria/report-verification.md @@ -0,0 +1,95 @@ +# Criteria Catalog — Report Verification + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) — and the loop OWNER +verifying a builder round — MUST run over every report, claim, and summary in the change set: +builder reports, owner claims, handover packets. **Standing from day one** in every review type: +report-vs-artifact caught real defects in three separate engagements before this catalog existed. +Criteria are never made up on the spot: the standing list below is the regression floor, run every +time; the exploratory mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### RV-1 — Report-vs-artifact on EVERY claim + +**Open the artifact behind every claim.** A report sentence asserting "X was done / is green / +was refreshed" is verified against the artifact itself, not trusted — claim by claim, no sampling +of the load-bearing ones. + +- Catching evidence, three separate engagements (260703-L8): review 3 caught a **hand-aligned + test** behind a wiring claim; cycle 6's closeout gate caught **"refreshed" overviews that were + history-only**; review 4 caught the **OWNER's own canvas overclaim** (L8 decision log, cycle-7 + entry) — builder reports and owner claims fail the same way. + +### RV-2 — CLASS-completeness *(promoted to standing at 260703-L18 — 2 catches)* + +**Hunt the siblings of every found instance.** A finding or a fix names an instance of a CLASS +(a directive surface, a census count, a vocabulary token). Enumerate the class — every sibling +surface, not just the instances the report names — and check each one. + +- Catching evidence: (1) 260703-L10 round 1 — the reviewer's completeness sweep found **six of + ten first-action surfaces** still shipping the retired directive when the report claimed the + flip done (L10 decision log). (2) 260703-L18 review (L18R-3) — the fix for + advertised-but-unimplemented recovery choices named the `cli.py` `custom` residual but missed + the SIBLING `_load_memory_ledger` block still advertising an inert `reconciliation`; the + sibling hunt found it. + +### RV-4 — Decision-log completeness for scope-expanding disclosures *(promoted to standing at 260703-L18 — 2 catches)* + +**A scope-expanding owner supplement or load-bearing builder disclosure must be verifiable in +the task-doc decision log, not only the builder report.** Continuity lives in the task_doc + +durable artifacts, never in transcripts; a ruling or environment finding that exists only in a +report is one lost file away from unrecoverable. Cross-check every supplement and disclosure the +builder report carries against the decision log. + +- Catching evidence: (1) 260703-L17 review (L17R-1) — supplement 2 (the wait-loop-era remnant + sweep with per-hit verdicts and two named follow-ups) was recorded only in the builder report. + (2) 260703-L18 review (L18R-4) — the load-bearing editable-install/PYTHONPATH environment + finding + named follow-ups lived only in the builder report; the leaf's `decisions[]` was + empty. Both folded by the owner at closeout. + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### RV-3 — Partial-fix-creates-falsehoods *(candidate — 1 catch)* + +**Verify claims ABOUT the changed artifacts, not only the artifacts.** A partial fix can turn +previously-true sentences elsewhere false (docs describing the artifact, install guides quoting +it, counts referencing it). Sweep for statements about what changed and re-verify their truth +after the change. + +- Catching evidence (single engagement): 260703-L10 round 1 — the partial hook flip made **two + install-doc claims false** ("injects the same startup directive" no longer held); round 2 + restored byte-identity so the claims became true again (L10 decision log + builder report). + +### RV-5 — Worktree-shadowed regression pins *(candidate — 1 catch)* + +**A regression test must bite under the invocation the owner actually runs.** An editable +install pointing at another checkout can shadow the worktree's sources, making a mutation-tested +pin pass vacuously under the canonical invocation while failing only under a hand-set +`PYTHONPATH`. Verify sensitivity by mutating the target and running the CANONICAL invocation; +a pin that only bites under a nonstandard environment is not yet a pin. + +- Catching evidence (single engagement): 260703-L18 review (L18R-1) — the inbox + delivered/unconfirmed pin failed its mutation check only under `PYTHONPATH=src`; under the + canonical `pytest mcp/tests` the main-repo editable install shadowed the worktree and the + mutated code still passed. Remedy: the `sys.path` pin idiom the sibling suites carry. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS report could mislead that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests (RV-1 is itself the precedent: promoted on three catches). Promotion is proposed in the + verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.cursor/skills/l-01-session-job-lifecycle/job-variants.md b/.claude/skills/l-01-agent-lifecycles/lenses.md similarity index 82% rename from .cursor/skills/l-01-session-job-lifecycle/job-variants.md rename to .claude/skills/l-01-agent-lifecycles/lenses.md index 48f032c6..0f277b06 100644 --- a/.cursor/skills/l-01-session-job-lifecycle/job-variants.md +++ b/.claude/skills/l-01-agent-lifecycles/lenses.md @@ -1,7 +1,9 @@ -# l-01-session-job-lifecycle Job Variants — The Lenses +# Lenses — How the Scoping Seats Read a Job -The job type is a **lens**, picked during `reframe-research` and re-pickable at any time. It is not a gate and it -never changes the spine (`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three +Read by the **scoping seats** (orchestrator, designer); a dispatched role never picks a lens — its +brief already carries the flavor. The job type is a **lens**, picked during `reframe-research` and +re-pickable at any time. It is not a gate and it never changes the orchestrator phase axis +(`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three things only: - **Opening move** — the first concrete thing `reframe-research` does for this kind of job. @@ -25,8 +27,8 @@ invariant the bug violates. Defaults to a build; the fix lands through `decide - Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the -contracts the feature must respect. Defaults to a build; size decides chat vs durable `w-02-light-task-workflow` task at -`decide`. +contracts the feature must respect. Defaults to a build; size decides the minimal `w-02-light-task-workflow` artifact vs a master + +sub-task series at `decide`. ## triage diff --git a/.claude/skills/l-01-agent-lifecycles/roles/designer.md b/.claude/skills/l-01-agent-lifecycles/roles/designer.md new file mode 100644 index 00000000..c67cec40 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/roles/designer.md @@ -0,0 +1,91 @@ +# Lifecycle — Designer (the hat) + +> The design lifecycle the **orchestrator pulls inline** whenever design is needed — front of the +> pipeline or mid-flight. **A hat, not a seat**: it cannot sit in a coordination leaf because the +> task is what it exists to create — no leaf, no worktree, no branch, no spawn required. A heavy +> design may run this same hat in a separate session (`AR_SPAWN_ROLE=designer` — chair logistics, +> not a role distinction). +> +> Drawn as the **DESIGNER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Hat Is + +Task design is **its own job** (developer decision 2026-07-04). Before orchestration one implicit +do-it-all role did design, features, and fixes; the roles now diversify, and design routes +**through the orchestrator, which wears this hat** — at the front of the pipeline AND mid-flight +(most leaves of a live series are designed mid-flight). It is the `tasks/AGENTS.md` collaboration +doctrine (meta-questioning, reframe-before-execution, evidence-first) given a distinct, optimized +shape as a job. Nothing here assumes a master exists yet — producing one is the point. + +The designer shares the orchestrator's **bird's-eye toolkit** — route indexes, onboarding, the +`grepai_search` MCP tool, the code-graph (`cgc_*`) MCP tools, blast-radius analysis — but is **scoped +to one master**. Collisions with *other* — especially **future** — masters can slip past a +single-master view. That residual risk is **owned downstream, not here**: at portfolio streamlining the +**orchestrator doubles as the designer's adversarial reviewer** (planned-vs-planned and +planned-vs-past). The designer's duty is to *declare* the limit, not to close it. + +## Lens + +- **Opening move:** meta-question the ask. Surface the request, the deeper objective, and the + highest-leverage framing before any structure exists — do not jump from the developer's first + phrasing to a plan. +- **Retrieval lean:** evidence-first, within the master's scope. Route indexes and onboarding for the + map; `grepai_search` for semantics; `cgc_*` for relationships/impact; bounded `read_ar_files` for + intent confirmation. Sub-agents fan out and write durable reports. +- **Decide default:** a `w-02-light-task-workflow`-shaped master + leaf task_doc, handed into the + portfolio — **not** a build. The designer designs; it does not implement. + +## Duties + +1. **Reframe with `tasks/AGENTS.md`.** Distinguish surface request · deeper objective · highest-leverage + framing · assumptions · boundaries · invariants · truth gaps. Material scope/intent/sequencing + changes are **played back and wait for confirmation**; a pure clarification may be presented and + continued. +2. **Evidence-first, master-scoped.** Make the evidence model visible before or alongside the plan + (external · repo-internal · cross-repo · executable). Gather it through the + `c-04-retrieval-strategy-router` skill, not ad-hoc reads. +3. **Blast-radius WITHIN the master.** Routes touched · invariants at risk · regressions — bounded to + this master's scope. Cross-master and future-master reasoning is explicitly out of the designer's + reach. +4. **Author the task_doc.** Master + leaves (requirements · steps · code examples per distinct change, + the `w-02-light-task-workflow` shape), leaves scoped around routes/areas, via the `task_doc` MCP + tool. Include a **code example for every distinct change** when code is in scope. + Decision-needing questions land in the task doc's `openQuestions` — the rendered decision + surface; `notes/` carries the analysis behind them. +5. **Declare the designer limit.** Record on the doc that this is a **master-scoped bird's-eye**: + cross-master and future-master collisions can slip and are owned downstream at streamlining. Never + hide the limit. +6. **Ask, never fill silently.** Assumptions and truth gaps only the developer can resolve are asked as + a short, high-leverage list — never filled silently. + +## Artifact Obligations + +- The **task_doc** (master + leaves) is the durable artifact of the designer job. +- A **designer-limits note** on the doc — the declared master-scoped blind spot, for the orchestrator's + later adversarial pass. +- Evidence reports from fan-out sub-agents (durable), so the framing survives into streamlining. + +## Comms Protocol + +- **Primary channel:** the developer, directly, in the designer's attached chat — this seat is a + co-thinking loop, so the developer is the standing interlocutor here (unlike the deeper seats, which + relay through the ladder). +- **Handover:** the finished design **joins the portfolio**. At streamlining the orchestrator + adversarially reviews it; hand the task_doc + the designer-limits note over via the inbox + (`operator_inbox_post`) and, for a hosted orchestrator, stdin push. +- **Escalation:** the hat's "escalation" is simply the handover into the portfolio job — the + orchestrator that wears it is already the last resolver before the developer. + +## Knobs + +| Knob | Default | Notes | +| ------- | ------------------ | --------------------------------------------------------------------- | +| harness | (the wearer's) | the hat runs inside the orchestrator session, or a spawned design chair | +| model | high-reasoning | reframe + blast-radius reasoning wants a strong model | +| effort | high | design leverage justifies the thinking budget | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | bird's-eye toolkit | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · inbox | + +Settings.json `orchestration.roles.designer` overrides these, and `orchestration.rolesPerLevel..designer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.claude/skills/l-01-agent-lifecycles/roles/manager.md b/.claude/skills/l-01-agent-lifecycles/roles/manager.md new file mode 100644 index 00000000..0b42124a --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/roles/manager.md @@ -0,0 +1,168 @@ +# Lifecycle — Manager + +> One master, one seat, self-contained. The manager lifecycle drives exactly one master series: +> spawn a fresh worker per leaf, review turn reports, decide the delegated leaf gates, close out and +> integrate each leaf, hand the completed master to the orchestrator through the master-exit seam. +> Your **brief is your session start**. +> +> Drawn as the **MANAGER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**One per master task.** Spawned by the orchestrator with the master's context packet. It owns its own +coordination leaf + chat (**no worktree**) and drives exactly one master series: spawns/respawns a fresh +worker per leaf, reviews turn-report artifacts, decides **delegated** leaf gates, integrates leaves into +the master integration branch via the `c-11-memory-carryover-from-branch` skill, and hands the completed +master to the orchestrator through the master-exit adversarial seam. + +The manager owns the leaf lifecycle machinery **end-to-end**: `worktree_start` → (the worker +builds) → closeout preview/apply (deciding the delegated gates per the gate policy) → +`worktree_integrate` → finalize — task-doc statuses via the finalizer, **steps checked by this +seat by hand** (the tool does not reconcile checkboxes). The worker's terminal +state is checks-green + turn report; everything after that is this seat's. + +**Flat-run note:** in a flat series (no managers spawned) the **orchestrator wears this hat** — +same duties, same artifacts, one chair. + +A manager has **no bird's-eye view** — it sees one master, not the portfolio. That boundary shapes +everything below. + +## Lens + +- **Opening move:** read the master `task_doc` + its leaf docs; order the leaves (parallel where safe — + the C-11 reconcile absorbs a moved base). +- **Retrieval lean:** intent-confirmation on the master's own routes (paired `read_ar_files`); the + breadth/blast-radius reasoning belongs to the orchestrator, not here. +- **Decide default:** dispatch the next ready leaf; the master exits through the master-exit seam. + +## The Default-Behavior Rule (read this before anything else) + +The **default agent behavior stands**: **fulfill the task, fill small blanks.** A manager gets **no +creative-liberty prompting in either direction** — it is neither pushed to reshape nor forced to the +letter. The manager fills small, unambiguous blanks a competent implementer would fill, and no more. + +> **The spirit test does NOT apply to this seat.** It is orchestrator-only. A manager's changes can +> collide with what it cannot see, so a **plan delta beyond blank-filling escalates to the +> orchestrator** — the manager does not reshape plans. This is not a licence to be timid and it is not a +> licence to be creative; it is the ordinary "do the task well, ask when the task itself is in +> question" default, with the ask routed **up the ladder to the orchestrator**, never to the developer. + +## Duties + +### 1 — Seat & intake + +Take the master's own coordination leaf (`task_doc`, no enclosure); the chat is attached so the +developer can walk in any time. Read the master + leaf docs; order the leaves. + +### 2 — Leaf dispatch loop (per leaf) + +- **Score the leaf's loop tier at dispatch** (loop doctrine: `../SKILL.md`, The Three-Party Loop): + blast radius · novelty · size → **direct** (NO loop machinery: the leaf's worker implements as + usual — worker self-check + checks ladder + this seat's ordinary artifact review; this seat + still dispatches per leaf and never grows a build surface) | **builder-verified** (the worker + implements; this seat additionally verifies its report claim-by-claim against the artifacts; no + reviewer) | **full loop** (worker + independent reviewer rounds). When an orchestration task + exists, its **blast-radius register is the scoring input**. Record the mark (tier + scope: + manager | orchestrator — the owning level runs the loop with ITS agent set) on the leaf doc with + a decision-log entry. **A master whose leaves all score `direct` is a workflow-free manager** — + no loop machinery, just the dispatch-review-integrate spine below. +- On a full-loop leaf, run the loop with this level's controls: a round = implement → review; + **hard cap 3 full rounds** (delta-verifies by the SAME reviewer close rounds, they do not count; + fix rounds resume the SAME builder); **every round must shrink the finding set** — a + non-shrinking round escalates to the orchestrator immediately, with the full round history + attached, regardless of the count. +- `spawn_agent_session(worker)` — a **fresh session** on the leaf: the brief (compiled from + `../templates/worker-brief.md`) is pasted + submitted, with `env={"AR_SPAWN_ROLE": "worker"}` and + the **qualified** leaf key `//`; the worker edits inside the leaf + worktrees the brief names. +- **Monitor the worker** — a turn-report artifact is expected at **every** hand-off. Inactivity or a + missing artifact → a **rate-limited stdin nudge** (logged as an event, never spammy). Escalation + intake via the inbox. +- **Review artifact vs `task_doc`** — completion vs requirements/steps · checks green · + onboarding refreshed in the same pass (the manager's own leaf-level review; **this is not an + adversarial seam**). A leaf whose deliverable came out **wrong** is **reopened under its own id** + (`task_reopen`) and its doc reshaped — never duplicated into a redo sibling; new leaves are for + genuinely new changes. +- **Delegated leaf gates (plan · closeout)** — decide the leaf's delegated gates, **attributed** + (`decidedBy: `, `decidedVia: orchestration`), appended and dashboard-visible. The + **owning agent never self-approves; a distinct configured role may** — that configured role is the + manager. (Enforced as-built by the gate policy: `orchestration.gateDelegation` in settings, + `controlplane/gate_policy.py` — human-pinned kinds stay human, decisions attributed.) + Your own hand-off idiom, this seat only: durable gates + inbox posts — you never call the + developer-facing notification; your counterparty is the orchestrator. +- **Integrate leaf → master branch** via the `c-11-memory-carryover-from-branch` skill (ff-only / replay + per the `c-09-git-worktree-manager` skill). Know the human-pinned gate kinds by name: + `integration-approval`, `push-approval`, `cleanup-approval` — none is ever delegable. When a + durable `integration-approval` gate is raised on this step it awaits the **developer** (via the + dashboard GateResponder or your attached chat — you do not relay; if the wait blocks the loop, + escalate to the orchestrator). Absent a durable gate, the **series' standing approval** governs: + the developer's portfolio-gate approval of this series, recorded in the planner master's + decision log, covers dependency-ordered leaf integrations. Loop until the master's leaves are + done. + +### 3 — Master-exit seam + +When all leaves have landed on the master integration branch, spawn the **adversarial reviewer** +(master-exit) via `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "reviewer"}` and the reviewer +role file (`roles/reviewer.md`), passing the master branch ref, +master/leaf task docs, worker turn reports, decision logs, changed paths, resolved +`system/tools.md` evidence, and carry-over state. The verdict lands at +`notes/reports/-master-exit-verdict.md` and attaches to the handover gate as +`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"pass|pass-with-notes|block"}]` +— a verdict over completion vs task docs · `system/tools.md` quality · onboarding-vs-code. **Blocked? → the verdict decomposes into fix leaves** the manager dispatches (loop +back to the leaf loop). Verdicts are **evidence, not decisions**. The seam channel, exactly: +**raise without blocking** — `lifecycle_gate(kind="master-handover-approval", +enclosure="", evidence_refs=[], wait=false)` (raise-and-continue +is allowed precisely because the kind is a delegated seam kind; the `enclosure` MUST carry the +master's identity — it is the address integration enforcement matches the gate by, and the match +is exact-string: pass the EXACT master task name as the contracts carry it (`worktree_start`'s +`task_name`) — the raise refuses without an enclosure; the call +returns the **gateId**); then **carry that gateId in the handover +packet** (§4) — the packet is the orchestrator's trigger AND its address for the gate. Under an +all-human policy the raise blocks and the developer decides — do not pass wait=false. Identity +truth, as-built: the gate pins to your ambient lifecycle when you raise it; the deciding +orchestrator resolves the gate **by the packet-carried gate id** (gate ids are model-visible — +only LIFECYCLE ids stay server-side) and its own ambient identity becomes `decidedBy`; +owner-never-self-approves holds by construction. A handover carrying serious issues the +orchestrator cannot answer on its own escalates up the ladder (orchestrator → developer). + +### 4 — Handover to the orchestrator + +Post the **master-handover packet** (`../templates/master-handover-packet.md`) — inbox (durable) + stdin +push — integration branch ref · change-set summary · verdict ref · **handover gateId** · +carry-over state. The seat (chat + coordination leaf) **stays reachable** until the series +retires; your raised gate stays open until the orchestrator decides it (poll `gate_list` on your +own lifecycle if you need its state). + +## Artifact Obligations + +- The **master-handover packet** at master exit (the manager's primary durable artifact). +- Leaf-review notes (completion vs task_doc) — lightweight, on the master's coordination leaf. +- Delegated-gate decision records (attributed). + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down to workers, escalation + intake up from workers, handover up to the orchestrator; all durable + dashboard-visible. +- **Stdin push** — nudges and messages delivered into hosted worker sessions; poll is the fallback. +- **Escalation** — **up to the orchestrator, never straight to the developer.** A stumped manager, and + any plan delta beyond blank-filling, raises to the orchestrator. The manager resolves within its own + master's view first. A loop that hits the 3-round cap or stops converging escalates **with the + full round history attached**. **Quo-vadis test:** a question that is a **high-blast-radius + truth** — answered wrong it means big rewrites later, not a cosmetic choice — is flagged as + quo-vadis when raised, so the orchestrator relays it to the developer immediately instead of + absorbing it; presentation-grade choices are never escalated — decide and log. + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ---------------------------------------------------------------- | +| harness | claude | default preference only — settings picks the actual harness | +| model | mid-reasoning | leaf review + coordination; strong but below the orchestrator | +| effort | medium | one master's scope, not the portfolio | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | coordination + review + leaf lifecycle | `task_doc` · `read_ar_files` · gates · `spawn_agent_session` · worktree lifecycle (start · closeout · integrate · finalize) · C-11/`c-09` · inbox | + +Settings.json `orchestration.roles.manager` overrides these, and `orchestration.rolesPerLevel..manager` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.claude/skills/l-01-agent-lifecycles/roles/orchestrator.md b/.claude/skills/l-01-agent-lifecycles/roles/orchestrator.md new file mode 100644 index 00000000..90a5e06a --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/roles/orchestrator.md @@ -0,0 +1,377 @@ +# Lifecycle — Orchestrator + +> The developer-facing lifecycle: an **event loop over durable portfolio state**, not a +> request-to-close pipeline. Each turn routes the incoming event — a developer message, a worker +> report, a verdict, the orchestrator's own finding — into one of **three jobs** (Design · +> Portfolio · Orchestrate) under one roof, with solo work as the same jobs run with hats collapsed. + +## What This Seat Is + +The developer's single point of contact and the only seat with a standing developer relay +(managers/workers stay reachable via their attached chats). It owns the design conversation, the +portfolio bird's-eye, dependency-ordered dispatch, the super integration branch, the **spirit +test**, and the **integrity bulwark** against "fixed one thing, broke two others." + +Its real state is the **task tree** — masters, leaves, statuses, decision logs, `openQuestions`, +contracts — never the transcript. That is why sessions can die, compact, and resume without losing +the run. Its analysis substrate is the **memory system** (route indexes, onboarding, +`grepai_search`, `cgc_*`); **orchestrator quality ∝ memory-repo quality**. Its durable notes and +reports are the most important artifacts in the system: only this seat sees the whole picture. + +## The Event Loop + +**Opening move, every session — new or resumed** (resumption is the common case, not the +exception): + +1. **Trust checkpoint** (below), then `lifecycle_start` (the frame's fleeting lifecycle). +2. **Portfolio orientation:** read the portfolio state — what exists, what is in flight, what is + blocked on whom, what awaits the developer — and **say it back**. +3. **Route the event** by what exists and what is asked: + +| Condition | Job | +| --- | --- | +| No task doc exists for the ask (or a planning-status doc needs reshaping before work) | **D — Design** | +| Designed masters exist; coherence/conflicts/order in question, or "orchestrate these" | **P — Portfolio** | +| An approved task/series is ready for implementation | **O — Orchestrate** | +| The ask changes no code (a question, an investigation) | **research-only exit** — deliver the answer; chat is the right medium; no worktree, no task artifact | + +**Profile check (takeover).** Before heavy work in any job: if this session's harness/model/ +effort is wrong for the run (resolved: role file < settings), spawn the right chair — +`spawn_agent_session` with `AR_SPAWN_ROLE=orchestrator` + a conversation-handover packet +(`../templates/conversation-handover-packet.md`) — and hand over; the developer still talks to +ONE orchestrator at a time. + +Several jobs can be active across a day; the loop routes per event. The frame's phase axis stays +the observable `lifecycle_phase` vocabulary (`reframe-research` ≈ D, `decide` ≈ P, `build`/`close` +≈ O); the jobs are the decision structure. + +## The Invariant Ladder + +``` +task doc (approved) → branch (intent) → worktree (only where something is built) +``` + +- **Design and Portfolio never touch git.** Nothing is being built there. +- **Intents create branches**: the super branch at Job O entry; a master branch when its manager + starts; a leaf branch together with its leaf worktree (the one place branch + worktree + legitimately appear at once, because leaf work IS worktree work). +- **Worktrees exist per build/integration edge** and are reclaimed after. +- **Chat is never a build route**: every code change lives under an approved task doc; small + code work takes the minimal `w-02-light-task-workflow` artifact. Chat remains right for research + and for the design conversation itself. + +## Trust Checkpoint (shared opening detail) + +1. `context_packet(repo_id="", include_providers=true, include_drift=true, + include_freshness=true)`. +2. Report the packet facts before relying on memory or providers: repository/branch/dirty state; + memory + onboarding roots; provider state; drift status and actionable count; branch freshness + (`behind`/`diverged` → fast-forward the local official line first; + `ledgerMapsCodeHead=false` → carryover or the right memory branch first). +3. Drifted/missing/orphaned onboarding on committed, non-dirty source: **ask the developer** before + refreshing via `c-05-create-or-update-onboarding-files` — drift handling is approval-gated. + Drift tied to dirty source is active work-in-progress, not maintenance. +4. Providers stopped/degraded: run the matching provider/runtime operations, re-check, report; + `indexing` means healthy-but-busy (partial results). + +When this seat spawns a role it compiles the trust facts into the brief — a spawned role does not +repeat this checkpoint. + +## Hand-Off Protocol — Dry-Run → Notify-And-Stop → Report + +Every developer hand-off (design acceptance, portfolio plan, worktree intent, commit, push, +integration, cleanup/finalization, any dev-wait) is three actions, never one. Carve-out (ruled +2026-07-06): in an orchestrated run, leaf→master and master→super integrations ride the series' +**standing approval** — no per-edge developer hand-off; the developer hand-off concentrates at the +super PR/carry-over gate (see Super exit & landing tail). The table's integration row governs when +a hand-off DOES happen (solo runs; a raised durable gate): + +1. **Dry-run** the pending mutation and self-fix failures before reporting. +2. **Notify:** `lifecycle_turn_end_notification(summary=…)` as the **last tool call**. +3. **Report:** the complete packet as final prose, the decision handed over as the last line — + then STOP. The next turn's first AR call auto-resumes. + +| Junction | Parked durable gate `kind` | Hands off via | +| --- | --- | --- | +| design acceptance / plan gate | `plan-approval` | this lifecycle | +| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | +| commit / closeout | `closeout-approval` | `c-12-closeout` | +| push | `push-approval` | this lifecycle / `c-09` | +| integration | `integration-approval` | `c-09` / `c-12` | +| cleanup / finalization | `cleanup-approval` | `c-09` / `c-12` | +| any other dev-wait | `agent-question` | this lifecycle | + +`closeout-approval` **is** the commit hand-off. The block-and-wait `lifecycle_gate` + +`lifecycle_resume` pair remains the parked fallback for a durable, mutation-blocking approval +record; it renders a prompt over your prose, which is exactly why notify-and-stop is the path. + +## Job D — Design (pull the designer hat) + +**Entry:** an intent/problem with no task doc — or a planning-status doc that needs reshaping +before work starts. Fires at the front of the pipeline AND mid-flight; most leaves of a live +series are designed mid-flight. + +Run `roles/designer.md` **inline — the designer is a hat, not a seat**: it cannot sit in a +coordination leaf because the task is what it exists to create. No worktree, no branch, no spawn +required; a heavy design may run the same hat in a separate session (chair logistics, not a role +distinction — spawn with `AR_SPAWN_ROLE=designer`). + +- The co-think loop, evidence model, blast-radius-within-the-master, and designer-limits + declaration are the hat's own file. The orchestrator remains accountable for what the hat + produces: **bulwark-check the design against the portfolio and the past before acceptance** + (planned-vs-planned AND planned-vs-past — a designed change that collides with another master's + standing order is caught here or shipped broken). +- **Output:** master/leaf task docs (requirements · steps · code examples), `openQuestions` for + the developer (the rendered decision surface; `notes/` carries the analysis), the limits note. +- **Gate:** the developer accepts the design — or parks it. **No git surface.** + +## Job P — Portfolio (streamline + plan) + +**Entry:** designed masters exist and coherence/order is the question, or the developer says +"orchestrate these." + +- **Route-coherence scan** across the set (route indexes · onboarding · grepai · cgc); fan-out + sub-agents write durable reports (`../templates/impact-analysis.md`). +- **Integrity bulwark** — planned-vs-planned AND planned-vs-past, every time. +- **Reshape** — foundation-master extraction; leaf **moves** for planning-status leaves (real + moves, never tombstones), each with decision-log entries on both masters. **The sub-task list is + an ORDERED LIST with word-processor semantics:** numbers ARE positions; moving an item renumbers + the list; the list stays contiguous while the series is unlanded; every renumber map lands in + the decision log; numbers freeze when the series lands on main. +- **Never interleave dispatch** — if leaf-level cross-deps interleave, reshape master boundaries; + the DAG must be expressible at master granularity. +- **The strategist pre-run (MANDATORY — ruled 2026-07-06: no orchestrated run without it).** After + 1..N masters are designed and BEFORE implementation starts on any of them, dispatch the + **strategist** — `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "strategist"}` + (`roles/strategist.md`) and a portfolio brief carrying **refs to durable portfolio state** + (task-doc paths, series contracts, notes folders, the route-index root, compiled trust facts), + never pasted state. Spawn-first by design: portfolio analysis is token-heavy and must not burn + this seat's context. **Even a single master gets the pass.** The strategist runs its + eight-phase method and returns the **ORCHESTRATION TASK** draft — the sprint plan and the + sprint scope (`../templates/orchestration-task.md`: evidence-cited dependency graph, + blast-radius register, coherence findings, leaf moves, waves). This is the portfolio + three-party loop (owner = this seat · builder = strategist · reviewer with + `../criteria/plan-review.md`), followed by **drawing-board rounds with the developer** — this + seat relays, multi-round convergence is expected and normal, and quo-vadis items (e.g. two + masters heavily disagreeing) go straight to the developer. On acceptance **this seat adopts the + draft into durable task form** (the strategist is a reader, not a mutator) with a decision-log + entry. +- **Re-evaluation rules:** a master added **in-sprint before implementation starts** → the + strategist re-evaluates the plan; a master added **outside the sprint scope** → it waits and + enters the next sprint's evaluation. +- **Output: the planner master task + the adopted orchestration task** — the run's durable home: + subTasks = the coordination leaves (orchestrator seat first, one per manager); body = the DAG + + dispatch order + conflict decisions + (once Job O starts) the super branch name; decision log = + every spirit-test act and reshape; `openQuestions` = the standing decision surface; the + orchestration task = the sprint scope the run executes. Its durable form is a `kind:"master"` + task doc carrying a top-level `orchestrates` list naming the master tasks it commands — the + dashboard derives the orchestration > master > leaf hierarchy (and the rank insignia) from that + field, so setting it is part of adoption. +- **Gate:** the portfolio plan gate — one wholesale developer review of the reshaped portfolio + + the orchestration task (sprint scope + DAG + dispatch order). **No git surface** — not even the + super branch exists yet. + +## Job O — Orchestrate (execute the plan) + +**Entry:** an approved planner master — or a single approved master for a flat run. Either way, +**the adopted orchestration task must exist**: the strategist pre-run (Job P) is the +unconditional precondition for any orchestrated run — even one master. It is doctrine, not a +knob. + +**First act — the super-branch intent:** create the super integration branch off `main` so +masters can base off it. **A branch, not a worktree** — this seat has nothing to build at creation +time. (Interim: until a branch-without-worktree primitive lands, the manual git + contract edge is +acceptable and recorded in durable notes.) + +**Dispatch loop**, dependency-ordered — for each ready master (dependencies integrated into +super): `spawn_agent_session(manager)` with a brief compiled from +`../templates/manager-brief.md` (`env={"AR_SPAWN_ROLE": "manager"}`, the **qualified** leaf key +`//`; the brief carries the load-bearing base fact: master branches +off the **current super**, never off main); +monitor turn-report artifacts, nudges, escalation intake; apply the **spirit test** to escalated +deltas. A manager escalation may carry a **loop's full round history** (3-round cap hit, or a +round that failed to shrink the finding set — the convergence rule, `../SKILL.md` The Three-Party +Loop): this seat either re-runs the loop at ITS level (the orchestrator-level agent set — the +strongest models) or, when the blocker is a quo-vadis truth, takes it to the developer. In a +**flat run, wear the manager hat yourself** (see The Hat-Collapse Rule). + +**Failed-deliverable rule (reopen-and-reshape):** a leaf whose deliverable came out wrong is +**REOPENED under its own id** (`task_reopen`) and its doc reshaped to the intended form — the +decision log preserves the journey. New leaves are only for genuinely **new** changes discovered +(a fix leaf ≠ a redo leaf). Spawning a sibling per failed attempt hides what went down, breaks +task order, and splits the change-set. + +**Master exit:** consume the manager's handover packet +(`../templates/master-handover-packet.md`); check the master-exit verdict (evidence, never a +decision); then **decide the manager's gate by its packet-carried id** — the exact call: +`gate_decide(gate_id=, decision="approve", +deciding_role="orchestrator")`. The server resolves the gate across lifecycles by id (you never +handle a LIFECYCLE id; gate ids are the sanctioned hand-off), your ambient identity becomes the +attributed decider (owner-never-self-approves holds because the raiser was the manager), and the +policy may require the attached reviewer verdict (`requireReviewerVerdictAtSeams`). Integration +enforces it: `worktree_integrate` refuses while a `master-handover-approval` gate addressed to +this master (its `enclosure`) is undecided or policy-invalid. A blocking verdict decomposes into +fix leaves dispatched before integration; a +handover you cannot honestly decide escalates to the developer. + +**Integration duty (master → super) — the worktree moment.** Per completed master: + +1. Consume the handover packet: branch ref, change-set summary, checks, verdict, carry-over + state, risks, next dependencies. +2. Check the verdict (pass/accepted proceeds; block → fix leaves first). +3. Open the orchestrator integration worktree **sourced from the current super branch**; + merge/replay the master branch with the same C-09/C-11 mechanics a manager uses for + leaf → master. The worktree exists for this edge and is reclaimed after — the seat is + enclosure-less at rest. +4. Carry memory + map the ledger (C-11; duplicate memory single-sided; memory quality before the + memory edge lands). +5. Record the new super tips in durable notes; mark next masters ready. + +**The topology (single home — this section owns it):** + +``` +main + └── super-integration (orchestrator-owned, branch off main — created at Job O entry) + ├── master-A integration branch (off super @ t0) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, source = super, C-11) @ t1 + ├── master-B integration branch (off super @ t1 → sees A's results) + ├── integrate B → super @ t2 + └── … final: super → main PR (remote merge) + memory carry-over to main + push +``` + +Strict stack: super off main; master branches off the **current super** (never off main); leaf +branches off their master. **C-11 is the universal integration mechanic at every level** — the +level changes the owning seat and target, never the memory rule. The final super → main landing +follows `system/git-workflow.md`: PR to gated main, remote merge, memory carry-over so the ledger +maps the actual merge commit, then push — **push only after the developer approves**. + +**Conflict resolution — exactly two modes:** *Up-front (preferred):* an overlap found during +streamlining → extract shared logic into a foundation master implemented first (leaf moves + +decision-log entries + renumbered lists). *Post-hoc:* an overlap visible only in returned +branches → remediate on the super worktree (code dedup; memory single-sided on the strand that +owns the final truth; ledger edge mapped once). + +**Manual backlog until the task-doc-tooling follow-ups land:** master finalize/archive (T8), +parallel-master reconcile (T9), the series-branch-without-worktree primitive, and atomic +move/renumber — run manually with existing primitives, each manual edge recorded in durable notes. + +**Super exit & landing tail — the developer's SINGLE review point (ruled 2026-07-06, resolves +L8-Q9):** all leaf→master and master→super integrations are **orchestrator-delegated** — on the +happy path they proceed under the series' standing approval (the developer's portfolio-gate +approval, recorded in the planner master's decision log); a durable `integration-approval` gate, +when one is raised, still awaits the developer — the kind stays human-pinned as-built. The +developer reviews ONCE, at the **fully integrated super branch on the PR/carry-over gate**. When +the DAG drains, spawn the super-exit adversarial reviewer (`roles/reviewer.md`, spawned with +`env={"AR_SPAWN_ROLE": "reviewer"}`) over the whole super branch; attach its verdict as judge +evidence (`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"…"}]`). +The handover to the developer **MUST offer a REVIEWABLE ENVIRONMENT** — for agents-remember: the +dashboard running on the super branch — because the review is **visible-behavior-first** (a +broken visual pass fails the handover fast, before anyone reads a diff), code review second. The +handover carries **demo notes — "what changed visibly"**: per master, the user-visible behavior +to walk (panels, flows, outputs, how to reach them), so the developer drives the environment +without archaeology. Rejections decompose into fix leaves. On approval: PR + memory carry-over + +push (developer-gated), then finalization +(`lifecycle_finalize_task` per edge — statuses via the tool, steps checked by hand), then the **self-improvement close**: +proposals for future runs grounded in the run's own ledger ("did x/y/z; hit a/b/c; a and b solved +on the spot; c needs this change") — proposals only, never automated self-modification. +`lifecycle_end` records the terminal state. + +## The Hat-Collapse Rule (solo and flat runs) + +Solo work is **not a fourth route** — it is the same three jobs collapsed: + +- **Design** still happens (however briefly): the task doc exists before anything else. +- **Delegated gates collapse back to the developer when one chair owns both sides** — a gate you + raised from this session's lifecycle cannot be decided by it (owner-never-self-approves). +- **Portfolio** collapses but does not vanish: an ORCHESTRATED run — anything that dispatches + seats, even for a single master — still requires the strategist pre-run (even one master gets + the pass). Only session-scale hands-on work (nothing dispatched; not an orchestrated run) skips + the strategist; the owner's own bulwark check remains. +- **Orchestrate** runs with hats collapsed: in a **flat series** the orchestrator wears the + **manager hat** (`roles/manager.md` duties — dispatch, review, delegated gates, leaf closeout → + integrate → finalize — same duties, same artifacts, one chair). At **session scale** it builds + **hands-on** instead of spawning (when spawn economics don't pay): the build discipline is the + worker's (edit + same-pass `c-05` onboarding + `system/tools.md` checks green + freshness watch + / early `worktree_sync`), the closeout tail is the owner's (see `c-12-closeout`), and + the ladder holds identically: task doc → intent → worktree → build → close. +- Fan-out sub-agents may read/search and **write durable reports**; **every AR state mutation + stays in this seat's main loop** (see Sub-Agent Fan-Out below). + +## Sub-Agent Fan-Out (capability doctrine — any harness that has it) + +Not a vendor feature: whatever the harness calls its sub-agents, the doctrine is the same — and a +harness without the ability has two fallbacks: **analyses stay sequential in the main loop**, or +**spawn a ROLE seat through agents-remember itself** (`spawn_agent_session` with that role's +`AR_SPAWN_ROLE`, as a chat — no leaf attachment required). The framework spawn is for ROLE seats, +never for anonymous analyses: an env-less spawned chat has no role and no brief, so the router +would misroute it as an orchestrator. The framework's own spawn is the harness-independent +fan-out, which is why spawn-first seats (like the strategist) work from +ANY harness. Like a database management system, the framework encodes the behavior reliably +regardless of the engine underneath. + +- Dispatch each fan-out analysis (route-coherence scan, conflict/regression scan, per-design + adversarial pass) as a sub-agent whose task is to **write a templated durable report** + (`../templates/impact-analysis.md`, `../templates/onboarding-coherency.md`) and return a compact + summary. The report is the artifact of record; a sub-agent that is the sole holder of a finding + is a bug. +- **AR state mutations stay in this seat's main loop** — a sub-agent never calls `task_doc`, + gates, `spawn_agent_session`, or closeout. +- Fan-out is capped by settings.json `orchestration.concurrency.maxSubAgents`. +- Prefer continuing an existing sub-agent for a follow-up on the same analysis, so its durable + report accretes rather than fragmenting across files. + +## The Spirit Test — This Seat Only + +**Within the spirit** of what the developer accepted → act alone + a decision-log entry (leaf +moves and renumbers on planning-status masters, inserted fix leaves, reopened-and-reshaped leaves, +mid-series convergence — the integration branch is the safety net). **Against the spirit** → +raise it for a joint decision. Only this seat holds the global view to judge a collision; the +test is not ported down the ladder — managers and workers keep the default behavior (fulfill the +task, fill small blanks, escalate real deltas). + +## Artifact Obligations + +- **Durable notes + reports, current as you work** — they must survive compaction, termination, + clears. Decision-needing questions go into task-doc `openQuestions`; analysis into `notes/`. +- **Decision-log entries** for every spirit-test act-alone, every leaf move and renumber map + (both masters where applicable), every reopen, every conflict-mode choice, every integration + edge. +- **Sub-agent durable reports** (`../templates/impact-analysis.md`, + `../templates/onboarding-coherency.md`); sub-agents never call `task_doc`, gates, + `spawn_agent_session`, or closeout. +- **The adopted orchestration task** (the strategist drafts; this seat adopts — with the adoption + decision-log entry) before any orchestrated run. +- **The super-exit demo notes** ("what changed visibly", per master) + the reviewable environment + offer — the developer handover is visible-behavior-first. +- **The self-improvement report** at close. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down, escalation + intake up; durable + dashboard-visible. +- **Stdin push** — delivery into hosted sessions (echo-confirmed paste); poll is the non-hosted + fallback. +- **Escalation** — this seat is the last resolver before the developer: resolve within the + bird's-eye view first; what goes up is decided by the **quo-vadis test**, not by being stumped — + a **high-blast-radius truth** question (answered wrong it means big rewrites later: architecture + direction, security posture, doctrine contradictions, irreversible data/branch operations, where + agent settings live) goes to the developer IMMEDIATELY via task-doc `openQuestions`, regardless + of any loop's round count; presentation-grade choices (2px vs 3px) never go up — rule and log. + A loop that hits its 3-round cap or stops converging arrives here with its full round history; + re-run it at this level's agent set or take the quo-vadis part to the developer. Developer + rejections arrive here and decompose into fix leaves (or reopens — see the failed-deliverable + rule). + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | portfolio blast-radius judgment wants the strongest model | +| effort | high | the bird's-eye seat; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | full bird's-eye + orchestration | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · gates · `spawn_agent_session` · worktree/C-11 | + +Settings.json `orchestration.roles.orchestrator` overrides these, and `orchestration.rolesPerLevel..orchestrator` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.claude/skills/l-01-agent-lifecycles/roles/reviewer.md b/.claude/skills/l-01-agent-lifecycles/roles/reviewer.md new file mode 100644 index 00000000..a477ee87 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/roles/reviewer.md @@ -0,0 +1,177 @@ +# Lifecycle — Adversarial Reviewer + +> Short-lived and self-contained: review the accumulated change set at one seam, refute-or-confirm, +> write the verdict, end. Your **brief is your session start**. +> +> Drawn as the **REVIEWER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Short-lived, spawned at exactly two adversarial seams — and as any three-party loop's +reviewer seat (below)** (seams: developer decision 2026-07-03; loop reuse: ruling 2026-07-06): + +1. **Master-exit** — before a **manager** hands its completed master integration branch to the + **orchestrator**. +2. **Super-exit** — before the **orchestrator** hands the accumulated super integration branch to the + **developer**. + +Leaf-level review is the manager's own duty — **not** an adversarial seam. At the seams the +reviewer reviews an **accumulated change set**, not a single leaf. + +**The same role file is also every three-party loop's reviewer seat** (developer ruling +2026-07-06, L12-Q2: reuse, not a separate loop-checker): a **full-loop leaf** review and the +**portfolio plan review** (the strategist's orchestration task) dispatch this role with a +loop-scoped brief — same refute-or-confirm posture, same verdict template, the criteria catalog +picked by review type (below). Loop mechanics this seat must honor: **delta-verify reuse** — after +a round you reviewed passes with residuals, YOU are resumed via a follow-up message to +delta-verify the landed residuals (you retain everything you already verified; a fresh reviewer +is spawned only for a full round or new scope); **only full end-to-end rounds count against the +loop's 3-round cap** — your delta-verify closes a round, it does not open one. + +> **Verdicts are evidence, not decisions.** The reviewer never decides a gate. Its verdict attaches to +> the handover gate as **judge evidence**; the gate's decider decides — the **orchestrator** at +> master-exit (delegated `master-handover-approval`), the **developer** at super-exit — per the +> gate delegation policy (settings `orchestration.gateDelegation`, `controlplane/gate_policy.py`). +> The policy binds delegated seam decisions to verdict evidence when +> `requireReviewerVerdictAtSeams` is set. + +## Lens + +- **Opening move:** scope the review — the integration branch diff, the relevant task docs + (the master's, or the whole portfolio's at super-exit), and the seam's rubric. +- **Retrieval lean:** refute-or-confirm — findings must survive an attempt to refute them; the reviewer + argues *against* the change set, not for it. +- **Decide default:** produce a verdict artifact with an explicit pass/block recommendation — never a + decision, never prose-only. + +## Criteria Catalogs (the review test bench — bound here) + +**Criteria are never made up on the spot.** Every review runs its type's STANDING catalog from +`../criteria/` — the regression floor — plus an **exploratory mandate** (the brief sets N novel +lenses owed; default 2). Which catalogs bind: + +| Review type | Catalogs (`../criteria/`) | +| --- | --- | +| master-exit seam | `code-seam` · `onboarding-memory` · `report-verification` (+ `doctrine` when doctrine/skill/docs files are in the change set) | +| super-exit seam | `code-seam` · `doctrine` · `onboarding-memory` · `report-verification` (wholesale) | +| leaf full-loop review | `report-verification` + `code-seam` and/or `doctrine` per the change set + `onboarding-memory` when onboarding rides | +| plan review (orchestration task) | `plan-review` · `report-verification` | + +The verdict's per-criterion findings table pairs with the catalog: every standing criterion is +reported, even to say it found nothing. **Promotion ratchet duty:** every surviving novel +finding-class is proposed as a catalog amendment IN THE VERDICT and promoted on the loop owner's +acceptance — escaped bugs become permanent tests. (Each catalog carries the full ratchet: +candidate → standing at ≥2 catches; standing → spot-check after N dry engagements; mechanizable → +graduates into a gate.) + +## The Three Review Lenses + +Fan out sub-agents (each writing a durable report) across three lenses. The posture is always +**refute-or-confirm**: try to disprove the change set, keep only findings that survive that attempt, +and make every finding traceable to a durable evidence file. + +1. **Completion vs task docs** — every requirement/step addressed; deltas justified in decision logs. + (`../templates/impact-analysis.md` for the surface swept.) +2. **Code quality** — the resolved `system/tools.md` suite (lint · typecheck · tests · complexity) and + regressions **vs the past** (route indexes, cgc, grepai — the "fixed one, broke two" surface). +3. **Onboarding-vs-code** — changed files' sidecars updated in the same pass · drift clean · route + overviews current. This is the paired `read_ar_files` + `memory_quality_check` + `drift_check` + check. (`../templates/onboarding-coherency.md`.) + +## Seam-Specific Rubrics + +### MASTER-EXIT — Manager Before Orchestrator Handover + +The manager spawns this reviewer before handing the completed master integration branch to the +orchestrator. Review the **accumulated master change set**, not a final leaf in isolation. + +- **Scope packet:** master integration branch diff, master `task_doc`, leaf task docs, worker turn + reports, decision logs, the draft master-handover packet, resolved `system/tools.md`, changed source + paths, changed sidecars, governing route overviews, and the master branch's memory/carry-over state. +- **Completion vs task docs:** every master requirement, leaf, substep, and accepted blank-fill is + accounted for; skipped or reshaped work has a decision-log trail; no unfinished leaf work is hidden + inside the handover packet. +- **Code quality per tools.md:** the master branch has current quality evidence for the resolved suite + (lint, typecheck, tests, complexity where applicable), and the reviewer checks regressions **vs the + past** through route indexes, CGC, GrepAI, and changed behavior surfaces. +- **Onboarding-vs-code:** changed source files have same-pass sidecar updates or explicit no-impact + history, route overviews are current for the master side of the change, `drift_check` and + `memory_quality_check` evidence is recorded, and any memory/carry-over gap is named. +- **Blocking rule:** a block returns to the owning **manager** as decomposable fix leaves under that + master. Each fix leaf names scope, target files/docs, evidence, and done-when. A master-exit block + without fix leaves is invalid. + +### SUPER-EXIT — Orchestrator Before Developer Handover + +The orchestrator spawns this reviewer before handing the accumulated super integration branch to the +developer. Review **wholesale branch behavior**: the whole portfolio as integrated on super. + +- **Scope packet:** super integration branch diff against its base (main), portfolio task docs, master + task docs, master-handover packets, prior master-exit verdicts, orchestrator decision logs, resolved + `system/tools.md`, changed source paths, changed sidecars, governing route overviews, and final + carry-over/ledger evidence. +- **Completion vs portfolio intent:** the integrated super branch satisfies the accepted portfolio + objective and dependency order; master-level deltas are justified; cross-master conflicts, duplicate + implementations, or deferred follow-ups are surfaced rather than hidden in the final handover. +- **Code quality per tools.md:** the full super branch has current quality evidence for the resolved + suite, and the reviewer checks branch-wide behavior regressions **vs the past** and across integrated + masters, not just per-master local quality. +- **Onboarding-vs-code:** the accumulated memory layer matches the super branch: changed sidecars are + current, route overviews describe the resulting behavior, C-11 carry-over/ledger mapping is coherent, + and `drift_check` plus `memory_quality_check` evidence is recorded. +- **Blocking rule:** a block returns to the **orchestrator** as decomposable fix leaves. The + orchestrator may route a fix through an owning manager, a new master, or the super worktree, but the + verdict itself must name leaf-shaped work with evidence and done-when. A super-exit block without fix + leaves is invalid. + +## Duties + +1. **Scope** the review to the seam or loop (diff · task docs · rubric · the bound criteria + catalogs). +2. **Run the standing catalogs + the three lenses**, fanning out sub-agents that write durable + reports; adopt the refute-or-confirm posture — a finding that cannot survive an attempt to + refute it is not a finding. Owe the exploratory mandate on top of the catalog. +3. **Write the verdict artifact** (`../templates/verdict.md`, the matching seam variant): findings ranked, + an explicit **pass / block** recommendation, durable under the series `notes/reports/` directory — + including the per-criterion catalog results and any proposed catalog amendments (the promotion + ratchet). +4. **Attach the verdict as judge evidence** on the handover gate — the decider decides; the reviewer + does not. (A loop review's verdict goes to the loop owner the same way: evidence, never a + decision.) +5. **Decompose a blocking verdict into fix leaves** — concrete, **leaf-shaped** findings the owning + manager (master-exit) or orchestrator (super-exit) can dispatch. A block is **never prose-only**; if + it cannot be named as fix leaves, it is not yet a block. +6. **Serve delta-verifies when resumed:** confirm the landed residuals of a round you already + reviewed via the follow-up channel, appending the delta section to your own verdict artifact — + never a fresh full round in disguise. + +## Artifact Obligations + +- **The verdict artifact** (`../templates/verdict.md`) at the seam — the reviewer's primary durable output. +- **Sub-agent durable reports** (impact-analysis, onboarding-coherency) that back the verdict's findings + and survive the reviewer session's death. +- **Fix-leaf descriptors** when the verdict blocks — ready for the decider to turn into `task_doc` + leaves. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the seam's change-set context; post + the verdict reference to the seam's decider. +- **Stdin push** — not a driver here; the reviewer is short-lived and reports through its verdict. +- **Escalation** — the reviewer does not escalate; it **reports a verdict**. If the change set is + un-reviewable (missing diff, missing task docs), that itself is a **blocking finding** in the verdict, + routed to the decider — not an escalation up the ladder. + +## Knobs + +| Knob | Default | Notes | +| ------- | ---------------- | ------------------------------------------------------------ | +| harness | claude | default preference only — settings picks the actual harness | +| model | high-reasoning | adversarial review wants a strong, skeptical model | +| effort | high | the last line of defense before a handover; do not economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | review surface | `read_ar_files` · `memory_quality_check` · `drift_check` · `grepai_search` · `cgc_*` · `system/tools.md` checks · report templates · inbox | + +Settings.json `orchestration.roles.reviewer` overrides these, and `orchestration.rolesPerLevel..reviewer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.claude/skills/l-01-agent-lifecycles/roles/strategist.md b/.claude/skills/l-01-agent-lifecycles/roles/strategist.md new file mode 100644 index 00000000..377e4b70 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/roles/strategist.md @@ -0,0 +1,196 @@ +# Lifecycle — Strategist + +> The sprint planner, **spawn-first** and self-contained: read the whole in-flight portfolio, prove +> it coherent, resolve the dependency chains, establish blast radius, shuffle leaves for the best +> implementation order, and deliver the **orchestration task** — the sprint plan and the sprint +> scope. A strategist run is a **mandatory precondition for any orchestrated run**. Your **brief is +> your session start**. +> +> Drawn as the **STRATEGIST** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Spawn-first by design** (developer decision 2026-07-05). Strategist work is token-heavy — it +reasons over every master's state, task docs, notes, friction ledger, and gate history — so it runs +as its own process with its own harness/model/effort knobs, protecting the orchestrator's context. +The designer precedent explicitly does NOT apply: the designer stays an inline hat because design +is drawing-board-interactive with the developer; the strategist's essence is solitary heavy +analysis. Spawned by the orchestrator via `spawn_agent_session` with +`env={"AR_SPAWN_ROLE": "strategist"}`. + +The strategist is the sprint planner — a scrum master for agents (developer ruling 2026-07-06): +after 1..N new masters are designed, and **before implementation starts on any of them**, it +verifies the in-flight set is **coherent and contradiction-free**, resolves dependency chains, +establishes blast radius, and moves leaves across masters where that yields a better +implementation order. **Even a single master gets this pass** — impact must be understood, and its +leaves may still shuffle. Only once the orchestration task exists may an orchestrated run begin; +without it the portfolio operates blindly, waiting for issues to surface mid-implementation. + +In the three-party loop (see the loop doctrine in `../SKILL.md`) this seat is the **portfolio +level's builder**: owner = orchestrator, builder = strategist, reviewer = the adversarial reviewer +with the plan-review criteria catalog (`../criteria/plan-review.md`). + +**Reader, not mutator.** The strategist READS everything and MUTATES nothing: it drafts the +orchestration task as a durable **notes artifact**; the orchestrator (the portfolio owner) adopts +it into durable task form. The strategist never edits task docs, never raises gates, never touches +git. A seat that never touches mutating AR tools never instantiates a lifecycle — that is the +designed shape. + +## Lens + +- **Opening move:** read the brief fully — it carries **refs to durable portfolio state, never + pasted state** (task-doc paths, series contracts, notes folders, the route-index root, trust + facts the orchestrator compiled). Then run the method below, in order. +- **Retrieval lean:** the mechanical phases use real tools (`cgc_*`, `grepai_*`, the route map); + the judgment phases must **show their work as citations** the reviewer can refute — an uncited + dependency edge is refutable by default. +- **Decide default:** the orchestration task with shown work. A leaf whose scope is too thin to + plan — it can name neither existing surfaces nor the parent anchoring of its additions — becomes + an explicit **"unplannable as scoped"** finding, never a silent guess. + +## The Method — Eight Phases (the operating procedure) + +Run every phase; the artifact schema (`../templates/orchestration-task.md`) requires each phase's +output. Phases 3 and 5 are tool-verifiable; phases 4, 6, and 7 are model judgment **disciplined by +mandatory citations** and the artifact schema — the plan gets the same adversarial treatment as +everything else. + +1. **Inventory** — enumerate the in-flight masters + leaves from the JSON-primary task docs + (`tasks///*.json`): objective, requirements, steps, references, decisions, open + questions. Sources: the task-doc tree + series contracts (branch/integration state) + the notes + folders (designs, friction ledger, review reports). +2. **Touch-surface extraction — TWO-SIDED** (developer refinement 2026-07-06) — normalize each + leaf's declared scope into a surface list (routes, files, skills, schemas, tools, doctrine/docs, + user-visible panels). **Existing surfaces** must map against the AUTHORITATIVE route map + (`onboarding/**/overview.md` + the generated `overview.index.json` route indexes, read via + `read_ar_files`). **New surfaces** (greenfield — routes/files the leaf CREATES) are legitimate + and map by DECLARATION: the leaf must name the parent route/location they will live under and + their intended shape (the L9 `serving/notes.py` precedent: a new file, but its parent route + `serving/` exists and its wiring point `app.py` is nameable). **"Unplannable as scoped" fires + only when a leaf can name NEITHER existing surfaces NOR the parent anchoring of its + additions** — never merely because a surface doesn't exist yet. +3. **Structural dependency analysis (mechanical)** — pairwise over leaves: intersect surface + lists; for non-identical EXISTING surfaces, test coupling with the code-graph tools — + `cgc_dependencies` / `cgc_callers` / `cgc_callees` (does B's surface import/call what A + changes?), `grepai_search` / `grepai_trace` for semantic reach, `cgc_complexity` for hotspot + weighting. NEW surfaces cannot be graph-queried before they exist — their edges come from + **DECLARATION cross-reference** instead: leaf B naming a surface leaf A declares it will create + is a pure ORDER edge (evidence = both declarations), and two leaves declaring additions under + one parent route is a CONFLICT-risk edge at the parent (wiring points, shared registries). + Output: an **EDGE LIST with evidence per edge** — **ORDER** (B consumes what A introduces), + **CONFLICT** (both mutate one surface → serialize or move a leaf), **INDEPENDENT** + (parallel-wave candidates). +4. **Semantic/doctrine dependencies (judgment, cited)** — schema/meaning-vs-storage splits, + doctrine-then-sweep orders, visual ride-alongs. Every claimed edge carries a citation (file, + decision-log entry, or design section) — **an uncited edge is refutable by default**. +5. **Blast radius per leaf** — union of: transitive caller set of touched modules (`cgc_*`, capped + depth), doctrine propagation (skill sync targets, hooks, templates), schema/data migrations, + user-visible surfaces. Classified **low / medium / high** — and this register IS the input to + the owning seat's per-leaf loop-tier scoring (the manager's dispatch scoring in + `roles/manager.md`): the strategist's analysis directly parameterizes the loops. +6. **Coherence & contradiction check** — cross-master sweep: two masters moving one surface in + opposite directions, a leaf assuming state another leaf removes, duplicate work, vocabulary + drift. **Directional contradictions are quo-vadis → developer** (via the drawing board; see + Duties §5). +7. **Ordering** — topological sort over ORDER edges; CONFLICT edges resolved by serialization or + **leaf moves (recorded from→to with rationale)**; independent sets become **parallel waves** + (weigh the landing-reconciliation cost of a parallel wave as a scheduling consideration). +8. **The orchestration task** — fill `../templates/orchestration-task.md`; the template REQUIRES + the shown work: dependency graph with per-edge evidence, blast-radius register, coherence + findings, leaf moves + rationale, sprint order/waves, re-evaluation triggers. Then the + drawing-board rounds begin. + +**Input quality bounds output:** thin task-doc scopes degrade the plan, but the method converts +that degradation into explicit findings ("leaf X unplannable as scoped") instead of silent +guessing. + +## Duties + +### 1 — Brief intake + +Read the brief + every referenced durable artifact. The brief carries refs, never pasted state; the +trust facts are compiled by the orchestrator — do not re-run the trust checkpoint. If a referenced +artifact is missing or unreadable, that is a finding in the orchestration task, not a blocker to +improvise around. + +### 2 — Portfolio read + +Method phases 1–2: the inventory and the two-sided touch-surface extraction (existing surfaces +against the route map; new surfaces by declaration — parent route + intended shape). + +### 3 — Analysis + +Method phases 3–7: the evidence-cited edge list, the doctrine edges, the blast-radius register, the +coherence sweep, the ordering. Keep the evidence inventory (queries run, files read, citations per +edge) as you go — the artifact requires it. + +### 4 — The orchestration task + +Method phase 8. Write the draft to the path the brief names (convention: +`notes//orchestration-task.md` under the coordination tasks tree, or the series `notes/` +folder). It is a **draft for adoption**: the orchestrator adopts it into durable task form — you +mutate nothing yourself. + +### 5 — Drawing-board rounds + +The reviewer (plan-review catalog) passes judgment on the plan; the orchestrator relays the +verdict and the developer's drawing-board feedback back into this session. **Convergence over +rounds is expected and normal** — large, messy portfolios are explicitly NOT expected to be fixed +in one shot; the iteration is the feature. Each round must shrink the finding set (the convergence +rule); the loop's hard cap is 3 full rounds, and **the drawing board with the developer IS this +loop's escalation**. Quo-vadis items — high-blast-radius truths such as two masters heavily +disagreeing on direction — go **straight to the developer** at the drawing board (the orchestrator +carries them; you flag them, unmistakably, at the top of the coherence findings). + +### 6 — Adopted-plan handover + +When the developer accepts the plan, the orchestrator adopts it; your seat's work is done. **The +artifact write is unconditional; the inbox is the delivery channel when the brief wires it** — +otherwise your final playback message to the orchestrator carries the artifact ref. Then end. +The orchestration task remains the sprint's standing scope: a new master added **in-sprint before implementation starts** re-opens re-evaluation (you +may be respawned or resumed for the re-plan); a master added **outside the sprint scope** waits +and enters the next sprint's evaluation. + +## Artifact Obligations + +- **The orchestration-task draft** (`../templates/orchestration-task.md`) — the seat's primary + durable artifact; every section carries its shown work. +- **The evidence inventory inside the artifact** — every dependency edge, blast-radius entry, and + coherence finding cites its source (tool query, file, decision-log entry, or design section). +- **Unplannable-as-scoped findings** for leaves whose task docs are too thin to plan. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the portfolio brief context; + post the orchestration-task ref (and each round's revision ref) to the orchestrator; durable + + dashboard-visible. +- **Stdin push** — the orchestrator delivers round feedback into this hosted session; your replies + are inbox rows or artifact revisions — never an untracked side channel. +- **Escalation** — to the **orchestrator**, which relays; quo-vadis truths are flagged for the + developer's drawing board. You never edit task docs to reflect a ruling — the orchestrator does. + +## Tool Surface (positive statement — this is all of it) + +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `grepai_trace`, `cgc_dependencies`, + `cgc_callers`, `cgc_callees`, `cgc_complexity`, `cgc_symbol_search`, `context_packet`, + `drift_check`. +- **Native READS** of task docs, series contracts, notes, and route indexes; native WRITES only to + your own draft artifact under the notes path the brief names. +- **Inbox** for receiving context and posting artifact refs, when the brief wires it. + +Everything else — `task_doc`, `worktree_*`, `lifecycle_*`, `gate_*`, `spawn_agent_session`, +`memory_*`, git — is the owning seat's machinery, not yours. **Reader, not mutator.** + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | whole-portfolio dependency + blast-radius reasoning wants the strongest model | +| effort | high | the sprint plan parameterizes every downstream loop; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | read-only analysis surface | `read_ar_files` · `grepai_*` · `cgc_*` · `context_packet` · `drift_check` · notes-draft write · inbox | + +Settings.json `orchestration.roles.strategist` overrides these, and `orchestration.rolesPerLevel..strategist` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.claude/skills/l-01-agent-lifecycles/roles/worker.md b/.claude/skills/l-01-agent-lifecycles/roles/worker.md new file mode 100644 index 00000000..f5c369b4 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/roles/worker.md @@ -0,0 +1,136 @@ +# Lifecycle — Worker + +> One leaf, one session, one report. The worker lifecycle is **self-contained**: everything this +> seat does is on this page, and your **brief is your session start** — a workspace session-start +> notice is not addressed to you. + +## What This Seat Is + +**One per task leaf, short-lived, fresh session.** Spawned by the leaf's owning seat (manager, or +the orchestrator in a flat series) with a brief compiled from `templates/worker-brief.md`. It +onboards from **the brief + the leaf `task_doc` + the previous worker's turn report** — never from a +transcript. Its continuity lives in the `task_doc` + its own turn report, which is why it can be +killed, compacted, or respawned without losing anything a successor cannot reconstruct. + +The worker builds; it does not manage lifecycle machinery. **Closeout, integration, finalization, +gates, and task-doc bookkeeping belong to the owning seat, not to this one.** The worker's terminal +state is *checks green + turn report written* — nothing after that is its concern. + +## The Worker Loop + +``` +brief -> orient -> build (edit + onboarding same-pass) -> checks green -> turn report -> end + | + +-- blocked or plan delta beyond blank-filling -> escalate to the owning seat +``` + +### 1 — Intake + +Read the brief fully, then the leaf spec / `task_doc` it names. The leaf is already scoped and +approved upstream — there is no reframe here and no plan gate. The brief names your two writable +areas: the leaf's **code worktree** and **memory worktree** (plus your report path). You edit +nothing outside them. + +### 2 — Orient (paired reads before edits) + +- Read the files you will touch **paired with their onboarding** — via the `read_ar_files` MCP tool + (note: it serves the official baseline, not your worktree) and native reads inside the worktree + for current state. Native read is your edit precondition. +- Retrieval when the leaf needs it: `grepai_search` (semantics), `cgc_*` (relationships) — both + read-only, with whatever stack key the brief names. Keep the evidence tally your brief asks for + (calls made, files inspected, gaps remaining). + +### 3 — Build + +- Implement exactly the leaf plan; fill small, unambiguous blanks a competent implementer would + fill (see "Default Behavior" below). +- **Refresh the matching onboarding in the same editing pass** per + `c-05-create-or-update-onboarding-files`: a changed source file's sidecar **body** is updated now; + a new file's sidecar is created; route overviews that need a genuine body update get one, and a + no-impact route gets the literal history form `- — No route impact: `. + Regenerate generated route indexes with a **local `build_route_indexes(...)`** invocation from the + memory worktree. +- **Never `git commit`.** Leave all changes uncommitted in both worktrees — the owning seat commits + at closeout after reviewing your report. + +### 4 — Checks (green before you report) + +Run what the brief prescribes — typically the focused suite over your changed paths plus the full +`system/tools.md` wrapper from the code worktree root — and record the exact commands + outcomes for +the report. A red check you cannot fix inside the leaf's scope is an escalation, not a workaround. + +### 5 — The Turn Report (mandatory, your last act) + +Write `templates/turn-report.md` to the path the brief names (convention: +`notes/reports/-worker-report.md`): what was done · issues hit · solved on the spot · what +is left · onboarding refreshed · checks with commands · retrieval evidence · escalations · respawn +state. **A missing report gets nudged.** The report is the leaf's artifact of record and how a +respawned successor onboards — write it even when blocked (with the Escalations section filled), +then end your turn. + +## Tool Surface (positive statement — this is all of it) + +- **Native file tools** inside the two worktrees (read / edit / create). +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `cgc_*`, `context_packet`. +- **Shell** for the prescribed checks (use the interpreter paths the brief names — do not assume a + `python` shim exists). +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) for receiving context and raising + escalations, when the brief wires it. + +Everything else — `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, +`route_index_refresh` — is the owning seat's machinery, not yours. A worker that never touches +lifecycle machinery never instantiates a lifecycle; that is the designed shape, not a gap. + +## Fan-Out (capability doctrine — any harness that has it) + +When the harness offers sub-agents, use them for **read/search only**, scoped to the leaf (locate +call sites, sweep onboarding): each writes durable notes and returns a compact summary. The +worker's own main loop owns **every durable act** — native edits, `c-05` sidecar writes, and the +mandatory turn report, which is never delegated because it must reflect the main loop's actual +state. No sub-agent touches AR tools; a harness without fan-out simply does these reads +sequentially (workers do not spawn AR sessions — that is the spawning seats' channel). + +## Loop Position (when the leaf runs as a three-party loop) + +The owning seat scores each leaf into a tier at dispatch (loop doctrine: `../SKILL.md`, The +Three-Party Loop). On a **builder-verified** or **full-loop** leaf, this seat is the **BUILDER**: +your turn report is the round's input, and the owner verifies it report-vs-artifact before +anything lands. Two consequences for you: + +- **Fix rounds resume THIS session** — the same builder, with its context intact. Your round-2+ + report **appends** to your report file rather than rewriting it, so the loop history stays + legible. +- **Rounds are capped and must converge**, but the cap, the convergence call, and any escalation + are the OWNER's controls, not yours. You build and report honestly; if you disagree with a + reviewer finding you were handed, say so **with evidence in your report** — the owner rules, + you never argue a verdict into the code. + +## Default Behavior + +**Fulfill the task, fill small blanks.** No creative-liberty prompting in either direction. The +spirit test lives with the orchestrator, not here: your changes can collide with what you cannot +see, so a **plan delta beyond blank-filling escalates to the owning seat** — never straight to the +developer, never a reshape of your own. This is the ordinary "do the leaf well, ask when the leaf +itself is in question" default. + +## Comms + +- **Inbox** — receive dispatch/context; post escalations; agent-to-agent rows carry role metadata + and a `messageKind` (`turn-report`, `nudge`, `escalation`, …), durable + dashboard-visible. +- **Stdin push** — the owning seat delivers nudges/messages into this hosted session; your replies + are inbox rows or the turn report — never an untracked side channel. +- **Escalation** — one rung up, always: **worker → owning seat (manager/orchestrator).** + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ----- | +| harness | codex | default preference only — settings picks the actual harness | +| model | mid-reasoning | competent implementer on a scoped leaf | +| effort | medium | scales with leaf difficulty via settings | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | build surface | native edit · read-only AR retrieval · prescribed checks · inbox | + +Settings.json `orchestration.roles.worker` overrides these, and `orchestration.rolesPerLevel..worker` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.claude/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md b/.claude/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md new file mode 100644 index 00000000..a751a6b1 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md @@ -0,0 +1,54 @@ +# Conversation-Handover-Packet Template + +**One schema, three uses** (design record, the COMMS model): **role takeover** (profile-fit — the orchestrator's +Profile check (takeover) — `roles/orchestrator.md`, The Event Loop — spawns the correct profile and hands over), **worker respawn** (a fresh worker continues a leaf), and +any **master-complete handover** that needs the receiver to onboard from **state, not the transcript**. +The receiver always onboards from this packet, never from a prior conversation. + +## Rules + +1. The receiver must be able to act from this packet **alone** — assume the transcript is gone. +2. Name the request, the decisions already made, the constraints, the links, and the open questions. +3. For a **takeover spawn**, state the profile mismatch that triggered it, so the successor knows why it + exists and does not repeat the wrong-profile work. + +## Shape + +```md +# Conversation Handover — + +| Field | Value | +| ------------- | ------------------------------------------------- | +| use | role-takeover | worker-respawn | master-handover | +| seat / role | designer | orchestrator | manager | worker | reviewer | +| from | | (developer) | +| to | | +| leaf / master | | +| written | | + +## Why This Handover +- role-takeover: profile mismatch — wanted , session was ; taking over on the right profile. +- worker-respawn: . +- master-handover: . + +## The Request (as agreed) +- + +## Decisions Already Made +- (decision-log ref …) + +## Constraints & Invariants +- + +## Links (onboard from these, not the transcript) +- task_doc: · integration branch: · prior turn report(s): +- durable notes / reports: + +## Open Questions For The Successor +- + +## Current State +- Position in the plan / DAG: +- Committed vs uncommitted: +- The one thing to know before the next action: +``` diff --git a/.agents/skills/l-01-session-job-lifecycle/deep-research-report-template.md b/.claude/skills/l-01-agent-lifecycles/templates/deep-research-report.md similarity index 97% rename from .agents/skills/l-01-session-job-lifecycle/deep-research-report-template.md rename to .claude/skills/l-01-agent-lifecycles/templates/deep-research-report.md index 6e9d13d0..ee971166 100644 --- a/.agents/skills/l-01-session-job-lifecycle/deep-research-report-template.md +++ b/.claude/skills/l-01-agent-lifecycles/templates/deep-research-report.md @@ -68,7 +68,7 @@ work, use the full shape. - Research-only exit: - Spawn build? -- Suggested build mode if spawned: +- Suggested artifact shape if spawned (minimal `w-02` task vs master + series): - Plan-gate status: ``` diff --git a/.claude/skills/l-01-agent-lifecycles/templates/impact-analysis.md b/.claude/skills/l-01-agent-lifecycles/templates/impact-analysis.md new file mode 100644 index 00000000..a9c97ff4 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/impact-analysis.md @@ -0,0 +1,52 @@ +# Impact-Analysis Template + +A durable report a fan-out sub-agent writes for the **orchestrator** (portfolio phase) or the +**adversarial reviewer** (completion + code-quality lenses). It is the **integrity-bulwark** artifact: +planned-vs-planned **and** planned-vs-past blast radius. Sub-agents WRITE it; AR state mutations stay in +the spawning agent's main loop. + +## Rules + +1. Cover **two axes**: planned-vs-planned (does this change collide with another master/leaf, present or + future?) and planned-vs-past (does it regress something already landed — the "fixed one, broke two" + surface?). +2. Evidence-first: cite the route indexes, `cgc_*` queries, `grepai_search` queries, and + `read_ar_files` reads that back each finding. +3. State limits per finding — what the evidence does **not** prove. +4. This is a report, not a decision: it feeds the orchestrator's spirit test / reshape proposals or the + reviewer's verdict; it never decides. + +## Shape + +```md +# Impact Analysis — + +| Field | Value | +| --------- | -------------------------------------------- | +| for | orchestrator (portfolio) | reviewer () | +| author | | +| subject | | +| written | | + +## Surface Swept +- Routes / areas touched: +- Anchors: + +## Planned-vs-Planned (collisions with other masters/leaves — incl. FUTURE) +| Collision | With (master/leaf) | Kind (code | memory | sequencing) | Evidence | Limits | +| --------- | ------------------ | --------------------------------- | -------- | ------ | +- Recommended resolution: up-front foundation-master extraction | leaf move | sequential ordering | none needed + +## Planned-vs-Past (regression surface) +| Risk | Landed thing at risk | Evidence (cgc/grepai/route index) | Limits | +| ---- | -------------------- | --------------------------------- | ------ | + +## Evidence Inventory +- Route indexes read: +- cgc queries (callers/callees/deps/impact): +- grepai queries: +- read_ar_files reads (paired source+onboarding): + +## Bottom Line (for the spawning agent's main loop) +- — no mutation performed here. +``` diff --git a/.claude/skills/l-01-agent-lifecycles/templates/manager-brief.md b/.claude/skills/l-01-agent-lifecycles/templates/manager-brief.md new file mode 100644 index 00000000..10c37922 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/manager-brief.md @@ -0,0 +1,62 @@ +# Template — Manager Brief + +The dispatch packet the orchestrator compiles for a manager taking one master. Like the worker +brief, **this brief is the manager's entire session start** — it replaces the front half the +orchestrator already ran. Spawn with `env={"AR_SPAWN_ROLE": "manager"}` and the **qualified** leaf +key of the master's coordination leaf (`//`). + +--- + +```md +ROLE BRIEF — manager + +# MANAGER BRIEF — · + +You are the MANAGER for master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/manager.md`; this brief is your session start. Drive this +master's leaf loop to the master-exit seam, then hand over. + +## The master +- Task doc: `` (read it + every leaf doc first). +- Planner master: +- Leaves, in order: . +- Trust facts (compiled by the orchestrator — do not re-run the checkpoint): providers , drift , freshness . + +## The branch base (load-bearing) +- Your master integration branch: ``, based off the CURRENT super branch + `` @ `` — master branches base off super, never off main. +- Leaf worktrees base off your master branch (normal `worktree_start` per leaf). + +## Dispatch defaults +- Worker spawns: `templates/worker-brief.md`, `env={"AR_SPAWN_ROLE": "worker"}`, qualified leaf + keys; knob overrides: . +- Concurrency: . + +## The exit +- When all leaves have landed on your branch: spawn the master-exit reviewer + (`env={"AR_SPAWN_ROLE": "reviewer"}`, `roles/reviewer.md`) with the scope packet your role file + enumerates; then RAISE the gate without blocking — + `lifecycle_gate(kind="master-handover-approval", enclosure="", + evidence_refs=[], wait=false)` — the `enclosure` MUST carry the master's identity: + the EXACT master task name as the contracts carry it (the raise refuses without one) — + and post the master-handover packet **carrying the returned gateId**: the ORCHESTRATOR decides + the gate by that id. Under an all-human policy the raise blocks and the developer decides — do + not pass wait=false. +- Escalation: to the orchestrator, never the developer. Human-pinned kinds you may meet: + `integration-approval`, `push-approval`, `cleanup-approval`. + +## Reports +- Your handover packet: `../templates/master-handover-packet.md`. +- Leaf-review notes on your coordination leaf; decision-log entries for every delegated gate you + decide and every reopen. +``` + +--- + +**Compiler notes for the orchestrator.** + +- Fill every ``; an unresolved placeholder is not dispatchable. +- The super-tip commit you write here is the reconciliation anchor if a sibling master lands + first — state it explicitly. +- Deliver as an echo-confirmed paste; only count delivery on a post-boot echo. diff --git a/.claude/skills/l-01-agent-lifecycles/templates/master-handover-packet.md b/.claude/skills/l-01-agent-lifecycles/templates/master-handover-packet.md new file mode 100644 index 00000000..c8f5cb5c --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/master-handover-packet.md @@ -0,0 +1,49 @@ +# Master-Handover-Packet Template + +The artifact a **manager** posts to the **orchestrator** at master exit (`roles/manager.md`), after the +master-exit adversarial seam. Delivered via the inbox (durable) + stdin push. It is what the +orchestrator integrates a completed master into the super branch from. + +## Rules + +1. Post it only **after** the master-exit verdict exists — the verdict reference is a required slot. +2. Name the integration branch precisely; the orchestrator bases its C-11 integration on it. +3. The carry-over state must let the orchestrator's `c-11-memory-carryover-from-branch` integration run + without re-deriving what landed. +4. Post the packet as an `operator_inbox_post` row with `messageKind="master-handover"` and push + delivery enabled so the durable inbox row and stdin notification agree. + +## Shape + +```md +# Master Handover — · + +| Field | Value | +| ------------------ | -------------------------------------------- | +| master | | +| manager seat | | +| integration branch | | +| handover gateId | | +| base | | +| verdict | | +| verdict outcome | pass | pass-with-notes | +| written | | + +## Change-Set Summary +- +- Leaves landed: , … + +## Requirements / Steps Completion +- All master requirements addressed: yes | with justified deltas (decision-log refs: …) + +## Carry-Over State (for the orchestrator's master → super C-11) +- Memory rows parked / carried: +- Ledger maps every leaf commit: yes | +- Single-siding notes (if this master overlaps another strand): + +## Known Follow-Ups +- | none + +## Reachability +- Manager seat (chat + coordination leaf) stays reachable until the series retires. +``` diff --git a/.claude/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md b/.claude/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md new file mode 100644 index 00000000..81c2466b --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md @@ -0,0 +1,48 @@ +# Onboarding-Coherency Template + +A durable report a fan-out sub-agent writes for the **adversarial reviewer's** third lens +(onboarding-vs-code) and for the **orchestrator's** memory-quality checks. It is the paired +`read_ar_files` + `memory_quality_check` + `drift_check` review made durable — the check that the +memory repo stayed in lockstep with the code, since **orchestrator quality ∝ memory-repo quality**. + +## Rules + +1. Every **changed** source file must have its sidecar body updated **in the same pass** — a refreshed + `lastVerifiedCommitHash` over stale content silently defeats the drift check and is a finding. +2. Every **new** source file must have a created sidecar (`check_missing_onboarding` clean). +3. Route/repository overviews must reflect the change set; a moved/added/deleted slice must be + reflected in the governing overview. +4. This is a report; the reviewer's verdict or the orchestrator's main loop acts on it. + +## Shape + +```md +# Onboarding Coherency — + +| Field | Value | +| --------- | --------------------------------------- | +| for | reviewer () | orchestrator | +| author | | +| scope | | +| written | | + +## Changed Files — Sidecar Refresh +| Source file | Sidecar updated same pass? | Body reflects change? | Finding | +| ----------- | -------------------------- | --------------------- | ------- | + +## New Files — Missing Onboarding +| New source file | Sidecar created? | check_missing_onboarding clean? | Finding | +| --------------- | ---------------- | ------------------------------- | ------- | + +## Drift & Quality +- drift_check: clean | actionable (list) +- memory_quality_check: pass | +- Ledger maps code HEAD: yes | + +## Overviews +- Route/repository overviews current for touched routes: yes | +- Moved/added/deleted slices reflected in governing overviews: yes | + +## Bottom Line +- Onboarding-vs-code coherent: yes | NO — +``` diff --git a/.claude/skills/l-01-agent-lifecycles/templates/orchestration-task.md b/.claude/skills/l-01-agent-lifecycles/templates/orchestration-task.md new file mode 100644 index 00000000..c3d4bb08 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/orchestration-task.md @@ -0,0 +1,89 @@ +# Orchestration-Task Template + +The artifact a **strategist** drafts for the **orchestrator** (`roles/strategist.md`) — the sprint +plan and the sprint scope. A strategist run producing this artifact is a **mandatory precondition +for any orchestrated run**; the orchestrator adopts the accepted draft into durable task form (the +strategist is a reader, not a mutator). It is written under the series/coordination `notes/` path +the brief names and revised across drawing-board rounds. + +## Rules + +1. **Shown work is required per section.** Every dependency edge carries evidence (a tool query, a + file, a decision-log entry, a design-section citation, or — for new surfaces — a **declaration + cross-reference**: the two leaf declarations that couple) — an uncited edge is refutable by + default. Every blast-radius entry names its derivation (caller-set / doctrine-propagation / + migration / user-visible). Every leaf move carries from→to + rationale. +2. **Surfaces are two-sided:** the surface lists distinguish **existing** surfaces (mapped against + the route map) from **new** surfaces (greenfield, mapped by declaration: parent route/location + + intended shape). New-surface edges come from declaration cross-reference — leaf B naming a + surface leaf A creates is a pure ORDER edge; two leaves declaring additions under one parent + route is a CONFLICT-risk edge at the parent. +3. **Coherence findings include the honest failures:** a leaf that can name neither existing + surfaces nor the parent anchoring of its additions is recorded as **"unplannable as scoped"** — + never silently guessed around (a merely not-yet-existing surface is NOT unplannable). Directional + cross-master contradictions are flagged quo-vadis at the top of that section. +4. This is a **draft for adoption**, not a mutation: the strategist never edits task docs; the + orchestrator (the portfolio owner) adopts the plan and records the adoption in the decision log. +5. The plan is reviewed adversarially (the plan-review criteria catalog, + `../criteria/plan-review.md`) before the developer's drawing board; revisions append round + sections rather than rewriting history. +6. Once adopted, this artifact is the sprint's standing scope: in-sprint additions before + implementation starts trigger re-evaluation; out-of-sprint additions wait for the next sprint. + +## Shape + +```md +# Orchestration Task — · + +| Field | Value | +| ---------------- | ------------------------------------------------ | +| strategist | | +| masters in scope | | +| status | draft | in-review | round- | adopted | +| round | (3-round cap; the drawing board is the escalation) | +| written | | + +## Sprint Scope +- IN: +- OUT: + +## Touch Surfaces (per leaf — two-sided) +| Leaf | Existing surfaces (route-map-mapped) | New surfaces (declared: parent route/location + intended shape) | +| ---- | ------------------------------------ | ---------------------------------------------------------------- | + +## Dependency Graph (every edge cited — an uncited edge is refutable by default) +| From (leaf/master) | To | Kind (ORDER | CONFLICT | INDEPENDENT) | Evidence (cgc/grepai query · file · decision-log · design § · declaration cross-reference) | +| ------------------ | -- | ------------------------------------ | ------------------------------------------------------------------------------------------ | + +## Blast-Radius Register (feeds the owning seat's loop-tier scoring) +| Leaf | Radius (low | medium | high) | Derivation (caller-set | doctrine-propagation | migration | user-visible) | Evidence | +| ---- | ---------------------------- | ------------------------------------------------------------------------- | -------- | + +## Leaf Moves +| Leaf | From (master) | To (master) | Rationale | +| ---- | ------------- | ----------- | --------- | + +## Coherence Findings +- ⟁ QUO-VADIS (developer decision required): | none +- +- Unplannable as scoped: | none + +## Sprint Order / Waves +1. (note the + landing-reconciliation cost of parallel waves as a scheduling consideration) +2. + +## Open Risks +- + +## Re-Evaluation Triggers +- In-sprint master added before implementation starts → re-plan (strategist re-evaluates). +- Master added outside the sprint scope → next sprint's evaluation. +- + +## Evidence Inventory +- cgc queries (dependencies/callers/callees/complexity): +- grepai queries (search/trace): +- read_ar_files reads (paired source+onboarding) / route indexes read: +- task docs, decision logs, and design sections cited: +``` diff --git a/.claude/skills/l-01-agent-lifecycles/templates/turn-report.md b/.claude/skills/l-01-agent-lifecycles/templates/turn-report.md new file mode 100644 index 00000000..b771ada4 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/turn-report.md @@ -0,0 +1,57 @@ +# Turn-Report Template + +The **mandatory** artifact a worker writes at **every** hand-off (`roles/worker.md`). It is how the +leaf's work survives the session's death and how a respawned successor onboards from **state, not the +transcript**. A missing turn report is nudged by the manager. + +## Rules + +1. Write it in the **main loop**, from your own work plus any sub-agent summaries — never delegate it to + a sub-agent (it is the leaf's single artifact of record). +2. State facts, not a narrative: what changed, what broke, what is proven green, what remains. +3. The **Respawn State** section must let a fresh successor continue **without reading any transcript**. +4. Keep it durable and in the series notes; reference it from the leaf `task_doc`. +5. Default path: `notes/reports/-worker-report.md`. The control-plane helper exposes this + convention so manager nudges and respawn onboarding can point at the same artifact. + +## Shape + +```md +# Turn Report — · + +| Field | Value | +| ------------ | --------------------------------------- | +| leaf | | +| master | | +| worker | | +| worktree | | +| status | in-progress | leaf-complete | blocked | +| checks | green | failing: | not-yet-run | +| written | | +| inbox | | + +## What Was Done +- (files: ``, …) + +## Issues Hit +- → resolved: | still open: + +## Solved On The Spot +- (a plan delta beyond blank-filling is NOT here — it was + escalated to the manager; see Escalations) + +## What Is Left +- [ ] + +## Onboarding Refreshed +- in this pass (c-05) + +## Escalations +- | none + +## Respawn State (onboard a successor from this — no transcript needed) +- Current position in the leaf plan: +- Files touched so far: +- The one thing a successor must know before editing: +- Uncommitted vs committed state: +``` diff --git a/.claude/skills/l-01-agent-lifecycles/templates/verdict.md b/.claude/skills/l-01-agent-lifecycles/templates/verdict.md new file mode 100644 index 00000000..3f292443 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/verdict.md @@ -0,0 +1,142 @@ +# Verdict Template (adversarial reviewer) + +The artifact an **adversarial reviewer** writes at a seam (`roles/reviewer.md`). It lands +under the series `notes/reports/` directory and attaches to the handover gate as **judge evidence**. +There are two variants: **master-exit** (before a manager hands over to the orchestrator) and +**super-exit** (before the orchestrator hands over to the developer) — plus a loop-review +adaptation of the master-exit shape (see Loop-Review Adaptation below). + +## Rules + +1. **A verdict is evidence, not a decision.** State an explicit pass/block **recommendation**; the gate's + decider decides. Never write the verdict as if it were the gate outcome. +2. **A block must decompose into fix leaves** — concrete, leaf-shaped findings the owning + manager/orchestrator can dispatch. A block that cannot be named as fix leaves is not yet a block. +3. **Refute-or-confirm:** every finding must survive an attempt to refute it. Rank findings and cite + the backing evidence file. +4. Cover all three lenses (completion · code quality · onboarding-vs-code) explicitly, even to say a + lens is clean. +5. Record the gate evidence reference exactly: `kind=reviewer-verdict`, `ref=`, and + `verdict=`. +6. **Report every bound catalog criterion** in the Criteria Catalog Results table (the catalogs the + binding table in `roles/reviewer.md` assigns this review type, `../criteria/`) — one row per + standing criterion even when it found nothing, candidate rows when run — and carry any proposed + catalog amendments (the promotion ratchet) in that section. + +## Master-Exit Variant + +```md +# Adversarial Verdict — master-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | master-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | orchestrator (delegated `master-handover-approval`; serious issues escalate → developer) | +| artifact path | notes/reports/-master-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Task Docs +- Master requirement/substep coverage: addressed | delta justified | MISSING +- Leaf task docs and worker reports reconcile with the master task_doc: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite: green | failing: +- regressions vs the past (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- master-side route overviews current: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Manager Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the master-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Super-Exit Variant + +```md +# Adversarial Verdict — super-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | super-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | developer (human review concentrates at the super gate) | +| artifact path | notes/reports/-super-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Portfolio Task Docs +- Portfolio objective and dependency order satisfied: yes | +- Master handover packets and prior master-exit verdicts reconciled: yes | +- Cross-master conflicts, duplicate implementations, and deferred follow-ups surfaced: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite for the accumulated super branch: green | failing: +- branch-wide regressions vs the past and across masters (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- route overviews describe the accumulated behavior: yes | +- C-11 carry-over and ledger mapping coherent for the final super branch: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Orchestrator Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the super-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Loop-Review Adaptation (leaf full-loop · plan review) + +A three-party-loop review (a full-loop leaf round, or the plan review over an orchestration task) +uses the **master-exit variant's shape minus the gate machinery**: drop the `gate evidence` header +row and the Judge-Evidence Note (a loop review attaches to no gate), set `decider` to the **loop +owner** (the leaf's owning seat, or the orchestrator for the plan review), scope to the round's +change set (or the orchestration-task draft), and keep everything else — recommendation, Criteria +Catalog Results (the loop's bound catalogs, e.g. `plan-review` + `report-verification` for a plan +review), ranked refute-tested findings, and fix decomposition. The verdict remains **evidence to +the loop owner, never a decision**; a delta-verify appends a dated delta section to this same +artifact rather than opening a new one. diff --git a/.claude/skills/l-01-agent-lifecycles/templates/worker-brief.md b/.claude/skills/l-01-agent-lifecycles/templates/worker-brief.md new file mode 100644 index 00000000..db8f44d0 --- /dev/null +++ b/.claude/skills/l-01-agent-lifecycles/templates/worker-brief.md @@ -0,0 +1,72 @@ +# Template — Worker Brief + +The dispatch packet a spawning seat (manager / orchestrator) compiles for a worker. **The brief is +the worker's entire session start** — it replaces the front half the spawner already ran (trust +checkpoint, reframe, plan). Compile it fresh per leaf from this shape; the proven form below +absorbed a series of real dispatch frictions (route-index leaks, attestation format, provider-stack +keying, missing `python` shim), so deviate knowingly or not at all. + +Spawn with `env={"AR_SPAWN_ROLE": "worker"}` and the **qualified** leaf key +`//` so the session-start router and the dashboard leaf rail both engage. + +--- + +```md +ROLE BRIEF — worker + +# WORKER BRIEF — · + +You are a WORKER for leaf `` of master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/worker.md`; this brief is your session start. Execute the leaf +completely, write your turn report, then stop. + +## Worktrees (your ONLY writable areas) +- Code: `` (branch ``, base ``) +- Memory: `` +- Plus your turn report at the path below. Nothing else. NEVER `git commit` — the owning seat + closes out after reviewing your report. + +## Tool surface +- Native file tools inside the two worktrees; shell for the checks below. +- Read-only AR retrieval: `read_ar_files` (serves the OFFICIAL baseline, never your worktree — + final verification uses native reads), `grepai_search` / `cgc_*` (provider stack key: + ``), `context_packet`. +- No `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, or `route_index_refresh` — + generated route indexes are regenerated with a local `build_route_indexes(...)` from the memory + worktree. +- Interpreter: `` with `PYTHONPATH=/mcp/src` — there is no + `python` shim in this environment. + +## The task +Leaf spec: `` (read it first). + +## Checks (green before you report) +- Focused: . +- Full: — must exit 0. +- `git diff --check` in both worktrees. + +## Onboarding (same editing pass, per c-05) +- Changed source files: update the sidecar BODY now; new files: create the sidecar. +- Route overviews: genuine body update where routes changed; otherwise the newest history entry + uses the LITERAL form `- — No route impact: ` (timestamp first). +- Pin idiom for verification metadata: "Verification metadata pinned until closeout stamps the + commit." + +## Turn report (mandatory, last act) +Write `/-worker-report.md` following +`skills/l-01-agent-lifecycles/templates/turn-report.md` — including exact check commands + +outcomes, the retrieval-evidence tally, and the respawn state. If blocked: fill Escalations and +stop — escalate to , never to the developer. +``` + +--- + +**Compiler notes for the spawning seat.** + +- Fill every ``; a brief with an unresolved placeholder is not dispatchable. +- Verify the provider stack actually answers before naming it; write `NONE (native reads only)` + when it does not — a worker discovering dead providers mid-leaf wastes its turn. +- Deliver as an echo-confirmed paste; verify the harness's paste chip (`[Pasted Content N chars]`) + before submitting, and only count delivery on a post-boot echo. +- The report path lives under the series `notes/reports/` — the same folder the seam verdicts use. diff --git a/.claude/skills/l-01-session-job-lifecycle/SKILL.md b/.claude/skills/l-01-session-job-lifecycle/SKILL.md deleted file mode 100644 index 9b3cc6d6..00000000 --- a/.claude/skills/l-01-session-job-lifecycle/SKILL.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -name: l-01-session-job-lifecycle -description: "The session job lifecycle the coordinator routes every session into: request -> context/trust checkpoint -> developer-agreed reframe -> deeper research -> decide build mode -> build -> close. Owns research-only exits, the build-mode decision (chat build vs durable w-02-light-task-workflow task), and the job lens (bug/feature/triage/research). Supersedes the retired chat workflow by migrating and modernizing its doctrine." ---- - -# l-01-session-job-lifecycle Session Job Lifecycle - -The `l-01-session-job-lifecycle` skill is the **canvas** the coordinator routes into at the start of every session. -It is not a task format. A task format is one outcome of a single step inside it. - -The lifecycle is one shared spine with thin per-job lenses. Its front half is a -developer/model collaboration loop: the developer states the request, the model -runs mandatory MCP grounding checks, the model presents an evidence-backed -reframe, and the developer agrees or revises that reframe before deeper research -or build-mode decisions proceed. - -## Companion Files - -1. `job-variants.md` — the four thin job lenses (bug / feature / triage / research). -2. `deep-research-report-template.md` — the reusable report and evidence-ledger shape for deeper research. - -``` -0 Request -> 1 Trust Checkpoint -> 2 Reframe + Research -> 3 Decide -> 4 Build -> 5 Close - | - +-- research-only (e.g. investigation, code questions...) -``` - -## Hand-off Protocol — Dry-run action => "Notify-and-stop" Action => "Report" Action - -Every developer hand-off / gate moment — reframe agreement, plan gate, worktree intent, commit -approval, push approval, integration, cleanup/finalization, regular turn-end — is **notify-and-continue**: -surface an attention item, present the result, and **end your turn**; the developer responds and your -**next** turn picks up automatically. It is **three actions, never one**: - -1. **Dry-run action.** Run applicable MCP tools in `dry-run` for the hand-off. If dry run succeeds, - proceed with the notify-and-stop action. If dry run fails, try to ammend the issue first before reporting failure. -2. **Notify-and-stop action.** Call `lifecycle_turn_end_notification(summary=…)`. It sets the new - **`awaiting-developer`** lifecycle state, surfaces a dashboard attention item, and **returns - immediately — no wait, no inbox.** This is the **last tool call of the turn** — the report prose - still follows it; do not STOP here. The developer responds on the - dashboard or in the leaf's attached chat, and the **first AR tool call of your next turn** - automatically resumes the lifecycle (`running`) and clears the attention item — you send **no** - explicit resume. -3. **Report action.** Deliver the complete hand-off report as plain assistant output - (the reframe, the plan, the intent packet, or the closeout relay with - preview facts, quality results, proposed commit messages, and - attestations), and make the decision you are handing to the developer the last - line of prose. **The report is the last thing in the turn — then STOP / end your turn.** - -Use the `dry-run` step to verify that the planned tool call (for example the closeout apply) will -succeed before you hand off, and self-fix any failure before reporting it. - -`lifecycle_turn_end_notification` returns immediately and does **not** render a prompt over your prose, -so the report you deliver after it is exactly what the developer sees — call the -notification, then deliver the report as your final prose, then stop. Keep the report turn free of any mutating or permission-triggering operation so -nothing obscures the report. - -Junction → Dry-run → notify (`lifecycle_turn_end_notification`) → Report. Every junction below now hands -off through that one notification; the named `kind` is the **parked** durable-gate label the fallback -would use (see "Parked fallback" below), kept so the dashboard can still classify each hand-off: - -| Junction | Parked durable gate `kind` | Skill that hands off | -| -------------------------------- | -------------------------- | ---------------------------------------------------------- | -| plan gate | `plan-approval` | `l-01-session-job-lifecycle` | -| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | -| commit / closeout | `closeout-approval` | `c-12-closeout` | -| push | `push-approval` | `l-01-session-job-lifecycle` / `c-09-git-worktree-manager` | -| integration | `integration-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| cleanup / lifecycle finalization | `cleanup-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| any other dev-wait | `agent-question` | `l-01-session-job-lifecycle` | - -`closeout-approval` **is** the commit hand-off — there is no separate -`commit-approval`. Closeout is the single commit-of-record for code, memory, and -ledger, so every commit (including a singular one) routes through the closeout -hand-off. `agent-question` is the non-exhaustive catch-all so any dev-wait that is -not a structured junction is still observable. - -### Parked fallback — block-and-wait `lifecycle_gate` - -The block-and-wait `lifecycle_gate(kind=…)` junction (which creates a durable gate and waits for a -developer decision), the operator inbox, and the dashboard GateResponder **still exist and still work** -when explicitly raised — but they are **no longer the active path**, and nothing routes toward them: -`next_step.py` repoints every gate moment to `lifecycle_turn_end_notification`. Reach for the -server-enforced `lifecycle_gate` (followed by `lifecycle_resume` after the developer decides) only when -you deliberately need a durable, developer-attributed, mutation-blocking approval record; its `kind` -values are the table above. If you ever do raise it, it renders an approval prompt **over** your prose, -so the report must land in an earlier turn — which is exactly why notify-and-stop is preferred. - -## Lifecycle Signals — Making The Session Observable - -Every session in a managed repo is a **lifecycle**: the six `lifecycle_*` signals -record where it is and what it is waiting on, so the work is observable and -resumable across chat deaths (design `docs/design/observable-lifecycle.md`). The -model **never handles a lifecycle id** — identity is server-side, anchored in the -worktree contract. - -| When (phase) | Signal | Why | -| ---------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Trust Checkpoint passes (managed repo) | `lifecycle_start` | Begin a **fleeting** lifecycle (guarded: one per session; takes no id). | -| Entering each phase | `lifecycle_phase` | Move the orthogonal phase axis (`request`/`trust-checkpoint`/`reframe-research`/`decide`/`build`/`close`). | -| At a hand-off (reframe, plan, commit, …) | `lifecycle_turn_end_notification(summary=…)` (last tool call), then the report prose, then **STOP** | Set `awaiting-developer`, surface the dashboard attention item, and return immediately (no wait, no inbox); the next turn's first AR tool call auto-resumes (`running`) and clears the item. Block-and-wait `lifecycle_gate(kind=, ask=…, packet=…)` + `lifecycle_resume` is the parked fallback. | -| `worktree_start` (Decide → Build) | _(promotion — automatic)_ | The fleeting lifecycle becomes **persistent**, anchored in the contract; no separate signal. | -| Resuming an existing task | `worktree_attach` | Re-adopts the contract's lifecycle (contract-resolved); the model passes no id. | -| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | The save gate: promote it or abandon it — never dropped silently. | -| Close | `lifecycle_end` (`completed`\|`abandoned`) | The terminal record. | - -Rules: `lifecycle_start` is guarded (one active lifecycle, no id). `paused` is -**system-owned** — there is no pause signal. `awaiting-developer` is set by -`lifecycle_turn_end_notification` and auto-cleared back to `running` by the next -turn's first AR tool call — you never resume it by hand. A tool call outside any -lifecycle is **dropped, never misattributed**. `worktree_start` **promotes** the current -lifecycle (fleeting → persistent); `worktree_attach` **resumes** the contract's -lifecycle; both keep identity server-side. - -## 0 — Request - -Receive the developer's raw request and identify the active repository. - -1. Treat the developer's statement as raw input, not yet as an implementation plan. -2. Infer the target code repository from the request and local context. Ask the - developer if the target is unclear. - -Request intake changes nothing. It only establishes which repository the next -checkpoint must inspect. - -The upcoming `Trust Checkpoint` reveals whether or not the request is related to repositories managed by Agents Remember. If not, then the lifecycle exits early and the agent can work as usual. - -However, if later work is to enter the boundary of repositories being managed by Agents Remember, -the lifecycle must be re-entered. - ---- - -## 1 — Trust Checkpoint - -Establish whether memory and providers are trustworthy enough to use. - -1. For the target repository, resolve coordination/memory context with - the MCP tool call: - - ```text - context_packet(repo_id="", include_providers=true, include_drift=true, include_freshness=true) - ``` - -2. Report the packet facts before relying on memory or providers: - - repository, branch, and dirty state - - memory root and onboarding root - - provider state - - drift status and actionable drift count - - branch freshness: whether the code and memory checkouts are current with - their upstreams (`behind`/`diverged` means the local official line is - stale — fast-forward it before trusting analysis or basing work on it) - and whether the ledger maps code HEAD (`ledgerMapsCodeHead=false` means - the memory checkout does not match the code state; run carryover or - check out the right memory branch first) -3. If onboarding for committed source is drifted, missing verification, or - orphaned, and the corresponding source file is not dirty in the code - worktree, stop and ask the developer whether or not to refresh it through - `c-05-create-or-update-onboarding-files`. Drift handling is approval-gated! -4. If drift is tied to dirty source, report it as active work-in-progress. Do - not adopt it as maintenance or silently trust it as current state unless the - developer explicitly says this job owns it. -5. If providers are stopped or degraded, use the matching MCP provider/runtime - operations, then re-run the provider check. If providers are ready, report - readiness and continue. If issues persist, report it to the developer and - wait for instructions. If the packet's providers summary lists `indexing` - targets, report them to the developer: those providers are healthy but - busy, and their results may be partial until the scan completes. -6. After the trust checkpoint passes, read committed-state onboarding for the - in-scope anchors as needed. A file dirty in another chat is still valid for - HEAD and worth comparing, but its dirty-source drift remains active work. - ---- - -## 2 — Reframe And Research - -Turn the developer's raw request into an agreed piece of work, then perform the -deeper research that the agreed frame requires. The `tasks/AGENTS.md` -collaboration doctrine applies here in plain chat, before any task file or task -format exists. - -**Read tool for this phase.** Until the build-mode decision (Phase 3), read managed-repo source -through the `read_ar_files` MCP tool, not the harness's native read — it returns paired -source+onboarding plus the repository/route overviews in one observable, lifecycle-attributed -call, and you keep a running count of those calls as evidence. Native read is the edit -precondition in Phase 4. - -1. **Gather evidence for the reframe** through reading the - `c-04-retrieval-strategy-router` skill. Pick the strategy by the question: - - _Semantics_ (grepai over onboarding) — "where does X live / what handles Y." - - _Relationship_ (cgc) — callers/callees/dependencies/impact. - - _Intent_ (onboarding + bounded source confirmation) — hidden contracts, invariants, - branch-valid truths, behavioral expectations. This is a workflow of paired - source+onboarding reads via the `read_ar_files` MCP tool: one call pairs each source - file with its verified onboarding and auto-attaches the repository overview + governing - route-overview chain (the bird's-eye view). -2. **Reframe** the request through `tasks/AGENTS.md`: distinguish the surface - request, deeper objective, highest-leverage framing, assumptions, boundaries, - invariants, and truth gaps. Do not rush a statement into a plan. -3. Present the reframe to the developer. If the developer disagrees, discuss and - revise the reframe. If the developer agrees, proceed to deeper research. -4. **Perform deeper research** for the agreed frame. This research still uses - `c-04-retrieval-strategy-router`, but it is now scoped by the developer-agreed - frame rather than by the model's first guess. Use - `deep-research-report-template.md` for the report shape; the lifecycle owns - the required proof categories, while the template owns evidence formatting. -5. The deeper research report must list its proof and tie evidence to the claim it supports: - - `read_ar_files` calls (paired source+onboarding reads — the running count) - - onboarding docs read - - semantic queries performed - - code graph queries performed - - source files inspected - - remaining truth gaps -6. Run the **job opening move** for the job lens (see `job-variants.md`) and use - the deeper research to name the truth gaps that remain. -7. Continue until the developer agrees the design is defined well enough to write - down, then produce the **plan**: the steps, and a **code example for every - distinct change** you intend to make. - -**Plan gate:** **hand off** before changing any code. No implementation begins -before the developer approves. Call -`lifecycle_turn_end_notification(summary={…the plan + the developer-facing approval ask…})` as the -**last tool call**, then present the plan as your final prose and **STOP**; -the developer approves on the dashboard or in chat and your next turn auto-resumes to begin -implementation. (Parked fallback: the server-enforced -`lifecycle_gate(kind="plan-approval", ask=…, packet=…)` + `lifecycle_resume` still exist if you -deliberately need a mutation-blocking approval record.) - ---- - -## 3 — Decide (build mode) - -One decision: does this job change code? - -- **No -> research-only exit.** Deliver the answer/assessment. No worktree, no task artifact, no closeout. - A research-only job may recommend or spawn a follow-up build job; it does not perform one itself. -- **Yes -> worktree intent hand-off, then always a worktree.** Read `c-09-git-worktree-manager` - and `system/git-workflow.md`, call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the worktree - intent packet as your final prose and **STOP**. The developer approves and your next turn - auto-resumes to `worktree_start`. Then open it with - `c-09-git-worktree-manager` and pick the build mode: - - **Chat build** — small enough to carry inline this session: worktree-backed, **no** `task.md`. - - **Durable task build** — hand off to `w-02-light-task-workflow`: `task.md`, checklist, decision - log, proposed code examples. Escalate to a master + light sub-task series when the work outgrows a - single-page plan. - -The worktree intent packet names the target repo, build mode, discovered branch policy, proposed -`source_branch`, proposed work branch/worktree name, memory mode, landing path, and material risks. -On PR-gated repos, the packet must prove that the recorded `source_branch` is pushable and that -protected targets are reached later through the repo's PR flow. - -Worktree granularity = the leaf task unit. A single task gets its own leaf enclosure/worktree. A -master multi-task owns a root `series-contract.md` and integration branch, while each active leaf -sub-task gets its own `enclosures//series-contract.md`, branch, and worktree. A chat build -gets its own leaf worktree without a task artifact. The git-landing decision (direct vs PR-gated) is -deferred to the repo's `system/git-workflow.md` — read it before landing on a gated branch. - ---- - -## 4 — Build - -Implement inside the worktree, keeping memory and tests in lockstep with the code. - -1. Apply the approved code changes. -2. **Refresh the matching onboarding in the same editing pass**, per completed plan-section — never - deferred to the end of the job. When a change affects durable current-state knowledge, the sidecar - is updated alongside it through `c-05-create-or-update-onboarding-files`. - - For **changed** (already-onboarded) source files, update the sidecar **body** now: the closeout - gate rejects a changed source file whose existing sidecar was not modified this job, because - refreshing `lastVerifiedCommitHash` over stale content silently defeats the drift check. - - For **new** source files, run `check_missing_onboarding` before the commit and create the - reported missing sidecars through the `c-05-create-or-update-onboarding-files` skill; the post-code-commit memory refresh stamps them with - the real code commit hash and date. -3. Run the checks from the `c-08-ar-coordination-context-resolver` resolved `system/tools.md` (lint, typecheck, complexity, tests) and - get them **green before each incremental commit**. Testing is never deferred to a final task; the - pre-commit/pre-push hooks enforce it. -4. **Watch the official line and sync early.** `worktree_status`'s `freshness` block reports when the - recorded base pair fell behind the local source branch tips (a parallel cycle landed). Pull the - moved official line in with `worktree_sync` — preferably **before memories are written**: with - parked memory the sync is a pure fast-forward, the other cycle's sidecars and ledger rows end up - beneath this task's future work, and end-of-series integration stays `ff-only` with no carryover - reconciliation. - -Incremental, pushable commits keep the work-loss window small. Each closeout below is one such commit. - ---- - -## 5 — Close - -Land the work. **Implementation approval is not commit approval.** - -1. Run the `c-09-git-worktree-manager` closeout **preview** for the worktree (`worktree_closeout_preview`). - Every build closes through its worktree — there is no direct-checkout closeout. - Relay the proposed code, memory, and ledger commit messages. -2. **Commit gate:** run the closeout **preview** (dry-run), then **hand off** before any real commit or closeout - apply. If required onboarding is missing, run the `c-05-create-or-update-onboarding-files` skill for the affected file and re-run the preview. - Call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the - **last tool call**, then deliver the preview facts as your final prose and **STOP**; - the developer approves on the dashboard or in chat and your next turn auto-resumes to - `worktree_closeout_apply`. The `c-12-closeout` skill owns this hand-off. Parked fallback: when you - deliberately raise the durable `closeout-approval` `lifecycle_gate`, it is enforced **server-side** — - `worktree_closeout_apply` refuses unless it is approved by the developer, and an agent self-approval - never satisfies it. -3. On approval, the `c-09-git-worktree-manager` skill owns the external-memory invariant in order: commit code → refresh affected - onboarding metadata to the new code commit → run memory quality control → commit memory content → - update and commit the ledger. -4. **Integrate + land** per `c-09-git-worktree-manager` and `system/git-workflow.md`: integrate the - worktree branch into the approved source/integration branch, then on a PR-gated repo push that - source branch, open the PR, wait for green checks, and merge per the repo convention. Never push a - protected branch directly. The agent does not push on its own authority — call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the push intent - as your final prose, and **STOP**; push only after the developer - approves and your next turn auto-resumes. The `c-09-git-worktree-manager` skill makes the matching - integration and cleanup/finalization hand-offs at its landing tail (parked durable kinds - `integration-approval` / `cleanup-approval`). -5. **Map the ledger to the landed commit.** A PR merge usually lands a **merge commit** on top of the - work — tree-identical to the verified tip but a new SHA the ledger does not yet map. Ensure the - ledger maps that merge commit so the next worktree can base off the merged branch without a manual - reconciliation. `system/git-workflow.md` owns this step. -6. **Finalize the lifecycle:** run `lifecycle_finalize_task(..., dry_run=true)` once the local parent - branch contains the landed commit and memory carryover is done. Call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then relay its landed-commit - proof, cleanup plan, and task-document updates as your final prose, and - **STOP**. The developer approves cleanup/finalization and your next turn auto-resumes to run the real - finalizer. The tool proves one parent-child branch edge, - reclaims the worktrees, and marks the leaf task plus immediate parent row `Completed` when those - task-doc paths are supplied. It does not recursively complete ancestors; repeat the edge at the next - parent level when that parent task lands. -7. **Keep squash out of the normal path.** A PR-gated edge is structurally the same as a direct edge - after the model finishes the PR merge and pulls the target branch locally. Do not use squash-merge - equivalence as a default finalization proof; squash is an emergency/manual recovery path because it - erases commit lineage and can make memory lookup history wrong. - -A research-only exit skips this phase entirely. - -## Relationship To Other Instructions - -This skill extends the coordinator `AGENTS.md` and the repository memory layer; it does not replace -them. Read `job-variants.md` for the per-job lenses, and `deep-research-report-template.md` for the -deeper research report shape. diff --git a/.claude/skills/w-02-light-task-workflow/SKILL.md b/.claude/skills/w-02-light-task-workflow/SKILL.md index 248e6f3c..b34f3017 100644 --- a/.claude/skills/w-02-light-task-workflow/SKILL.md +++ b/.claude/skills/w-02-light-task-workflow/SKILL.md @@ -40,7 +40,7 @@ Light-task artifacts use minute-precision timestamps in `YYYY-MM-DDTHH:MM` forma The task document is **JSON-primary**: an `ar-task-document/v1` JSON file is the source of truth, and the `task.md` (or `.md` for a sub-task) is a deterministic **render** of it. Author and update it with the `task_doc` MCP tool — `create`, `set_status`, `set_step`, `append_decision`, `set_field` — which writes the JSON and re-renders the markdown on every write. Do not hand-edit a tool-managed `task.md`; edit through the tool and let it re-render. `template.md` and `master-template.md` document the **render spec** (the shape the renderer produces), not a separate hand-authored format. When a planning slice defers its code examples to the plan gate, record that with `codeExamplesNote` (a `set_field` value, e.g. "Drafted at the plan gate.") so the rendered "Proposed Code Examples" section reads as *deferred* rather than as if none are needed. A leaf doc may also carry a descriptive `statusNote` (a suffix beside the strict status enum), `headerNotes` (extra `**Key:** value` header lines such as Verified/Source), and freeform `sections` appended after References — the escape hatch for bespoke prose (e.g. a Status history) while the standard template sections stay the backbone. Pass `dry_run=true` to any op to **preview** — it builds + validates and returns the rendered markdown, a unified `diff` vs the on-disk `.md`, and a `wouldLose` flag, **without writing**; use it before adopting a hand-authored `.md` into JSON-primary (author the JSON → dry-run → confirm `wouldLose` is false → then write). -Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for a chat build (a thin doc: title plus a few steps, so even a no-`task.md` session is legible) and a *full* one for a durable task; the difference is content completeness, not a separate format. +Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for the smallest single-session build (a THIN doc: title plus a few steps — chat is never a build route, so even micro-work gets this thin doc and stays legible on the dashboard) and a *full* one for a durable task; the difference is content completeness, not a separate format. Scope and transition: the tool manages **`light` and `subTask`** documents, and the format also covers a series **master** (`kind:"master"`: a structured `subTasks` index + ordered `sections` that preserve a master's bespoke prose, so a re-render is lossless). Masters and existing markdown task files stay hand-authored markdown until the runtime ships `task_doc` and they are intentionally migrated — new tasks adopt the JSON-primary format going forward. diff --git a/.claude/skills/w-02-light-task-workflow/master-template.md b/.claude/skills/w-02-light-task-workflow/master-template.md index 7cb4e85a..42738c16 100644 --- a/.claude/skills/w-02-light-task-workflow/master-template.md +++ b/.claude/skills/w-02-light-task-workflow/master-template.md @@ -7,7 +7,7 @@ built to grow as the work unfolds. ## When to escalate to a series -The `l-01-session-job-lifecycle` skill's `decide` build-mode step escalates a single task to a series once its size is apparent — the +The `l-01-agent-lifecycles` orchestrator lifecycle's `decide` step escalates a single task to a series once its size is apparent — the implementation plan no longer fits on a single page, or the work splits into distinct slices that each deserve their own checklist and commit. You can also start single and escalate later: drop in the master `task.md` and move the existing plan into the first `NN_.md`. diff --git a/.codex/hooks/agents-remember-session-start.md b/.codex/hooks/agents-remember-session-start.md index 427c30f3..cd999a73 100644 --- a/.codex/hooks/agents-remember-session-start.md +++ b/.codex/hooks/agents-remember-session-start.md @@ -1,14 +1,12 @@ -MANDATORY FIRST ACTION for this workspace +**Agents Remember — session start.** -You are not allowed to read, write, or execute code on any repository -until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure! +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** -Until the build/job decision is made, read managed-repo source with the -`read_ar_files` MCP tool — not the harness's native read tool. One call returns -each file paired with its onboarding plus the repository and governing route -overviews. Native read is reserved as the edit precondition once building begins. - -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent), and -keep a running count of your `read_ar_files` calls. Include the onboarding files -inspected and every CGC, GrepAI, and `read_ar_files` call made as evidence. +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`ar-coordination/AGENTS.md`, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. diff --git a/.codex/skills/c-01-findings-capture/SKILL.md b/.codex/skills/c-01-findings-capture/SKILL.md index e145d7ee..d413e8fe 100644 --- a/.codex/skills/c-01-findings-capture/SKILL.md +++ b/.codex/skills/c-01-findings-capture/SKILL.md @@ -13,7 +13,7 @@ Companion file: ## Operating Modes -1. Inside a task workflow (an `l-01-session-job-lifecycle` build job or a `w-02-light-task-workflow` task, including a master + light sub-task series). +1. Inside a task workflow (an `l-01-agent-lifecycles` orchestrator build phase or a `w-02-light-task-workflow` task, including a master + light sub-task series). 2. Standalone during direct clarification. ## Durable Destinations diff --git a/.codex/skills/c-03-repo-bootstrap/SKILL.md b/.codex/skills/c-03-repo-bootstrap/SKILL.md index 40148918..44f14f78 100644 --- a/.codex/skills/c-03-repo-bootstrap/SKILL.md +++ b/.codex/skills/c-03-repo-bootstrap/SKILL.md @@ -1240,7 +1240,7 @@ The orchestrator remains thin throughout. | `c-05-create-or-update-onboarding-files` | Owns final file-level onboarding semantics and routes structural slice maintenance back to the `c-03-repo-bootstrap` skill. The `c-03-repo-bootstrap` skill creates cards/waves and delegates file output rules to the `c-05-create-or-update-onboarding-files` skill. | | `c-04-retrieval-strategy-router` | Consumes bootstrapped overviews and file maps as the Intent substrate and can route to semantic/relationship providers first. | | `c-02-memory-quality-control` | Becomes relevant after bootstrap; touched files can be promoted from deferred to covered. | -| `l-01-session-job-lifecycle` | May trigger targeted bootstrap when an active job enters an uncovered area. | +| `l-01-agent-lifecycles` | May trigger targeted bootstrap when an active job enters an uncovered area. | | `confluence-search` / documentation search skills | Feed the docs evidence pass through approved sources from the input ledger. | --- diff --git a/.codex/skills/c-04-retrieval-strategy-router/SKILL.md b/.codex/skills/c-04-retrieval-strategy-router/SKILL.md index 01434c77..e226f8c0 100644 --- a/.codex/skills/c-04-retrieval-strategy-router/SKILL.md +++ b/.codex/skills/c-04-retrieval-strategy-router/SKILL.md @@ -160,7 +160,7 @@ names an unresolved source question. ### Rules: -- During the research phase (the lifecycle up to the build/job decision), read managed-repo +- During the research phase (the lifecycle up to the build decision), read managed-repo source with `read_ar_files`, not the native read tool — one call returns each file paired with its onboarding plus the repository and governing route overviews (the recipe above, batched and observable). diff --git a/.codex/skills/c-09-git-worktree-manager/SKILL.md b/.codex/skills/c-09-git-worktree-manager/SKILL.md index e19c7902..692dec19 100644 --- a/.codex/skills/c-09-git-worktree-manager/SKILL.md +++ b/.codex/skills/c-09-git-worktree-manager/SKILL.md @@ -7,7 +7,7 @@ description: "Create, attach to, report on, integrate, finalize, and clean up Ag Use this skill when a task should run through an explicit code/memory worktree wrapper. -The `c-09-git-worktree-manager` skill wraps the existing chat-build, light-task, or external workflow. It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. +The `c-09-git-worktree-manager` skill wraps the existing light-task or external workflow (a build that fits one session still rides a THIN `w-02-light-task-workflow` doc — chat is never a build route, per the `l-01-agent-lifecycles` invariant). It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. For closeout, use the `c-12-closeout` skill. The `c-09-git-worktree-manager` skill only supplies the worktree-specific contract path and integration/finalization follow-up rules. @@ -67,7 +67,7 @@ The intended order is: 1. run the `c-08-ar-coordination-context-resolver` skill for the target repository 2. run the `c-02-memory-quality-control` skill's task-start drift check and follow the existing AGENTS Gate 3/4 choice point 3. when onboarding is refreshed, commit the memory content and ledger before starting any worktree -4. decide whether the work is a chat build, a `w-02-light-task-workflow` light task (or master + light sub-task series), or external workflow +4. decide whether the work is a `w-02-light-task-workflow` light task — possibly a THIN one for single-session work; chat never builds — a master + light sub-task series, or external workflow 5. read the repository's `system/git-workflow.md` and identify the parent branch edge. For a standalone task, the leaf worktree branches from the approved source branch. For a master series, the master owns a root `series-contract.md` @@ -198,7 +198,9 @@ moved since task start. ## Integration -Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. +Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. Orchestrated-run carve-out (ruled 2026-07-06): dependency-ordered leaf→master and master→super integrations ride the series' standing approval (the developer's portfolio-gate approval recorded in the planner master) — the developer hand-off concentrates at the super PR/carry-over gate per the `l-01-agent-lifecycles` loop/orchestrator doctrine; a raised durable `integration-approval` gate still awaits the developer. + +On an orchestrated master's exit (master → super integration) the integrate step additionally enforces the delegated `master-handover-approval` seam: an undecided or policy-invalid handover gate addressed to the master (by `enclosure` = master task name) returns `handover-gate-blocked` instead of landing — decide the gate per the `l-01-agent-lifecycles` seam doctrine, then rerun. When no gate addresses the integrating master but open `master-handover-approval` gates exist elsewhere, integrate still proceeds and its result carries a `handover_gate_warning` naming them — treat it as a spelling check on the raised gate's `enclosure`. Run `worktree_integrate(..., dry_run=true)` first, then **hand off**: call `lifecycle_turn_end_notification(summary={…the integration plan…})` as the **last tool call**, then diff --git a/.codex/skills/c-12-closeout/SKILL.md b/.codex/skills/c-12-closeout/SKILL.md index f83071d9..2c7fe3ff 100644 --- a/.codex/skills/c-12-closeout/SKILL.md +++ b/.codex/skills/c-12-closeout/SKILL.md @@ -40,7 +40,7 @@ records the developer's explicit commit approval. Agents must not treat implementation approval, a previous "looks good", or their own judgment as commit approval. -The relay follows the `l-01-session-job-lifecycle` skill hand-off protocol: run the +The relay follows the `l-01-agent-lifecycles` orchestrator hand-off protocol: run the preview/dry-run first, then call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the **last tool call**, then deliver the preview facts and proposed messages as plain diff --git a/.codex/skills/c-13-install-and-onboard/SKILL.md b/.codex/skills/c-13-install-and-onboard/SKILL.md index 6515ae46..d583fd13 100644 --- a/.codex/skills/c-13-install-and-onboard/SKILL.md +++ b/.codex/skills/c-13-install-and-onboard/SKILL.md @@ -52,10 +52,12 @@ Run this sequence in order: 0. Preflight: verify the copied package and MCP setup are usable enough to continue. 1. Runtime scaffold: run or verify `runtime_install()`. -2. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. -3. Bootstrap: when a new memory repo was scaffolded, hand off to +2. Agentic settings: walk the developer through the orchestration defaults in + the seeded global settings file. +3. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. +4. Bootstrap: when a new memory repo was scaffolded, hand off to `c-03-repo-bootstrap`. -4. Providers: when providers are enabled, start/refresh indexing and verify +5. Providers: when providers are enabled, start/refresh indexing and verify readiness. This skill orchestrates and delegates. It does not reimplement @@ -79,7 +81,9 @@ Check, in order: 3. **Settings sane.** Confirm `server_info` reports the expected `coordinationRoot`, `workspaceRoot`, allowed repositories, and providers. Surface the resolved absolute paths because wrong paths are the common cause - of resolver failures. + of resolver failures. Also report whether the global agentic settings file + (`/system/settings.json`) exists yet; Stage 1 seeds it + when missing and Stage 2 configures it. 4. **Runtime state.** Check whether the coordinator scaffold already exists under `coordinationRoot` (`AGENTS.md`, `skills/`, `tasks/`, `memory-repos/`, `system/` as applicable). If it is missing or stale, Stage 1 will run @@ -118,7 +122,61 @@ Do not run `skills_install()` as part of first-run setup. The harness starter package already carries the skills. `skills_install()` remains available for manual maintenance or non-package setups, but it is not the default path. -## Stage 2 - Memory Repo: Ask Scaffold Vs Existing +## Stage 2 - Agentic Settings: Interview The Developer + +`runtime_install()` seeds the GLOBAL agentic settings file at +`/system/settings.json` copy-if-missing, with every knob at +its documented default: all-human gate delegation, the standard three-party-loop +defaults, no concurrency caps, no spawn harness preference. This stage turns +those defaults into the developer's actual posture so the intended workflows +run on ANY harness. The schema reference is `docs/reference/settings-json.md` +(Agentic Settings); unknown `orchestration.*` keys fail loud, so write only +documented keys. + +Walk the developer through the four knob families and edit the global file with +their answers (leave a family at its seeded default when they have no +preference): + +1. **Gate delegation posture** (`orchestration.gateDelegation`; GLOBAL file only - the + loader refuses it repo-locally and the boot snapshot reads the coordinator file) - keep every + gate human (`all-human`, the default), or delegate leaf gates with the + `manager-decides-leaf-gates` policy, optional per-kind `kinds` overrides, + and `requireReviewerVerdictAtSeams`. Say explicitly that this one key is + boot-snapshot: a change needs an MCP/harness restart. +2. **Loop defaults** (`orchestration.loops`) - the review-round cap + (`defaults.maxRounds`), reviewer reuse (`defaults.reviewerReuse`), + complexity thresholds (`defaults.complexity`), and per-level loop postures + (`perLevel`). Read per-use; edits apply on the next use, no restart. +3. **Concurrency caps** (`orchestration.concurrency`) - `maxParallelMasters`, + `maxParallelLeaves`, `maxSubAgents`. Default: uncapped. +4. **Harness preference + role knobs** (`orchestration.spawn.harness`, + per-role `orchestration.roles.`, per-level + `orchestration.rolesPerLevel..`) - which installed harness + `spawn_agent_session` uses when the spawning seat passes none, per-role + harness/model/effort overrides, and per-LEVEL overrides + (leaf|master|portfolio) for tiered economics (e.g. a cheap leaf reviewer, + a smarter master-seam reviewer). Harness values must be known ids: the + builtin registry (`claude`, `codex`, `pi`) or an `orchestration.harnesses` + entry the developer defines (new TUIs, or a pre-customized launch argv for + a builtin). `effort` is validated per-harness at dispatch (claude: + `low|medium|high|xhigh|max` on the `--effort` flag plus the session-level + `ultracode`); mention the FREE-FORM escape hatch for anything outside the + vocabularies - `launchArgs` (verbatim argv), `sessionCommands` (pasted + before the brief), `promptKeywords` (prepended to the brief) - never + validated, recorded in spawn provenance. Default: detection-gated (the + first detected harness). The full spawn-surface manual is + `docs/reference/harnesses.md`. + +If the developer wants to skip the interview, confirm the seeded defaults +apply and continue; tell them the file can be edited any time (picked up +per-use, except the gateDelegation restart note above). + +Per-repo overrides: a code repo may carry its own `/system/settings.json` +with the same `orchestration.*` shape; repo-local leaf values override the +global file (arrays replace). Offer this only when the developer asks for +repo-specific behavior; do not create the file unprompted. + +## Stage 3 - Memory Repo: Ask Scaffold Vs Existing Do not assume the developer wants a fresh memory repo. Ask which case applies, unless a memory repo is already present and resolvable: @@ -126,10 +184,10 @@ unless a memory repo is already present and resolvable: 1. **Scaffold a new memory repo** - they have no existing memory for this code repo. Run `c-00-initialize-memory-repo` (internal by default; external only if the developer asks or the configured topology requires it). Continue to Stage - 3. + 4. 2. **Use an existing memory repo** - they already have one. Clone or checkout it to the resolved memory location, then adopt it as the ledgered baseline with - `c-10-adopt-memory-baseline`. Skip Stage 3 because its onboarding already + `c-10-adopt-memory-baseline`. Skip Stage 4 because its onboarding already exists. Internal-memory note: pre-existing internal memory lives inside the code repo @@ -137,9 +195,9 @@ Internal-memory note: pre-existing internal memory lives inside the code repo `c-08-ar-coordination-context-resolver` and skip the question when the memory layer is already there. -## Stage 3 - Bootstrap +## Stage 4 - Bootstrap -Run this stage only when Stage 2 scaffolded a new memory repo. +Run this stage only when Stage 3 scaffolded a new memory repo. Hand off to `c-03-repo-bootstrap` to generate initial onboarding. A thin `overview.md` is enough to start; deeper route-local overviews and file-level @@ -147,7 +205,7 @@ onboarding should grow as work touches new areas. Skip this stage when an existing memory repo was adopted. -## Stage 4 - Configure Providers To Index +## Stage 5 - Configure Providers To Index If providers are enabled, make them index the configured code and memory: @@ -177,10 +235,12 @@ Summarize: step the developer must perform; 2. runtime scaffold: `runtime_install()` run or already current, with the resolved coordination root; -3. memory repo: scaffolded, existing-adopted, or already present, with the +3. agentic settings: interviewed and written, or left at the seeded defaults, + with the global file path; +4. memory repo: scaffolded, existing-adopted, or already present, with the resolved memory root; -4. bootstrap: run via `c-03-repo-bootstrap` or skipped; -5. providers: indexing status and any deferred/degraded state. +5. bootstrap: run via `c-03-repo-bootstrap` or skipped; +6. providers: indexing status and any deferred/degraded state. End by telling the developer whether the project is ready for normal work. Do not tell them to restart for hooks installed by this skill, because this skill no diff --git a/.codex/skills/l-01-agent-lifecycles/SKILL.md b/.codex/skills/l-01-agent-lifecycles/SKILL.md new file mode 100644 index 00000000..1d390618 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/SKILL.md @@ -0,0 +1,259 @@ +--- +name: l-01-agent-lifecycles +description: "The agent lifecycles: one lifecycle per agent type, under one roof. Routes every session by exactly three conditions (spawn-role env -> role brief -> otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator, designer, strategist, manager, worker, adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. A developer-facing session IS the orchestrator; solo work is the degenerate portfolio. Supersedes and replaces both l-01-session-job-lifecycle and l-02-agent-orchestration." +--- + +# l-01-agent-lifecycles — The Agent Lifecycles + +Lifecycle and job are **one entity**: each agent type runs its own, self-contained lifecycle. This +skill is the single roof over all of them — a thin router, the minimal frame every session shares, +and the role lifecycles as the payload files. No role is defined by reference to another role's +lifecycle, and no role reads another role's file. + +## Which Lifecycle Am I? (the router — exactly three conditions, in order) + +1. **`AR_SPAWN_ROLE` is set** (spawn env, injected by `spawn_agent_session`) → run + `roles/.md`. Nothing else in this file's "developer session" material applies to you. + (`designer` here means the same design hat in a separate chair — see `roles/designer.md`.) +2. **Else: the first user message is a role brief** — a `templates/*-brief.md`-shaped dispatch or + a first line of the form `ROLE BRIEF — ` from an orchestrating agent → run that role's + lifecycle. The brief is your session start; a workspace session-start notice is not addressed + to you. +3. **Else** (a developer opened this session) → you are the **orchestrator**: run + `roles/orchestrator.md`. Solo work is the degenerate portfolio — the same three jobs with hats + collapsed (the orchestrator wears the manager hat in flat runs and builds hands-on at session + scale); the task doc still comes first. + +There is no fourth entry, and the edge cases are decided: an **unresolvable `AR_SPAWN_ROLE` +value** (no matching `roles/.md`) falls through to condition 2 (the brief); a role-env +session **whose brief never arrives** announces itself on the inbox and waits — it never +improvises a task; `AR_SPAWN_ROLE=orchestrator` is valid only as a takeover chair (the Profile +check (takeover) in `roles/orchestrator.md`, The Event Loop) — the developer still talks to **one** orchestrator. Orchestrated +fan-out (spawning managers/workers at scale) begins only on an explicit developer request (e.g. +*"orchestrate these masters"*) — no agent promotes itself into a spawning seat. + +One exception to the no-cross-reading rule above: **a seat that WEARS a hat runs that hat's file +as its own** — the orchestrator always for `roles/designer.md`, and in flat runs for +`roles/manager.md` (the hat-collapse rule). + +## The Role Registry + +| Role | Seat | Lifecycle file | +| --- | --- | --- | +| **orchestrator** | the developer-facing session; first coordination leaf of an orchestrated series | `roles/orchestrator.md` | +| **designer** | a HAT the orchestrator pulls inline (front of the pipeline or mid-flight; separate chair optional) | `roles/designer.md` | +| **strategist** | the sprint planner, SPAWN-FIRST; a strategist run is a **mandatory precondition for any orchestrated run** — its deliverable is the orchestration task (sprint plan + scope); spawn value `strategist` | `roles/strategist.md` | +| **manager** | one coordination leaf per master; drives that master's leaf loop | `roles/manager.md` | +| **worker** | one leaf worktree, short-lived, fresh session | `roles/worker.md` | +| **adversarial reviewer** | short-lived, spawned at the two seams (master-exit, super-exit) and as any three-party loop's reviewer seat (criteria catalogs bound per review type); spawn value `reviewer` | `roles/reviewer.md` | + +The **lenses** (bug · feature · triage · research — `lenses.md`) are how the scoping seats +(orchestrator, designer) read a piece of work; a dispatched role never picks a lens — its brief +already carries the flavor. + +## The Minimal Frame (the only machinery every session shares) + +Every session in a managed repo may be a **lifecycle**: six signals — `lifecycle_start` · +`lifecycle_phase` · `lifecycle_turn_end_notification` · `worktree_attach` · `switch_lifecycle` · +`lifecycle_end` (plus the automatic `worktree_start` promotion) — record where it +is and what it waits on, so work is observable and resumable across chat deaths. The model **never +handles a lifecycle id** — identity is server-side, anchored in the worktree contract. + +| When | Signal | Effect | +| --- | --- | --- | +| Trust checkpoint passes (managed repo) | `lifecycle_start` | begin a **fleeting** lifecycle (guarded: one per session; no id) | +| Entering a phase | `lifecycle_phase` | move the phase axis (`request` / `trust-checkpoint` / `reframe-research` / `decide` / `build` / `close`) | +| A developer hand-off | `lifecycle_turn_end_notification(summary=…)` | set `awaiting-developer`, surface the attention item, return immediately; the **next turn's first AR call auto-resumes** — never resume by hand | +| `worktree_start` | *(automatic promotion)* | the fleeting lifecycle becomes **persistent**, anchored in the contract | +| Resuming an existing task | `worktree_attach` | re-adopts the contract's lifecycle (contract-resolved) | +| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | the save gate — never dropped silently | +| Close | `lifecycle_end` (`completed`\|`abandoned`) | the terminal record | + +Rules: a tool call outside any lifecycle is **dropped, never misattributed**; `paused` is +system-owned. **A spawned role that never touches mutating AR tools simply never instantiates a +lifecycle — that is correct, not a violation.** A spawned role runs its **own** lifecycle when it +runs one; it never adopts its spawner's. The session↔leaf association is the catalog binding made +at spawn (the **qualified** leaf key `//`), not lifecycle adoption. + +## Shared Invariants (every role can count on these) + +- **Continuity lives in the `task_doc` + durable artifacts, never in transcripts** — which is why + short-lived workers and reviewers are safe, and why every seat writes its artifact of record. +- **Escalation ladder: worker → manager → orchestrator → developer.** No rung is skipped, ever. + Each role file states only its own rung. +- **Observability:** coordination seats are `task_doc` leaves with attached chats; the developer + can walk into any seat at any level. +- **Decision-needing questions land in the task doc's `openQuestions`** — the rendered decision + surface; `notes/` carries the analysis behind them. + +## The Three-Party Loop (one home — this section owns the loop doctrine) + +**OWNER → BUILDER → REVIEWER → owner, at every level that owns work.** The owner never +self-approves; the builder never lands; the reviewer never decides — verdicts are evidence. The +owner checks the verdict and either redispatches a builder or escalates. Role files reference this +section; they do not restate it. + +| Level | Owner (holds the deliverable, rules, lands) | Builder | Reviewer | +| --- | --- | --- | --- | +| Leaf | the leaf's owning seat (manager; orchestrator in tight/flat mode) | spawned worker (no-commit contract) | spawned reviewer, criteria catalog + liberty | +| Master | the manager | the leaf workers | the master-exit seam reviewer (verdict rides `master-handover-approval`) | +| Portfolio | the orchestrator | the STRATEGIST (spawn-first) | reviewer with the plan-review catalog | + +**Complexity-scored tiers (per leaf, at dispatch).** The owning seat scores three axes — blast +radius (doctrine/enforcement/public surface vs leaf-local) · novelty (new subsystem vs +pattern-following) · size (files × steps) — into three tiers: **direct** (no loop +machinery — the level's ordinary build channel implements: hands-on at session scale, the leaf's +worker under a manager; self-check + checks ladder only), **builder-verified** (builder +implements; owner verifies report-vs-artifact; no reviewer), **full loop** (builder + independent +reviewer rounds). The +strategist's blast-radius register is the scoring input when an orchestration task exists. A +leaf's loop mark (tier + scope: manager | orchestrator — the owning level runs the loop with ITS +agent set) is recorded on the leaf doc with a decision-log entry. **A master whose leaves all +score `direct` is a workflow-free manager** — no loop machinery; the knobs make every loop +optional per level, never mandatory ceremony. + +**Rounds and the HARD cap.** A round = implement → review. **Hard cap: 3 rounds per loop — and +ONLY full end-to-end rounds count against it.** Residuals of a passing round are landed and +**delta-verified by the SAME reviewer via a follow-up message** (it retains everything it already +verified, at a fraction of a fresh round's cost); **fix rounds resume the SAME builder**. A fresh +reviewer is spawned only for a full round or when new scope opens. Delta-verifies close rounds; +they do not open them. + +**The convergence rule (the real control; the cap is the backstop).** Every round must SHRINK the +open finding set. A round that does not shrink it escalates immediately, regardless of the count; +a monotonically converging loop may never hit the cap at all. At the cap, or on non-convergence, +the owner does not spin another round — it **escalates one seat up the ladder (worker → manager → +orchestrator → developer) with the full round history attached**; the escalation packet IS the +upper seat's visibility. + +**Quo-vadis (the written developer-escalation criterion).** A question is developer-worthy when it +is a **high-blast-radius truth** — answered wrong it means big rewrites later (architecture +direction, security posture, doctrine contradictions, irreversible data/branch operations, where +agent settings live). Quo-vadis questions escalate IMMEDIATELY, regardless of round count. +Presentation-grade choices (2px vs 3px) never do — the owner rules and logs. + +**Criteria catalogs (the reviewer as test bench).** Criteria are never made up on the spot: every +review runs its type's standing catalog from `criteria/` (code-seam · doctrine · +onboarding-memory · report-verification · plan-review) plus an exploratory mandate, under the +promotion ratchet (each catalog carries it). `roles/reviewer.md` binds them. + +**Per-level agent sets.** Each level runs its loop with its own harness/model/effort set — the +orchestrator-level set (the strongest models) and the manager-level set (cheaper, possibly +workflow-free) are configured per level in the `orchestration.loops` settings block (schema in +`docs/reference/settings-json.md`; stored in the global agentic settings file with repo-local +override, parsed by the kernel agentic-settings loader — L13, landed). The strategist's mandatory +pre-run is doctrine, not a knob — it is unconditional. + +## Knob Block & Capability Doctrine (no per-harness files) + +Role files are **model-interpreted markdown, never an executor**. Each carries a portable **knob +block** (harness / model / effort / tools) — the defaults the terminal host injects at spawn. +Resolution: **role-file defaults < settings.json orchestration block.** There are deliberately +**no per-harness role files** (developer decision 2026-07-05): harness-specific ABILITIES — +sub-agent fan-out and the like — are covered inside the portable files as capability-conditional +doctrine any coding agent can apply, and harness PREFERENCE is deployment configuration +(settings), not doctrine. Hard-coding a vendor would fork the doctrine per harness. For spawning +seats, `spawn_agent_session` is itself the harness-independent fan-out: a harness with no +sub-agent facility still dispatches seats through the framework (a chat, no leaf attachment +required) — the DBMS principle: one behavior, any engine. + +## settings.json Orchestration Block + +Machine/user overrides layer over the role-file defaults, in the **global agentic settings file** +(`/system/settings.json`), with `/system/settings.json` as the +repo-local override layer (leaf-key deep merge, arrays replace, unknown `orchestration.*` keys +fail loud — schema in `docs/reference/settings-json.md`, Agentic Settings). Precedence: role-file +defaults < global settings < repo-local settings. + +```jsonc +{ + "orchestration": { + "roles": { // role → knob override; validated: harness/model/effort · free-form: launchArgs/promptKeywords/sessionCommands + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { // per-LEVEL agent sets (leaf|master|portfolio), deep-merged over roles + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" }, // spawn_agent_session default when the seat passes none + "gateDelegation": { + "policy": "manager-decides-leaf-gates", + "requireReviewerVerdictAtSeams": true + } + } +} +``` + +**As-built (L13 + L16):** the whole block is parsed by the kernel agentic-settings loader +(`kernel/agentic_settings.py`) — typed models for `roles` / `rolesPerLevel` / `concurrency` / +`spawn` / `harnesses` / `loops`, +read PER-USE (an edit applies on the next use, no restart). `orchestration.gateDelegation` is +parsed and **enforced** (`controlplane/gate_policy.py` — all-human default, opt-in delegation, +human-pinned kinds `integration-approval` / `push-approval` / `cleanup-approval`, owner never +self-approves); it is the ONE boot-snapshot key — read from the global file at MCP boot, a change +needs a restart (an authority-file value is a one-cycle legacy fallback with a boot warning). +`requireReviewerVerdictAtSeams` **binds delegated seam decisions** (`master-handover-approval`) to +attached reviewer-verdict evidence; the named policy `manager-decides-leaf-gates` routes leaf gates +to the manager and the master-exit handover to the **orchestrator** (human review concentrates at +the super gate). `spawn_agent_session` resolves its knobs (260703-L16) as explicit args > +repo-local level override > global level override > repo-local role default > global role default +> detection-gated default — the dispatcher declares its `level` (leaf|master|portfolio, default +leaf) and the resolved level rides spawn provenance — and **applies** them at the harness +boundary: model/effort ride as `AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` env AND map onto the launch argv +per-harness via the effective registry (claude `--model`/`--effort`; a mapping-less harness stays +env-only; a session-vocabulary effort like claude's `ultracode` is delivered as a post-launch +`/effort` paste). Unknown effort values REFUSE at dispatch naming the harness's vocabulary — the +CLI would warn-and-silently-degrade. The free-form escape hatch (`launchArgs` verbatim argv, +`promptKeywords` riding the brief paste, `sessionCommands` pasted before the brief) is never +validated, only recorded in spawn provenance; `orchestration.harnesses` teaches the framework new +TUIs or pre-customizes builtin launches (manual: `docs/reference/harnesses.md`). +`orchestration.loops` (the three-party-loop knobs: per-level loop sets, round cap, reviewer +reuse, complexity thresholds) lives in the same block — meaning in +`docs/reference/settings-json.md`; no knob touches the master-exit seam gate. + +## Companion Files + +- `lenses.md` — the four job lenses for the scoping seats. +- `roles/…` — the six self-contained role lifecycles (the registry above). +- `templates/…` — turn-report · worker-brief · manager-brief (`ROLE BRIEF — manager`; the + orchestrator compiles a manager's session start from it) · master-handover-packet · + conversation-handover-packet · verdict · impact-analysis · onboarding-coherency · + deep-research-report · orchestration-task (the strategist's sprint plan). Spawning seats compile + briefs FROM these; sub-agents fan out and fill them, so analysis survives compaction. +- `criteria/…` — the reviewer criteria catalogs (code-seam · doctrine · onboarding-memory · + report-verification · plan-review), the review test bench the three-party loop binds; maintained + through the promotion ratchet, never made up on the spot. + +## The Super Integration Branch (orientation only — the doctrine lives with its owner) + +``` +main + └── super-integration (orchestrator-owned, off main) + ├── master-A branch (off super) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, C-11) + ├── master-B branch (off the moved super — sees A) + └── … final: super → main PR + memory carry-over + push +``` + +The full topology — dependency-ordered dispatch, the integration-duty procedure, the two +conflict-resolution modes, leaf moves — lives in **`roles/orchestrator.md`** and only there. + +## Credits + +This skill absorbs and supersedes `l-01-session-job-lifecycle` and `l-02-agent-orchestration` +(converged 2026-07-05: lifecycle and job are one entity — one lifecycle per agent type). The +orchestration vocabulary adopts the parked `260619_agentic-control-plane` spec — jobs as +model-interpreted markdown (D6), the knob block (D7), role + lens in one file (D10), the +ambient-singleton rule (D11), per-harness variants (D12), the judge rung, short-lived workers with +structured handoff, dev-talks-to-one-orchestrator (D15) — which in turn credits **Archon** and the +**agent-control-plane** project (D14); that credit carries forward. + +## Relationship To Other Instructions + +This skill extends — never replaces — the coordinator `AGENTS.md`, the `w-02-light-task-workflow` +task format, and the memory layer (`c-…` skills). Each `roles/.md` is self-contained for its +seat; read exactly the one the router selects. diff --git a/.codex/skills/l-01-agent-lifecycles/criteria/code-seam.md b/.codex/skills/l-01-agent-lifecycles/criteria/code-seam.md new file mode 100644 index 00000000..053feb1b --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/criteria/code-seam.md @@ -0,0 +1,85 @@ +# Criteria Catalog — Code-Seam Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review wires code seams: consumers, enforcement points, gates, addresses, tool contracts. +Binds at the master-exit and super-exit seams and in any loop review whose change set touches code +(see the binding table in `../roles/reviewer.md`). Criteria are never made up on the spot: the +standing list below is the regression floor, run every time; the exploratory mandate and the +promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### CS-1 — Production-wiring walk + +**Trace the real call path, never a hand-aligned harness.** A claim that a consumer or an +enforcement point exists must be walked through the PRODUCTION call path — the controller, the +tool registration, the store fold — not through a test that hand-assembles the pieces into +alignment. A test can pass while the production consumer is inert. + +- Catching evidence: 260703-L8 review 3 (AR3-1) — the integrate consumer was proven **inert**: the + policy was omitted at the controller and the gate was looked up on the wrong lifecycle, while a + hand-aligned test passed (L8 decision log, cycle-6 entry). + +### CS-2 — Fail-open hunt + +**What happens when the address/config is absent or mistyped?** For every identity, address, key, +or config the seam matches on: feed it nothing, feed it a near-miss, and confirm the seam fails +CLOSED (refuses) rather than open (silently proceeds unmatched). + +- Catching evidence: 260703-L8 review 4 (AR4-1) — the seam's `enclosure` address had to be pinned + as an exact-string contract and the enclosure-less raise made a refusal (L8 decision log, + cycle-7 entry). + +### CS-3 — Validate-then-mutate + +**Every raise/write validates before it mutates.** A call that records state (a gate raise, a +store append, a contract write) must perform its refusal checks before any durable effect; a +mutation that precedes validation leaves half-states behind on refusal. + +- Catching evidence: 260703-L8 cycle 6 — the `wait=false` raise was reworked to be + validate-then-mutate and seam-kind-restricted (L8 decision log, cycle-6 entry). + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### CS-4 — Reused-primitive affordance parity *(candidate — 1 catch)* + +**When a screen reuses a shared content primitive, verify every branch of the ORIGINAL's +affordances (banners, status chips, truncation notices, error states) still fires on the reuse +path.** A dropped affordance is a silent regression the reuse's own tests won't catch — they +assert the new screen's happy paths, not the primitive's full surface. + +- Catching evidence (single engagement): 260703-L17 review (L17R-2) — the notes reader's + `DualPane` reuse drops the "first 2 MiB" truncation banner on the markdown path (the banner + lives in `CodeSide`, which markdown never reaches); text and binary keep it. + +### CS-5 — Cross-repo side-effect safety *(candidate — seeded from a clean exemplar, 0 catches)* + +**Any step that writes to a repository OTHER than the one it operates in gets the full +validate-then-mutate treatment plus partial-failure and dirty-target analysis.** Check the order +of validation vs the foreign write, the state left behind when the write lands but the caller +fails afterward, behavior against a dirty target repo, and an exact format round-trip with the +foreign artifact's consumer. + +- Seeding evidence: 260703-L18 finding 7 (`_reconcile_missing_mapping` writing the official + memory repo's ledger mid-`worktree_start`) PASSED all four lenses under this analysis — the + clean exemplar that defined the class. A catch in a later engagement promotes. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS change set the catalog does not name yet. Every novel finding-class that survives +refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.codex/skills/l-01-agent-lifecycles/criteria/doctrine.md b/.codex/skills/l-01-agent-lifecycles/criteria/doctrine.md new file mode 100644 index 00000000..9b9ccae1 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/criteria/doctrine.md @@ -0,0 +1,58 @@ +# Criteria Catalog — Doctrine Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review is doctrine: skill files, role lifecycles, templates, instruction surfaces, docs +that agents obey. Binds whenever doctrine/skill files are in the change set (see the binding table +in `../roles/reviewer.md`). Criteria are never made up on the spot: the standing list below is the +regression floor, run every time; the exploratory mandate and the promotion ratchet keep the +catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### D-1 — Doctrine-vs-code anchoring + +**Every "X enforces Y" needs a code anchor.** A doctrine sentence claiming enforcement, refusal, +or automatic behavior must resolve to the code that does it (file + mechanism). Doctrine that +narrates enforcement which does not exist is a defect, not an aspiration. + +- Catching evidence: 260703-L8 review 1 (AR-5) — `requireReviewerVerdictAtSeams` was documented as + binding while the flag was **inert**; the finding forced the wiring (L8 decision log, AR-1 + entry: "closing AR-5's inert flag"). + +### D-2 — Cross-file contradiction sweep + +**Sweep sibling doctrine for statements the change set now contradicts.** A doctrine change is +reviewed against the whole doctrine surface (skills, role files, templates, docs, hooks, canvas +prose), not just the edited files — one file's new invariant is another file's stale sentence. + +- Catching evidence: 260703-L10 — the landed "chat is never a build route" invariant contradicted + surviving chat-build wording inside `c-09` / `w-02` (builder escalation 1, owner-sanctioned + sweep; L10 builder report). + +### D-3 — Stuck-state walk + +**Can an agent following the prose deadlock?** Walk the doctrine as the obeying agent: at every +wait, gate, and handover, ask who unblocks it and through which channel. Prose in which two seats +each wait on the other — or a seat waits on a channel nobody is told to serve — is a blocking +finding. + +- Catching evidence: 260703-L8 review 2 — the seam deadlock: the manager's blocking raise and the + orchestrator's decide path could not meet as written; the ruled `wait=false` + + packet-carried-gateId channel resolved it (L8 rounds 2/4b history). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS doctrine change the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.codex/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md b/.codex/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md new file mode 100644 index 00000000..e47783e3 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md @@ -0,0 +1,67 @@ +# Criteria Catalog — Onboarding/Memory Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run over the +memory side of a change set: sidecars, route overviews, route indexes, update histories. Binds at +the master-exit and super-exit seams (the onboarding-vs-code lens) and in loop reviews whose change +set carries onboarding (see the binding table in `../roles/reviewer.md`). Criteria are never made +up on the spot: the standing list below is the regression floor, run every time; the exploratory +mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### OM-1 — Staleness diff vs as-landed code + +**Diff every body claim about current behavior against the as-landed code.** A sidecar or overview +body that describes the present tense is checked against what the branch actually ships — deleted +things still described, renamed things under old names, duplicated rows. + +- Catching evidence, two separate engagements: 260703-L8 cycle 6 (owner follow-up pass) — route + overview bodies still described **deleted canvas models** (the panels overview's build-job/frame + tail) and carried **duplicated table rows** (the tools and controlplane overviews' Layout + tables), durably recorded in those overviews' own 2026-07-05T19:25 Update History entries; + 260703-L10 — the flowModels sidecar body was still the pre-convergence 8-model census and its + references row still said "8 models" (the sidecar's 2026-07-06T12:05 history entry + L10R-3). + +### OM-2 — History-only-update detection + +**"Refreshed" must mean a genuine body edit.** An onboarding file whose only change is a new +Update History line has NOT been refreshed — the body still asserts the old truth. Check that +every claimed refresh touched body sentences, not just the history list. + +- Catching evidence: 260703-L8 cycle 6 — the builder reported route overviews as refreshed when + they were **history-only**; the closeout body gate caught it (L8 decision log, cycle-6 entry: + "report-vs-artifact verification belongs in the reviewer criteria catalog"). + +## Candidate Criteria (seeded exploratory — one catching engagement; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### OM-3 — Newest-first with the checker's own semantics *(candidate — 1 catch)* + +**Update History sorts newest-first under the CHECKER's datetime parse, not lexicographically.** +The quality checker compares naive timestamps as-is and folds tz-aware stamps to UTC; a merge or +mechanical insert that sorts by string can pass the eye and fail the gate (or worse, pass the gate +in the wrong order). Verify ordering with the checker's semantics. + +- Catching evidence (single engagement): 260703-L11 — four onboarding history collisions from the + parallel wave had to be re-sorted **with the checker's own datetime semantics** (naive compare + as-is, tz-aware folds to UTC); the quality gates caught the owner's wrong sort key (L11 decision + log). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS memory delta the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate is the working example, and it is THIS catalog's own OM-2 mechanized: the gate catches + history-only "refreshes" at commit time, where prose requests did not. diff --git a/.codex/skills/l-01-agent-lifecycles/criteria/plan-review.md b/.codex/skills/l-01-agent-lifecycles/criteria/plan-review.md new file mode 100644 index 00000000..ef4d2d90 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/criteria/plan-review.md @@ -0,0 +1,69 @@ +# Criteria Catalog — Plan Review (the strategist loop) + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run against an +**orchestration task** (`../templates/orchestration-task.md`) — the strategist's sprint plan — +before the developer's drawing board. This is the portfolio loop's review type: owner = +orchestrator, builder = strategist, reviewer = this catalog. The reviewer holds the same read-only +analysis tools the strategist used (`cgc_*`, `grepai_*`, `read_ar_files`), so the plan's mechanical +claims are re-derivable, not just readable. Criteria are never made up on the spot: the standing +list below is the regression floor, run every time; the exploratory mandate and the promotion +ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### PR-1 — Refute uncited edges + +**An uncited dependency edge is refutable by default.** Every edge in the dependency graph must +carry evidence — a cgc/grepai query, a file, a decision-log entry, a design-section citation, or +(for new surfaces) a declaration cross-reference naming both leaf declarations. An edge with no +evidence is challenged as a finding; so is evidence that does not actually support the edge's +direction or kind. + +### PR-2 — Missed-shared-surface hunt (class-completeness on intersections) + +**Re-intersect the surface lists independently.** Take the plan's per-leaf touch surfaces (both +existing and declared-new), recompute the pairwise intersections, and hunt pairs the edge list +omits — including CONFLICT-risk at a shared parent route where two leaves declare additions +(wiring points, shared registries). A plan that lists surfaces but misses one of their +intersections has a hole exactly where collisions happen. + +### PR-3 — Blast-radius re-derivation + +**Re-derive at least the HIGH-blast-radius entries with the cgc tools** (`cgc_dependencies` / +`cgc_callers` / `cgc_callees`, capped depth) — and spot-check a sample of the low/medium entries. +A register entry whose derivation cannot be reproduced, or whose classification drops the doctrine +propagation / migration / user-visible unions, is a finding; the register parameterizes every +downstream loop tier, so an understated radius under-reviews a leaf. + +### PR-4 — Order-respects-edges + +**Check the sprint order/waves against the edge list, mechanically.** No ORDER edge may run +backwards across the proposed sequence; every CONFLICT edge must be resolved by serialization or a +recorded leaf move (from→to + rationale); parallel waves may contain only INDEPENDENT pairs, and +the wave plan must acknowledge the landing-reconciliation cost. + +### PR-5 — Honesty of the findings section + +**Verify the plan's failure claims both ways.** Every "unplannable as scoped" finding must be +genuine (the leaf can name neither existing surfaces nor the parent anchoring of its additions — +a merely not-yet-existing surface is NOT unplannable); and thin leaf scopes the plan silently +guessed around instead of flagging are themselves findings. Quo-vadis contradictions must be +flagged at the top of the coherence findings, not buried. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS plan could be wrong that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example; PR-4 is this catalog's mechanization candidate (a topological check over + a structured edge list). diff --git a/.codex/skills/l-01-agent-lifecycles/criteria/report-verification.md b/.codex/skills/l-01-agent-lifecycles/criteria/report-verification.md new file mode 100644 index 00000000..fb3bdda8 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/criteria/report-verification.md @@ -0,0 +1,95 @@ +# Criteria Catalog — Report Verification + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) — and the loop OWNER +verifying a builder round — MUST run over every report, claim, and summary in the change set: +builder reports, owner claims, handover packets. **Standing from day one** in every review type: +report-vs-artifact caught real defects in three separate engagements before this catalog existed. +Criteria are never made up on the spot: the standing list below is the regression floor, run every +time; the exploratory mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### RV-1 — Report-vs-artifact on EVERY claim + +**Open the artifact behind every claim.** A report sentence asserting "X was done / is green / +was refreshed" is verified against the artifact itself, not trusted — claim by claim, no sampling +of the load-bearing ones. + +- Catching evidence, three separate engagements (260703-L8): review 3 caught a **hand-aligned + test** behind a wiring claim; cycle 6's closeout gate caught **"refreshed" overviews that were + history-only**; review 4 caught the **OWNER's own canvas overclaim** (L8 decision log, cycle-7 + entry) — builder reports and owner claims fail the same way. + +### RV-2 — CLASS-completeness *(promoted to standing at 260703-L18 — 2 catches)* + +**Hunt the siblings of every found instance.** A finding or a fix names an instance of a CLASS +(a directive surface, a census count, a vocabulary token). Enumerate the class — every sibling +surface, not just the instances the report names — and check each one. + +- Catching evidence: (1) 260703-L10 round 1 — the reviewer's completeness sweep found **six of + ten first-action surfaces** still shipping the retired directive when the report claimed the + flip done (L10 decision log). (2) 260703-L18 review (L18R-3) — the fix for + advertised-but-unimplemented recovery choices named the `cli.py` `custom` residual but missed + the SIBLING `_load_memory_ledger` block still advertising an inert `reconciliation`; the + sibling hunt found it. + +### RV-4 — Decision-log completeness for scope-expanding disclosures *(promoted to standing at 260703-L18 — 2 catches)* + +**A scope-expanding owner supplement or load-bearing builder disclosure must be verifiable in +the task-doc decision log, not only the builder report.** Continuity lives in the task_doc + +durable artifacts, never in transcripts; a ruling or environment finding that exists only in a +report is one lost file away from unrecoverable. Cross-check every supplement and disclosure the +builder report carries against the decision log. + +- Catching evidence: (1) 260703-L17 review (L17R-1) — supplement 2 (the wait-loop-era remnant + sweep with per-hit verdicts and two named follow-ups) was recorded only in the builder report. + (2) 260703-L18 review (L18R-4) — the load-bearing editable-install/PYTHONPATH environment + finding + named follow-ups lived only in the builder report; the leaf's `decisions[]` was + empty. Both folded by the owner at closeout. + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### RV-3 — Partial-fix-creates-falsehoods *(candidate — 1 catch)* + +**Verify claims ABOUT the changed artifacts, not only the artifacts.** A partial fix can turn +previously-true sentences elsewhere false (docs describing the artifact, install guides quoting +it, counts referencing it). Sweep for statements about what changed and re-verify their truth +after the change. + +- Catching evidence (single engagement): 260703-L10 round 1 — the partial hook flip made **two + install-doc claims false** ("injects the same startup directive" no longer held); round 2 + restored byte-identity so the claims became true again (L10 decision log + builder report). + +### RV-5 — Worktree-shadowed regression pins *(candidate — 1 catch)* + +**A regression test must bite under the invocation the owner actually runs.** An editable +install pointing at another checkout can shadow the worktree's sources, making a mutation-tested +pin pass vacuously under the canonical invocation while failing only under a hand-set +`PYTHONPATH`. Verify sensitivity by mutating the target and running the CANONICAL invocation; +a pin that only bites under a nonstandard environment is not yet a pin. + +- Catching evidence (single engagement): 260703-L18 review (L18R-1) — the inbox + delivered/unconfirmed pin failed its mutation check only under `PYTHONPATH=src`; under the + canonical `pytest mcp/tests` the main-repo editable install shadowed the worktree and the + mutated code still passed. Remedy: the `sys.path` pin idiom the sibling suites carry. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS report could mislead that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests (RV-1 is itself the precedent: promoted on three catches). Promotion is proposed in the + verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.agents/skills/l-01-session-job-lifecycle/job-variants.md b/.codex/skills/l-01-agent-lifecycles/lenses.md similarity index 82% rename from .agents/skills/l-01-session-job-lifecycle/job-variants.md rename to .codex/skills/l-01-agent-lifecycles/lenses.md index 48f032c6..0f277b06 100644 --- a/.agents/skills/l-01-session-job-lifecycle/job-variants.md +++ b/.codex/skills/l-01-agent-lifecycles/lenses.md @@ -1,7 +1,9 @@ -# l-01-session-job-lifecycle Job Variants — The Lenses +# Lenses — How the Scoping Seats Read a Job -The job type is a **lens**, picked during `reframe-research` and re-pickable at any time. It is not a gate and it -never changes the spine (`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three +Read by the **scoping seats** (orchestrator, designer); a dispatched role never picks a lens — its +brief already carries the flavor. The job type is a **lens**, picked during `reframe-research` and +re-pickable at any time. It is not a gate and it never changes the orchestrator phase axis +(`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three things only: - **Opening move** — the first concrete thing `reframe-research` does for this kind of job. @@ -25,8 +27,8 @@ invariant the bug violates. Defaults to a build; the fix lands through `decide - Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the -contracts the feature must respect. Defaults to a build; size decides chat vs durable `w-02-light-task-workflow` task at -`decide`. +contracts the feature must respect. Defaults to a build; size decides the minimal `w-02-light-task-workflow` artifact vs a master + +sub-task series at `decide`. ## triage diff --git a/.codex/skills/l-01-agent-lifecycles/roles/designer.md b/.codex/skills/l-01-agent-lifecycles/roles/designer.md new file mode 100644 index 00000000..c67cec40 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/roles/designer.md @@ -0,0 +1,91 @@ +# Lifecycle — Designer (the hat) + +> The design lifecycle the **orchestrator pulls inline** whenever design is needed — front of the +> pipeline or mid-flight. **A hat, not a seat**: it cannot sit in a coordination leaf because the +> task is what it exists to create — no leaf, no worktree, no branch, no spawn required. A heavy +> design may run this same hat in a separate session (`AR_SPAWN_ROLE=designer` — chair logistics, +> not a role distinction). +> +> Drawn as the **DESIGNER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Hat Is + +Task design is **its own job** (developer decision 2026-07-04). Before orchestration one implicit +do-it-all role did design, features, and fixes; the roles now diversify, and design routes +**through the orchestrator, which wears this hat** — at the front of the pipeline AND mid-flight +(most leaves of a live series are designed mid-flight). It is the `tasks/AGENTS.md` collaboration +doctrine (meta-questioning, reframe-before-execution, evidence-first) given a distinct, optimized +shape as a job. Nothing here assumes a master exists yet — producing one is the point. + +The designer shares the orchestrator's **bird's-eye toolkit** — route indexes, onboarding, the +`grepai_search` MCP tool, the code-graph (`cgc_*`) MCP tools, blast-radius analysis — but is **scoped +to one master**. Collisions with *other* — especially **future** — masters can slip past a +single-master view. That residual risk is **owned downstream, not here**: at portfolio streamlining the +**orchestrator doubles as the designer's adversarial reviewer** (planned-vs-planned and +planned-vs-past). The designer's duty is to *declare* the limit, not to close it. + +## Lens + +- **Opening move:** meta-question the ask. Surface the request, the deeper objective, and the + highest-leverage framing before any structure exists — do not jump from the developer's first + phrasing to a plan. +- **Retrieval lean:** evidence-first, within the master's scope. Route indexes and onboarding for the + map; `grepai_search` for semantics; `cgc_*` for relationships/impact; bounded `read_ar_files` for + intent confirmation. Sub-agents fan out and write durable reports. +- **Decide default:** a `w-02-light-task-workflow`-shaped master + leaf task_doc, handed into the + portfolio — **not** a build. The designer designs; it does not implement. + +## Duties + +1. **Reframe with `tasks/AGENTS.md`.** Distinguish surface request · deeper objective · highest-leverage + framing · assumptions · boundaries · invariants · truth gaps. Material scope/intent/sequencing + changes are **played back and wait for confirmation**; a pure clarification may be presented and + continued. +2. **Evidence-first, master-scoped.** Make the evidence model visible before or alongside the plan + (external · repo-internal · cross-repo · executable). Gather it through the + `c-04-retrieval-strategy-router` skill, not ad-hoc reads. +3. **Blast-radius WITHIN the master.** Routes touched · invariants at risk · regressions — bounded to + this master's scope. Cross-master and future-master reasoning is explicitly out of the designer's + reach. +4. **Author the task_doc.** Master + leaves (requirements · steps · code examples per distinct change, + the `w-02-light-task-workflow` shape), leaves scoped around routes/areas, via the `task_doc` MCP + tool. Include a **code example for every distinct change** when code is in scope. + Decision-needing questions land in the task doc's `openQuestions` — the rendered decision + surface; `notes/` carries the analysis behind them. +5. **Declare the designer limit.** Record on the doc that this is a **master-scoped bird's-eye**: + cross-master and future-master collisions can slip and are owned downstream at streamlining. Never + hide the limit. +6. **Ask, never fill silently.** Assumptions and truth gaps only the developer can resolve are asked as + a short, high-leverage list — never filled silently. + +## Artifact Obligations + +- The **task_doc** (master + leaves) is the durable artifact of the designer job. +- A **designer-limits note** on the doc — the declared master-scoped blind spot, for the orchestrator's + later adversarial pass. +- Evidence reports from fan-out sub-agents (durable), so the framing survives into streamlining. + +## Comms Protocol + +- **Primary channel:** the developer, directly, in the designer's attached chat — this seat is a + co-thinking loop, so the developer is the standing interlocutor here (unlike the deeper seats, which + relay through the ladder). +- **Handover:** the finished design **joins the portfolio**. At streamlining the orchestrator + adversarially reviews it; hand the task_doc + the designer-limits note over via the inbox + (`operator_inbox_post`) and, for a hosted orchestrator, stdin push. +- **Escalation:** the hat's "escalation" is simply the handover into the portfolio job — the + orchestrator that wears it is already the last resolver before the developer. + +## Knobs + +| Knob | Default | Notes | +| ------- | ------------------ | --------------------------------------------------------------------- | +| harness | (the wearer's) | the hat runs inside the orchestrator session, or a spawned design chair | +| model | high-reasoning | reframe + blast-radius reasoning wants a strong model | +| effort | high | design leverage justifies the thinking budget | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | bird's-eye toolkit | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · inbox | + +Settings.json `orchestration.roles.designer` overrides these, and `orchestration.rolesPerLevel..designer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.codex/skills/l-01-agent-lifecycles/roles/manager.md b/.codex/skills/l-01-agent-lifecycles/roles/manager.md new file mode 100644 index 00000000..0b42124a --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/roles/manager.md @@ -0,0 +1,168 @@ +# Lifecycle — Manager + +> One master, one seat, self-contained. The manager lifecycle drives exactly one master series: +> spawn a fresh worker per leaf, review turn reports, decide the delegated leaf gates, close out and +> integrate each leaf, hand the completed master to the orchestrator through the master-exit seam. +> Your **brief is your session start**. +> +> Drawn as the **MANAGER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**One per master task.** Spawned by the orchestrator with the master's context packet. It owns its own +coordination leaf + chat (**no worktree**) and drives exactly one master series: spawns/respawns a fresh +worker per leaf, reviews turn-report artifacts, decides **delegated** leaf gates, integrates leaves into +the master integration branch via the `c-11-memory-carryover-from-branch` skill, and hands the completed +master to the orchestrator through the master-exit adversarial seam. + +The manager owns the leaf lifecycle machinery **end-to-end**: `worktree_start` → (the worker +builds) → closeout preview/apply (deciding the delegated gates per the gate policy) → +`worktree_integrate` → finalize — task-doc statuses via the finalizer, **steps checked by this +seat by hand** (the tool does not reconcile checkboxes). The worker's terminal +state is checks-green + turn report; everything after that is this seat's. + +**Flat-run note:** in a flat series (no managers spawned) the **orchestrator wears this hat** — +same duties, same artifacts, one chair. + +A manager has **no bird's-eye view** — it sees one master, not the portfolio. That boundary shapes +everything below. + +## Lens + +- **Opening move:** read the master `task_doc` + its leaf docs; order the leaves (parallel where safe — + the C-11 reconcile absorbs a moved base). +- **Retrieval lean:** intent-confirmation on the master's own routes (paired `read_ar_files`); the + breadth/blast-radius reasoning belongs to the orchestrator, not here. +- **Decide default:** dispatch the next ready leaf; the master exits through the master-exit seam. + +## The Default-Behavior Rule (read this before anything else) + +The **default agent behavior stands**: **fulfill the task, fill small blanks.** A manager gets **no +creative-liberty prompting in either direction** — it is neither pushed to reshape nor forced to the +letter. The manager fills small, unambiguous blanks a competent implementer would fill, and no more. + +> **The spirit test does NOT apply to this seat.** It is orchestrator-only. A manager's changes can +> collide with what it cannot see, so a **plan delta beyond blank-filling escalates to the +> orchestrator** — the manager does not reshape plans. This is not a licence to be timid and it is not a +> licence to be creative; it is the ordinary "do the task well, ask when the task itself is in +> question" default, with the ask routed **up the ladder to the orchestrator**, never to the developer. + +## Duties + +### 1 — Seat & intake + +Take the master's own coordination leaf (`task_doc`, no enclosure); the chat is attached so the +developer can walk in any time. Read the master + leaf docs; order the leaves. + +### 2 — Leaf dispatch loop (per leaf) + +- **Score the leaf's loop tier at dispatch** (loop doctrine: `../SKILL.md`, The Three-Party Loop): + blast radius · novelty · size → **direct** (NO loop machinery: the leaf's worker implements as + usual — worker self-check + checks ladder + this seat's ordinary artifact review; this seat + still dispatches per leaf and never grows a build surface) | **builder-verified** (the worker + implements; this seat additionally verifies its report claim-by-claim against the artifacts; no + reviewer) | **full loop** (worker + independent reviewer rounds). When an orchestration task + exists, its **blast-radius register is the scoring input**. Record the mark (tier + scope: + manager | orchestrator — the owning level runs the loop with ITS agent set) on the leaf doc with + a decision-log entry. **A master whose leaves all score `direct` is a workflow-free manager** — + no loop machinery, just the dispatch-review-integrate spine below. +- On a full-loop leaf, run the loop with this level's controls: a round = implement → review; + **hard cap 3 full rounds** (delta-verifies by the SAME reviewer close rounds, they do not count; + fix rounds resume the SAME builder); **every round must shrink the finding set** — a + non-shrinking round escalates to the orchestrator immediately, with the full round history + attached, regardless of the count. +- `spawn_agent_session(worker)` — a **fresh session** on the leaf: the brief (compiled from + `../templates/worker-brief.md`) is pasted + submitted, with `env={"AR_SPAWN_ROLE": "worker"}` and + the **qualified** leaf key `//`; the worker edits inside the leaf + worktrees the brief names. +- **Monitor the worker** — a turn-report artifact is expected at **every** hand-off. Inactivity or a + missing artifact → a **rate-limited stdin nudge** (logged as an event, never spammy). Escalation + intake via the inbox. +- **Review artifact vs `task_doc`** — completion vs requirements/steps · checks green · + onboarding refreshed in the same pass (the manager's own leaf-level review; **this is not an + adversarial seam**). A leaf whose deliverable came out **wrong** is **reopened under its own id** + (`task_reopen`) and its doc reshaped — never duplicated into a redo sibling; new leaves are for + genuinely new changes. +- **Delegated leaf gates (plan · closeout)** — decide the leaf's delegated gates, **attributed** + (`decidedBy: `, `decidedVia: orchestration`), appended and dashboard-visible. The + **owning agent never self-approves; a distinct configured role may** — that configured role is the + manager. (Enforced as-built by the gate policy: `orchestration.gateDelegation` in settings, + `controlplane/gate_policy.py` — human-pinned kinds stay human, decisions attributed.) + Your own hand-off idiom, this seat only: durable gates + inbox posts — you never call the + developer-facing notification; your counterparty is the orchestrator. +- **Integrate leaf → master branch** via the `c-11-memory-carryover-from-branch` skill (ff-only / replay + per the `c-09-git-worktree-manager` skill). Know the human-pinned gate kinds by name: + `integration-approval`, `push-approval`, `cleanup-approval` — none is ever delegable. When a + durable `integration-approval` gate is raised on this step it awaits the **developer** (via the + dashboard GateResponder or your attached chat — you do not relay; if the wait blocks the loop, + escalate to the orchestrator). Absent a durable gate, the **series' standing approval** governs: + the developer's portfolio-gate approval of this series, recorded in the planner master's + decision log, covers dependency-ordered leaf integrations. Loop until the master's leaves are + done. + +### 3 — Master-exit seam + +When all leaves have landed on the master integration branch, spawn the **adversarial reviewer** +(master-exit) via `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "reviewer"}` and the reviewer +role file (`roles/reviewer.md`), passing the master branch ref, +master/leaf task docs, worker turn reports, decision logs, changed paths, resolved +`system/tools.md` evidence, and carry-over state. The verdict lands at +`notes/reports/-master-exit-verdict.md` and attaches to the handover gate as +`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"pass|pass-with-notes|block"}]` +— a verdict over completion vs task docs · `system/tools.md` quality · onboarding-vs-code. **Blocked? → the verdict decomposes into fix leaves** the manager dispatches (loop +back to the leaf loop). Verdicts are **evidence, not decisions**. The seam channel, exactly: +**raise without blocking** — `lifecycle_gate(kind="master-handover-approval", +enclosure="", evidence_refs=[], wait=false)` (raise-and-continue +is allowed precisely because the kind is a delegated seam kind; the `enclosure` MUST carry the +master's identity — it is the address integration enforcement matches the gate by, and the match +is exact-string: pass the EXACT master task name as the contracts carry it (`worktree_start`'s +`task_name`) — the raise refuses without an enclosure; the call +returns the **gateId**); then **carry that gateId in the handover +packet** (§4) — the packet is the orchestrator's trigger AND its address for the gate. Under an +all-human policy the raise blocks and the developer decides — do not pass wait=false. Identity +truth, as-built: the gate pins to your ambient lifecycle when you raise it; the deciding +orchestrator resolves the gate **by the packet-carried gate id** (gate ids are model-visible — +only LIFECYCLE ids stay server-side) and its own ambient identity becomes `decidedBy`; +owner-never-self-approves holds by construction. A handover carrying serious issues the +orchestrator cannot answer on its own escalates up the ladder (orchestrator → developer). + +### 4 — Handover to the orchestrator + +Post the **master-handover packet** (`../templates/master-handover-packet.md`) — inbox (durable) + stdin +push — integration branch ref · change-set summary · verdict ref · **handover gateId** · +carry-over state. The seat (chat + coordination leaf) **stays reachable** until the series +retires; your raised gate stays open until the orchestrator decides it (poll `gate_list` on your +own lifecycle if you need its state). + +## Artifact Obligations + +- The **master-handover packet** at master exit (the manager's primary durable artifact). +- Leaf-review notes (completion vs task_doc) — lightweight, on the master's coordination leaf. +- Delegated-gate decision records (attributed). + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down to workers, escalation + intake up from workers, handover up to the orchestrator; all durable + dashboard-visible. +- **Stdin push** — nudges and messages delivered into hosted worker sessions; poll is the fallback. +- **Escalation** — **up to the orchestrator, never straight to the developer.** A stumped manager, and + any plan delta beyond blank-filling, raises to the orchestrator. The manager resolves within its own + master's view first. A loop that hits the 3-round cap or stops converging escalates **with the + full round history attached**. **Quo-vadis test:** a question that is a **high-blast-radius + truth** — answered wrong it means big rewrites later, not a cosmetic choice — is flagged as + quo-vadis when raised, so the orchestrator relays it to the developer immediately instead of + absorbing it; presentation-grade choices are never escalated — decide and log. + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ---------------------------------------------------------------- | +| harness | claude | default preference only — settings picks the actual harness | +| model | mid-reasoning | leaf review + coordination; strong but below the orchestrator | +| effort | medium | one master's scope, not the portfolio | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | coordination + review + leaf lifecycle | `task_doc` · `read_ar_files` · gates · `spawn_agent_session` · worktree lifecycle (start · closeout · integrate · finalize) · C-11/`c-09` · inbox | + +Settings.json `orchestration.roles.manager` overrides these, and `orchestration.rolesPerLevel..manager` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.codex/skills/l-01-agent-lifecycles/roles/orchestrator.md b/.codex/skills/l-01-agent-lifecycles/roles/orchestrator.md new file mode 100644 index 00000000..90a5e06a --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/roles/orchestrator.md @@ -0,0 +1,377 @@ +# Lifecycle — Orchestrator + +> The developer-facing lifecycle: an **event loop over durable portfolio state**, not a +> request-to-close pipeline. Each turn routes the incoming event — a developer message, a worker +> report, a verdict, the orchestrator's own finding — into one of **three jobs** (Design · +> Portfolio · Orchestrate) under one roof, with solo work as the same jobs run with hats collapsed. + +## What This Seat Is + +The developer's single point of contact and the only seat with a standing developer relay +(managers/workers stay reachable via their attached chats). It owns the design conversation, the +portfolio bird's-eye, dependency-ordered dispatch, the super integration branch, the **spirit +test**, and the **integrity bulwark** against "fixed one thing, broke two others." + +Its real state is the **task tree** — masters, leaves, statuses, decision logs, `openQuestions`, +contracts — never the transcript. That is why sessions can die, compact, and resume without losing +the run. Its analysis substrate is the **memory system** (route indexes, onboarding, +`grepai_search`, `cgc_*`); **orchestrator quality ∝ memory-repo quality**. Its durable notes and +reports are the most important artifacts in the system: only this seat sees the whole picture. + +## The Event Loop + +**Opening move, every session — new or resumed** (resumption is the common case, not the +exception): + +1. **Trust checkpoint** (below), then `lifecycle_start` (the frame's fleeting lifecycle). +2. **Portfolio orientation:** read the portfolio state — what exists, what is in flight, what is + blocked on whom, what awaits the developer — and **say it back**. +3. **Route the event** by what exists and what is asked: + +| Condition | Job | +| --- | --- | +| No task doc exists for the ask (or a planning-status doc needs reshaping before work) | **D — Design** | +| Designed masters exist; coherence/conflicts/order in question, or "orchestrate these" | **P — Portfolio** | +| An approved task/series is ready for implementation | **O — Orchestrate** | +| The ask changes no code (a question, an investigation) | **research-only exit** — deliver the answer; chat is the right medium; no worktree, no task artifact | + +**Profile check (takeover).** Before heavy work in any job: if this session's harness/model/ +effort is wrong for the run (resolved: role file < settings), spawn the right chair — +`spawn_agent_session` with `AR_SPAWN_ROLE=orchestrator` + a conversation-handover packet +(`../templates/conversation-handover-packet.md`) — and hand over; the developer still talks to +ONE orchestrator at a time. + +Several jobs can be active across a day; the loop routes per event. The frame's phase axis stays +the observable `lifecycle_phase` vocabulary (`reframe-research` ≈ D, `decide` ≈ P, `build`/`close` +≈ O); the jobs are the decision structure. + +## The Invariant Ladder + +``` +task doc (approved) → branch (intent) → worktree (only where something is built) +``` + +- **Design and Portfolio never touch git.** Nothing is being built there. +- **Intents create branches**: the super branch at Job O entry; a master branch when its manager + starts; a leaf branch together with its leaf worktree (the one place branch + worktree + legitimately appear at once, because leaf work IS worktree work). +- **Worktrees exist per build/integration edge** and are reclaimed after. +- **Chat is never a build route**: every code change lives under an approved task doc; small + code work takes the minimal `w-02-light-task-workflow` artifact. Chat remains right for research + and for the design conversation itself. + +## Trust Checkpoint (shared opening detail) + +1. `context_packet(repo_id="", include_providers=true, include_drift=true, + include_freshness=true)`. +2. Report the packet facts before relying on memory or providers: repository/branch/dirty state; + memory + onboarding roots; provider state; drift status and actionable count; branch freshness + (`behind`/`diverged` → fast-forward the local official line first; + `ledgerMapsCodeHead=false` → carryover or the right memory branch first). +3. Drifted/missing/orphaned onboarding on committed, non-dirty source: **ask the developer** before + refreshing via `c-05-create-or-update-onboarding-files` — drift handling is approval-gated. + Drift tied to dirty source is active work-in-progress, not maintenance. +4. Providers stopped/degraded: run the matching provider/runtime operations, re-check, report; + `indexing` means healthy-but-busy (partial results). + +When this seat spawns a role it compiles the trust facts into the brief — a spawned role does not +repeat this checkpoint. + +## Hand-Off Protocol — Dry-Run → Notify-And-Stop → Report + +Every developer hand-off (design acceptance, portfolio plan, worktree intent, commit, push, +integration, cleanup/finalization, any dev-wait) is three actions, never one. Carve-out (ruled +2026-07-06): in an orchestrated run, leaf→master and master→super integrations ride the series' +**standing approval** — no per-edge developer hand-off; the developer hand-off concentrates at the +super PR/carry-over gate (see Super exit & landing tail). The table's integration row governs when +a hand-off DOES happen (solo runs; a raised durable gate): + +1. **Dry-run** the pending mutation and self-fix failures before reporting. +2. **Notify:** `lifecycle_turn_end_notification(summary=…)` as the **last tool call**. +3. **Report:** the complete packet as final prose, the decision handed over as the last line — + then STOP. The next turn's first AR call auto-resumes. + +| Junction | Parked durable gate `kind` | Hands off via | +| --- | --- | --- | +| design acceptance / plan gate | `plan-approval` | this lifecycle | +| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | +| commit / closeout | `closeout-approval` | `c-12-closeout` | +| push | `push-approval` | this lifecycle / `c-09` | +| integration | `integration-approval` | `c-09` / `c-12` | +| cleanup / finalization | `cleanup-approval` | `c-09` / `c-12` | +| any other dev-wait | `agent-question` | this lifecycle | + +`closeout-approval` **is** the commit hand-off. The block-and-wait `lifecycle_gate` + +`lifecycle_resume` pair remains the parked fallback for a durable, mutation-blocking approval +record; it renders a prompt over your prose, which is exactly why notify-and-stop is the path. + +## Job D — Design (pull the designer hat) + +**Entry:** an intent/problem with no task doc — or a planning-status doc that needs reshaping +before work starts. Fires at the front of the pipeline AND mid-flight; most leaves of a live +series are designed mid-flight. + +Run `roles/designer.md` **inline — the designer is a hat, not a seat**: it cannot sit in a +coordination leaf because the task is what it exists to create. No worktree, no branch, no spawn +required; a heavy design may run the same hat in a separate session (chair logistics, not a role +distinction — spawn with `AR_SPAWN_ROLE=designer`). + +- The co-think loop, evidence model, blast-radius-within-the-master, and designer-limits + declaration are the hat's own file. The orchestrator remains accountable for what the hat + produces: **bulwark-check the design against the portfolio and the past before acceptance** + (planned-vs-planned AND planned-vs-past — a designed change that collides with another master's + standing order is caught here or shipped broken). +- **Output:** master/leaf task docs (requirements · steps · code examples), `openQuestions` for + the developer (the rendered decision surface; `notes/` carries the analysis), the limits note. +- **Gate:** the developer accepts the design — or parks it. **No git surface.** + +## Job P — Portfolio (streamline + plan) + +**Entry:** designed masters exist and coherence/order is the question, or the developer says +"orchestrate these." + +- **Route-coherence scan** across the set (route indexes · onboarding · grepai · cgc); fan-out + sub-agents write durable reports (`../templates/impact-analysis.md`). +- **Integrity bulwark** — planned-vs-planned AND planned-vs-past, every time. +- **Reshape** — foundation-master extraction; leaf **moves** for planning-status leaves (real + moves, never tombstones), each with decision-log entries on both masters. **The sub-task list is + an ORDERED LIST with word-processor semantics:** numbers ARE positions; moving an item renumbers + the list; the list stays contiguous while the series is unlanded; every renumber map lands in + the decision log; numbers freeze when the series lands on main. +- **Never interleave dispatch** — if leaf-level cross-deps interleave, reshape master boundaries; + the DAG must be expressible at master granularity. +- **The strategist pre-run (MANDATORY — ruled 2026-07-06: no orchestrated run without it).** After + 1..N masters are designed and BEFORE implementation starts on any of them, dispatch the + **strategist** — `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "strategist"}` + (`roles/strategist.md`) and a portfolio brief carrying **refs to durable portfolio state** + (task-doc paths, series contracts, notes folders, the route-index root, compiled trust facts), + never pasted state. Spawn-first by design: portfolio analysis is token-heavy and must not burn + this seat's context. **Even a single master gets the pass.** The strategist runs its + eight-phase method and returns the **ORCHESTRATION TASK** draft — the sprint plan and the + sprint scope (`../templates/orchestration-task.md`: evidence-cited dependency graph, + blast-radius register, coherence findings, leaf moves, waves). This is the portfolio + three-party loop (owner = this seat · builder = strategist · reviewer with + `../criteria/plan-review.md`), followed by **drawing-board rounds with the developer** — this + seat relays, multi-round convergence is expected and normal, and quo-vadis items (e.g. two + masters heavily disagreeing) go straight to the developer. On acceptance **this seat adopts the + draft into durable task form** (the strategist is a reader, not a mutator) with a decision-log + entry. +- **Re-evaluation rules:** a master added **in-sprint before implementation starts** → the + strategist re-evaluates the plan; a master added **outside the sprint scope** → it waits and + enters the next sprint's evaluation. +- **Output: the planner master task + the adopted orchestration task** — the run's durable home: + subTasks = the coordination leaves (orchestrator seat first, one per manager); body = the DAG + + dispatch order + conflict decisions + (once Job O starts) the super branch name; decision log = + every spirit-test act and reshape; `openQuestions` = the standing decision surface; the + orchestration task = the sprint scope the run executes. Its durable form is a `kind:"master"` + task doc carrying a top-level `orchestrates` list naming the master tasks it commands — the + dashboard derives the orchestration > master > leaf hierarchy (and the rank insignia) from that + field, so setting it is part of adoption. +- **Gate:** the portfolio plan gate — one wholesale developer review of the reshaped portfolio + + the orchestration task (sprint scope + DAG + dispatch order). **No git surface** — not even the + super branch exists yet. + +## Job O — Orchestrate (execute the plan) + +**Entry:** an approved planner master — or a single approved master for a flat run. Either way, +**the adopted orchestration task must exist**: the strategist pre-run (Job P) is the +unconditional precondition for any orchestrated run — even one master. It is doctrine, not a +knob. + +**First act — the super-branch intent:** create the super integration branch off `main` so +masters can base off it. **A branch, not a worktree** — this seat has nothing to build at creation +time. (Interim: until a branch-without-worktree primitive lands, the manual git + contract edge is +acceptable and recorded in durable notes.) + +**Dispatch loop**, dependency-ordered — for each ready master (dependencies integrated into +super): `spawn_agent_session(manager)` with a brief compiled from +`../templates/manager-brief.md` (`env={"AR_SPAWN_ROLE": "manager"}`, the **qualified** leaf key +`//`; the brief carries the load-bearing base fact: master branches +off the **current super**, never off main); +monitor turn-report artifacts, nudges, escalation intake; apply the **spirit test** to escalated +deltas. A manager escalation may carry a **loop's full round history** (3-round cap hit, or a +round that failed to shrink the finding set — the convergence rule, `../SKILL.md` The Three-Party +Loop): this seat either re-runs the loop at ITS level (the orchestrator-level agent set — the +strongest models) or, when the blocker is a quo-vadis truth, takes it to the developer. In a +**flat run, wear the manager hat yourself** (see The Hat-Collapse Rule). + +**Failed-deliverable rule (reopen-and-reshape):** a leaf whose deliverable came out wrong is +**REOPENED under its own id** (`task_reopen`) and its doc reshaped to the intended form — the +decision log preserves the journey. New leaves are only for genuinely **new** changes discovered +(a fix leaf ≠ a redo leaf). Spawning a sibling per failed attempt hides what went down, breaks +task order, and splits the change-set. + +**Master exit:** consume the manager's handover packet +(`../templates/master-handover-packet.md`); check the master-exit verdict (evidence, never a +decision); then **decide the manager's gate by its packet-carried id** — the exact call: +`gate_decide(gate_id=, decision="approve", +deciding_role="orchestrator")`. The server resolves the gate across lifecycles by id (you never +handle a LIFECYCLE id; gate ids are the sanctioned hand-off), your ambient identity becomes the +attributed decider (owner-never-self-approves holds because the raiser was the manager), and the +policy may require the attached reviewer verdict (`requireReviewerVerdictAtSeams`). Integration +enforces it: `worktree_integrate` refuses while a `master-handover-approval` gate addressed to +this master (its `enclosure`) is undecided or policy-invalid. A blocking verdict decomposes into +fix leaves dispatched before integration; a +handover you cannot honestly decide escalates to the developer. + +**Integration duty (master → super) — the worktree moment.** Per completed master: + +1. Consume the handover packet: branch ref, change-set summary, checks, verdict, carry-over + state, risks, next dependencies. +2. Check the verdict (pass/accepted proceeds; block → fix leaves first). +3. Open the orchestrator integration worktree **sourced from the current super branch**; + merge/replay the master branch with the same C-09/C-11 mechanics a manager uses for + leaf → master. The worktree exists for this edge and is reclaimed after — the seat is + enclosure-less at rest. +4. Carry memory + map the ledger (C-11; duplicate memory single-sided; memory quality before the + memory edge lands). +5. Record the new super tips in durable notes; mark next masters ready. + +**The topology (single home — this section owns it):** + +``` +main + └── super-integration (orchestrator-owned, branch off main — created at Job O entry) + ├── master-A integration branch (off super @ t0) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, source = super, C-11) @ t1 + ├── master-B integration branch (off super @ t1 → sees A's results) + ├── integrate B → super @ t2 + └── … final: super → main PR (remote merge) + memory carry-over to main + push +``` + +Strict stack: super off main; master branches off the **current super** (never off main); leaf +branches off their master. **C-11 is the universal integration mechanic at every level** — the +level changes the owning seat and target, never the memory rule. The final super → main landing +follows `system/git-workflow.md`: PR to gated main, remote merge, memory carry-over so the ledger +maps the actual merge commit, then push — **push only after the developer approves**. + +**Conflict resolution — exactly two modes:** *Up-front (preferred):* an overlap found during +streamlining → extract shared logic into a foundation master implemented first (leaf moves + +decision-log entries + renumbered lists). *Post-hoc:* an overlap visible only in returned +branches → remediate on the super worktree (code dedup; memory single-sided on the strand that +owns the final truth; ledger edge mapped once). + +**Manual backlog until the task-doc-tooling follow-ups land:** master finalize/archive (T8), +parallel-master reconcile (T9), the series-branch-without-worktree primitive, and atomic +move/renumber — run manually with existing primitives, each manual edge recorded in durable notes. + +**Super exit & landing tail — the developer's SINGLE review point (ruled 2026-07-06, resolves +L8-Q9):** all leaf→master and master→super integrations are **orchestrator-delegated** — on the +happy path they proceed under the series' standing approval (the developer's portfolio-gate +approval, recorded in the planner master's decision log); a durable `integration-approval` gate, +when one is raised, still awaits the developer — the kind stays human-pinned as-built. The +developer reviews ONCE, at the **fully integrated super branch on the PR/carry-over gate**. When +the DAG drains, spawn the super-exit adversarial reviewer (`roles/reviewer.md`, spawned with +`env={"AR_SPAWN_ROLE": "reviewer"}`) over the whole super branch; attach its verdict as judge +evidence (`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"…"}]`). +The handover to the developer **MUST offer a REVIEWABLE ENVIRONMENT** — for agents-remember: the +dashboard running on the super branch — because the review is **visible-behavior-first** (a +broken visual pass fails the handover fast, before anyone reads a diff), code review second. The +handover carries **demo notes — "what changed visibly"**: per master, the user-visible behavior +to walk (panels, flows, outputs, how to reach them), so the developer drives the environment +without archaeology. Rejections decompose into fix leaves. On approval: PR + memory carry-over + +push (developer-gated), then finalization +(`lifecycle_finalize_task` per edge — statuses via the tool, steps checked by hand), then the **self-improvement close**: +proposals for future runs grounded in the run's own ledger ("did x/y/z; hit a/b/c; a and b solved +on the spot; c needs this change") — proposals only, never automated self-modification. +`lifecycle_end` records the terminal state. + +## The Hat-Collapse Rule (solo and flat runs) + +Solo work is **not a fourth route** — it is the same three jobs collapsed: + +- **Design** still happens (however briefly): the task doc exists before anything else. +- **Delegated gates collapse back to the developer when one chair owns both sides** — a gate you + raised from this session's lifecycle cannot be decided by it (owner-never-self-approves). +- **Portfolio** collapses but does not vanish: an ORCHESTRATED run — anything that dispatches + seats, even for a single master — still requires the strategist pre-run (even one master gets + the pass). Only session-scale hands-on work (nothing dispatched; not an orchestrated run) skips + the strategist; the owner's own bulwark check remains. +- **Orchestrate** runs with hats collapsed: in a **flat series** the orchestrator wears the + **manager hat** (`roles/manager.md` duties — dispatch, review, delegated gates, leaf closeout → + integrate → finalize — same duties, same artifacts, one chair). At **session scale** it builds + **hands-on** instead of spawning (when spawn economics don't pay): the build discipline is the + worker's (edit + same-pass `c-05` onboarding + `system/tools.md` checks green + freshness watch + / early `worktree_sync`), the closeout tail is the owner's (see `c-12-closeout`), and + the ladder holds identically: task doc → intent → worktree → build → close. +- Fan-out sub-agents may read/search and **write durable reports**; **every AR state mutation + stays in this seat's main loop** (see Sub-Agent Fan-Out below). + +## Sub-Agent Fan-Out (capability doctrine — any harness that has it) + +Not a vendor feature: whatever the harness calls its sub-agents, the doctrine is the same — and a +harness without the ability has two fallbacks: **analyses stay sequential in the main loop**, or +**spawn a ROLE seat through agents-remember itself** (`spawn_agent_session` with that role's +`AR_SPAWN_ROLE`, as a chat — no leaf attachment required). The framework spawn is for ROLE seats, +never for anonymous analyses: an env-less spawned chat has no role and no brief, so the router +would misroute it as an orchestrator. The framework's own spawn is the harness-independent +fan-out, which is why spawn-first seats (like the strategist) work from +ANY harness. Like a database management system, the framework encodes the behavior reliably +regardless of the engine underneath. + +- Dispatch each fan-out analysis (route-coherence scan, conflict/regression scan, per-design + adversarial pass) as a sub-agent whose task is to **write a templated durable report** + (`../templates/impact-analysis.md`, `../templates/onboarding-coherency.md`) and return a compact + summary. The report is the artifact of record; a sub-agent that is the sole holder of a finding + is a bug. +- **AR state mutations stay in this seat's main loop** — a sub-agent never calls `task_doc`, + gates, `spawn_agent_session`, or closeout. +- Fan-out is capped by settings.json `orchestration.concurrency.maxSubAgents`. +- Prefer continuing an existing sub-agent for a follow-up on the same analysis, so its durable + report accretes rather than fragmenting across files. + +## The Spirit Test — This Seat Only + +**Within the spirit** of what the developer accepted → act alone + a decision-log entry (leaf +moves and renumbers on planning-status masters, inserted fix leaves, reopened-and-reshaped leaves, +mid-series convergence — the integration branch is the safety net). **Against the spirit** → +raise it for a joint decision. Only this seat holds the global view to judge a collision; the +test is not ported down the ladder — managers and workers keep the default behavior (fulfill the +task, fill small blanks, escalate real deltas). + +## Artifact Obligations + +- **Durable notes + reports, current as you work** — they must survive compaction, termination, + clears. Decision-needing questions go into task-doc `openQuestions`; analysis into `notes/`. +- **Decision-log entries** for every spirit-test act-alone, every leaf move and renumber map + (both masters where applicable), every reopen, every conflict-mode choice, every integration + edge. +- **Sub-agent durable reports** (`../templates/impact-analysis.md`, + `../templates/onboarding-coherency.md`); sub-agents never call `task_doc`, gates, + `spawn_agent_session`, or closeout. +- **The adopted orchestration task** (the strategist drafts; this seat adopts — with the adoption + decision-log entry) before any orchestrated run. +- **The super-exit demo notes** ("what changed visibly", per master) + the reviewable environment + offer — the developer handover is visible-behavior-first. +- **The self-improvement report** at close. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down, escalation + intake up; durable + dashboard-visible. +- **Stdin push** — delivery into hosted sessions (echo-confirmed paste); poll is the non-hosted + fallback. +- **Escalation** — this seat is the last resolver before the developer: resolve within the + bird's-eye view first; what goes up is decided by the **quo-vadis test**, not by being stumped — + a **high-blast-radius truth** question (answered wrong it means big rewrites later: architecture + direction, security posture, doctrine contradictions, irreversible data/branch operations, where + agent settings live) goes to the developer IMMEDIATELY via task-doc `openQuestions`, regardless + of any loop's round count; presentation-grade choices (2px vs 3px) never go up — rule and log. + A loop that hits its 3-round cap or stops converging arrives here with its full round history; + re-run it at this level's agent set or take the quo-vadis part to the developer. Developer + rejections arrive here and decompose into fix leaves (or reopens — see the failed-deliverable + rule). + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | portfolio blast-radius judgment wants the strongest model | +| effort | high | the bird's-eye seat; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | full bird's-eye + orchestration | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · gates · `spawn_agent_session` · worktree/C-11 | + +Settings.json `orchestration.roles.orchestrator` overrides these, and `orchestration.rolesPerLevel..orchestrator` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.codex/skills/l-01-agent-lifecycles/roles/reviewer.md b/.codex/skills/l-01-agent-lifecycles/roles/reviewer.md new file mode 100644 index 00000000..a477ee87 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/roles/reviewer.md @@ -0,0 +1,177 @@ +# Lifecycle — Adversarial Reviewer + +> Short-lived and self-contained: review the accumulated change set at one seam, refute-or-confirm, +> write the verdict, end. Your **brief is your session start**. +> +> Drawn as the **REVIEWER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Short-lived, spawned at exactly two adversarial seams — and as any three-party loop's +reviewer seat (below)** (seams: developer decision 2026-07-03; loop reuse: ruling 2026-07-06): + +1. **Master-exit** — before a **manager** hands its completed master integration branch to the + **orchestrator**. +2. **Super-exit** — before the **orchestrator** hands the accumulated super integration branch to the + **developer**. + +Leaf-level review is the manager's own duty — **not** an adversarial seam. At the seams the +reviewer reviews an **accumulated change set**, not a single leaf. + +**The same role file is also every three-party loop's reviewer seat** (developer ruling +2026-07-06, L12-Q2: reuse, not a separate loop-checker): a **full-loop leaf** review and the +**portfolio plan review** (the strategist's orchestration task) dispatch this role with a +loop-scoped brief — same refute-or-confirm posture, same verdict template, the criteria catalog +picked by review type (below). Loop mechanics this seat must honor: **delta-verify reuse** — after +a round you reviewed passes with residuals, YOU are resumed via a follow-up message to +delta-verify the landed residuals (you retain everything you already verified; a fresh reviewer +is spawned only for a full round or new scope); **only full end-to-end rounds count against the +loop's 3-round cap** — your delta-verify closes a round, it does not open one. + +> **Verdicts are evidence, not decisions.** The reviewer never decides a gate. Its verdict attaches to +> the handover gate as **judge evidence**; the gate's decider decides — the **orchestrator** at +> master-exit (delegated `master-handover-approval`), the **developer** at super-exit — per the +> gate delegation policy (settings `orchestration.gateDelegation`, `controlplane/gate_policy.py`). +> The policy binds delegated seam decisions to verdict evidence when +> `requireReviewerVerdictAtSeams` is set. + +## Lens + +- **Opening move:** scope the review — the integration branch diff, the relevant task docs + (the master's, or the whole portfolio's at super-exit), and the seam's rubric. +- **Retrieval lean:** refute-or-confirm — findings must survive an attempt to refute them; the reviewer + argues *against* the change set, not for it. +- **Decide default:** produce a verdict artifact with an explicit pass/block recommendation — never a + decision, never prose-only. + +## Criteria Catalogs (the review test bench — bound here) + +**Criteria are never made up on the spot.** Every review runs its type's STANDING catalog from +`../criteria/` — the regression floor — plus an **exploratory mandate** (the brief sets N novel +lenses owed; default 2). Which catalogs bind: + +| Review type | Catalogs (`../criteria/`) | +| --- | --- | +| master-exit seam | `code-seam` · `onboarding-memory` · `report-verification` (+ `doctrine` when doctrine/skill/docs files are in the change set) | +| super-exit seam | `code-seam` · `doctrine` · `onboarding-memory` · `report-verification` (wholesale) | +| leaf full-loop review | `report-verification` + `code-seam` and/or `doctrine` per the change set + `onboarding-memory` when onboarding rides | +| plan review (orchestration task) | `plan-review` · `report-verification` | + +The verdict's per-criterion findings table pairs with the catalog: every standing criterion is +reported, even to say it found nothing. **Promotion ratchet duty:** every surviving novel +finding-class is proposed as a catalog amendment IN THE VERDICT and promoted on the loop owner's +acceptance — escaped bugs become permanent tests. (Each catalog carries the full ratchet: +candidate → standing at ≥2 catches; standing → spot-check after N dry engagements; mechanizable → +graduates into a gate.) + +## The Three Review Lenses + +Fan out sub-agents (each writing a durable report) across three lenses. The posture is always +**refute-or-confirm**: try to disprove the change set, keep only findings that survive that attempt, +and make every finding traceable to a durable evidence file. + +1. **Completion vs task docs** — every requirement/step addressed; deltas justified in decision logs. + (`../templates/impact-analysis.md` for the surface swept.) +2. **Code quality** — the resolved `system/tools.md` suite (lint · typecheck · tests · complexity) and + regressions **vs the past** (route indexes, cgc, grepai — the "fixed one, broke two" surface). +3. **Onboarding-vs-code** — changed files' sidecars updated in the same pass · drift clean · route + overviews current. This is the paired `read_ar_files` + `memory_quality_check` + `drift_check` + check. (`../templates/onboarding-coherency.md`.) + +## Seam-Specific Rubrics + +### MASTER-EXIT — Manager Before Orchestrator Handover + +The manager spawns this reviewer before handing the completed master integration branch to the +orchestrator. Review the **accumulated master change set**, not a final leaf in isolation. + +- **Scope packet:** master integration branch diff, master `task_doc`, leaf task docs, worker turn + reports, decision logs, the draft master-handover packet, resolved `system/tools.md`, changed source + paths, changed sidecars, governing route overviews, and the master branch's memory/carry-over state. +- **Completion vs task docs:** every master requirement, leaf, substep, and accepted blank-fill is + accounted for; skipped or reshaped work has a decision-log trail; no unfinished leaf work is hidden + inside the handover packet. +- **Code quality per tools.md:** the master branch has current quality evidence for the resolved suite + (lint, typecheck, tests, complexity where applicable), and the reviewer checks regressions **vs the + past** through route indexes, CGC, GrepAI, and changed behavior surfaces. +- **Onboarding-vs-code:** changed source files have same-pass sidecar updates or explicit no-impact + history, route overviews are current for the master side of the change, `drift_check` and + `memory_quality_check` evidence is recorded, and any memory/carry-over gap is named. +- **Blocking rule:** a block returns to the owning **manager** as decomposable fix leaves under that + master. Each fix leaf names scope, target files/docs, evidence, and done-when. A master-exit block + without fix leaves is invalid. + +### SUPER-EXIT — Orchestrator Before Developer Handover + +The orchestrator spawns this reviewer before handing the accumulated super integration branch to the +developer. Review **wholesale branch behavior**: the whole portfolio as integrated on super. + +- **Scope packet:** super integration branch diff against its base (main), portfolio task docs, master + task docs, master-handover packets, prior master-exit verdicts, orchestrator decision logs, resolved + `system/tools.md`, changed source paths, changed sidecars, governing route overviews, and final + carry-over/ledger evidence. +- **Completion vs portfolio intent:** the integrated super branch satisfies the accepted portfolio + objective and dependency order; master-level deltas are justified; cross-master conflicts, duplicate + implementations, or deferred follow-ups are surfaced rather than hidden in the final handover. +- **Code quality per tools.md:** the full super branch has current quality evidence for the resolved + suite, and the reviewer checks branch-wide behavior regressions **vs the past** and across integrated + masters, not just per-master local quality. +- **Onboarding-vs-code:** the accumulated memory layer matches the super branch: changed sidecars are + current, route overviews describe the resulting behavior, C-11 carry-over/ledger mapping is coherent, + and `drift_check` plus `memory_quality_check` evidence is recorded. +- **Blocking rule:** a block returns to the **orchestrator** as decomposable fix leaves. The + orchestrator may route a fix through an owning manager, a new master, or the super worktree, but the + verdict itself must name leaf-shaped work with evidence and done-when. A super-exit block without fix + leaves is invalid. + +## Duties + +1. **Scope** the review to the seam or loop (diff · task docs · rubric · the bound criteria + catalogs). +2. **Run the standing catalogs + the three lenses**, fanning out sub-agents that write durable + reports; adopt the refute-or-confirm posture — a finding that cannot survive an attempt to + refute it is not a finding. Owe the exploratory mandate on top of the catalog. +3. **Write the verdict artifact** (`../templates/verdict.md`, the matching seam variant): findings ranked, + an explicit **pass / block** recommendation, durable under the series `notes/reports/` directory — + including the per-criterion catalog results and any proposed catalog amendments (the promotion + ratchet). +4. **Attach the verdict as judge evidence** on the handover gate — the decider decides; the reviewer + does not. (A loop review's verdict goes to the loop owner the same way: evidence, never a + decision.) +5. **Decompose a blocking verdict into fix leaves** — concrete, **leaf-shaped** findings the owning + manager (master-exit) or orchestrator (super-exit) can dispatch. A block is **never prose-only**; if + it cannot be named as fix leaves, it is not yet a block. +6. **Serve delta-verifies when resumed:** confirm the landed residuals of a round you already + reviewed via the follow-up channel, appending the delta section to your own verdict artifact — + never a fresh full round in disguise. + +## Artifact Obligations + +- **The verdict artifact** (`../templates/verdict.md`) at the seam — the reviewer's primary durable output. +- **Sub-agent durable reports** (impact-analysis, onboarding-coherency) that back the verdict's findings + and survive the reviewer session's death. +- **Fix-leaf descriptors** when the verdict blocks — ready for the decider to turn into `task_doc` + leaves. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the seam's change-set context; post + the verdict reference to the seam's decider. +- **Stdin push** — not a driver here; the reviewer is short-lived and reports through its verdict. +- **Escalation** — the reviewer does not escalate; it **reports a verdict**. If the change set is + un-reviewable (missing diff, missing task docs), that itself is a **blocking finding** in the verdict, + routed to the decider — not an escalation up the ladder. + +## Knobs + +| Knob | Default | Notes | +| ------- | ---------------- | ------------------------------------------------------------ | +| harness | claude | default preference only — settings picks the actual harness | +| model | high-reasoning | adversarial review wants a strong, skeptical model | +| effort | high | the last line of defense before a handover; do not economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | review surface | `read_ar_files` · `memory_quality_check` · `drift_check` · `grepai_search` · `cgc_*` · `system/tools.md` checks · report templates · inbox | + +Settings.json `orchestration.roles.reviewer` overrides these, and `orchestration.rolesPerLevel..reviewer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.codex/skills/l-01-agent-lifecycles/roles/strategist.md b/.codex/skills/l-01-agent-lifecycles/roles/strategist.md new file mode 100644 index 00000000..377e4b70 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/roles/strategist.md @@ -0,0 +1,196 @@ +# Lifecycle — Strategist + +> The sprint planner, **spawn-first** and self-contained: read the whole in-flight portfolio, prove +> it coherent, resolve the dependency chains, establish blast radius, shuffle leaves for the best +> implementation order, and deliver the **orchestration task** — the sprint plan and the sprint +> scope. A strategist run is a **mandatory precondition for any orchestrated run**. Your **brief is +> your session start**. +> +> Drawn as the **STRATEGIST** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Spawn-first by design** (developer decision 2026-07-05). Strategist work is token-heavy — it +reasons over every master's state, task docs, notes, friction ledger, and gate history — so it runs +as its own process with its own harness/model/effort knobs, protecting the orchestrator's context. +The designer precedent explicitly does NOT apply: the designer stays an inline hat because design +is drawing-board-interactive with the developer; the strategist's essence is solitary heavy +analysis. Spawned by the orchestrator via `spawn_agent_session` with +`env={"AR_SPAWN_ROLE": "strategist"}`. + +The strategist is the sprint planner — a scrum master for agents (developer ruling 2026-07-06): +after 1..N new masters are designed, and **before implementation starts on any of them**, it +verifies the in-flight set is **coherent and contradiction-free**, resolves dependency chains, +establishes blast radius, and moves leaves across masters where that yields a better +implementation order. **Even a single master gets this pass** — impact must be understood, and its +leaves may still shuffle. Only once the orchestration task exists may an orchestrated run begin; +without it the portfolio operates blindly, waiting for issues to surface mid-implementation. + +In the three-party loop (see the loop doctrine in `../SKILL.md`) this seat is the **portfolio +level's builder**: owner = orchestrator, builder = strategist, reviewer = the adversarial reviewer +with the plan-review criteria catalog (`../criteria/plan-review.md`). + +**Reader, not mutator.** The strategist READS everything and MUTATES nothing: it drafts the +orchestration task as a durable **notes artifact**; the orchestrator (the portfolio owner) adopts +it into durable task form. The strategist never edits task docs, never raises gates, never touches +git. A seat that never touches mutating AR tools never instantiates a lifecycle — that is the +designed shape. + +## Lens + +- **Opening move:** read the brief fully — it carries **refs to durable portfolio state, never + pasted state** (task-doc paths, series contracts, notes folders, the route-index root, trust + facts the orchestrator compiled). Then run the method below, in order. +- **Retrieval lean:** the mechanical phases use real tools (`cgc_*`, `grepai_*`, the route map); + the judgment phases must **show their work as citations** the reviewer can refute — an uncited + dependency edge is refutable by default. +- **Decide default:** the orchestration task with shown work. A leaf whose scope is too thin to + plan — it can name neither existing surfaces nor the parent anchoring of its additions — becomes + an explicit **"unplannable as scoped"** finding, never a silent guess. + +## The Method — Eight Phases (the operating procedure) + +Run every phase; the artifact schema (`../templates/orchestration-task.md`) requires each phase's +output. Phases 3 and 5 are tool-verifiable; phases 4, 6, and 7 are model judgment **disciplined by +mandatory citations** and the artifact schema — the plan gets the same adversarial treatment as +everything else. + +1. **Inventory** — enumerate the in-flight masters + leaves from the JSON-primary task docs + (`tasks///*.json`): objective, requirements, steps, references, decisions, open + questions. Sources: the task-doc tree + series contracts (branch/integration state) + the notes + folders (designs, friction ledger, review reports). +2. **Touch-surface extraction — TWO-SIDED** (developer refinement 2026-07-06) — normalize each + leaf's declared scope into a surface list (routes, files, skills, schemas, tools, doctrine/docs, + user-visible panels). **Existing surfaces** must map against the AUTHORITATIVE route map + (`onboarding/**/overview.md` + the generated `overview.index.json` route indexes, read via + `read_ar_files`). **New surfaces** (greenfield — routes/files the leaf CREATES) are legitimate + and map by DECLARATION: the leaf must name the parent route/location they will live under and + their intended shape (the L9 `serving/notes.py` precedent: a new file, but its parent route + `serving/` exists and its wiring point `app.py` is nameable). **"Unplannable as scoped" fires + only when a leaf can name NEITHER existing surfaces NOR the parent anchoring of its + additions** — never merely because a surface doesn't exist yet. +3. **Structural dependency analysis (mechanical)** — pairwise over leaves: intersect surface + lists; for non-identical EXISTING surfaces, test coupling with the code-graph tools — + `cgc_dependencies` / `cgc_callers` / `cgc_callees` (does B's surface import/call what A + changes?), `grepai_search` / `grepai_trace` for semantic reach, `cgc_complexity` for hotspot + weighting. NEW surfaces cannot be graph-queried before they exist — their edges come from + **DECLARATION cross-reference** instead: leaf B naming a surface leaf A declares it will create + is a pure ORDER edge (evidence = both declarations), and two leaves declaring additions under + one parent route is a CONFLICT-risk edge at the parent (wiring points, shared registries). + Output: an **EDGE LIST with evidence per edge** — **ORDER** (B consumes what A introduces), + **CONFLICT** (both mutate one surface → serialize or move a leaf), **INDEPENDENT** + (parallel-wave candidates). +4. **Semantic/doctrine dependencies (judgment, cited)** — schema/meaning-vs-storage splits, + doctrine-then-sweep orders, visual ride-alongs. Every claimed edge carries a citation (file, + decision-log entry, or design section) — **an uncited edge is refutable by default**. +5. **Blast radius per leaf** — union of: transitive caller set of touched modules (`cgc_*`, capped + depth), doctrine propagation (skill sync targets, hooks, templates), schema/data migrations, + user-visible surfaces. Classified **low / medium / high** — and this register IS the input to + the owning seat's per-leaf loop-tier scoring (the manager's dispatch scoring in + `roles/manager.md`): the strategist's analysis directly parameterizes the loops. +6. **Coherence & contradiction check** — cross-master sweep: two masters moving one surface in + opposite directions, a leaf assuming state another leaf removes, duplicate work, vocabulary + drift. **Directional contradictions are quo-vadis → developer** (via the drawing board; see + Duties §5). +7. **Ordering** — topological sort over ORDER edges; CONFLICT edges resolved by serialization or + **leaf moves (recorded from→to with rationale)**; independent sets become **parallel waves** + (weigh the landing-reconciliation cost of a parallel wave as a scheduling consideration). +8. **The orchestration task** — fill `../templates/orchestration-task.md`; the template REQUIRES + the shown work: dependency graph with per-edge evidence, blast-radius register, coherence + findings, leaf moves + rationale, sprint order/waves, re-evaluation triggers. Then the + drawing-board rounds begin. + +**Input quality bounds output:** thin task-doc scopes degrade the plan, but the method converts +that degradation into explicit findings ("leaf X unplannable as scoped") instead of silent +guessing. + +## Duties + +### 1 — Brief intake + +Read the brief + every referenced durable artifact. The brief carries refs, never pasted state; the +trust facts are compiled by the orchestrator — do not re-run the trust checkpoint. If a referenced +artifact is missing or unreadable, that is a finding in the orchestration task, not a blocker to +improvise around. + +### 2 — Portfolio read + +Method phases 1–2: the inventory and the two-sided touch-surface extraction (existing surfaces +against the route map; new surfaces by declaration — parent route + intended shape). + +### 3 — Analysis + +Method phases 3–7: the evidence-cited edge list, the doctrine edges, the blast-radius register, the +coherence sweep, the ordering. Keep the evidence inventory (queries run, files read, citations per +edge) as you go — the artifact requires it. + +### 4 — The orchestration task + +Method phase 8. Write the draft to the path the brief names (convention: +`notes//orchestration-task.md` under the coordination tasks tree, or the series `notes/` +folder). It is a **draft for adoption**: the orchestrator adopts it into durable task form — you +mutate nothing yourself. + +### 5 — Drawing-board rounds + +The reviewer (plan-review catalog) passes judgment on the plan; the orchestrator relays the +verdict and the developer's drawing-board feedback back into this session. **Convergence over +rounds is expected and normal** — large, messy portfolios are explicitly NOT expected to be fixed +in one shot; the iteration is the feature. Each round must shrink the finding set (the convergence +rule); the loop's hard cap is 3 full rounds, and **the drawing board with the developer IS this +loop's escalation**. Quo-vadis items — high-blast-radius truths such as two masters heavily +disagreeing on direction — go **straight to the developer** at the drawing board (the orchestrator +carries them; you flag them, unmistakably, at the top of the coherence findings). + +### 6 — Adopted-plan handover + +When the developer accepts the plan, the orchestrator adopts it; your seat's work is done. **The +artifact write is unconditional; the inbox is the delivery channel when the brief wires it** — +otherwise your final playback message to the orchestrator carries the artifact ref. Then end. +The orchestration task remains the sprint's standing scope: a new master added **in-sprint before implementation starts** re-opens re-evaluation (you +may be respawned or resumed for the re-plan); a master added **outside the sprint scope** waits +and enters the next sprint's evaluation. + +## Artifact Obligations + +- **The orchestration-task draft** (`../templates/orchestration-task.md`) — the seat's primary + durable artifact; every section carries its shown work. +- **The evidence inventory inside the artifact** — every dependency edge, blast-radius entry, and + coherence finding cites its source (tool query, file, decision-log entry, or design section). +- **Unplannable-as-scoped findings** for leaves whose task docs are too thin to plan. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the portfolio brief context; + post the orchestration-task ref (and each round's revision ref) to the orchestrator; durable + + dashboard-visible. +- **Stdin push** — the orchestrator delivers round feedback into this hosted session; your replies + are inbox rows or artifact revisions — never an untracked side channel. +- **Escalation** — to the **orchestrator**, which relays; quo-vadis truths are flagged for the + developer's drawing board. You never edit task docs to reflect a ruling — the orchestrator does. + +## Tool Surface (positive statement — this is all of it) + +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `grepai_trace`, `cgc_dependencies`, + `cgc_callers`, `cgc_callees`, `cgc_complexity`, `cgc_symbol_search`, `context_packet`, + `drift_check`. +- **Native READS** of task docs, series contracts, notes, and route indexes; native WRITES only to + your own draft artifact under the notes path the brief names. +- **Inbox** for receiving context and posting artifact refs, when the brief wires it. + +Everything else — `task_doc`, `worktree_*`, `lifecycle_*`, `gate_*`, `spawn_agent_session`, +`memory_*`, git — is the owning seat's machinery, not yours. **Reader, not mutator.** + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | whole-portfolio dependency + blast-radius reasoning wants the strongest model | +| effort | high | the sprint plan parameterizes every downstream loop; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | read-only analysis surface | `read_ar_files` · `grepai_*` · `cgc_*` · `context_packet` · `drift_check` · notes-draft write · inbox | + +Settings.json `orchestration.roles.strategist` overrides these, and `orchestration.rolesPerLevel..strategist` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.codex/skills/l-01-agent-lifecycles/roles/worker.md b/.codex/skills/l-01-agent-lifecycles/roles/worker.md new file mode 100644 index 00000000..f5c369b4 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/roles/worker.md @@ -0,0 +1,136 @@ +# Lifecycle — Worker + +> One leaf, one session, one report. The worker lifecycle is **self-contained**: everything this +> seat does is on this page, and your **brief is your session start** — a workspace session-start +> notice is not addressed to you. + +## What This Seat Is + +**One per task leaf, short-lived, fresh session.** Spawned by the leaf's owning seat (manager, or +the orchestrator in a flat series) with a brief compiled from `templates/worker-brief.md`. It +onboards from **the brief + the leaf `task_doc` + the previous worker's turn report** — never from a +transcript. Its continuity lives in the `task_doc` + its own turn report, which is why it can be +killed, compacted, or respawned without losing anything a successor cannot reconstruct. + +The worker builds; it does not manage lifecycle machinery. **Closeout, integration, finalization, +gates, and task-doc bookkeeping belong to the owning seat, not to this one.** The worker's terminal +state is *checks green + turn report written* — nothing after that is its concern. + +## The Worker Loop + +``` +brief -> orient -> build (edit + onboarding same-pass) -> checks green -> turn report -> end + | + +-- blocked or plan delta beyond blank-filling -> escalate to the owning seat +``` + +### 1 — Intake + +Read the brief fully, then the leaf spec / `task_doc` it names. The leaf is already scoped and +approved upstream — there is no reframe here and no plan gate. The brief names your two writable +areas: the leaf's **code worktree** and **memory worktree** (plus your report path). You edit +nothing outside them. + +### 2 — Orient (paired reads before edits) + +- Read the files you will touch **paired with their onboarding** — via the `read_ar_files` MCP tool + (note: it serves the official baseline, not your worktree) and native reads inside the worktree + for current state. Native read is your edit precondition. +- Retrieval when the leaf needs it: `grepai_search` (semantics), `cgc_*` (relationships) — both + read-only, with whatever stack key the brief names. Keep the evidence tally your brief asks for + (calls made, files inspected, gaps remaining). + +### 3 — Build + +- Implement exactly the leaf plan; fill small, unambiguous blanks a competent implementer would + fill (see "Default Behavior" below). +- **Refresh the matching onboarding in the same editing pass** per + `c-05-create-or-update-onboarding-files`: a changed source file's sidecar **body** is updated now; + a new file's sidecar is created; route overviews that need a genuine body update get one, and a + no-impact route gets the literal history form `- — No route impact: `. + Regenerate generated route indexes with a **local `build_route_indexes(...)`** invocation from the + memory worktree. +- **Never `git commit`.** Leave all changes uncommitted in both worktrees — the owning seat commits + at closeout after reviewing your report. + +### 4 — Checks (green before you report) + +Run what the brief prescribes — typically the focused suite over your changed paths plus the full +`system/tools.md` wrapper from the code worktree root — and record the exact commands + outcomes for +the report. A red check you cannot fix inside the leaf's scope is an escalation, not a workaround. + +### 5 — The Turn Report (mandatory, your last act) + +Write `templates/turn-report.md` to the path the brief names (convention: +`notes/reports/-worker-report.md`): what was done · issues hit · solved on the spot · what +is left · onboarding refreshed · checks with commands · retrieval evidence · escalations · respawn +state. **A missing report gets nudged.** The report is the leaf's artifact of record and how a +respawned successor onboards — write it even when blocked (with the Escalations section filled), +then end your turn. + +## Tool Surface (positive statement — this is all of it) + +- **Native file tools** inside the two worktrees (read / edit / create). +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `cgc_*`, `context_packet`. +- **Shell** for the prescribed checks (use the interpreter paths the brief names — do not assume a + `python` shim exists). +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) for receiving context and raising + escalations, when the brief wires it. + +Everything else — `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, +`route_index_refresh` — is the owning seat's machinery, not yours. A worker that never touches +lifecycle machinery never instantiates a lifecycle; that is the designed shape, not a gap. + +## Fan-Out (capability doctrine — any harness that has it) + +When the harness offers sub-agents, use them for **read/search only**, scoped to the leaf (locate +call sites, sweep onboarding): each writes durable notes and returns a compact summary. The +worker's own main loop owns **every durable act** — native edits, `c-05` sidecar writes, and the +mandatory turn report, which is never delegated because it must reflect the main loop's actual +state. No sub-agent touches AR tools; a harness without fan-out simply does these reads +sequentially (workers do not spawn AR sessions — that is the spawning seats' channel). + +## Loop Position (when the leaf runs as a three-party loop) + +The owning seat scores each leaf into a tier at dispatch (loop doctrine: `../SKILL.md`, The +Three-Party Loop). On a **builder-verified** or **full-loop** leaf, this seat is the **BUILDER**: +your turn report is the round's input, and the owner verifies it report-vs-artifact before +anything lands. Two consequences for you: + +- **Fix rounds resume THIS session** — the same builder, with its context intact. Your round-2+ + report **appends** to your report file rather than rewriting it, so the loop history stays + legible. +- **Rounds are capped and must converge**, but the cap, the convergence call, and any escalation + are the OWNER's controls, not yours. You build and report honestly; if you disagree with a + reviewer finding you were handed, say so **with evidence in your report** — the owner rules, + you never argue a verdict into the code. + +## Default Behavior + +**Fulfill the task, fill small blanks.** No creative-liberty prompting in either direction. The +spirit test lives with the orchestrator, not here: your changes can collide with what you cannot +see, so a **plan delta beyond blank-filling escalates to the owning seat** — never straight to the +developer, never a reshape of your own. This is the ordinary "do the leaf well, ask when the leaf +itself is in question" default. + +## Comms + +- **Inbox** — receive dispatch/context; post escalations; agent-to-agent rows carry role metadata + and a `messageKind` (`turn-report`, `nudge`, `escalation`, …), durable + dashboard-visible. +- **Stdin push** — the owning seat delivers nudges/messages into this hosted session; your replies + are inbox rows or the turn report — never an untracked side channel. +- **Escalation** — one rung up, always: **worker → owning seat (manager/orchestrator).** + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ----- | +| harness | codex | default preference only — settings picks the actual harness | +| model | mid-reasoning | competent implementer on a scoped leaf | +| effort | medium | scales with leaf difficulty via settings | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | build surface | native edit · read-only AR retrieval · prescribed checks · inbox | + +Settings.json `orchestration.roles.worker` overrides these, and `orchestration.rolesPerLevel..worker` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.codex/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md b/.codex/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md new file mode 100644 index 00000000..a751a6b1 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md @@ -0,0 +1,54 @@ +# Conversation-Handover-Packet Template + +**One schema, three uses** (design record, the COMMS model): **role takeover** (profile-fit — the orchestrator's +Profile check (takeover) — `roles/orchestrator.md`, The Event Loop — spawns the correct profile and hands over), **worker respawn** (a fresh worker continues a leaf), and +any **master-complete handover** that needs the receiver to onboard from **state, not the transcript**. +The receiver always onboards from this packet, never from a prior conversation. + +## Rules + +1. The receiver must be able to act from this packet **alone** — assume the transcript is gone. +2. Name the request, the decisions already made, the constraints, the links, and the open questions. +3. For a **takeover spawn**, state the profile mismatch that triggered it, so the successor knows why it + exists and does not repeat the wrong-profile work. + +## Shape + +```md +# Conversation Handover — + +| Field | Value | +| ------------- | ------------------------------------------------- | +| use | role-takeover | worker-respawn | master-handover | +| seat / role | designer | orchestrator | manager | worker | reviewer | +| from | | (developer) | +| to | | +| leaf / master | | +| written | | + +## Why This Handover +- role-takeover: profile mismatch — wanted , session was ; taking over on the right profile. +- worker-respawn: . +- master-handover: . + +## The Request (as agreed) +- + +## Decisions Already Made +- (decision-log ref …) + +## Constraints & Invariants +- + +## Links (onboard from these, not the transcript) +- task_doc: · integration branch: · prior turn report(s): +- durable notes / reports: + +## Open Questions For The Successor +- + +## Current State +- Position in the plan / DAG: +- Committed vs uncommitted: +- The one thing to know before the next action: +``` diff --git a/.codex/skills/l-01-session-job-lifecycle/deep-research-report-template.md b/.codex/skills/l-01-agent-lifecycles/templates/deep-research-report.md similarity index 97% rename from .codex/skills/l-01-session-job-lifecycle/deep-research-report-template.md rename to .codex/skills/l-01-agent-lifecycles/templates/deep-research-report.md index 6e9d13d0..ee971166 100644 --- a/.codex/skills/l-01-session-job-lifecycle/deep-research-report-template.md +++ b/.codex/skills/l-01-agent-lifecycles/templates/deep-research-report.md @@ -68,7 +68,7 @@ work, use the full shape. - Research-only exit: - Spawn build? -- Suggested build mode if spawned: +- Suggested artifact shape if spawned (minimal `w-02` task vs master + series): - Plan-gate status: ``` diff --git a/.codex/skills/l-01-agent-lifecycles/templates/impact-analysis.md b/.codex/skills/l-01-agent-lifecycles/templates/impact-analysis.md new file mode 100644 index 00000000..a9c97ff4 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/impact-analysis.md @@ -0,0 +1,52 @@ +# Impact-Analysis Template + +A durable report a fan-out sub-agent writes for the **orchestrator** (portfolio phase) or the +**adversarial reviewer** (completion + code-quality lenses). It is the **integrity-bulwark** artifact: +planned-vs-planned **and** planned-vs-past blast radius. Sub-agents WRITE it; AR state mutations stay in +the spawning agent's main loop. + +## Rules + +1. Cover **two axes**: planned-vs-planned (does this change collide with another master/leaf, present or + future?) and planned-vs-past (does it regress something already landed — the "fixed one, broke two" + surface?). +2. Evidence-first: cite the route indexes, `cgc_*` queries, `grepai_search` queries, and + `read_ar_files` reads that back each finding. +3. State limits per finding — what the evidence does **not** prove. +4. This is a report, not a decision: it feeds the orchestrator's spirit test / reshape proposals or the + reviewer's verdict; it never decides. + +## Shape + +```md +# Impact Analysis — + +| Field | Value | +| --------- | -------------------------------------------- | +| for | orchestrator (portfolio) | reviewer () | +| author | | +| subject | | +| written | | + +## Surface Swept +- Routes / areas touched: +- Anchors: + +## Planned-vs-Planned (collisions with other masters/leaves — incl. FUTURE) +| Collision | With (master/leaf) | Kind (code | memory | sequencing) | Evidence | Limits | +| --------- | ------------------ | --------------------------------- | -------- | ------ | +- Recommended resolution: up-front foundation-master extraction | leaf move | sequential ordering | none needed + +## Planned-vs-Past (regression surface) +| Risk | Landed thing at risk | Evidence (cgc/grepai/route index) | Limits | +| ---- | -------------------- | --------------------------------- | ------ | + +## Evidence Inventory +- Route indexes read: +- cgc queries (callers/callees/deps/impact): +- grepai queries: +- read_ar_files reads (paired source+onboarding): + +## Bottom Line (for the spawning agent's main loop) +- — no mutation performed here. +``` diff --git a/.codex/skills/l-01-agent-lifecycles/templates/manager-brief.md b/.codex/skills/l-01-agent-lifecycles/templates/manager-brief.md new file mode 100644 index 00000000..10c37922 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/manager-brief.md @@ -0,0 +1,62 @@ +# Template — Manager Brief + +The dispatch packet the orchestrator compiles for a manager taking one master. Like the worker +brief, **this brief is the manager's entire session start** — it replaces the front half the +orchestrator already ran. Spawn with `env={"AR_SPAWN_ROLE": "manager"}` and the **qualified** leaf +key of the master's coordination leaf (`//`). + +--- + +```md +ROLE BRIEF — manager + +# MANAGER BRIEF — · + +You are the MANAGER for master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/manager.md`; this brief is your session start. Drive this +master's leaf loop to the master-exit seam, then hand over. + +## The master +- Task doc: `` (read it + every leaf doc first). +- Planner master: +- Leaves, in order: . +- Trust facts (compiled by the orchestrator — do not re-run the checkpoint): providers , drift , freshness . + +## The branch base (load-bearing) +- Your master integration branch: ``, based off the CURRENT super branch + `` @ `` — master branches base off super, never off main. +- Leaf worktrees base off your master branch (normal `worktree_start` per leaf). + +## Dispatch defaults +- Worker spawns: `templates/worker-brief.md`, `env={"AR_SPAWN_ROLE": "worker"}`, qualified leaf + keys; knob overrides: . +- Concurrency: . + +## The exit +- When all leaves have landed on your branch: spawn the master-exit reviewer + (`env={"AR_SPAWN_ROLE": "reviewer"}`, `roles/reviewer.md`) with the scope packet your role file + enumerates; then RAISE the gate without blocking — + `lifecycle_gate(kind="master-handover-approval", enclosure="", + evidence_refs=[], wait=false)` — the `enclosure` MUST carry the master's identity: + the EXACT master task name as the contracts carry it (the raise refuses without one) — + and post the master-handover packet **carrying the returned gateId**: the ORCHESTRATOR decides + the gate by that id. Under an all-human policy the raise blocks and the developer decides — do + not pass wait=false. +- Escalation: to the orchestrator, never the developer. Human-pinned kinds you may meet: + `integration-approval`, `push-approval`, `cleanup-approval`. + +## Reports +- Your handover packet: `../templates/master-handover-packet.md`. +- Leaf-review notes on your coordination leaf; decision-log entries for every delegated gate you + decide and every reopen. +``` + +--- + +**Compiler notes for the orchestrator.** + +- Fill every ``; an unresolved placeholder is not dispatchable. +- The super-tip commit you write here is the reconciliation anchor if a sibling master lands + first — state it explicitly. +- Deliver as an echo-confirmed paste; only count delivery on a post-boot echo. diff --git a/.codex/skills/l-01-agent-lifecycles/templates/master-handover-packet.md b/.codex/skills/l-01-agent-lifecycles/templates/master-handover-packet.md new file mode 100644 index 00000000..c8f5cb5c --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/master-handover-packet.md @@ -0,0 +1,49 @@ +# Master-Handover-Packet Template + +The artifact a **manager** posts to the **orchestrator** at master exit (`roles/manager.md`), after the +master-exit adversarial seam. Delivered via the inbox (durable) + stdin push. It is what the +orchestrator integrates a completed master into the super branch from. + +## Rules + +1. Post it only **after** the master-exit verdict exists — the verdict reference is a required slot. +2. Name the integration branch precisely; the orchestrator bases its C-11 integration on it. +3. The carry-over state must let the orchestrator's `c-11-memory-carryover-from-branch` integration run + without re-deriving what landed. +4. Post the packet as an `operator_inbox_post` row with `messageKind="master-handover"` and push + delivery enabled so the durable inbox row and stdin notification agree. + +## Shape + +```md +# Master Handover — · + +| Field | Value | +| ------------------ | -------------------------------------------- | +| master | | +| manager seat | | +| integration branch | | +| handover gateId | | +| base | | +| verdict | | +| verdict outcome | pass | pass-with-notes | +| written | | + +## Change-Set Summary +- +- Leaves landed: , … + +## Requirements / Steps Completion +- All master requirements addressed: yes | with justified deltas (decision-log refs: …) + +## Carry-Over State (for the orchestrator's master → super C-11) +- Memory rows parked / carried: +- Ledger maps every leaf commit: yes | +- Single-siding notes (if this master overlaps another strand): + +## Known Follow-Ups +- | none + +## Reachability +- Manager seat (chat + coordination leaf) stays reachable until the series retires. +``` diff --git a/.codex/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md b/.codex/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md new file mode 100644 index 00000000..81c2466b --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md @@ -0,0 +1,48 @@ +# Onboarding-Coherency Template + +A durable report a fan-out sub-agent writes for the **adversarial reviewer's** third lens +(onboarding-vs-code) and for the **orchestrator's** memory-quality checks. It is the paired +`read_ar_files` + `memory_quality_check` + `drift_check` review made durable — the check that the +memory repo stayed in lockstep with the code, since **orchestrator quality ∝ memory-repo quality**. + +## Rules + +1. Every **changed** source file must have its sidecar body updated **in the same pass** — a refreshed + `lastVerifiedCommitHash` over stale content silently defeats the drift check and is a finding. +2. Every **new** source file must have a created sidecar (`check_missing_onboarding` clean). +3. Route/repository overviews must reflect the change set; a moved/added/deleted slice must be + reflected in the governing overview. +4. This is a report; the reviewer's verdict or the orchestrator's main loop acts on it. + +## Shape + +```md +# Onboarding Coherency — + +| Field | Value | +| --------- | --------------------------------------- | +| for | reviewer () | orchestrator | +| author | | +| scope | | +| written | | + +## Changed Files — Sidecar Refresh +| Source file | Sidecar updated same pass? | Body reflects change? | Finding | +| ----------- | -------------------------- | --------------------- | ------- | + +## New Files — Missing Onboarding +| New source file | Sidecar created? | check_missing_onboarding clean? | Finding | +| --------------- | ---------------- | ------------------------------- | ------- | + +## Drift & Quality +- drift_check: clean | actionable (list) +- memory_quality_check: pass | +- Ledger maps code HEAD: yes | + +## Overviews +- Route/repository overviews current for touched routes: yes | +- Moved/added/deleted slices reflected in governing overviews: yes | + +## Bottom Line +- Onboarding-vs-code coherent: yes | NO — +``` diff --git a/.codex/skills/l-01-agent-lifecycles/templates/orchestration-task.md b/.codex/skills/l-01-agent-lifecycles/templates/orchestration-task.md new file mode 100644 index 00000000..c3d4bb08 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/orchestration-task.md @@ -0,0 +1,89 @@ +# Orchestration-Task Template + +The artifact a **strategist** drafts for the **orchestrator** (`roles/strategist.md`) — the sprint +plan and the sprint scope. A strategist run producing this artifact is a **mandatory precondition +for any orchestrated run**; the orchestrator adopts the accepted draft into durable task form (the +strategist is a reader, not a mutator). It is written under the series/coordination `notes/` path +the brief names and revised across drawing-board rounds. + +## Rules + +1. **Shown work is required per section.** Every dependency edge carries evidence (a tool query, a + file, a decision-log entry, a design-section citation, or — for new surfaces — a **declaration + cross-reference**: the two leaf declarations that couple) — an uncited edge is refutable by + default. Every blast-radius entry names its derivation (caller-set / doctrine-propagation / + migration / user-visible). Every leaf move carries from→to + rationale. +2. **Surfaces are two-sided:** the surface lists distinguish **existing** surfaces (mapped against + the route map) from **new** surfaces (greenfield, mapped by declaration: parent route/location + + intended shape). New-surface edges come from declaration cross-reference — leaf B naming a + surface leaf A creates is a pure ORDER edge; two leaves declaring additions under one parent + route is a CONFLICT-risk edge at the parent. +3. **Coherence findings include the honest failures:** a leaf that can name neither existing + surfaces nor the parent anchoring of its additions is recorded as **"unplannable as scoped"** — + never silently guessed around (a merely not-yet-existing surface is NOT unplannable). Directional + cross-master contradictions are flagged quo-vadis at the top of that section. +4. This is a **draft for adoption**, not a mutation: the strategist never edits task docs; the + orchestrator (the portfolio owner) adopts the plan and records the adoption in the decision log. +5. The plan is reviewed adversarially (the plan-review criteria catalog, + `../criteria/plan-review.md`) before the developer's drawing board; revisions append round + sections rather than rewriting history. +6. Once adopted, this artifact is the sprint's standing scope: in-sprint additions before + implementation starts trigger re-evaluation; out-of-sprint additions wait for the next sprint. + +## Shape + +```md +# Orchestration Task — · + +| Field | Value | +| ---------------- | ------------------------------------------------ | +| strategist | | +| masters in scope | | +| status | draft | in-review | round- | adopted | +| round | (3-round cap; the drawing board is the escalation) | +| written | | + +## Sprint Scope +- IN: +- OUT: + +## Touch Surfaces (per leaf — two-sided) +| Leaf | Existing surfaces (route-map-mapped) | New surfaces (declared: parent route/location + intended shape) | +| ---- | ------------------------------------ | ---------------------------------------------------------------- | + +## Dependency Graph (every edge cited — an uncited edge is refutable by default) +| From (leaf/master) | To | Kind (ORDER | CONFLICT | INDEPENDENT) | Evidence (cgc/grepai query · file · decision-log · design § · declaration cross-reference) | +| ------------------ | -- | ------------------------------------ | ------------------------------------------------------------------------------------------ | + +## Blast-Radius Register (feeds the owning seat's loop-tier scoring) +| Leaf | Radius (low | medium | high) | Derivation (caller-set | doctrine-propagation | migration | user-visible) | Evidence | +| ---- | ---------------------------- | ------------------------------------------------------------------------- | -------- | + +## Leaf Moves +| Leaf | From (master) | To (master) | Rationale | +| ---- | ------------- | ----------- | --------- | + +## Coherence Findings +- ⟁ QUO-VADIS (developer decision required): | none +- +- Unplannable as scoped: | none + +## Sprint Order / Waves +1. (note the + landing-reconciliation cost of parallel waves as a scheduling consideration) +2. + +## Open Risks +- + +## Re-Evaluation Triggers +- In-sprint master added before implementation starts → re-plan (strategist re-evaluates). +- Master added outside the sprint scope → next sprint's evaluation. +- + +## Evidence Inventory +- cgc queries (dependencies/callers/callees/complexity): +- grepai queries (search/trace): +- read_ar_files reads (paired source+onboarding) / route indexes read: +- task docs, decision logs, and design sections cited: +``` diff --git a/.codex/skills/l-01-agent-lifecycles/templates/turn-report.md b/.codex/skills/l-01-agent-lifecycles/templates/turn-report.md new file mode 100644 index 00000000..b771ada4 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/turn-report.md @@ -0,0 +1,57 @@ +# Turn-Report Template + +The **mandatory** artifact a worker writes at **every** hand-off (`roles/worker.md`). It is how the +leaf's work survives the session's death and how a respawned successor onboards from **state, not the +transcript**. A missing turn report is nudged by the manager. + +## Rules + +1. Write it in the **main loop**, from your own work plus any sub-agent summaries — never delegate it to + a sub-agent (it is the leaf's single artifact of record). +2. State facts, not a narrative: what changed, what broke, what is proven green, what remains. +3. The **Respawn State** section must let a fresh successor continue **without reading any transcript**. +4. Keep it durable and in the series notes; reference it from the leaf `task_doc`. +5. Default path: `notes/reports/-worker-report.md`. The control-plane helper exposes this + convention so manager nudges and respawn onboarding can point at the same artifact. + +## Shape + +```md +# Turn Report — · + +| Field | Value | +| ------------ | --------------------------------------- | +| leaf | | +| master | | +| worker | | +| worktree | | +| status | in-progress | leaf-complete | blocked | +| checks | green | failing: | not-yet-run | +| written | | +| inbox | | + +## What Was Done +- (files: ``, …) + +## Issues Hit +- → resolved: | still open: + +## Solved On The Spot +- (a plan delta beyond blank-filling is NOT here — it was + escalated to the manager; see Escalations) + +## What Is Left +- [ ] + +## Onboarding Refreshed +- in this pass (c-05) + +## Escalations +- | none + +## Respawn State (onboard a successor from this — no transcript needed) +- Current position in the leaf plan: +- Files touched so far: +- The one thing a successor must know before editing: +- Uncommitted vs committed state: +``` diff --git a/.codex/skills/l-01-agent-lifecycles/templates/verdict.md b/.codex/skills/l-01-agent-lifecycles/templates/verdict.md new file mode 100644 index 00000000..3f292443 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/verdict.md @@ -0,0 +1,142 @@ +# Verdict Template (adversarial reviewer) + +The artifact an **adversarial reviewer** writes at a seam (`roles/reviewer.md`). It lands +under the series `notes/reports/` directory and attaches to the handover gate as **judge evidence**. +There are two variants: **master-exit** (before a manager hands over to the orchestrator) and +**super-exit** (before the orchestrator hands over to the developer) — plus a loop-review +adaptation of the master-exit shape (see Loop-Review Adaptation below). + +## Rules + +1. **A verdict is evidence, not a decision.** State an explicit pass/block **recommendation**; the gate's + decider decides. Never write the verdict as if it were the gate outcome. +2. **A block must decompose into fix leaves** — concrete, leaf-shaped findings the owning + manager/orchestrator can dispatch. A block that cannot be named as fix leaves is not yet a block. +3. **Refute-or-confirm:** every finding must survive an attempt to refute it. Rank findings and cite + the backing evidence file. +4. Cover all three lenses (completion · code quality · onboarding-vs-code) explicitly, even to say a + lens is clean. +5. Record the gate evidence reference exactly: `kind=reviewer-verdict`, `ref=`, and + `verdict=`. +6. **Report every bound catalog criterion** in the Criteria Catalog Results table (the catalogs the + binding table in `roles/reviewer.md` assigns this review type, `../criteria/`) — one row per + standing criterion even when it found nothing, candidate rows when run — and carry any proposed + catalog amendments (the promotion ratchet) in that section. + +## Master-Exit Variant + +```md +# Adversarial Verdict — master-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | master-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | orchestrator (delegated `master-handover-approval`; serious issues escalate → developer) | +| artifact path | notes/reports/-master-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Task Docs +- Master requirement/substep coverage: addressed | delta justified | MISSING +- Leaf task docs and worker reports reconcile with the master task_doc: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite: green | failing: +- regressions vs the past (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- master-side route overviews current: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Manager Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the master-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Super-Exit Variant + +```md +# Adversarial Verdict — super-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | super-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | developer (human review concentrates at the super gate) | +| artifact path | notes/reports/-super-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Portfolio Task Docs +- Portfolio objective and dependency order satisfied: yes | +- Master handover packets and prior master-exit verdicts reconciled: yes | +- Cross-master conflicts, duplicate implementations, and deferred follow-ups surfaced: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite for the accumulated super branch: green | failing: +- branch-wide regressions vs the past and across masters (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- route overviews describe the accumulated behavior: yes | +- C-11 carry-over and ledger mapping coherent for the final super branch: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Orchestrator Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the super-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Loop-Review Adaptation (leaf full-loop · plan review) + +A three-party-loop review (a full-loop leaf round, or the plan review over an orchestration task) +uses the **master-exit variant's shape minus the gate machinery**: drop the `gate evidence` header +row and the Judge-Evidence Note (a loop review attaches to no gate), set `decider` to the **loop +owner** (the leaf's owning seat, or the orchestrator for the plan review), scope to the round's +change set (or the orchestration-task draft), and keep everything else — recommendation, Criteria +Catalog Results (the loop's bound catalogs, e.g. `plan-review` + `report-verification` for a plan +review), ranked refute-tested findings, and fix decomposition. The verdict remains **evidence to +the loop owner, never a decision**; a delta-verify appends a dated delta section to this same +artifact rather than opening a new one. diff --git a/.codex/skills/l-01-agent-lifecycles/templates/worker-brief.md b/.codex/skills/l-01-agent-lifecycles/templates/worker-brief.md new file mode 100644 index 00000000..db8f44d0 --- /dev/null +++ b/.codex/skills/l-01-agent-lifecycles/templates/worker-brief.md @@ -0,0 +1,72 @@ +# Template — Worker Brief + +The dispatch packet a spawning seat (manager / orchestrator) compiles for a worker. **The brief is +the worker's entire session start** — it replaces the front half the spawner already ran (trust +checkpoint, reframe, plan). Compile it fresh per leaf from this shape; the proven form below +absorbed a series of real dispatch frictions (route-index leaks, attestation format, provider-stack +keying, missing `python` shim), so deviate knowingly or not at all. + +Spawn with `env={"AR_SPAWN_ROLE": "worker"}` and the **qualified** leaf key +`//` so the session-start router and the dashboard leaf rail both engage. + +--- + +```md +ROLE BRIEF — worker + +# WORKER BRIEF — · + +You are a WORKER for leaf `` of master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/worker.md`; this brief is your session start. Execute the leaf +completely, write your turn report, then stop. + +## Worktrees (your ONLY writable areas) +- Code: `` (branch ``, base ``) +- Memory: `` +- Plus your turn report at the path below. Nothing else. NEVER `git commit` — the owning seat + closes out after reviewing your report. + +## Tool surface +- Native file tools inside the two worktrees; shell for the checks below. +- Read-only AR retrieval: `read_ar_files` (serves the OFFICIAL baseline, never your worktree — + final verification uses native reads), `grepai_search` / `cgc_*` (provider stack key: + ``), `context_packet`. +- No `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, or `route_index_refresh` — + generated route indexes are regenerated with a local `build_route_indexes(...)` from the memory + worktree. +- Interpreter: `` with `PYTHONPATH=/mcp/src` — there is no + `python` shim in this environment. + +## The task +Leaf spec: `` (read it first). + +## Checks (green before you report) +- Focused: . +- Full: — must exit 0. +- `git diff --check` in both worktrees. + +## Onboarding (same editing pass, per c-05) +- Changed source files: update the sidecar BODY now; new files: create the sidecar. +- Route overviews: genuine body update where routes changed; otherwise the newest history entry + uses the LITERAL form `- — No route impact: ` (timestamp first). +- Pin idiom for verification metadata: "Verification metadata pinned until closeout stamps the + commit." + +## Turn report (mandatory, last act) +Write `/-worker-report.md` following +`skills/l-01-agent-lifecycles/templates/turn-report.md` — including exact check commands + +outcomes, the retrieval-evidence tally, and the respawn state. If blocked: fill Escalations and +stop — escalate to , never to the developer. +``` + +--- + +**Compiler notes for the spawning seat.** + +- Fill every ``; a brief with an unresolved placeholder is not dispatchable. +- Verify the provider stack actually answers before naming it; write `NONE (native reads only)` + when it does not — a worker discovering dead providers mid-leaf wastes its turn. +- Deliver as an echo-confirmed paste; verify the harness's paste chip (`[Pasted Content N chars]`) + before submitting, and only count delivery on a post-boot echo. +- The report path lives under the series `notes/reports/` — the same folder the seam verdicts use. diff --git a/.codex/skills/l-01-session-job-lifecycle/SKILL.md b/.codex/skills/l-01-session-job-lifecycle/SKILL.md deleted file mode 100644 index 9b3cc6d6..00000000 --- a/.codex/skills/l-01-session-job-lifecycle/SKILL.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -name: l-01-session-job-lifecycle -description: "The session job lifecycle the coordinator routes every session into: request -> context/trust checkpoint -> developer-agreed reframe -> deeper research -> decide build mode -> build -> close. Owns research-only exits, the build-mode decision (chat build vs durable w-02-light-task-workflow task), and the job lens (bug/feature/triage/research). Supersedes the retired chat workflow by migrating and modernizing its doctrine." ---- - -# l-01-session-job-lifecycle Session Job Lifecycle - -The `l-01-session-job-lifecycle` skill is the **canvas** the coordinator routes into at the start of every session. -It is not a task format. A task format is one outcome of a single step inside it. - -The lifecycle is one shared spine with thin per-job lenses. Its front half is a -developer/model collaboration loop: the developer states the request, the model -runs mandatory MCP grounding checks, the model presents an evidence-backed -reframe, and the developer agrees or revises that reframe before deeper research -or build-mode decisions proceed. - -## Companion Files - -1. `job-variants.md` — the four thin job lenses (bug / feature / triage / research). -2. `deep-research-report-template.md` — the reusable report and evidence-ledger shape for deeper research. - -``` -0 Request -> 1 Trust Checkpoint -> 2 Reframe + Research -> 3 Decide -> 4 Build -> 5 Close - | - +-- research-only (e.g. investigation, code questions...) -``` - -## Hand-off Protocol — Dry-run action => "Notify-and-stop" Action => "Report" Action - -Every developer hand-off / gate moment — reframe agreement, plan gate, worktree intent, commit -approval, push approval, integration, cleanup/finalization, regular turn-end — is **notify-and-continue**: -surface an attention item, present the result, and **end your turn**; the developer responds and your -**next** turn picks up automatically. It is **three actions, never one**: - -1. **Dry-run action.** Run applicable MCP tools in `dry-run` for the hand-off. If dry run succeeds, - proceed with the notify-and-stop action. If dry run fails, try to ammend the issue first before reporting failure. -2. **Notify-and-stop action.** Call `lifecycle_turn_end_notification(summary=…)`. It sets the new - **`awaiting-developer`** lifecycle state, surfaces a dashboard attention item, and **returns - immediately — no wait, no inbox.** This is the **last tool call of the turn** — the report prose - still follows it; do not STOP here. The developer responds on the - dashboard or in the leaf's attached chat, and the **first AR tool call of your next turn** - automatically resumes the lifecycle (`running`) and clears the attention item — you send **no** - explicit resume. -3. **Report action.** Deliver the complete hand-off report as plain assistant output - (the reframe, the plan, the intent packet, or the closeout relay with - preview facts, quality results, proposed commit messages, and - attestations), and make the decision you are handing to the developer the last - line of prose. **The report is the last thing in the turn — then STOP / end your turn.** - -Use the `dry-run` step to verify that the planned tool call (for example the closeout apply) will -succeed before you hand off, and self-fix any failure before reporting it. - -`lifecycle_turn_end_notification` returns immediately and does **not** render a prompt over your prose, -so the report you deliver after it is exactly what the developer sees — call the -notification, then deliver the report as your final prose, then stop. Keep the report turn free of any mutating or permission-triggering operation so -nothing obscures the report. - -Junction → Dry-run → notify (`lifecycle_turn_end_notification`) → Report. Every junction below now hands -off through that one notification; the named `kind` is the **parked** durable-gate label the fallback -would use (see "Parked fallback" below), kept so the dashboard can still classify each hand-off: - -| Junction | Parked durable gate `kind` | Skill that hands off | -| -------------------------------- | -------------------------- | ---------------------------------------------------------- | -| plan gate | `plan-approval` | `l-01-session-job-lifecycle` | -| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | -| commit / closeout | `closeout-approval` | `c-12-closeout` | -| push | `push-approval` | `l-01-session-job-lifecycle` / `c-09-git-worktree-manager` | -| integration | `integration-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| cleanup / lifecycle finalization | `cleanup-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| any other dev-wait | `agent-question` | `l-01-session-job-lifecycle` | - -`closeout-approval` **is** the commit hand-off — there is no separate -`commit-approval`. Closeout is the single commit-of-record for code, memory, and -ledger, so every commit (including a singular one) routes through the closeout -hand-off. `agent-question` is the non-exhaustive catch-all so any dev-wait that is -not a structured junction is still observable. - -### Parked fallback — block-and-wait `lifecycle_gate` - -The block-and-wait `lifecycle_gate(kind=…)` junction (which creates a durable gate and waits for a -developer decision), the operator inbox, and the dashboard GateResponder **still exist and still work** -when explicitly raised — but they are **no longer the active path**, and nothing routes toward them: -`next_step.py` repoints every gate moment to `lifecycle_turn_end_notification`. Reach for the -server-enforced `lifecycle_gate` (followed by `lifecycle_resume` after the developer decides) only when -you deliberately need a durable, developer-attributed, mutation-blocking approval record; its `kind` -values are the table above. If you ever do raise it, it renders an approval prompt **over** your prose, -so the report must land in an earlier turn — which is exactly why notify-and-stop is preferred. - -## Lifecycle Signals — Making The Session Observable - -Every session in a managed repo is a **lifecycle**: the six `lifecycle_*` signals -record where it is and what it is waiting on, so the work is observable and -resumable across chat deaths (design `docs/design/observable-lifecycle.md`). The -model **never handles a lifecycle id** — identity is server-side, anchored in the -worktree contract. - -| When (phase) | Signal | Why | -| ---------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Trust Checkpoint passes (managed repo) | `lifecycle_start` | Begin a **fleeting** lifecycle (guarded: one per session; takes no id). | -| Entering each phase | `lifecycle_phase` | Move the orthogonal phase axis (`request`/`trust-checkpoint`/`reframe-research`/`decide`/`build`/`close`). | -| At a hand-off (reframe, plan, commit, …) | `lifecycle_turn_end_notification(summary=…)` (last tool call), then the report prose, then **STOP** | Set `awaiting-developer`, surface the dashboard attention item, and return immediately (no wait, no inbox); the next turn's first AR tool call auto-resumes (`running`) and clears the item. Block-and-wait `lifecycle_gate(kind=, ask=…, packet=…)` + `lifecycle_resume` is the parked fallback. | -| `worktree_start` (Decide → Build) | _(promotion — automatic)_ | The fleeting lifecycle becomes **persistent**, anchored in the contract; no separate signal. | -| Resuming an existing task | `worktree_attach` | Re-adopts the contract's lifecycle (contract-resolved); the model passes no id. | -| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | The save gate: promote it or abandon it — never dropped silently. | -| Close | `lifecycle_end` (`completed`\|`abandoned`) | The terminal record. | - -Rules: `lifecycle_start` is guarded (one active lifecycle, no id). `paused` is -**system-owned** — there is no pause signal. `awaiting-developer` is set by -`lifecycle_turn_end_notification` and auto-cleared back to `running` by the next -turn's first AR tool call — you never resume it by hand. A tool call outside any -lifecycle is **dropped, never misattributed**. `worktree_start` **promotes** the current -lifecycle (fleeting → persistent); `worktree_attach` **resumes** the contract's -lifecycle; both keep identity server-side. - -## 0 — Request - -Receive the developer's raw request and identify the active repository. - -1. Treat the developer's statement as raw input, not yet as an implementation plan. -2. Infer the target code repository from the request and local context. Ask the - developer if the target is unclear. - -Request intake changes nothing. It only establishes which repository the next -checkpoint must inspect. - -The upcoming `Trust Checkpoint` reveals whether or not the request is related to repositories managed by Agents Remember. If not, then the lifecycle exits early and the agent can work as usual. - -However, if later work is to enter the boundary of repositories being managed by Agents Remember, -the lifecycle must be re-entered. - ---- - -## 1 — Trust Checkpoint - -Establish whether memory and providers are trustworthy enough to use. - -1. For the target repository, resolve coordination/memory context with - the MCP tool call: - - ```text - context_packet(repo_id="", include_providers=true, include_drift=true, include_freshness=true) - ``` - -2. Report the packet facts before relying on memory or providers: - - repository, branch, and dirty state - - memory root and onboarding root - - provider state - - drift status and actionable drift count - - branch freshness: whether the code and memory checkouts are current with - their upstreams (`behind`/`diverged` means the local official line is - stale — fast-forward it before trusting analysis or basing work on it) - and whether the ledger maps code HEAD (`ledgerMapsCodeHead=false` means - the memory checkout does not match the code state; run carryover or - check out the right memory branch first) -3. If onboarding for committed source is drifted, missing verification, or - orphaned, and the corresponding source file is not dirty in the code - worktree, stop and ask the developer whether or not to refresh it through - `c-05-create-or-update-onboarding-files`. Drift handling is approval-gated! -4. If drift is tied to dirty source, report it as active work-in-progress. Do - not adopt it as maintenance or silently trust it as current state unless the - developer explicitly says this job owns it. -5. If providers are stopped or degraded, use the matching MCP provider/runtime - operations, then re-run the provider check. If providers are ready, report - readiness and continue. If issues persist, report it to the developer and - wait for instructions. If the packet's providers summary lists `indexing` - targets, report them to the developer: those providers are healthy but - busy, and their results may be partial until the scan completes. -6. After the trust checkpoint passes, read committed-state onboarding for the - in-scope anchors as needed. A file dirty in another chat is still valid for - HEAD and worth comparing, but its dirty-source drift remains active work. - ---- - -## 2 — Reframe And Research - -Turn the developer's raw request into an agreed piece of work, then perform the -deeper research that the agreed frame requires. The `tasks/AGENTS.md` -collaboration doctrine applies here in plain chat, before any task file or task -format exists. - -**Read tool for this phase.** Until the build-mode decision (Phase 3), read managed-repo source -through the `read_ar_files` MCP tool, not the harness's native read — it returns paired -source+onboarding plus the repository/route overviews in one observable, lifecycle-attributed -call, and you keep a running count of those calls as evidence. Native read is the edit -precondition in Phase 4. - -1. **Gather evidence for the reframe** through reading the - `c-04-retrieval-strategy-router` skill. Pick the strategy by the question: - - _Semantics_ (grepai over onboarding) — "where does X live / what handles Y." - - _Relationship_ (cgc) — callers/callees/dependencies/impact. - - _Intent_ (onboarding + bounded source confirmation) — hidden contracts, invariants, - branch-valid truths, behavioral expectations. This is a workflow of paired - source+onboarding reads via the `read_ar_files` MCP tool: one call pairs each source - file with its verified onboarding and auto-attaches the repository overview + governing - route-overview chain (the bird's-eye view). -2. **Reframe** the request through `tasks/AGENTS.md`: distinguish the surface - request, deeper objective, highest-leverage framing, assumptions, boundaries, - invariants, and truth gaps. Do not rush a statement into a plan. -3. Present the reframe to the developer. If the developer disagrees, discuss and - revise the reframe. If the developer agrees, proceed to deeper research. -4. **Perform deeper research** for the agreed frame. This research still uses - `c-04-retrieval-strategy-router`, but it is now scoped by the developer-agreed - frame rather than by the model's first guess. Use - `deep-research-report-template.md` for the report shape; the lifecycle owns - the required proof categories, while the template owns evidence formatting. -5. The deeper research report must list its proof and tie evidence to the claim it supports: - - `read_ar_files` calls (paired source+onboarding reads — the running count) - - onboarding docs read - - semantic queries performed - - code graph queries performed - - source files inspected - - remaining truth gaps -6. Run the **job opening move** for the job lens (see `job-variants.md`) and use - the deeper research to name the truth gaps that remain. -7. Continue until the developer agrees the design is defined well enough to write - down, then produce the **plan**: the steps, and a **code example for every - distinct change** you intend to make. - -**Plan gate:** **hand off** before changing any code. No implementation begins -before the developer approves. Call -`lifecycle_turn_end_notification(summary={…the plan + the developer-facing approval ask…})` as the -**last tool call**, then present the plan as your final prose and **STOP**; -the developer approves on the dashboard or in chat and your next turn auto-resumes to begin -implementation. (Parked fallback: the server-enforced -`lifecycle_gate(kind="plan-approval", ask=…, packet=…)` + `lifecycle_resume` still exist if you -deliberately need a mutation-blocking approval record.) - ---- - -## 3 — Decide (build mode) - -One decision: does this job change code? - -- **No -> research-only exit.** Deliver the answer/assessment. No worktree, no task artifact, no closeout. - A research-only job may recommend or spawn a follow-up build job; it does not perform one itself. -- **Yes -> worktree intent hand-off, then always a worktree.** Read `c-09-git-worktree-manager` - and `system/git-workflow.md`, call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the worktree - intent packet as your final prose and **STOP**. The developer approves and your next turn - auto-resumes to `worktree_start`. Then open it with - `c-09-git-worktree-manager` and pick the build mode: - - **Chat build** — small enough to carry inline this session: worktree-backed, **no** `task.md`. - - **Durable task build** — hand off to `w-02-light-task-workflow`: `task.md`, checklist, decision - log, proposed code examples. Escalate to a master + light sub-task series when the work outgrows a - single-page plan. - -The worktree intent packet names the target repo, build mode, discovered branch policy, proposed -`source_branch`, proposed work branch/worktree name, memory mode, landing path, and material risks. -On PR-gated repos, the packet must prove that the recorded `source_branch` is pushable and that -protected targets are reached later through the repo's PR flow. - -Worktree granularity = the leaf task unit. A single task gets its own leaf enclosure/worktree. A -master multi-task owns a root `series-contract.md` and integration branch, while each active leaf -sub-task gets its own `enclosures//series-contract.md`, branch, and worktree. A chat build -gets its own leaf worktree without a task artifact. The git-landing decision (direct vs PR-gated) is -deferred to the repo's `system/git-workflow.md` — read it before landing on a gated branch. - ---- - -## 4 — Build - -Implement inside the worktree, keeping memory and tests in lockstep with the code. - -1. Apply the approved code changes. -2. **Refresh the matching onboarding in the same editing pass**, per completed plan-section — never - deferred to the end of the job. When a change affects durable current-state knowledge, the sidecar - is updated alongside it through `c-05-create-or-update-onboarding-files`. - - For **changed** (already-onboarded) source files, update the sidecar **body** now: the closeout - gate rejects a changed source file whose existing sidecar was not modified this job, because - refreshing `lastVerifiedCommitHash` over stale content silently defeats the drift check. - - For **new** source files, run `check_missing_onboarding` before the commit and create the - reported missing sidecars through the `c-05-create-or-update-onboarding-files` skill; the post-code-commit memory refresh stamps them with - the real code commit hash and date. -3. Run the checks from the `c-08-ar-coordination-context-resolver` resolved `system/tools.md` (lint, typecheck, complexity, tests) and - get them **green before each incremental commit**. Testing is never deferred to a final task; the - pre-commit/pre-push hooks enforce it. -4. **Watch the official line and sync early.** `worktree_status`'s `freshness` block reports when the - recorded base pair fell behind the local source branch tips (a parallel cycle landed). Pull the - moved official line in with `worktree_sync` — preferably **before memories are written**: with - parked memory the sync is a pure fast-forward, the other cycle's sidecars and ledger rows end up - beneath this task's future work, and end-of-series integration stays `ff-only` with no carryover - reconciliation. - -Incremental, pushable commits keep the work-loss window small. Each closeout below is one such commit. - ---- - -## 5 — Close - -Land the work. **Implementation approval is not commit approval.** - -1. Run the `c-09-git-worktree-manager` closeout **preview** for the worktree (`worktree_closeout_preview`). - Every build closes through its worktree — there is no direct-checkout closeout. - Relay the proposed code, memory, and ledger commit messages. -2. **Commit gate:** run the closeout **preview** (dry-run), then **hand off** before any real commit or closeout - apply. If required onboarding is missing, run the `c-05-create-or-update-onboarding-files` skill for the affected file and re-run the preview. - Call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the - **last tool call**, then deliver the preview facts as your final prose and **STOP**; - the developer approves on the dashboard or in chat and your next turn auto-resumes to - `worktree_closeout_apply`. The `c-12-closeout` skill owns this hand-off. Parked fallback: when you - deliberately raise the durable `closeout-approval` `lifecycle_gate`, it is enforced **server-side** — - `worktree_closeout_apply` refuses unless it is approved by the developer, and an agent self-approval - never satisfies it. -3. On approval, the `c-09-git-worktree-manager` skill owns the external-memory invariant in order: commit code → refresh affected - onboarding metadata to the new code commit → run memory quality control → commit memory content → - update and commit the ledger. -4. **Integrate + land** per `c-09-git-worktree-manager` and `system/git-workflow.md`: integrate the - worktree branch into the approved source/integration branch, then on a PR-gated repo push that - source branch, open the PR, wait for green checks, and merge per the repo convention. Never push a - protected branch directly. The agent does not push on its own authority — call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the push intent - as your final prose, and **STOP**; push only after the developer - approves and your next turn auto-resumes. The `c-09-git-worktree-manager` skill makes the matching - integration and cleanup/finalization hand-offs at its landing tail (parked durable kinds - `integration-approval` / `cleanup-approval`). -5. **Map the ledger to the landed commit.** A PR merge usually lands a **merge commit** on top of the - work — tree-identical to the verified tip but a new SHA the ledger does not yet map. Ensure the - ledger maps that merge commit so the next worktree can base off the merged branch without a manual - reconciliation. `system/git-workflow.md` owns this step. -6. **Finalize the lifecycle:** run `lifecycle_finalize_task(..., dry_run=true)` once the local parent - branch contains the landed commit and memory carryover is done. Call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then relay its landed-commit - proof, cleanup plan, and task-document updates as your final prose, and - **STOP**. The developer approves cleanup/finalization and your next turn auto-resumes to run the real - finalizer. The tool proves one parent-child branch edge, - reclaims the worktrees, and marks the leaf task plus immediate parent row `Completed` when those - task-doc paths are supplied. It does not recursively complete ancestors; repeat the edge at the next - parent level when that parent task lands. -7. **Keep squash out of the normal path.** A PR-gated edge is structurally the same as a direct edge - after the model finishes the PR merge and pulls the target branch locally. Do not use squash-merge - equivalence as a default finalization proof; squash is an emergency/manual recovery path because it - erases commit lineage and can make memory lookup history wrong. - -A research-only exit skips this phase entirely. - -## Relationship To Other Instructions - -This skill extends the coordinator `AGENTS.md` and the repository memory layer; it does not replace -them. Read `job-variants.md` for the per-job lenses, and `deep-research-report-template.md` for the -deeper research report shape. diff --git a/.codex/skills/w-02-light-task-workflow/SKILL.md b/.codex/skills/w-02-light-task-workflow/SKILL.md index 248e6f3c..b34f3017 100644 --- a/.codex/skills/w-02-light-task-workflow/SKILL.md +++ b/.codex/skills/w-02-light-task-workflow/SKILL.md @@ -40,7 +40,7 @@ Light-task artifacts use minute-precision timestamps in `YYYY-MM-DDTHH:MM` forma The task document is **JSON-primary**: an `ar-task-document/v1` JSON file is the source of truth, and the `task.md` (or `.md` for a sub-task) is a deterministic **render** of it. Author and update it with the `task_doc` MCP tool — `create`, `set_status`, `set_step`, `append_decision`, `set_field` — which writes the JSON and re-renders the markdown on every write. Do not hand-edit a tool-managed `task.md`; edit through the tool and let it re-render. `template.md` and `master-template.md` document the **render spec** (the shape the renderer produces), not a separate hand-authored format. When a planning slice defers its code examples to the plan gate, record that with `codeExamplesNote` (a `set_field` value, e.g. "Drafted at the plan gate.") so the rendered "Proposed Code Examples" section reads as *deferred* rather than as if none are needed. A leaf doc may also carry a descriptive `statusNote` (a suffix beside the strict status enum), `headerNotes` (extra `**Key:** value` header lines such as Verified/Source), and freeform `sections` appended after References — the escape hatch for bespoke prose (e.g. a Status history) while the standard template sections stay the backbone. Pass `dry_run=true` to any op to **preview** — it builds + validates and returns the rendered markdown, a unified `diff` vs the on-disk `.md`, and a `wouldLose` flag, **without writing**; use it before adopting a hand-authored `.md` into JSON-primary (author the JSON → dry-run → confirm `wouldLose` is false → then write). -Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for a chat build (a thin doc: title plus a few steps, so even a no-`task.md` session is legible) and a *full* one for a durable task; the difference is content completeness, not a separate format. +Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for the smallest single-session build (a THIN doc: title plus a few steps — chat is never a build route, so even micro-work gets this thin doc and stays legible on the dashboard) and a *full* one for a durable task; the difference is content completeness, not a separate format. Scope and transition: the tool manages **`light` and `subTask`** documents, and the format also covers a series **master** (`kind:"master"`: a structured `subTasks` index + ordered `sections` that preserve a master's bespoke prose, so a re-render is lossless). Masters and existing markdown task files stay hand-authored markdown until the runtime ships `task_doc` and they are intentionally migrated — new tasks adopt the JSON-primary format going forward. diff --git a/.codex/skills/w-02-light-task-workflow/master-template.md b/.codex/skills/w-02-light-task-workflow/master-template.md index 7cb4e85a..42738c16 100644 --- a/.codex/skills/w-02-light-task-workflow/master-template.md +++ b/.codex/skills/w-02-light-task-workflow/master-template.md @@ -7,7 +7,7 @@ built to grow as the work unfolds. ## When to escalate to a series -The `l-01-session-job-lifecycle` skill's `decide` build-mode step escalates a single task to a series once its size is apparent — the +The `l-01-agent-lifecycles` orchestrator lifecycle's `decide` step escalates a single task to a series once its size is apparent — the implementation plan no longer fits on a single page, or the work splits into distinct slices that each deserve their own checklist and commit. You can also start single and escalate later: drop in the master `task.md` and move the existing plan into the first `NN_.md`. diff --git a/.cursor/hooks/agents-remember-session-start.md b/.cursor/hooks/agents-remember-session-start.md index 427c30f3..cd999a73 100644 --- a/.cursor/hooks/agents-remember-session-start.md +++ b/.cursor/hooks/agents-remember-session-start.md @@ -1,14 +1,12 @@ -MANDATORY FIRST ACTION for this workspace +**Agents Remember — session start.** -You are not allowed to read, write, or execute code on any repository -until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure! +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** -Until the build/job decision is made, read managed-repo source with the -`read_ar_files` MCP tool — not the harness's native read tool. One call returns -each file paired with its onboarding plus the repository and governing route -overviews. Native read is reserved as the edit precondition once building begins. - -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent), and -keep a running count of your `read_ar_files` calls. Include the onboarding files -inspected and every CGC, GrepAI, and `read_ar_files` call made as evidence. +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`ar-coordination/AGENTS.md`, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. diff --git a/.cursor/rules/agents-remember.mdc b/.cursor/rules/agents-remember.mdc index ccf59462..bceeb41b 100644 --- a/.cursor/rules/agents-remember.mdc +++ b/.cursor/rules/agents-remember.mdc @@ -2,18 +2,17 @@ alwaysApply: true --- -MANDATORY FIRST ACTION for this workspace +**Agents Remember — session start.** -You are not allowed to read, write, or execute code on any repository -until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure. +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** -Read and follow `/ar-coordination/AGENTS.md` -before working in any sibling project. Treat those rules as workspace -instructions. - -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent). -Include the onboarding files inspected and every CGC and GrepAI query made as -evidence. +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`ar-coordination/AGENTS.md`, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. @/ar-coordination/AGENTS.md diff --git a/.cursor/skills/c-01-findings-capture/SKILL.md b/.cursor/skills/c-01-findings-capture/SKILL.md index e145d7ee..d413e8fe 100644 --- a/.cursor/skills/c-01-findings-capture/SKILL.md +++ b/.cursor/skills/c-01-findings-capture/SKILL.md @@ -13,7 +13,7 @@ Companion file: ## Operating Modes -1. Inside a task workflow (an `l-01-session-job-lifecycle` build job or a `w-02-light-task-workflow` task, including a master + light sub-task series). +1. Inside a task workflow (an `l-01-agent-lifecycles` orchestrator build phase or a `w-02-light-task-workflow` task, including a master + light sub-task series). 2. Standalone during direct clarification. ## Durable Destinations diff --git a/.cursor/skills/c-03-repo-bootstrap/SKILL.md b/.cursor/skills/c-03-repo-bootstrap/SKILL.md index 40148918..44f14f78 100644 --- a/.cursor/skills/c-03-repo-bootstrap/SKILL.md +++ b/.cursor/skills/c-03-repo-bootstrap/SKILL.md @@ -1240,7 +1240,7 @@ The orchestrator remains thin throughout. | `c-05-create-or-update-onboarding-files` | Owns final file-level onboarding semantics and routes structural slice maintenance back to the `c-03-repo-bootstrap` skill. The `c-03-repo-bootstrap` skill creates cards/waves and delegates file output rules to the `c-05-create-or-update-onboarding-files` skill. | | `c-04-retrieval-strategy-router` | Consumes bootstrapped overviews and file maps as the Intent substrate and can route to semantic/relationship providers first. | | `c-02-memory-quality-control` | Becomes relevant after bootstrap; touched files can be promoted from deferred to covered. | -| `l-01-session-job-lifecycle` | May trigger targeted bootstrap when an active job enters an uncovered area. | +| `l-01-agent-lifecycles` | May trigger targeted bootstrap when an active job enters an uncovered area. | | `confluence-search` / documentation search skills | Feed the docs evidence pass through approved sources from the input ledger. | --- diff --git a/.cursor/skills/c-04-retrieval-strategy-router/SKILL.md b/.cursor/skills/c-04-retrieval-strategy-router/SKILL.md index 01434c77..e226f8c0 100644 --- a/.cursor/skills/c-04-retrieval-strategy-router/SKILL.md +++ b/.cursor/skills/c-04-retrieval-strategy-router/SKILL.md @@ -160,7 +160,7 @@ names an unresolved source question. ### Rules: -- During the research phase (the lifecycle up to the build/job decision), read managed-repo +- During the research phase (the lifecycle up to the build decision), read managed-repo source with `read_ar_files`, not the native read tool — one call returns each file paired with its onboarding plus the repository and governing route overviews (the recipe above, batched and observable). diff --git a/.cursor/skills/c-09-git-worktree-manager/SKILL.md b/.cursor/skills/c-09-git-worktree-manager/SKILL.md index e19c7902..692dec19 100644 --- a/.cursor/skills/c-09-git-worktree-manager/SKILL.md +++ b/.cursor/skills/c-09-git-worktree-manager/SKILL.md @@ -7,7 +7,7 @@ description: "Create, attach to, report on, integrate, finalize, and clean up Ag Use this skill when a task should run through an explicit code/memory worktree wrapper. -The `c-09-git-worktree-manager` skill wraps the existing chat-build, light-task, or external workflow. It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. +The `c-09-git-worktree-manager` skill wraps the existing light-task or external workflow (a build that fits one session still rides a THIN `w-02-light-task-workflow` doc — chat is never a build route, per the `l-01-agent-lifecycles` invariant). It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. For closeout, use the `c-12-closeout` skill. The `c-09-git-worktree-manager` skill only supplies the worktree-specific contract path and integration/finalization follow-up rules. @@ -67,7 +67,7 @@ The intended order is: 1. run the `c-08-ar-coordination-context-resolver` skill for the target repository 2. run the `c-02-memory-quality-control` skill's task-start drift check and follow the existing AGENTS Gate 3/4 choice point 3. when onboarding is refreshed, commit the memory content and ledger before starting any worktree -4. decide whether the work is a chat build, a `w-02-light-task-workflow` light task (or master + light sub-task series), or external workflow +4. decide whether the work is a `w-02-light-task-workflow` light task — possibly a THIN one for single-session work; chat never builds — a master + light sub-task series, or external workflow 5. read the repository's `system/git-workflow.md` and identify the parent branch edge. For a standalone task, the leaf worktree branches from the approved source branch. For a master series, the master owns a root `series-contract.md` @@ -198,7 +198,9 @@ moved since task start. ## Integration -Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. +Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. Orchestrated-run carve-out (ruled 2026-07-06): dependency-ordered leaf→master and master→super integrations ride the series' standing approval (the developer's portfolio-gate approval recorded in the planner master) — the developer hand-off concentrates at the super PR/carry-over gate per the `l-01-agent-lifecycles` loop/orchestrator doctrine; a raised durable `integration-approval` gate still awaits the developer. + +On an orchestrated master's exit (master → super integration) the integrate step additionally enforces the delegated `master-handover-approval` seam: an undecided or policy-invalid handover gate addressed to the master (by `enclosure` = master task name) returns `handover-gate-blocked` instead of landing — decide the gate per the `l-01-agent-lifecycles` seam doctrine, then rerun. When no gate addresses the integrating master but open `master-handover-approval` gates exist elsewhere, integrate still proceeds and its result carries a `handover_gate_warning` naming them — treat it as a spelling check on the raised gate's `enclosure`. Run `worktree_integrate(..., dry_run=true)` first, then **hand off**: call `lifecycle_turn_end_notification(summary={…the integration plan…})` as the **last tool call**, then diff --git a/.cursor/skills/c-12-closeout/SKILL.md b/.cursor/skills/c-12-closeout/SKILL.md index f83071d9..2c7fe3ff 100644 --- a/.cursor/skills/c-12-closeout/SKILL.md +++ b/.cursor/skills/c-12-closeout/SKILL.md @@ -40,7 +40,7 @@ records the developer's explicit commit approval. Agents must not treat implementation approval, a previous "looks good", or their own judgment as commit approval. -The relay follows the `l-01-session-job-lifecycle` skill hand-off protocol: run the +The relay follows the `l-01-agent-lifecycles` orchestrator hand-off protocol: run the preview/dry-run first, then call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the **last tool call**, then deliver the preview facts and proposed messages as plain diff --git a/.cursor/skills/c-13-install-and-onboard/SKILL.md b/.cursor/skills/c-13-install-and-onboard/SKILL.md index 6515ae46..d583fd13 100644 --- a/.cursor/skills/c-13-install-and-onboard/SKILL.md +++ b/.cursor/skills/c-13-install-and-onboard/SKILL.md @@ -52,10 +52,12 @@ Run this sequence in order: 0. Preflight: verify the copied package and MCP setup are usable enough to continue. 1. Runtime scaffold: run or verify `runtime_install()`. -2. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. -3. Bootstrap: when a new memory repo was scaffolded, hand off to +2. Agentic settings: walk the developer through the orchestration defaults in + the seeded global settings file. +3. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. +4. Bootstrap: when a new memory repo was scaffolded, hand off to `c-03-repo-bootstrap`. -4. Providers: when providers are enabled, start/refresh indexing and verify +5. Providers: when providers are enabled, start/refresh indexing and verify readiness. This skill orchestrates and delegates. It does not reimplement @@ -79,7 +81,9 @@ Check, in order: 3. **Settings sane.** Confirm `server_info` reports the expected `coordinationRoot`, `workspaceRoot`, allowed repositories, and providers. Surface the resolved absolute paths because wrong paths are the common cause - of resolver failures. + of resolver failures. Also report whether the global agentic settings file + (`/system/settings.json`) exists yet; Stage 1 seeds it + when missing and Stage 2 configures it. 4. **Runtime state.** Check whether the coordinator scaffold already exists under `coordinationRoot` (`AGENTS.md`, `skills/`, `tasks/`, `memory-repos/`, `system/` as applicable). If it is missing or stale, Stage 1 will run @@ -118,7 +122,61 @@ Do not run `skills_install()` as part of first-run setup. The harness starter package already carries the skills. `skills_install()` remains available for manual maintenance or non-package setups, but it is not the default path. -## Stage 2 - Memory Repo: Ask Scaffold Vs Existing +## Stage 2 - Agentic Settings: Interview The Developer + +`runtime_install()` seeds the GLOBAL agentic settings file at +`/system/settings.json` copy-if-missing, with every knob at +its documented default: all-human gate delegation, the standard three-party-loop +defaults, no concurrency caps, no spawn harness preference. This stage turns +those defaults into the developer's actual posture so the intended workflows +run on ANY harness. The schema reference is `docs/reference/settings-json.md` +(Agentic Settings); unknown `orchestration.*` keys fail loud, so write only +documented keys. + +Walk the developer through the four knob families and edit the global file with +their answers (leave a family at its seeded default when they have no +preference): + +1. **Gate delegation posture** (`orchestration.gateDelegation`; GLOBAL file only - the + loader refuses it repo-locally and the boot snapshot reads the coordinator file) - keep every + gate human (`all-human`, the default), or delegate leaf gates with the + `manager-decides-leaf-gates` policy, optional per-kind `kinds` overrides, + and `requireReviewerVerdictAtSeams`. Say explicitly that this one key is + boot-snapshot: a change needs an MCP/harness restart. +2. **Loop defaults** (`orchestration.loops`) - the review-round cap + (`defaults.maxRounds`), reviewer reuse (`defaults.reviewerReuse`), + complexity thresholds (`defaults.complexity`), and per-level loop postures + (`perLevel`). Read per-use; edits apply on the next use, no restart. +3. **Concurrency caps** (`orchestration.concurrency`) - `maxParallelMasters`, + `maxParallelLeaves`, `maxSubAgents`. Default: uncapped. +4. **Harness preference + role knobs** (`orchestration.spawn.harness`, + per-role `orchestration.roles.`, per-level + `orchestration.rolesPerLevel..`) - which installed harness + `spawn_agent_session` uses when the spawning seat passes none, per-role + harness/model/effort overrides, and per-LEVEL overrides + (leaf|master|portfolio) for tiered economics (e.g. a cheap leaf reviewer, + a smarter master-seam reviewer). Harness values must be known ids: the + builtin registry (`claude`, `codex`, `pi`) or an `orchestration.harnesses` + entry the developer defines (new TUIs, or a pre-customized launch argv for + a builtin). `effort` is validated per-harness at dispatch (claude: + `low|medium|high|xhigh|max` on the `--effort` flag plus the session-level + `ultracode`); mention the FREE-FORM escape hatch for anything outside the + vocabularies - `launchArgs` (verbatim argv), `sessionCommands` (pasted + before the brief), `promptKeywords` (prepended to the brief) - never + validated, recorded in spawn provenance. Default: detection-gated (the + first detected harness). The full spawn-surface manual is + `docs/reference/harnesses.md`. + +If the developer wants to skip the interview, confirm the seeded defaults +apply and continue; tell them the file can be edited any time (picked up +per-use, except the gateDelegation restart note above). + +Per-repo overrides: a code repo may carry its own `/system/settings.json` +with the same `orchestration.*` shape; repo-local leaf values override the +global file (arrays replace). Offer this only when the developer asks for +repo-specific behavior; do not create the file unprompted. + +## Stage 3 - Memory Repo: Ask Scaffold Vs Existing Do not assume the developer wants a fresh memory repo. Ask which case applies, unless a memory repo is already present and resolvable: @@ -126,10 +184,10 @@ unless a memory repo is already present and resolvable: 1. **Scaffold a new memory repo** - they have no existing memory for this code repo. Run `c-00-initialize-memory-repo` (internal by default; external only if the developer asks or the configured topology requires it). Continue to Stage - 3. + 4. 2. **Use an existing memory repo** - they already have one. Clone or checkout it to the resolved memory location, then adopt it as the ledgered baseline with - `c-10-adopt-memory-baseline`. Skip Stage 3 because its onboarding already + `c-10-adopt-memory-baseline`. Skip Stage 4 because its onboarding already exists. Internal-memory note: pre-existing internal memory lives inside the code repo @@ -137,9 +195,9 @@ Internal-memory note: pre-existing internal memory lives inside the code repo `c-08-ar-coordination-context-resolver` and skip the question when the memory layer is already there. -## Stage 3 - Bootstrap +## Stage 4 - Bootstrap -Run this stage only when Stage 2 scaffolded a new memory repo. +Run this stage only when Stage 3 scaffolded a new memory repo. Hand off to `c-03-repo-bootstrap` to generate initial onboarding. A thin `overview.md` is enough to start; deeper route-local overviews and file-level @@ -147,7 +205,7 @@ onboarding should grow as work touches new areas. Skip this stage when an existing memory repo was adopted. -## Stage 4 - Configure Providers To Index +## Stage 5 - Configure Providers To Index If providers are enabled, make them index the configured code and memory: @@ -177,10 +235,12 @@ Summarize: step the developer must perform; 2. runtime scaffold: `runtime_install()` run or already current, with the resolved coordination root; -3. memory repo: scaffolded, existing-adopted, or already present, with the +3. agentic settings: interviewed and written, or left at the seeded defaults, + with the global file path; +4. memory repo: scaffolded, existing-adopted, or already present, with the resolved memory root; -4. bootstrap: run via `c-03-repo-bootstrap` or skipped; -5. providers: indexing status and any deferred/degraded state. +5. bootstrap: run via `c-03-repo-bootstrap` or skipped; +6. providers: indexing status and any deferred/degraded state. End by telling the developer whether the project is ready for normal work. Do not tell them to restart for hooks installed by this skill, because this skill no diff --git a/.cursor/skills/l-01-agent-lifecycles/SKILL.md b/.cursor/skills/l-01-agent-lifecycles/SKILL.md new file mode 100644 index 00000000..1d390618 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/SKILL.md @@ -0,0 +1,259 @@ +--- +name: l-01-agent-lifecycles +description: "The agent lifecycles: one lifecycle per agent type, under one roof. Routes every session by exactly three conditions (spawn-role env -> role brief -> otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator, designer, strategist, manager, worker, adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. A developer-facing session IS the orchestrator; solo work is the degenerate portfolio. Supersedes and replaces both l-01-session-job-lifecycle and l-02-agent-orchestration." +--- + +# l-01-agent-lifecycles — The Agent Lifecycles + +Lifecycle and job are **one entity**: each agent type runs its own, self-contained lifecycle. This +skill is the single roof over all of them — a thin router, the minimal frame every session shares, +and the role lifecycles as the payload files. No role is defined by reference to another role's +lifecycle, and no role reads another role's file. + +## Which Lifecycle Am I? (the router — exactly three conditions, in order) + +1. **`AR_SPAWN_ROLE` is set** (spawn env, injected by `spawn_agent_session`) → run + `roles/.md`. Nothing else in this file's "developer session" material applies to you. + (`designer` here means the same design hat in a separate chair — see `roles/designer.md`.) +2. **Else: the first user message is a role brief** — a `templates/*-brief.md`-shaped dispatch or + a first line of the form `ROLE BRIEF — ` from an orchestrating agent → run that role's + lifecycle. The brief is your session start; a workspace session-start notice is not addressed + to you. +3. **Else** (a developer opened this session) → you are the **orchestrator**: run + `roles/orchestrator.md`. Solo work is the degenerate portfolio — the same three jobs with hats + collapsed (the orchestrator wears the manager hat in flat runs and builds hands-on at session + scale); the task doc still comes first. + +There is no fourth entry, and the edge cases are decided: an **unresolvable `AR_SPAWN_ROLE` +value** (no matching `roles/.md`) falls through to condition 2 (the brief); a role-env +session **whose brief never arrives** announces itself on the inbox and waits — it never +improvises a task; `AR_SPAWN_ROLE=orchestrator` is valid only as a takeover chair (the Profile +check (takeover) in `roles/orchestrator.md`, The Event Loop) — the developer still talks to **one** orchestrator. Orchestrated +fan-out (spawning managers/workers at scale) begins only on an explicit developer request (e.g. +*"orchestrate these masters"*) — no agent promotes itself into a spawning seat. + +One exception to the no-cross-reading rule above: **a seat that WEARS a hat runs that hat's file +as its own** — the orchestrator always for `roles/designer.md`, and in flat runs for +`roles/manager.md` (the hat-collapse rule). + +## The Role Registry + +| Role | Seat | Lifecycle file | +| --- | --- | --- | +| **orchestrator** | the developer-facing session; first coordination leaf of an orchestrated series | `roles/orchestrator.md` | +| **designer** | a HAT the orchestrator pulls inline (front of the pipeline or mid-flight; separate chair optional) | `roles/designer.md` | +| **strategist** | the sprint planner, SPAWN-FIRST; a strategist run is a **mandatory precondition for any orchestrated run** — its deliverable is the orchestration task (sprint plan + scope); spawn value `strategist` | `roles/strategist.md` | +| **manager** | one coordination leaf per master; drives that master's leaf loop | `roles/manager.md` | +| **worker** | one leaf worktree, short-lived, fresh session | `roles/worker.md` | +| **adversarial reviewer** | short-lived, spawned at the two seams (master-exit, super-exit) and as any three-party loop's reviewer seat (criteria catalogs bound per review type); spawn value `reviewer` | `roles/reviewer.md` | + +The **lenses** (bug · feature · triage · research — `lenses.md`) are how the scoping seats +(orchestrator, designer) read a piece of work; a dispatched role never picks a lens — its brief +already carries the flavor. + +## The Minimal Frame (the only machinery every session shares) + +Every session in a managed repo may be a **lifecycle**: six signals — `lifecycle_start` · +`lifecycle_phase` · `lifecycle_turn_end_notification` · `worktree_attach` · `switch_lifecycle` · +`lifecycle_end` (plus the automatic `worktree_start` promotion) — record where it +is and what it waits on, so work is observable and resumable across chat deaths. The model **never +handles a lifecycle id** — identity is server-side, anchored in the worktree contract. + +| When | Signal | Effect | +| --- | --- | --- | +| Trust checkpoint passes (managed repo) | `lifecycle_start` | begin a **fleeting** lifecycle (guarded: one per session; no id) | +| Entering a phase | `lifecycle_phase` | move the phase axis (`request` / `trust-checkpoint` / `reframe-research` / `decide` / `build` / `close`) | +| A developer hand-off | `lifecycle_turn_end_notification(summary=…)` | set `awaiting-developer`, surface the attention item, return immediately; the **next turn's first AR call auto-resumes** — never resume by hand | +| `worktree_start` | *(automatic promotion)* | the fleeting lifecycle becomes **persistent**, anchored in the contract | +| Resuming an existing task | `worktree_attach` | re-adopts the contract's lifecycle (contract-resolved) | +| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | the save gate — never dropped silently | +| Close | `lifecycle_end` (`completed`\|`abandoned`) | the terminal record | + +Rules: a tool call outside any lifecycle is **dropped, never misattributed**; `paused` is +system-owned. **A spawned role that never touches mutating AR tools simply never instantiates a +lifecycle — that is correct, not a violation.** A spawned role runs its **own** lifecycle when it +runs one; it never adopts its spawner's. The session↔leaf association is the catalog binding made +at spawn (the **qualified** leaf key `//`), not lifecycle adoption. + +## Shared Invariants (every role can count on these) + +- **Continuity lives in the `task_doc` + durable artifacts, never in transcripts** — which is why + short-lived workers and reviewers are safe, and why every seat writes its artifact of record. +- **Escalation ladder: worker → manager → orchestrator → developer.** No rung is skipped, ever. + Each role file states only its own rung. +- **Observability:** coordination seats are `task_doc` leaves with attached chats; the developer + can walk into any seat at any level. +- **Decision-needing questions land in the task doc's `openQuestions`** — the rendered decision + surface; `notes/` carries the analysis behind them. + +## The Three-Party Loop (one home — this section owns the loop doctrine) + +**OWNER → BUILDER → REVIEWER → owner, at every level that owns work.** The owner never +self-approves; the builder never lands; the reviewer never decides — verdicts are evidence. The +owner checks the verdict and either redispatches a builder or escalates. Role files reference this +section; they do not restate it. + +| Level | Owner (holds the deliverable, rules, lands) | Builder | Reviewer | +| --- | --- | --- | --- | +| Leaf | the leaf's owning seat (manager; orchestrator in tight/flat mode) | spawned worker (no-commit contract) | spawned reviewer, criteria catalog + liberty | +| Master | the manager | the leaf workers | the master-exit seam reviewer (verdict rides `master-handover-approval`) | +| Portfolio | the orchestrator | the STRATEGIST (spawn-first) | reviewer with the plan-review catalog | + +**Complexity-scored tiers (per leaf, at dispatch).** The owning seat scores three axes — blast +radius (doctrine/enforcement/public surface vs leaf-local) · novelty (new subsystem vs +pattern-following) · size (files × steps) — into three tiers: **direct** (no loop +machinery — the level's ordinary build channel implements: hands-on at session scale, the leaf's +worker under a manager; self-check + checks ladder only), **builder-verified** (builder +implements; owner verifies report-vs-artifact; no reviewer), **full loop** (builder + independent +reviewer rounds). The +strategist's blast-radius register is the scoring input when an orchestration task exists. A +leaf's loop mark (tier + scope: manager | orchestrator — the owning level runs the loop with ITS +agent set) is recorded on the leaf doc with a decision-log entry. **A master whose leaves all +score `direct` is a workflow-free manager** — no loop machinery; the knobs make every loop +optional per level, never mandatory ceremony. + +**Rounds and the HARD cap.** A round = implement → review. **Hard cap: 3 rounds per loop — and +ONLY full end-to-end rounds count against it.** Residuals of a passing round are landed and +**delta-verified by the SAME reviewer via a follow-up message** (it retains everything it already +verified, at a fraction of a fresh round's cost); **fix rounds resume the SAME builder**. A fresh +reviewer is spawned only for a full round or when new scope opens. Delta-verifies close rounds; +they do not open them. + +**The convergence rule (the real control; the cap is the backstop).** Every round must SHRINK the +open finding set. A round that does not shrink it escalates immediately, regardless of the count; +a monotonically converging loop may never hit the cap at all. At the cap, or on non-convergence, +the owner does not spin another round — it **escalates one seat up the ladder (worker → manager → +orchestrator → developer) with the full round history attached**; the escalation packet IS the +upper seat's visibility. + +**Quo-vadis (the written developer-escalation criterion).** A question is developer-worthy when it +is a **high-blast-radius truth** — answered wrong it means big rewrites later (architecture +direction, security posture, doctrine contradictions, irreversible data/branch operations, where +agent settings live). Quo-vadis questions escalate IMMEDIATELY, regardless of round count. +Presentation-grade choices (2px vs 3px) never do — the owner rules and logs. + +**Criteria catalogs (the reviewer as test bench).** Criteria are never made up on the spot: every +review runs its type's standing catalog from `criteria/` (code-seam · doctrine · +onboarding-memory · report-verification · plan-review) plus an exploratory mandate, under the +promotion ratchet (each catalog carries it). `roles/reviewer.md` binds them. + +**Per-level agent sets.** Each level runs its loop with its own harness/model/effort set — the +orchestrator-level set (the strongest models) and the manager-level set (cheaper, possibly +workflow-free) are configured per level in the `orchestration.loops` settings block (schema in +`docs/reference/settings-json.md`; stored in the global agentic settings file with repo-local +override, parsed by the kernel agentic-settings loader — L13, landed). The strategist's mandatory +pre-run is doctrine, not a knob — it is unconditional. + +## Knob Block & Capability Doctrine (no per-harness files) + +Role files are **model-interpreted markdown, never an executor**. Each carries a portable **knob +block** (harness / model / effort / tools) — the defaults the terminal host injects at spawn. +Resolution: **role-file defaults < settings.json orchestration block.** There are deliberately +**no per-harness role files** (developer decision 2026-07-05): harness-specific ABILITIES — +sub-agent fan-out and the like — are covered inside the portable files as capability-conditional +doctrine any coding agent can apply, and harness PREFERENCE is deployment configuration +(settings), not doctrine. Hard-coding a vendor would fork the doctrine per harness. For spawning +seats, `spawn_agent_session` is itself the harness-independent fan-out: a harness with no +sub-agent facility still dispatches seats through the framework (a chat, no leaf attachment +required) — the DBMS principle: one behavior, any engine. + +## settings.json Orchestration Block + +Machine/user overrides layer over the role-file defaults, in the **global agentic settings file** +(`/system/settings.json`), with `/system/settings.json` as the +repo-local override layer (leaf-key deep merge, arrays replace, unknown `orchestration.*` keys +fail loud — schema in `docs/reference/settings-json.md`, Agentic Settings). Precedence: role-file +defaults < global settings < repo-local settings. + +```jsonc +{ + "orchestration": { + "roles": { // role → knob override; validated: harness/model/effort · free-form: launchArgs/promptKeywords/sessionCommands + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { // per-LEVEL agent sets (leaf|master|portfolio), deep-merged over roles + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" }, // spawn_agent_session default when the seat passes none + "gateDelegation": { + "policy": "manager-decides-leaf-gates", + "requireReviewerVerdictAtSeams": true + } + } +} +``` + +**As-built (L13 + L16):** the whole block is parsed by the kernel agentic-settings loader +(`kernel/agentic_settings.py`) — typed models for `roles` / `rolesPerLevel` / `concurrency` / +`spawn` / `harnesses` / `loops`, +read PER-USE (an edit applies on the next use, no restart). `orchestration.gateDelegation` is +parsed and **enforced** (`controlplane/gate_policy.py` — all-human default, opt-in delegation, +human-pinned kinds `integration-approval` / `push-approval` / `cleanup-approval`, owner never +self-approves); it is the ONE boot-snapshot key — read from the global file at MCP boot, a change +needs a restart (an authority-file value is a one-cycle legacy fallback with a boot warning). +`requireReviewerVerdictAtSeams` **binds delegated seam decisions** (`master-handover-approval`) to +attached reviewer-verdict evidence; the named policy `manager-decides-leaf-gates` routes leaf gates +to the manager and the master-exit handover to the **orchestrator** (human review concentrates at +the super gate). `spawn_agent_session` resolves its knobs (260703-L16) as explicit args > +repo-local level override > global level override > repo-local role default > global role default +> detection-gated default — the dispatcher declares its `level` (leaf|master|portfolio, default +leaf) and the resolved level rides spawn provenance — and **applies** them at the harness +boundary: model/effort ride as `AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` env AND map onto the launch argv +per-harness via the effective registry (claude `--model`/`--effort`; a mapping-less harness stays +env-only; a session-vocabulary effort like claude's `ultracode` is delivered as a post-launch +`/effort` paste). Unknown effort values REFUSE at dispatch naming the harness's vocabulary — the +CLI would warn-and-silently-degrade. The free-form escape hatch (`launchArgs` verbatim argv, +`promptKeywords` riding the brief paste, `sessionCommands` pasted before the brief) is never +validated, only recorded in spawn provenance; `orchestration.harnesses` teaches the framework new +TUIs or pre-customizes builtin launches (manual: `docs/reference/harnesses.md`). +`orchestration.loops` (the three-party-loop knobs: per-level loop sets, round cap, reviewer +reuse, complexity thresholds) lives in the same block — meaning in +`docs/reference/settings-json.md`; no knob touches the master-exit seam gate. + +## Companion Files + +- `lenses.md` — the four job lenses for the scoping seats. +- `roles/…` — the six self-contained role lifecycles (the registry above). +- `templates/…` — turn-report · worker-brief · manager-brief (`ROLE BRIEF — manager`; the + orchestrator compiles a manager's session start from it) · master-handover-packet · + conversation-handover-packet · verdict · impact-analysis · onboarding-coherency · + deep-research-report · orchestration-task (the strategist's sprint plan). Spawning seats compile + briefs FROM these; sub-agents fan out and fill them, so analysis survives compaction. +- `criteria/…` — the reviewer criteria catalogs (code-seam · doctrine · onboarding-memory · + report-verification · plan-review), the review test bench the three-party loop binds; maintained + through the promotion ratchet, never made up on the spot. + +## The Super Integration Branch (orientation only — the doctrine lives with its owner) + +``` +main + └── super-integration (orchestrator-owned, off main) + ├── master-A branch (off super) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, C-11) + ├── master-B branch (off the moved super — sees A) + └── … final: super → main PR + memory carry-over + push +``` + +The full topology — dependency-ordered dispatch, the integration-duty procedure, the two +conflict-resolution modes, leaf moves — lives in **`roles/orchestrator.md`** and only there. + +## Credits + +This skill absorbs and supersedes `l-01-session-job-lifecycle` and `l-02-agent-orchestration` +(converged 2026-07-05: lifecycle and job are one entity — one lifecycle per agent type). The +orchestration vocabulary adopts the parked `260619_agentic-control-plane` spec — jobs as +model-interpreted markdown (D6), the knob block (D7), role + lens in one file (D10), the +ambient-singleton rule (D11), per-harness variants (D12), the judge rung, short-lived workers with +structured handoff, dev-talks-to-one-orchestrator (D15) — which in turn credits **Archon** and the +**agent-control-plane** project (D14); that credit carries forward. + +## Relationship To Other Instructions + +This skill extends — never replaces — the coordinator `AGENTS.md`, the `w-02-light-task-workflow` +task format, and the memory layer (`c-…` skills). Each `roles/.md` is self-contained for its +seat; read exactly the one the router selects. diff --git a/.cursor/skills/l-01-agent-lifecycles/criteria/code-seam.md b/.cursor/skills/l-01-agent-lifecycles/criteria/code-seam.md new file mode 100644 index 00000000..053feb1b --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/criteria/code-seam.md @@ -0,0 +1,85 @@ +# Criteria Catalog — Code-Seam Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review wires code seams: consumers, enforcement points, gates, addresses, tool contracts. +Binds at the master-exit and super-exit seams and in any loop review whose change set touches code +(see the binding table in `../roles/reviewer.md`). Criteria are never made up on the spot: the +standing list below is the regression floor, run every time; the exploratory mandate and the +promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### CS-1 — Production-wiring walk + +**Trace the real call path, never a hand-aligned harness.** A claim that a consumer or an +enforcement point exists must be walked through the PRODUCTION call path — the controller, the +tool registration, the store fold — not through a test that hand-assembles the pieces into +alignment. A test can pass while the production consumer is inert. + +- Catching evidence: 260703-L8 review 3 (AR3-1) — the integrate consumer was proven **inert**: the + policy was omitted at the controller and the gate was looked up on the wrong lifecycle, while a + hand-aligned test passed (L8 decision log, cycle-6 entry). + +### CS-2 — Fail-open hunt + +**What happens when the address/config is absent or mistyped?** For every identity, address, key, +or config the seam matches on: feed it nothing, feed it a near-miss, and confirm the seam fails +CLOSED (refuses) rather than open (silently proceeds unmatched). + +- Catching evidence: 260703-L8 review 4 (AR4-1) — the seam's `enclosure` address had to be pinned + as an exact-string contract and the enclosure-less raise made a refusal (L8 decision log, + cycle-7 entry). + +### CS-3 — Validate-then-mutate + +**Every raise/write validates before it mutates.** A call that records state (a gate raise, a +store append, a contract write) must perform its refusal checks before any durable effect; a +mutation that precedes validation leaves half-states behind on refusal. + +- Catching evidence: 260703-L8 cycle 6 — the `wait=false` raise was reworked to be + validate-then-mutate and seam-kind-restricted (L8 decision log, cycle-6 entry). + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### CS-4 — Reused-primitive affordance parity *(candidate — 1 catch)* + +**When a screen reuses a shared content primitive, verify every branch of the ORIGINAL's +affordances (banners, status chips, truncation notices, error states) still fires on the reuse +path.** A dropped affordance is a silent regression the reuse's own tests won't catch — they +assert the new screen's happy paths, not the primitive's full surface. + +- Catching evidence (single engagement): 260703-L17 review (L17R-2) — the notes reader's + `DualPane` reuse drops the "first 2 MiB" truncation banner on the markdown path (the banner + lives in `CodeSide`, which markdown never reaches); text and binary keep it. + +### CS-5 — Cross-repo side-effect safety *(candidate — seeded from a clean exemplar, 0 catches)* + +**Any step that writes to a repository OTHER than the one it operates in gets the full +validate-then-mutate treatment plus partial-failure and dirty-target analysis.** Check the order +of validation vs the foreign write, the state left behind when the write lands but the caller +fails afterward, behavior against a dirty target repo, and an exact format round-trip with the +foreign artifact's consumer. + +- Seeding evidence: 260703-L18 finding 7 (`_reconcile_missing_mapping` writing the official + memory repo's ledger mid-`worktree_start`) PASSED all four lenses under this analysis — the + clean exemplar that defined the class. A catch in a later engagement promotes. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS change set the catalog does not name yet. Every novel finding-class that survives +refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.cursor/skills/l-01-agent-lifecycles/criteria/doctrine.md b/.cursor/skills/l-01-agent-lifecycles/criteria/doctrine.md new file mode 100644 index 00000000..9b9ccae1 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/criteria/doctrine.md @@ -0,0 +1,58 @@ +# Criteria Catalog — Doctrine Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review is doctrine: skill files, role lifecycles, templates, instruction surfaces, docs +that agents obey. Binds whenever doctrine/skill files are in the change set (see the binding table +in `../roles/reviewer.md`). Criteria are never made up on the spot: the standing list below is the +regression floor, run every time; the exploratory mandate and the promotion ratchet keep the +catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### D-1 — Doctrine-vs-code anchoring + +**Every "X enforces Y" needs a code anchor.** A doctrine sentence claiming enforcement, refusal, +or automatic behavior must resolve to the code that does it (file + mechanism). Doctrine that +narrates enforcement which does not exist is a defect, not an aspiration. + +- Catching evidence: 260703-L8 review 1 (AR-5) — `requireReviewerVerdictAtSeams` was documented as + binding while the flag was **inert**; the finding forced the wiring (L8 decision log, AR-1 + entry: "closing AR-5's inert flag"). + +### D-2 — Cross-file contradiction sweep + +**Sweep sibling doctrine for statements the change set now contradicts.** A doctrine change is +reviewed against the whole doctrine surface (skills, role files, templates, docs, hooks, canvas +prose), not just the edited files — one file's new invariant is another file's stale sentence. + +- Catching evidence: 260703-L10 — the landed "chat is never a build route" invariant contradicted + surviving chat-build wording inside `c-09` / `w-02` (builder escalation 1, owner-sanctioned + sweep; L10 builder report). + +### D-3 — Stuck-state walk + +**Can an agent following the prose deadlock?** Walk the doctrine as the obeying agent: at every +wait, gate, and handover, ask who unblocks it and through which channel. Prose in which two seats +each wait on the other — or a seat waits on a channel nobody is told to serve — is a blocking +finding. + +- Catching evidence: 260703-L8 review 2 — the seam deadlock: the manager's blocking raise and the + orchestrator's decide path could not meet as written; the ruled `wait=false` + + packet-carried-gateId channel resolved it (L8 rounds 2/4b history). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS doctrine change the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.cursor/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md b/.cursor/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md new file mode 100644 index 00000000..e47783e3 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md @@ -0,0 +1,67 @@ +# Criteria Catalog — Onboarding/Memory Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run over the +memory side of a change set: sidecars, route overviews, route indexes, update histories. Binds at +the master-exit and super-exit seams (the onboarding-vs-code lens) and in loop reviews whose change +set carries onboarding (see the binding table in `../roles/reviewer.md`). Criteria are never made +up on the spot: the standing list below is the regression floor, run every time; the exploratory +mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### OM-1 — Staleness diff vs as-landed code + +**Diff every body claim about current behavior against the as-landed code.** A sidecar or overview +body that describes the present tense is checked against what the branch actually ships — deleted +things still described, renamed things under old names, duplicated rows. + +- Catching evidence, two separate engagements: 260703-L8 cycle 6 (owner follow-up pass) — route + overview bodies still described **deleted canvas models** (the panels overview's build-job/frame + tail) and carried **duplicated table rows** (the tools and controlplane overviews' Layout + tables), durably recorded in those overviews' own 2026-07-05T19:25 Update History entries; + 260703-L10 — the flowModels sidecar body was still the pre-convergence 8-model census and its + references row still said "8 models" (the sidecar's 2026-07-06T12:05 history entry + L10R-3). + +### OM-2 — History-only-update detection + +**"Refreshed" must mean a genuine body edit.** An onboarding file whose only change is a new +Update History line has NOT been refreshed — the body still asserts the old truth. Check that +every claimed refresh touched body sentences, not just the history list. + +- Catching evidence: 260703-L8 cycle 6 — the builder reported route overviews as refreshed when + they were **history-only**; the closeout body gate caught it (L8 decision log, cycle-6 entry: + "report-vs-artifact verification belongs in the reviewer criteria catalog"). + +## Candidate Criteria (seeded exploratory — one catching engagement; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### OM-3 — Newest-first with the checker's own semantics *(candidate — 1 catch)* + +**Update History sorts newest-first under the CHECKER's datetime parse, not lexicographically.** +The quality checker compares naive timestamps as-is and folds tz-aware stamps to UTC; a merge or +mechanical insert that sorts by string can pass the eye and fail the gate (or worse, pass the gate +in the wrong order). Verify ordering with the checker's semantics. + +- Catching evidence (single engagement): 260703-L11 — four onboarding history collisions from the + parallel wave had to be re-sorted **with the checker's own datetime semantics** (naive compare + as-is, tz-aware folds to UTC); the quality gates caught the owner's wrong sort key (L11 decision + log). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS memory delta the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate is the working example, and it is THIS catalog's own OM-2 mechanized: the gate catches + history-only "refreshes" at commit time, where prose requests did not. diff --git a/.cursor/skills/l-01-agent-lifecycles/criteria/plan-review.md b/.cursor/skills/l-01-agent-lifecycles/criteria/plan-review.md new file mode 100644 index 00000000..ef4d2d90 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/criteria/plan-review.md @@ -0,0 +1,69 @@ +# Criteria Catalog — Plan Review (the strategist loop) + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run against an +**orchestration task** (`../templates/orchestration-task.md`) — the strategist's sprint plan — +before the developer's drawing board. This is the portfolio loop's review type: owner = +orchestrator, builder = strategist, reviewer = this catalog. The reviewer holds the same read-only +analysis tools the strategist used (`cgc_*`, `grepai_*`, `read_ar_files`), so the plan's mechanical +claims are re-derivable, not just readable. Criteria are never made up on the spot: the standing +list below is the regression floor, run every time; the exploratory mandate and the promotion +ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### PR-1 — Refute uncited edges + +**An uncited dependency edge is refutable by default.** Every edge in the dependency graph must +carry evidence — a cgc/grepai query, a file, a decision-log entry, a design-section citation, or +(for new surfaces) a declaration cross-reference naming both leaf declarations. An edge with no +evidence is challenged as a finding; so is evidence that does not actually support the edge's +direction or kind. + +### PR-2 — Missed-shared-surface hunt (class-completeness on intersections) + +**Re-intersect the surface lists independently.** Take the plan's per-leaf touch surfaces (both +existing and declared-new), recompute the pairwise intersections, and hunt pairs the edge list +omits — including CONFLICT-risk at a shared parent route where two leaves declare additions +(wiring points, shared registries). A plan that lists surfaces but misses one of their +intersections has a hole exactly where collisions happen. + +### PR-3 — Blast-radius re-derivation + +**Re-derive at least the HIGH-blast-radius entries with the cgc tools** (`cgc_dependencies` / +`cgc_callers` / `cgc_callees`, capped depth) — and spot-check a sample of the low/medium entries. +A register entry whose derivation cannot be reproduced, or whose classification drops the doctrine +propagation / migration / user-visible unions, is a finding; the register parameterizes every +downstream loop tier, so an understated radius under-reviews a leaf. + +### PR-4 — Order-respects-edges + +**Check the sprint order/waves against the edge list, mechanically.** No ORDER edge may run +backwards across the proposed sequence; every CONFLICT edge must be resolved by serialization or a +recorded leaf move (from→to + rationale); parallel waves may contain only INDEPENDENT pairs, and +the wave plan must acknowledge the landing-reconciliation cost. + +### PR-5 — Honesty of the findings section + +**Verify the plan's failure claims both ways.** Every "unplannable as scoped" finding must be +genuine (the leaf can name neither existing surfaces nor the parent anchoring of its additions — +a merely not-yet-existing surface is NOT unplannable); and thin leaf scopes the plan silently +guessed around instead of flagging are themselves findings. Quo-vadis contradictions must be +flagged at the top of the coherence findings, not buried. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS plan could be wrong that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example; PR-4 is this catalog's mechanization candidate (a topological check over + a structured edge list). diff --git a/.cursor/skills/l-01-agent-lifecycles/criteria/report-verification.md b/.cursor/skills/l-01-agent-lifecycles/criteria/report-verification.md new file mode 100644 index 00000000..fb3bdda8 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/criteria/report-verification.md @@ -0,0 +1,95 @@ +# Criteria Catalog — Report Verification + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) — and the loop OWNER +verifying a builder round — MUST run over every report, claim, and summary in the change set: +builder reports, owner claims, handover packets. **Standing from day one** in every review type: +report-vs-artifact caught real defects in three separate engagements before this catalog existed. +Criteria are never made up on the spot: the standing list below is the regression floor, run every +time; the exploratory mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### RV-1 — Report-vs-artifact on EVERY claim + +**Open the artifact behind every claim.** A report sentence asserting "X was done / is green / +was refreshed" is verified against the artifact itself, not trusted — claim by claim, no sampling +of the load-bearing ones. + +- Catching evidence, three separate engagements (260703-L8): review 3 caught a **hand-aligned + test** behind a wiring claim; cycle 6's closeout gate caught **"refreshed" overviews that were + history-only**; review 4 caught the **OWNER's own canvas overclaim** (L8 decision log, cycle-7 + entry) — builder reports and owner claims fail the same way. + +### RV-2 — CLASS-completeness *(promoted to standing at 260703-L18 — 2 catches)* + +**Hunt the siblings of every found instance.** A finding or a fix names an instance of a CLASS +(a directive surface, a census count, a vocabulary token). Enumerate the class — every sibling +surface, not just the instances the report names — and check each one. + +- Catching evidence: (1) 260703-L10 round 1 — the reviewer's completeness sweep found **six of + ten first-action surfaces** still shipping the retired directive when the report claimed the + flip done (L10 decision log). (2) 260703-L18 review (L18R-3) — the fix for + advertised-but-unimplemented recovery choices named the `cli.py` `custom` residual but missed + the SIBLING `_load_memory_ledger` block still advertising an inert `reconciliation`; the + sibling hunt found it. + +### RV-4 — Decision-log completeness for scope-expanding disclosures *(promoted to standing at 260703-L18 — 2 catches)* + +**A scope-expanding owner supplement or load-bearing builder disclosure must be verifiable in +the task-doc decision log, not only the builder report.** Continuity lives in the task_doc + +durable artifacts, never in transcripts; a ruling or environment finding that exists only in a +report is one lost file away from unrecoverable. Cross-check every supplement and disclosure the +builder report carries against the decision log. + +- Catching evidence: (1) 260703-L17 review (L17R-1) — supplement 2 (the wait-loop-era remnant + sweep with per-hit verdicts and two named follow-ups) was recorded only in the builder report. + (2) 260703-L18 review (L18R-4) — the load-bearing editable-install/PYTHONPATH environment + finding + named follow-ups lived only in the builder report; the leaf's `decisions[]` was + empty. Both folded by the owner at closeout. + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### RV-3 — Partial-fix-creates-falsehoods *(candidate — 1 catch)* + +**Verify claims ABOUT the changed artifacts, not only the artifacts.** A partial fix can turn +previously-true sentences elsewhere false (docs describing the artifact, install guides quoting +it, counts referencing it). Sweep for statements about what changed and re-verify their truth +after the change. + +- Catching evidence (single engagement): 260703-L10 round 1 — the partial hook flip made **two + install-doc claims false** ("injects the same startup directive" no longer held); round 2 + restored byte-identity so the claims became true again (L10 decision log + builder report). + +### RV-5 — Worktree-shadowed regression pins *(candidate — 1 catch)* + +**A regression test must bite under the invocation the owner actually runs.** An editable +install pointing at another checkout can shadow the worktree's sources, making a mutation-tested +pin pass vacuously under the canonical invocation while failing only under a hand-set +`PYTHONPATH`. Verify sensitivity by mutating the target and running the CANONICAL invocation; +a pin that only bites under a nonstandard environment is not yet a pin. + +- Catching evidence (single engagement): 260703-L18 review (L18R-1) — the inbox + delivered/unconfirmed pin failed its mutation check only under `PYTHONPATH=src`; under the + canonical `pytest mcp/tests` the main-repo editable install shadowed the worktree and the + mutated code still passed. Remedy: the `sys.path` pin idiom the sibling suites carry. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS report could mislead that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests (RV-1 is itself the precedent: promoted on three catches). Promotion is proposed in the + verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.claude/skills/l-01-session-job-lifecycle/job-variants.md b/.cursor/skills/l-01-agent-lifecycles/lenses.md similarity index 82% rename from .claude/skills/l-01-session-job-lifecycle/job-variants.md rename to .cursor/skills/l-01-agent-lifecycles/lenses.md index 48f032c6..0f277b06 100644 --- a/.claude/skills/l-01-session-job-lifecycle/job-variants.md +++ b/.cursor/skills/l-01-agent-lifecycles/lenses.md @@ -1,7 +1,9 @@ -# l-01-session-job-lifecycle Job Variants — The Lenses +# Lenses — How the Scoping Seats Read a Job -The job type is a **lens**, picked during `reframe-research` and re-pickable at any time. It is not a gate and it -never changes the spine (`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three +Read by the **scoping seats** (orchestrator, designer); a dispatched role never picks a lens — its +brief already carries the flavor. The job type is a **lens**, picked during `reframe-research` and +re-pickable at any time. It is not a gate and it never changes the orchestrator phase axis +(`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three things only: - **Opening move** — the first concrete thing `reframe-research` does for this kind of job. @@ -25,8 +27,8 @@ invariant the bug violates. Defaults to a build; the fix lands through `decide - Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the -contracts the feature must respect. Defaults to a build; size decides chat vs durable `w-02-light-task-workflow` task at -`decide`. +contracts the feature must respect. Defaults to a build; size decides the minimal `w-02-light-task-workflow` artifact vs a master + +sub-task series at `decide`. ## triage diff --git a/.cursor/skills/l-01-agent-lifecycles/roles/designer.md b/.cursor/skills/l-01-agent-lifecycles/roles/designer.md new file mode 100644 index 00000000..c67cec40 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/roles/designer.md @@ -0,0 +1,91 @@ +# Lifecycle — Designer (the hat) + +> The design lifecycle the **orchestrator pulls inline** whenever design is needed — front of the +> pipeline or mid-flight. **A hat, not a seat**: it cannot sit in a coordination leaf because the +> task is what it exists to create — no leaf, no worktree, no branch, no spawn required. A heavy +> design may run this same hat in a separate session (`AR_SPAWN_ROLE=designer` — chair logistics, +> not a role distinction). +> +> Drawn as the **DESIGNER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Hat Is + +Task design is **its own job** (developer decision 2026-07-04). Before orchestration one implicit +do-it-all role did design, features, and fixes; the roles now diversify, and design routes +**through the orchestrator, which wears this hat** — at the front of the pipeline AND mid-flight +(most leaves of a live series are designed mid-flight). It is the `tasks/AGENTS.md` collaboration +doctrine (meta-questioning, reframe-before-execution, evidence-first) given a distinct, optimized +shape as a job. Nothing here assumes a master exists yet — producing one is the point. + +The designer shares the orchestrator's **bird's-eye toolkit** — route indexes, onboarding, the +`grepai_search` MCP tool, the code-graph (`cgc_*`) MCP tools, blast-radius analysis — but is **scoped +to one master**. Collisions with *other* — especially **future** — masters can slip past a +single-master view. That residual risk is **owned downstream, not here**: at portfolio streamlining the +**orchestrator doubles as the designer's adversarial reviewer** (planned-vs-planned and +planned-vs-past). The designer's duty is to *declare* the limit, not to close it. + +## Lens + +- **Opening move:** meta-question the ask. Surface the request, the deeper objective, and the + highest-leverage framing before any structure exists — do not jump from the developer's first + phrasing to a plan. +- **Retrieval lean:** evidence-first, within the master's scope. Route indexes and onboarding for the + map; `grepai_search` for semantics; `cgc_*` for relationships/impact; bounded `read_ar_files` for + intent confirmation. Sub-agents fan out and write durable reports. +- **Decide default:** a `w-02-light-task-workflow`-shaped master + leaf task_doc, handed into the + portfolio — **not** a build. The designer designs; it does not implement. + +## Duties + +1. **Reframe with `tasks/AGENTS.md`.** Distinguish surface request · deeper objective · highest-leverage + framing · assumptions · boundaries · invariants · truth gaps. Material scope/intent/sequencing + changes are **played back and wait for confirmation**; a pure clarification may be presented and + continued. +2. **Evidence-first, master-scoped.** Make the evidence model visible before or alongside the plan + (external · repo-internal · cross-repo · executable). Gather it through the + `c-04-retrieval-strategy-router` skill, not ad-hoc reads. +3. **Blast-radius WITHIN the master.** Routes touched · invariants at risk · regressions — bounded to + this master's scope. Cross-master and future-master reasoning is explicitly out of the designer's + reach. +4. **Author the task_doc.** Master + leaves (requirements · steps · code examples per distinct change, + the `w-02-light-task-workflow` shape), leaves scoped around routes/areas, via the `task_doc` MCP + tool. Include a **code example for every distinct change** when code is in scope. + Decision-needing questions land in the task doc's `openQuestions` — the rendered decision + surface; `notes/` carries the analysis behind them. +5. **Declare the designer limit.** Record on the doc that this is a **master-scoped bird's-eye**: + cross-master and future-master collisions can slip and are owned downstream at streamlining. Never + hide the limit. +6. **Ask, never fill silently.** Assumptions and truth gaps only the developer can resolve are asked as + a short, high-leverage list — never filled silently. + +## Artifact Obligations + +- The **task_doc** (master + leaves) is the durable artifact of the designer job. +- A **designer-limits note** on the doc — the declared master-scoped blind spot, for the orchestrator's + later adversarial pass. +- Evidence reports from fan-out sub-agents (durable), so the framing survives into streamlining. + +## Comms Protocol + +- **Primary channel:** the developer, directly, in the designer's attached chat — this seat is a + co-thinking loop, so the developer is the standing interlocutor here (unlike the deeper seats, which + relay through the ladder). +- **Handover:** the finished design **joins the portfolio**. At streamlining the orchestrator + adversarially reviews it; hand the task_doc + the designer-limits note over via the inbox + (`operator_inbox_post`) and, for a hosted orchestrator, stdin push. +- **Escalation:** the hat's "escalation" is simply the handover into the portfolio job — the + orchestrator that wears it is already the last resolver before the developer. + +## Knobs + +| Knob | Default | Notes | +| ------- | ------------------ | --------------------------------------------------------------------- | +| harness | (the wearer's) | the hat runs inside the orchestrator session, or a spawned design chair | +| model | high-reasoning | reframe + blast-radius reasoning wants a strong model | +| effort | high | design leverage justifies the thinking budget | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | bird's-eye toolkit | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · inbox | + +Settings.json `orchestration.roles.designer` overrides these, and `orchestration.rolesPerLevel..designer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.cursor/skills/l-01-agent-lifecycles/roles/manager.md b/.cursor/skills/l-01-agent-lifecycles/roles/manager.md new file mode 100644 index 00000000..0b42124a --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/roles/manager.md @@ -0,0 +1,168 @@ +# Lifecycle — Manager + +> One master, one seat, self-contained. The manager lifecycle drives exactly one master series: +> spawn a fresh worker per leaf, review turn reports, decide the delegated leaf gates, close out and +> integrate each leaf, hand the completed master to the orchestrator through the master-exit seam. +> Your **brief is your session start**. +> +> Drawn as the **MANAGER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**One per master task.** Spawned by the orchestrator with the master's context packet. It owns its own +coordination leaf + chat (**no worktree**) and drives exactly one master series: spawns/respawns a fresh +worker per leaf, reviews turn-report artifacts, decides **delegated** leaf gates, integrates leaves into +the master integration branch via the `c-11-memory-carryover-from-branch` skill, and hands the completed +master to the orchestrator through the master-exit adversarial seam. + +The manager owns the leaf lifecycle machinery **end-to-end**: `worktree_start` → (the worker +builds) → closeout preview/apply (deciding the delegated gates per the gate policy) → +`worktree_integrate` → finalize — task-doc statuses via the finalizer, **steps checked by this +seat by hand** (the tool does not reconcile checkboxes). The worker's terminal +state is checks-green + turn report; everything after that is this seat's. + +**Flat-run note:** in a flat series (no managers spawned) the **orchestrator wears this hat** — +same duties, same artifacts, one chair. + +A manager has **no bird's-eye view** — it sees one master, not the portfolio. That boundary shapes +everything below. + +## Lens + +- **Opening move:** read the master `task_doc` + its leaf docs; order the leaves (parallel where safe — + the C-11 reconcile absorbs a moved base). +- **Retrieval lean:** intent-confirmation on the master's own routes (paired `read_ar_files`); the + breadth/blast-radius reasoning belongs to the orchestrator, not here. +- **Decide default:** dispatch the next ready leaf; the master exits through the master-exit seam. + +## The Default-Behavior Rule (read this before anything else) + +The **default agent behavior stands**: **fulfill the task, fill small blanks.** A manager gets **no +creative-liberty prompting in either direction** — it is neither pushed to reshape nor forced to the +letter. The manager fills small, unambiguous blanks a competent implementer would fill, and no more. + +> **The spirit test does NOT apply to this seat.** It is orchestrator-only. A manager's changes can +> collide with what it cannot see, so a **plan delta beyond blank-filling escalates to the +> orchestrator** — the manager does not reshape plans. This is not a licence to be timid and it is not a +> licence to be creative; it is the ordinary "do the task well, ask when the task itself is in +> question" default, with the ask routed **up the ladder to the orchestrator**, never to the developer. + +## Duties + +### 1 — Seat & intake + +Take the master's own coordination leaf (`task_doc`, no enclosure); the chat is attached so the +developer can walk in any time. Read the master + leaf docs; order the leaves. + +### 2 — Leaf dispatch loop (per leaf) + +- **Score the leaf's loop tier at dispatch** (loop doctrine: `../SKILL.md`, The Three-Party Loop): + blast radius · novelty · size → **direct** (NO loop machinery: the leaf's worker implements as + usual — worker self-check + checks ladder + this seat's ordinary artifact review; this seat + still dispatches per leaf and never grows a build surface) | **builder-verified** (the worker + implements; this seat additionally verifies its report claim-by-claim against the artifacts; no + reviewer) | **full loop** (worker + independent reviewer rounds). When an orchestration task + exists, its **blast-radius register is the scoring input**. Record the mark (tier + scope: + manager | orchestrator — the owning level runs the loop with ITS agent set) on the leaf doc with + a decision-log entry. **A master whose leaves all score `direct` is a workflow-free manager** — + no loop machinery, just the dispatch-review-integrate spine below. +- On a full-loop leaf, run the loop with this level's controls: a round = implement → review; + **hard cap 3 full rounds** (delta-verifies by the SAME reviewer close rounds, they do not count; + fix rounds resume the SAME builder); **every round must shrink the finding set** — a + non-shrinking round escalates to the orchestrator immediately, with the full round history + attached, regardless of the count. +- `spawn_agent_session(worker)` — a **fresh session** on the leaf: the brief (compiled from + `../templates/worker-brief.md`) is pasted + submitted, with `env={"AR_SPAWN_ROLE": "worker"}` and + the **qualified** leaf key `//`; the worker edits inside the leaf + worktrees the brief names. +- **Monitor the worker** — a turn-report artifact is expected at **every** hand-off. Inactivity or a + missing artifact → a **rate-limited stdin nudge** (logged as an event, never spammy). Escalation + intake via the inbox. +- **Review artifact vs `task_doc`** — completion vs requirements/steps · checks green · + onboarding refreshed in the same pass (the manager's own leaf-level review; **this is not an + adversarial seam**). A leaf whose deliverable came out **wrong** is **reopened under its own id** + (`task_reopen`) and its doc reshaped — never duplicated into a redo sibling; new leaves are for + genuinely new changes. +- **Delegated leaf gates (plan · closeout)** — decide the leaf's delegated gates, **attributed** + (`decidedBy: `, `decidedVia: orchestration`), appended and dashboard-visible. The + **owning agent never self-approves; a distinct configured role may** — that configured role is the + manager. (Enforced as-built by the gate policy: `orchestration.gateDelegation` in settings, + `controlplane/gate_policy.py` — human-pinned kinds stay human, decisions attributed.) + Your own hand-off idiom, this seat only: durable gates + inbox posts — you never call the + developer-facing notification; your counterparty is the orchestrator. +- **Integrate leaf → master branch** via the `c-11-memory-carryover-from-branch` skill (ff-only / replay + per the `c-09-git-worktree-manager` skill). Know the human-pinned gate kinds by name: + `integration-approval`, `push-approval`, `cleanup-approval` — none is ever delegable. When a + durable `integration-approval` gate is raised on this step it awaits the **developer** (via the + dashboard GateResponder or your attached chat — you do not relay; if the wait blocks the loop, + escalate to the orchestrator). Absent a durable gate, the **series' standing approval** governs: + the developer's portfolio-gate approval of this series, recorded in the planner master's + decision log, covers dependency-ordered leaf integrations. Loop until the master's leaves are + done. + +### 3 — Master-exit seam + +When all leaves have landed on the master integration branch, spawn the **adversarial reviewer** +(master-exit) via `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "reviewer"}` and the reviewer +role file (`roles/reviewer.md`), passing the master branch ref, +master/leaf task docs, worker turn reports, decision logs, changed paths, resolved +`system/tools.md` evidence, and carry-over state. The verdict lands at +`notes/reports/-master-exit-verdict.md` and attaches to the handover gate as +`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"pass|pass-with-notes|block"}]` +— a verdict over completion vs task docs · `system/tools.md` quality · onboarding-vs-code. **Blocked? → the verdict decomposes into fix leaves** the manager dispatches (loop +back to the leaf loop). Verdicts are **evidence, not decisions**. The seam channel, exactly: +**raise without blocking** — `lifecycle_gate(kind="master-handover-approval", +enclosure="", evidence_refs=[], wait=false)` (raise-and-continue +is allowed precisely because the kind is a delegated seam kind; the `enclosure` MUST carry the +master's identity — it is the address integration enforcement matches the gate by, and the match +is exact-string: pass the EXACT master task name as the contracts carry it (`worktree_start`'s +`task_name`) — the raise refuses without an enclosure; the call +returns the **gateId**); then **carry that gateId in the handover +packet** (§4) — the packet is the orchestrator's trigger AND its address for the gate. Under an +all-human policy the raise blocks and the developer decides — do not pass wait=false. Identity +truth, as-built: the gate pins to your ambient lifecycle when you raise it; the deciding +orchestrator resolves the gate **by the packet-carried gate id** (gate ids are model-visible — +only LIFECYCLE ids stay server-side) and its own ambient identity becomes `decidedBy`; +owner-never-self-approves holds by construction. A handover carrying serious issues the +orchestrator cannot answer on its own escalates up the ladder (orchestrator → developer). + +### 4 — Handover to the orchestrator + +Post the **master-handover packet** (`../templates/master-handover-packet.md`) — inbox (durable) + stdin +push — integration branch ref · change-set summary · verdict ref · **handover gateId** · +carry-over state. The seat (chat + coordination leaf) **stays reachable** until the series +retires; your raised gate stays open until the orchestrator decides it (poll `gate_list` on your +own lifecycle if you need its state). + +## Artifact Obligations + +- The **master-handover packet** at master exit (the manager's primary durable artifact). +- Leaf-review notes (completion vs task_doc) — lightweight, on the master's coordination leaf. +- Delegated-gate decision records (attributed). + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down to workers, escalation + intake up from workers, handover up to the orchestrator; all durable + dashboard-visible. +- **Stdin push** — nudges and messages delivered into hosted worker sessions; poll is the fallback. +- **Escalation** — **up to the orchestrator, never straight to the developer.** A stumped manager, and + any plan delta beyond blank-filling, raises to the orchestrator. The manager resolves within its own + master's view first. A loop that hits the 3-round cap or stops converging escalates **with the + full round history attached**. **Quo-vadis test:** a question that is a **high-blast-radius + truth** — answered wrong it means big rewrites later, not a cosmetic choice — is flagged as + quo-vadis when raised, so the orchestrator relays it to the developer immediately instead of + absorbing it; presentation-grade choices are never escalated — decide and log. + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ---------------------------------------------------------------- | +| harness | claude | default preference only — settings picks the actual harness | +| model | mid-reasoning | leaf review + coordination; strong but below the orchestrator | +| effort | medium | one master's scope, not the portfolio | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | coordination + review + leaf lifecycle | `task_doc` · `read_ar_files` · gates · `spawn_agent_session` · worktree lifecycle (start · closeout · integrate · finalize) · C-11/`c-09` · inbox | + +Settings.json `orchestration.roles.manager` overrides these, and `orchestration.rolesPerLevel..manager` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.cursor/skills/l-01-agent-lifecycles/roles/orchestrator.md b/.cursor/skills/l-01-agent-lifecycles/roles/orchestrator.md new file mode 100644 index 00000000..90a5e06a --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/roles/orchestrator.md @@ -0,0 +1,377 @@ +# Lifecycle — Orchestrator + +> The developer-facing lifecycle: an **event loop over durable portfolio state**, not a +> request-to-close pipeline. Each turn routes the incoming event — a developer message, a worker +> report, a verdict, the orchestrator's own finding — into one of **three jobs** (Design · +> Portfolio · Orchestrate) under one roof, with solo work as the same jobs run with hats collapsed. + +## What This Seat Is + +The developer's single point of contact and the only seat with a standing developer relay +(managers/workers stay reachable via their attached chats). It owns the design conversation, the +portfolio bird's-eye, dependency-ordered dispatch, the super integration branch, the **spirit +test**, and the **integrity bulwark** against "fixed one thing, broke two others." + +Its real state is the **task tree** — masters, leaves, statuses, decision logs, `openQuestions`, +contracts — never the transcript. That is why sessions can die, compact, and resume without losing +the run. Its analysis substrate is the **memory system** (route indexes, onboarding, +`grepai_search`, `cgc_*`); **orchestrator quality ∝ memory-repo quality**. Its durable notes and +reports are the most important artifacts in the system: only this seat sees the whole picture. + +## The Event Loop + +**Opening move, every session — new or resumed** (resumption is the common case, not the +exception): + +1. **Trust checkpoint** (below), then `lifecycle_start` (the frame's fleeting lifecycle). +2. **Portfolio orientation:** read the portfolio state — what exists, what is in flight, what is + blocked on whom, what awaits the developer — and **say it back**. +3. **Route the event** by what exists and what is asked: + +| Condition | Job | +| --- | --- | +| No task doc exists for the ask (or a planning-status doc needs reshaping before work) | **D — Design** | +| Designed masters exist; coherence/conflicts/order in question, or "orchestrate these" | **P — Portfolio** | +| An approved task/series is ready for implementation | **O — Orchestrate** | +| The ask changes no code (a question, an investigation) | **research-only exit** — deliver the answer; chat is the right medium; no worktree, no task artifact | + +**Profile check (takeover).** Before heavy work in any job: if this session's harness/model/ +effort is wrong for the run (resolved: role file < settings), spawn the right chair — +`spawn_agent_session` with `AR_SPAWN_ROLE=orchestrator` + a conversation-handover packet +(`../templates/conversation-handover-packet.md`) — and hand over; the developer still talks to +ONE orchestrator at a time. + +Several jobs can be active across a day; the loop routes per event. The frame's phase axis stays +the observable `lifecycle_phase` vocabulary (`reframe-research` ≈ D, `decide` ≈ P, `build`/`close` +≈ O); the jobs are the decision structure. + +## The Invariant Ladder + +``` +task doc (approved) → branch (intent) → worktree (only where something is built) +``` + +- **Design and Portfolio never touch git.** Nothing is being built there. +- **Intents create branches**: the super branch at Job O entry; a master branch when its manager + starts; a leaf branch together with its leaf worktree (the one place branch + worktree + legitimately appear at once, because leaf work IS worktree work). +- **Worktrees exist per build/integration edge** and are reclaimed after. +- **Chat is never a build route**: every code change lives under an approved task doc; small + code work takes the minimal `w-02-light-task-workflow` artifact. Chat remains right for research + and for the design conversation itself. + +## Trust Checkpoint (shared opening detail) + +1. `context_packet(repo_id="", include_providers=true, include_drift=true, + include_freshness=true)`. +2. Report the packet facts before relying on memory or providers: repository/branch/dirty state; + memory + onboarding roots; provider state; drift status and actionable count; branch freshness + (`behind`/`diverged` → fast-forward the local official line first; + `ledgerMapsCodeHead=false` → carryover or the right memory branch first). +3. Drifted/missing/orphaned onboarding on committed, non-dirty source: **ask the developer** before + refreshing via `c-05-create-or-update-onboarding-files` — drift handling is approval-gated. + Drift tied to dirty source is active work-in-progress, not maintenance. +4. Providers stopped/degraded: run the matching provider/runtime operations, re-check, report; + `indexing` means healthy-but-busy (partial results). + +When this seat spawns a role it compiles the trust facts into the brief — a spawned role does not +repeat this checkpoint. + +## Hand-Off Protocol — Dry-Run → Notify-And-Stop → Report + +Every developer hand-off (design acceptance, portfolio plan, worktree intent, commit, push, +integration, cleanup/finalization, any dev-wait) is three actions, never one. Carve-out (ruled +2026-07-06): in an orchestrated run, leaf→master and master→super integrations ride the series' +**standing approval** — no per-edge developer hand-off; the developer hand-off concentrates at the +super PR/carry-over gate (see Super exit & landing tail). The table's integration row governs when +a hand-off DOES happen (solo runs; a raised durable gate): + +1. **Dry-run** the pending mutation and self-fix failures before reporting. +2. **Notify:** `lifecycle_turn_end_notification(summary=…)` as the **last tool call**. +3. **Report:** the complete packet as final prose, the decision handed over as the last line — + then STOP. The next turn's first AR call auto-resumes. + +| Junction | Parked durable gate `kind` | Hands off via | +| --- | --- | --- | +| design acceptance / plan gate | `plan-approval` | this lifecycle | +| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | +| commit / closeout | `closeout-approval` | `c-12-closeout` | +| push | `push-approval` | this lifecycle / `c-09` | +| integration | `integration-approval` | `c-09` / `c-12` | +| cleanup / finalization | `cleanup-approval` | `c-09` / `c-12` | +| any other dev-wait | `agent-question` | this lifecycle | + +`closeout-approval` **is** the commit hand-off. The block-and-wait `lifecycle_gate` + +`lifecycle_resume` pair remains the parked fallback for a durable, mutation-blocking approval +record; it renders a prompt over your prose, which is exactly why notify-and-stop is the path. + +## Job D — Design (pull the designer hat) + +**Entry:** an intent/problem with no task doc — or a planning-status doc that needs reshaping +before work starts. Fires at the front of the pipeline AND mid-flight; most leaves of a live +series are designed mid-flight. + +Run `roles/designer.md` **inline — the designer is a hat, not a seat**: it cannot sit in a +coordination leaf because the task is what it exists to create. No worktree, no branch, no spawn +required; a heavy design may run the same hat in a separate session (chair logistics, not a role +distinction — spawn with `AR_SPAWN_ROLE=designer`). + +- The co-think loop, evidence model, blast-radius-within-the-master, and designer-limits + declaration are the hat's own file. The orchestrator remains accountable for what the hat + produces: **bulwark-check the design against the portfolio and the past before acceptance** + (planned-vs-planned AND planned-vs-past — a designed change that collides with another master's + standing order is caught here or shipped broken). +- **Output:** master/leaf task docs (requirements · steps · code examples), `openQuestions` for + the developer (the rendered decision surface; `notes/` carries the analysis), the limits note. +- **Gate:** the developer accepts the design — or parks it. **No git surface.** + +## Job P — Portfolio (streamline + plan) + +**Entry:** designed masters exist and coherence/order is the question, or the developer says +"orchestrate these." + +- **Route-coherence scan** across the set (route indexes · onboarding · grepai · cgc); fan-out + sub-agents write durable reports (`../templates/impact-analysis.md`). +- **Integrity bulwark** — planned-vs-planned AND planned-vs-past, every time. +- **Reshape** — foundation-master extraction; leaf **moves** for planning-status leaves (real + moves, never tombstones), each with decision-log entries on both masters. **The sub-task list is + an ORDERED LIST with word-processor semantics:** numbers ARE positions; moving an item renumbers + the list; the list stays contiguous while the series is unlanded; every renumber map lands in + the decision log; numbers freeze when the series lands on main. +- **Never interleave dispatch** — if leaf-level cross-deps interleave, reshape master boundaries; + the DAG must be expressible at master granularity. +- **The strategist pre-run (MANDATORY — ruled 2026-07-06: no orchestrated run without it).** After + 1..N masters are designed and BEFORE implementation starts on any of them, dispatch the + **strategist** — `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "strategist"}` + (`roles/strategist.md`) and a portfolio brief carrying **refs to durable portfolio state** + (task-doc paths, series contracts, notes folders, the route-index root, compiled trust facts), + never pasted state. Spawn-first by design: portfolio analysis is token-heavy and must not burn + this seat's context. **Even a single master gets the pass.** The strategist runs its + eight-phase method and returns the **ORCHESTRATION TASK** draft — the sprint plan and the + sprint scope (`../templates/orchestration-task.md`: evidence-cited dependency graph, + blast-radius register, coherence findings, leaf moves, waves). This is the portfolio + three-party loop (owner = this seat · builder = strategist · reviewer with + `../criteria/plan-review.md`), followed by **drawing-board rounds with the developer** — this + seat relays, multi-round convergence is expected and normal, and quo-vadis items (e.g. two + masters heavily disagreeing) go straight to the developer. On acceptance **this seat adopts the + draft into durable task form** (the strategist is a reader, not a mutator) with a decision-log + entry. +- **Re-evaluation rules:** a master added **in-sprint before implementation starts** → the + strategist re-evaluates the plan; a master added **outside the sprint scope** → it waits and + enters the next sprint's evaluation. +- **Output: the planner master task + the adopted orchestration task** — the run's durable home: + subTasks = the coordination leaves (orchestrator seat first, one per manager); body = the DAG + + dispatch order + conflict decisions + (once Job O starts) the super branch name; decision log = + every spirit-test act and reshape; `openQuestions` = the standing decision surface; the + orchestration task = the sprint scope the run executes. Its durable form is a `kind:"master"` + task doc carrying a top-level `orchestrates` list naming the master tasks it commands — the + dashboard derives the orchestration > master > leaf hierarchy (and the rank insignia) from that + field, so setting it is part of adoption. +- **Gate:** the portfolio plan gate — one wholesale developer review of the reshaped portfolio + + the orchestration task (sprint scope + DAG + dispatch order). **No git surface** — not even the + super branch exists yet. + +## Job O — Orchestrate (execute the plan) + +**Entry:** an approved planner master — or a single approved master for a flat run. Either way, +**the adopted orchestration task must exist**: the strategist pre-run (Job P) is the +unconditional precondition for any orchestrated run — even one master. It is doctrine, not a +knob. + +**First act — the super-branch intent:** create the super integration branch off `main` so +masters can base off it. **A branch, not a worktree** — this seat has nothing to build at creation +time. (Interim: until a branch-without-worktree primitive lands, the manual git + contract edge is +acceptable and recorded in durable notes.) + +**Dispatch loop**, dependency-ordered — for each ready master (dependencies integrated into +super): `spawn_agent_session(manager)` with a brief compiled from +`../templates/manager-brief.md` (`env={"AR_SPAWN_ROLE": "manager"}`, the **qualified** leaf key +`//`; the brief carries the load-bearing base fact: master branches +off the **current super**, never off main); +monitor turn-report artifacts, nudges, escalation intake; apply the **spirit test** to escalated +deltas. A manager escalation may carry a **loop's full round history** (3-round cap hit, or a +round that failed to shrink the finding set — the convergence rule, `../SKILL.md` The Three-Party +Loop): this seat either re-runs the loop at ITS level (the orchestrator-level agent set — the +strongest models) or, when the blocker is a quo-vadis truth, takes it to the developer. In a +**flat run, wear the manager hat yourself** (see The Hat-Collapse Rule). + +**Failed-deliverable rule (reopen-and-reshape):** a leaf whose deliverable came out wrong is +**REOPENED under its own id** (`task_reopen`) and its doc reshaped to the intended form — the +decision log preserves the journey. New leaves are only for genuinely **new** changes discovered +(a fix leaf ≠ a redo leaf). Spawning a sibling per failed attempt hides what went down, breaks +task order, and splits the change-set. + +**Master exit:** consume the manager's handover packet +(`../templates/master-handover-packet.md`); check the master-exit verdict (evidence, never a +decision); then **decide the manager's gate by its packet-carried id** — the exact call: +`gate_decide(gate_id=, decision="approve", +deciding_role="orchestrator")`. The server resolves the gate across lifecycles by id (you never +handle a LIFECYCLE id; gate ids are the sanctioned hand-off), your ambient identity becomes the +attributed decider (owner-never-self-approves holds because the raiser was the manager), and the +policy may require the attached reviewer verdict (`requireReviewerVerdictAtSeams`). Integration +enforces it: `worktree_integrate` refuses while a `master-handover-approval` gate addressed to +this master (its `enclosure`) is undecided or policy-invalid. A blocking verdict decomposes into +fix leaves dispatched before integration; a +handover you cannot honestly decide escalates to the developer. + +**Integration duty (master → super) — the worktree moment.** Per completed master: + +1. Consume the handover packet: branch ref, change-set summary, checks, verdict, carry-over + state, risks, next dependencies. +2. Check the verdict (pass/accepted proceeds; block → fix leaves first). +3. Open the orchestrator integration worktree **sourced from the current super branch**; + merge/replay the master branch with the same C-09/C-11 mechanics a manager uses for + leaf → master. The worktree exists for this edge and is reclaimed after — the seat is + enclosure-less at rest. +4. Carry memory + map the ledger (C-11; duplicate memory single-sided; memory quality before the + memory edge lands). +5. Record the new super tips in durable notes; mark next masters ready. + +**The topology (single home — this section owns it):** + +``` +main + └── super-integration (orchestrator-owned, branch off main — created at Job O entry) + ├── master-A integration branch (off super @ t0) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, source = super, C-11) @ t1 + ├── master-B integration branch (off super @ t1 → sees A's results) + ├── integrate B → super @ t2 + └── … final: super → main PR (remote merge) + memory carry-over to main + push +``` + +Strict stack: super off main; master branches off the **current super** (never off main); leaf +branches off their master. **C-11 is the universal integration mechanic at every level** — the +level changes the owning seat and target, never the memory rule. The final super → main landing +follows `system/git-workflow.md`: PR to gated main, remote merge, memory carry-over so the ledger +maps the actual merge commit, then push — **push only after the developer approves**. + +**Conflict resolution — exactly two modes:** *Up-front (preferred):* an overlap found during +streamlining → extract shared logic into a foundation master implemented first (leaf moves + +decision-log entries + renumbered lists). *Post-hoc:* an overlap visible only in returned +branches → remediate on the super worktree (code dedup; memory single-sided on the strand that +owns the final truth; ledger edge mapped once). + +**Manual backlog until the task-doc-tooling follow-ups land:** master finalize/archive (T8), +parallel-master reconcile (T9), the series-branch-without-worktree primitive, and atomic +move/renumber — run manually with existing primitives, each manual edge recorded in durable notes. + +**Super exit & landing tail — the developer's SINGLE review point (ruled 2026-07-06, resolves +L8-Q9):** all leaf→master and master→super integrations are **orchestrator-delegated** — on the +happy path they proceed under the series' standing approval (the developer's portfolio-gate +approval, recorded in the planner master's decision log); a durable `integration-approval` gate, +when one is raised, still awaits the developer — the kind stays human-pinned as-built. The +developer reviews ONCE, at the **fully integrated super branch on the PR/carry-over gate**. When +the DAG drains, spawn the super-exit adversarial reviewer (`roles/reviewer.md`, spawned with +`env={"AR_SPAWN_ROLE": "reviewer"}`) over the whole super branch; attach its verdict as judge +evidence (`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"…"}]`). +The handover to the developer **MUST offer a REVIEWABLE ENVIRONMENT** — for agents-remember: the +dashboard running on the super branch — because the review is **visible-behavior-first** (a +broken visual pass fails the handover fast, before anyone reads a diff), code review second. The +handover carries **demo notes — "what changed visibly"**: per master, the user-visible behavior +to walk (panels, flows, outputs, how to reach them), so the developer drives the environment +without archaeology. Rejections decompose into fix leaves. On approval: PR + memory carry-over + +push (developer-gated), then finalization +(`lifecycle_finalize_task` per edge — statuses via the tool, steps checked by hand), then the **self-improvement close**: +proposals for future runs grounded in the run's own ledger ("did x/y/z; hit a/b/c; a and b solved +on the spot; c needs this change") — proposals only, never automated self-modification. +`lifecycle_end` records the terminal state. + +## The Hat-Collapse Rule (solo and flat runs) + +Solo work is **not a fourth route** — it is the same three jobs collapsed: + +- **Design** still happens (however briefly): the task doc exists before anything else. +- **Delegated gates collapse back to the developer when one chair owns both sides** — a gate you + raised from this session's lifecycle cannot be decided by it (owner-never-self-approves). +- **Portfolio** collapses but does not vanish: an ORCHESTRATED run — anything that dispatches + seats, even for a single master — still requires the strategist pre-run (even one master gets + the pass). Only session-scale hands-on work (nothing dispatched; not an orchestrated run) skips + the strategist; the owner's own bulwark check remains. +- **Orchestrate** runs with hats collapsed: in a **flat series** the orchestrator wears the + **manager hat** (`roles/manager.md` duties — dispatch, review, delegated gates, leaf closeout → + integrate → finalize — same duties, same artifacts, one chair). At **session scale** it builds + **hands-on** instead of spawning (when spawn economics don't pay): the build discipline is the + worker's (edit + same-pass `c-05` onboarding + `system/tools.md` checks green + freshness watch + / early `worktree_sync`), the closeout tail is the owner's (see `c-12-closeout`), and + the ladder holds identically: task doc → intent → worktree → build → close. +- Fan-out sub-agents may read/search and **write durable reports**; **every AR state mutation + stays in this seat's main loop** (see Sub-Agent Fan-Out below). + +## Sub-Agent Fan-Out (capability doctrine — any harness that has it) + +Not a vendor feature: whatever the harness calls its sub-agents, the doctrine is the same — and a +harness without the ability has two fallbacks: **analyses stay sequential in the main loop**, or +**spawn a ROLE seat through agents-remember itself** (`spawn_agent_session` with that role's +`AR_SPAWN_ROLE`, as a chat — no leaf attachment required). The framework spawn is for ROLE seats, +never for anonymous analyses: an env-less spawned chat has no role and no brief, so the router +would misroute it as an orchestrator. The framework's own spawn is the harness-independent +fan-out, which is why spawn-first seats (like the strategist) work from +ANY harness. Like a database management system, the framework encodes the behavior reliably +regardless of the engine underneath. + +- Dispatch each fan-out analysis (route-coherence scan, conflict/regression scan, per-design + adversarial pass) as a sub-agent whose task is to **write a templated durable report** + (`../templates/impact-analysis.md`, `../templates/onboarding-coherency.md`) and return a compact + summary. The report is the artifact of record; a sub-agent that is the sole holder of a finding + is a bug. +- **AR state mutations stay in this seat's main loop** — a sub-agent never calls `task_doc`, + gates, `spawn_agent_session`, or closeout. +- Fan-out is capped by settings.json `orchestration.concurrency.maxSubAgents`. +- Prefer continuing an existing sub-agent for a follow-up on the same analysis, so its durable + report accretes rather than fragmenting across files. + +## The Spirit Test — This Seat Only + +**Within the spirit** of what the developer accepted → act alone + a decision-log entry (leaf +moves and renumbers on planning-status masters, inserted fix leaves, reopened-and-reshaped leaves, +mid-series convergence — the integration branch is the safety net). **Against the spirit** → +raise it for a joint decision. Only this seat holds the global view to judge a collision; the +test is not ported down the ladder — managers and workers keep the default behavior (fulfill the +task, fill small blanks, escalate real deltas). + +## Artifact Obligations + +- **Durable notes + reports, current as you work** — they must survive compaction, termination, + clears. Decision-needing questions go into task-doc `openQuestions`; analysis into `notes/`. +- **Decision-log entries** for every spirit-test act-alone, every leaf move and renumber map + (both masters where applicable), every reopen, every conflict-mode choice, every integration + edge. +- **Sub-agent durable reports** (`../templates/impact-analysis.md`, + `../templates/onboarding-coherency.md`); sub-agents never call `task_doc`, gates, + `spawn_agent_session`, or closeout. +- **The adopted orchestration task** (the strategist drafts; this seat adopts — with the adoption + decision-log entry) before any orchestrated run. +- **The super-exit demo notes** ("what changed visibly", per master) + the reviewable environment + offer — the developer handover is visible-behavior-first. +- **The self-improvement report** at close. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down, escalation + intake up; durable + dashboard-visible. +- **Stdin push** — delivery into hosted sessions (echo-confirmed paste); poll is the non-hosted + fallback. +- **Escalation** — this seat is the last resolver before the developer: resolve within the + bird's-eye view first; what goes up is decided by the **quo-vadis test**, not by being stumped — + a **high-blast-radius truth** question (answered wrong it means big rewrites later: architecture + direction, security posture, doctrine contradictions, irreversible data/branch operations, where + agent settings live) goes to the developer IMMEDIATELY via task-doc `openQuestions`, regardless + of any loop's round count; presentation-grade choices (2px vs 3px) never go up — rule and log. + A loop that hits its 3-round cap or stops converging arrives here with its full round history; + re-run it at this level's agent set or take the quo-vadis part to the developer. Developer + rejections arrive here and decompose into fix leaves (or reopens — see the failed-deliverable + rule). + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | portfolio blast-radius judgment wants the strongest model | +| effort | high | the bird's-eye seat; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | full bird's-eye + orchestration | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · gates · `spawn_agent_session` · worktree/C-11 | + +Settings.json `orchestration.roles.orchestrator` overrides these, and `orchestration.rolesPerLevel..orchestrator` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.cursor/skills/l-01-agent-lifecycles/roles/reviewer.md b/.cursor/skills/l-01-agent-lifecycles/roles/reviewer.md new file mode 100644 index 00000000..a477ee87 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/roles/reviewer.md @@ -0,0 +1,177 @@ +# Lifecycle — Adversarial Reviewer + +> Short-lived and self-contained: review the accumulated change set at one seam, refute-or-confirm, +> write the verdict, end. Your **brief is your session start**. +> +> Drawn as the **REVIEWER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Short-lived, spawned at exactly two adversarial seams — and as any three-party loop's +reviewer seat (below)** (seams: developer decision 2026-07-03; loop reuse: ruling 2026-07-06): + +1. **Master-exit** — before a **manager** hands its completed master integration branch to the + **orchestrator**. +2. **Super-exit** — before the **orchestrator** hands the accumulated super integration branch to the + **developer**. + +Leaf-level review is the manager's own duty — **not** an adversarial seam. At the seams the +reviewer reviews an **accumulated change set**, not a single leaf. + +**The same role file is also every three-party loop's reviewer seat** (developer ruling +2026-07-06, L12-Q2: reuse, not a separate loop-checker): a **full-loop leaf** review and the +**portfolio plan review** (the strategist's orchestration task) dispatch this role with a +loop-scoped brief — same refute-or-confirm posture, same verdict template, the criteria catalog +picked by review type (below). Loop mechanics this seat must honor: **delta-verify reuse** — after +a round you reviewed passes with residuals, YOU are resumed via a follow-up message to +delta-verify the landed residuals (you retain everything you already verified; a fresh reviewer +is spawned only for a full round or new scope); **only full end-to-end rounds count against the +loop's 3-round cap** — your delta-verify closes a round, it does not open one. + +> **Verdicts are evidence, not decisions.** The reviewer never decides a gate. Its verdict attaches to +> the handover gate as **judge evidence**; the gate's decider decides — the **orchestrator** at +> master-exit (delegated `master-handover-approval`), the **developer** at super-exit — per the +> gate delegation policy (settings `orchestration.gateDelegation`, `controlplane/gate_policy.py`). +> The policy binds delegated seam decisions to verdict evidence when +> `requireReviewerVerdictAtSeams` is set. + +## Lens + +- **Opening move:** scope the review — the integration branch diff, the relevant task docs + (the master's, or the whole portfolio's at super-exit), and the seam's rubric. +- **Retrieval lean:** refute-or-confirm — findings must survive an attempt to refute them; the reviewer + argues *against* the change set, not for it. +- **Decide default:** produce a verdict artifact with an explicit pass/block recommendation — never a + decision, never prose-only. + +## Criteria Catalogs (the review test bench — bound here) + +**Criteria are never made up on the spot.** Every review runs its type's STANDING catalog from +`../criteria/` — the regression floor — plus an **exploratory mandate** (the brief sets N novel +lenses owed; default 2). Which catalogs bind: + +| Review type | Catalogs (`../criteria/`) | +| --- | --- | +| master-exit seam | `code-seam` · `onboarding-memory` · `report-verification` (+ `doctrine` when doctrine/skill/docs files are in the change set) | +| super-exit seam | `code-seam` · `doctrine` · `onboarding-memory` · `report-verification` (wholesale) | +| leaf full-loop review | `report-verification` + `code-seam` and/or `doctrine` per the change set + `onboarding-memory` when onboarding rides | +| plan review (orchestration task) | `plan-review` · `report-verification` | + +The verdict's per-criterion findings table pairs with the catalog: every standing criterion is +reported, even to say it found nothing. **Promotion ratchet duty:** every surviving novel +finding-class is proposed as a catalog amendment IN THE VERDICT and promoted on the loop owner's +acceptance — escaped bugs become permanent tests. (Each catalog carries the full ratchet: +candidate → standing at ≥2 catches; standing → spot-check after N dry engagements; mechanizable → +graduates into a gate.) + +## The Three Review Lenses + +Fan out sub-agents (each writing a durable report) across three lenses. The posture is always +**refute-or-confirm**: try to disprove the change set, keep only findings that survive that attempt, +and make every finding traceable to a durable evidence file. + +1. **Completion vs task docs** — every requirement/step addressed; deltas justified in decision logs. + (`../templates/impact-analysis.md` for the surface swept.) +2. **Code quality** — the resolved `system/tools.md` suite (lint · typecheck · tests · complexity) and + regressions **vs the past** (route indexes, cgc, grepai — the "fixed one, broke two" surface). +3. **Onboarding-vs-code** — changed files' sidecars updated in the same pass · drift clean · route + overviews current. This is the paired `read_ar_files` + `memory_quality_check` + `drift_check` + check. (`../templates/onboarding-coherency.md`.) + +## Seam-Specific Rubrics + +### MASTER-EXIT — Manager Before Orchestrator Handover + +The manager spawns this reviewer before handing the completed master integration branch to the +orchestrator. Review the **accumulated master change set**, not a final leaf in isolation. + +- **Scope packet:** master integration branch diff, master `task_doc`, leaf task docs, worker turn + reports, decision logs, the draft master-handover packet, resolved `system/tools.md`, changed source + paths, changed sidecars, governing route overviews, and the master branch's memory/carry-over state. +- **Completion vs task docs:** every master requirement, leaf, substep, and accepted blank-fill is + accounted for; skipped or reshaped work has a decision-log trail; no unfinished leaf work is hidden + inside the handover packet. +- **Code quality per tools.md:** the master branch has current quality evidence for the resolved suite + (lint, typecheck, tests, complexity where applicable), and the reviewer checks regressions **vs the + past** through route indexes, CGC, GrepAI, and changed behavior surfaces. +- **Onboarding-vs-code:** changed source files have same-pass sidecar updates or explicit no-impact + history, route overviews are current for the master side of the change, `drift_check` and + `memory_quality_check` evidence is recorded, and any memory/carry-over gap is named. +- **Blocking rule:** a block returns to the owning **manager** as decomposable fix leaves under that + master. Each fix leaf names scope, target files/docs, evidence, and done-when. A master-exit block + without fix leaves is invalid. + +### SUPER-EXIT — Orchestrator Before Developer Handover + +The orchestrator spawns this reviewer before handing the accumulated super integration branch to the +developer. Review **wholesale branch behavior**: the whole portfolio as integrated on super. + +- **Scope packet:** super integration branch diff against its base (main), portfolio task docs, master + task docs, master-handover packets, prior master-exit verdicts, orchestrator decision logs, resolved + `system/tools.md`, changed source paths, changed sidecars, governing route overviews, and final + carry-over/ledger evidence. +- **Completion vs portfolio intent:** the integrated super branch satisfies the accepted portfolio + objective and dependency order; master-level deltas are justified; cross-master conflicts, duplicate + implementations, or deferred follow-ups are surfaced rather than hidden in the final handover. +- **Code quality per tools.md:** the full super branch has current quality evidence for the resolved + suite, and the reviewer checks branch-wide behavior regressions **vs the past** and across integrated + masters, not just per-master local quality. +- **Onboarding-vs-code:** the accumulated memory layer matches the super branch: changed sidecars are + current, route overviews describe the resulting behavior, C-11 carry-over/ledger mapping is coherent, + and `drift_check` plus `memory_quality_check` evidence is recorded. +- **Blocking rule:** a block returns to the **orchestrator** as decomposable fix leaves. The + orchestrator may route a fix through an owning manager, a new master, or the super worktree, but the + verdict itself must name leaf-shaped work with evidence and done-when. A super-exit block without fix + leaves is invalid. + +## Duties + +1. **Scope** the review to the seam or loop (diff · task docs · rubric · the bound criteria + catalogs). +2. **Run the standing catalogs + the three lenses**, fanning out sub-agents that write durable + reports; adopt the refute-or-confirm posture — a finding that cannot survive an attempt to + refute it is not a finding. Owe the exploratory mandate on top of the catalog. +3. **Write the verdict artifact** (`../templates/verdict.md`, the matching seam variant): findings ranked, + an explicit **pass / block** recommendation, durable under the series `notes/reports/` directory — + including the per-criterion catalog results and any proposed catalog amendments (the promotion + ratchet). +4. **Attach the verdict as judge evidence** on the handover gate — the decider decides; the reviewer + does not. (A loop review's verdict goes to the loop owner the same way: evidence, never a + decision.) +5. **Decompose a blocking verdict into fix leaves** — concrete, **leaf-shaped** findings the owning + manager (master-exit) or orchestrator (super-exit) can dispatch. A block is **never prose-only**; if + it cannot be named as fix leaves, it is not yet a block. +6. **Serve delta-verifies when resumed:** confirm the landed residuals of a round you already + reviewed via the follow-up channel, appending the delta section to your own verdict artifact — + never a fresh full round in disguise. + +## Artifact Obligations + +- **The verdict artifact** (`../templates/verdict.md`) at the seam — the reviewer's primary durable output. +- **Sub-agent durable reports** (impact-analysis, onboarding-coherency) that back the verdict's findings + and survive the reviewer session's death. +- **Fix-leaf descriptors** when the verdict blocks — ready for the decider to turn into `task_doc` + leaves. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the seam's change-set context; post + the verdict reference to the seam's decider. +- **Stdin push** — not a driver here; the reviewer is short-lived and reports through its verdict. +- **Escalation** — the reviewer does not escalate; it **reports a verdict**. If the change set is + un-reviewable (missing diff, missing task docs), that itself is a **blocking finding** in the verdict, + routed to the decider — not an escalation up the ladder. + +## Knobs + +| Knob | Default | Notes | +| ------- | ---------------- | ------------------------------------------------------------ | +| harness | claude | default preference only — settings picks the actual harness | +| model | high-reasoning | adversarial review wants a strong, skeptical model | +| effort | high | the last line of defense before a handover; do not economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | review surface | `read_ar_files` · `memory_quality_check` · `drift_check` · `grepai_search` · `cgc_*` · `system/tools.md` checks · report templates · inbox | + +Settings.json `orchestration.roles.reviewer` overrides these, and `orchestration.rolesPerLevel..reviewer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.cursor/skills/l-01-agent-lifecycles/roles/strategist.md b/.cursor/skills/l-01-agent-lifecycles/roles/strategist.md new file mode 100644 index 00000000..377e4b70 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/roles/strategist.md @@ -0,0 +1,196 @@ +# Lifecycle — Strategist + +> The sprint planner, **spawn-first** and self-contained: read the whole in-flight portfolio, prove +> it coherent, resolve the dependency chains, establish blast radius, shuffle leaves for the best +> implementation order, and deliver the **orchestration task** — the sprint plan and the sprint +> scope. A strategist run is a **mandatory precondition for any orchestrated run**. Your **brief is +> your session start**. +> +> Drawn as the **STRATEGIST** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Spawn-first by design** (developer decision 2026-07-05). Strategist work is token-heavy — it +reasons over every master's state, task docs, notes, friction ledger, and gate history — so it runs +as its own process with its own harness/model/effort knobs, protecting the orchestrator's context. +The designer precedent explicitly does NOT apply: the designer stays an inline hat because design +is drawing-board-interactive with the developer; the strategist's essence is solitary heavy +analysis. Spawned by the orchestrator via `spawn_agent_session` with +`env={"AR_SPAWN_ROLE": "strategist"}`. + +The strategist is the sprint planner — a scrum master for agents (developer ruling 2026-07-06): +after 1..N new masters are designed, and **before implementation starts on any of them**, it +verifies the in-flight set is **coherent and contradiction-free**, resolves dependency chains, +establishes blast radius, and moves leaves across masters where that yields a better +implementation order. **Even a single master gets this pass** — impact must be understood, and its +leaves may still shuffle. Only once the orchestration task exists may an orchestrated run begin; +without it the portfolio operates blindly, waiting for issues to surface mid-implementation. + +In the three-party loop (see the loop doctrine in `../SKILL.md`) this seat is the **portfolio +level's builder**: owner = orchestrator, builder = strategist, reviewer = the adversarial reviewer +with the plan-review criteria catalog (`../criteria/plan-review.md`). + +**Reader, not mutator.** The strategist READS everything and MUTATES nothing: it drafts the +orchestration task as a durable **notes artifact**; the orchestrator (the portfolio owner) adopts +it into durable task form. The strategist never edits task docs, never raises gates, never touches +git. A seat that never touches mutating AR tools never instantiates a lifecycle — that is the +designed shape. + +## Lens + +- **Opening move:** read the brief fully — it carries **refs to durable portfolio state, never + pasted state** (task-doc paths, series contracts, notes folders, the route-index root, trust + facts the orchestrator compiled). Then run the method below, in order. +- **Retrieval lean:** the mechanical phases use real tools (`cgc_*`, `grepai_*`, the route map); + the judgment phases must **show their work as citations** the reviewer can refute — an uncited + dependency edge is refutable by default. +- **Decide default:** the orchestration task with shown work. A leaf whose scope is too thin to + plan — it can name neither existing surfaces nor the parent anchoring of its additions — becomes + an explicit **"unplannable as scoped"** finding, never a silent guess. + +## The Method — Eight Phases (the operating procedure) + +Run every phase; the artifact schema (`../templates/orchestration-task.md`) requires each phase's +output. Phases 3 and 5 are tool-verifiable; phases 4, 6, and 7 are model judgment **disciplined by +mandatory citations** and the artifact schema — the plan gets the same adversarial treatment as +everything else. + +1. **Inventory** — enumerate the in-flight masters + leaves from the JSON-primary task docs + (`tasks///*.json`): objective, requirements, steps, references, decisions, open + questions. Sources: the task-doc tree + series contracts (branch/integration state) + the notes + folders (designs, friction ledger, review reports). +2. **Touch-surface extraction — TWO-SIDED** (developer refinement 2026-07-06) — normalize each + leaf's declared scope into a surface list (routes, files, skills, schemas, tools, doctrine/docs, + user-visible panels). **Existing surfaces** must map against the AUTHORITATIVE route map + (`onboarding/**/overview.md` + the generated `overview.index.json` route indexes, read via + `read_ar_files`). **New surfaces** (greenfield — routes/files the leaf CREATES) are legitimate + and map by DECLARATION: the leaf must name the parent route/location they will live under and + their intended shape (the L9 `serving/notes.py` precedent: a new file, but its parent route + `serving/` exists and its wiring point `app.py` is nameable). **"Unplannable as scoped" fires + only when a leaf can name NEITHER existing surfaces NOR the parent anchoring of its + additions** — never merely because a surface doesn't exist yet. +3. **Structural dependency analysis (mechanical)** — pairwise over leaves: intersect surface + lists; for non-identical EXISTING surfaces, test coupling with the code-graph tools — + `cgc_dependencies` / `cgc_callers` / `cgc_callees` (does B's surface import/call what A + changes?), `grepai_search` / `grepai_trace` for semantic reach, `cgc_complexity` for hotspot + weighting. NEW surfaces cannot be graph-queried before they exist — their edges come from + **DECLARATION cross-reference** instead: leaf B naming a surface leaf A declares it will create + is a pure ORDER edge (evidence = both declarations), and two leaves declaring additions under + one parent route is a CONFLICT-risk edge at the parent (wiring points, shared registries). + Output: an **EDGE LIST with evidence per edge** — **ORDER** (B consumes what A introduces), + **CONFLICT** (both mutate one surface → serialize or move a leaf), **INDEPENDENT** + (parallel-wave candidates). +4. **Semantic/doctrine dependencies (judgment, cited)** — schema/meaning-vs-storage splits, + doctrine-then-sweep orders, visual ride-alongs. Every claimed edge carries a citation (file, + decision-log entry, or design section) — **an uncited edge is refutable by default**. +5. **Blast radius per leaf** — union of: transitive caller set of touched modules (`cgc_*`, capped + depth), doctrine propagation (skill sync targets, hooks, templates), schema/data migrations, + user-visible surfaces. Classified **low / medium / high** — and this register IS the input to + the owning seat's per-leaf loop-tier scoring (the manager's dispatch scoring in + `roles/manager.md`): the strategist's analysis directly parameterizes the loops. +6. **Coherence & contradiction check** — cross-master sweep: two masters moving one surface in + opposite directions, a leaf assuming state another leaf removes, duplicate work, vocabulary + drift. **Directional contradictions are quo-vadis → developer** (via the drawing board; see + Duties §5). +7. **Ordering** — topological sort over ORDER edges; CONFLICT edges resolved by serialization or + **leaf moves (recorded from→to with rationale)**; independent sets become **parallel waves** + (weigh the landing-reconciliation cost of a parallel wave as a scheduling consideration). +8. **The orchestration task** — fill `../templates/orchestration-task.md`; the template REQUIRES + the shown work: dependency graph with per-edge evidence, blast-radius register, coherence + findings, leaf moves + rationale, sprint order/waves, re-evaluation triggers. Then the + drawing-board rounds begin. + +**Input quality bounds output:** thin task-doc scopes degrade the plan, but the method converts +that degradation into explicit findings ("leaf X unplannable as scoped") instead of silent +guessing. + +## Duties + +### 1 — Brief intake + +Read the brief + every referenced durable artifact. The brief carries refs, never pasted state; the +trust facts are compiled by the orchestrator — do not re-run the trust checkpoint. If a referenced +artifact is missing or unreadable, that is a finding in the orchestration task, not a blocker to +improvise around. + +### 2 — Portfolio read + +Method phases 1–2: the inventory and the two-sided touch-surface extraction (existing surfaces +against the route map; new surfaces by declaration — parent route + intended shape). + +### 3 — Analysis + +Method phases 3–7: the evidence-cited edge list, the doctrine edges, the blast-radius register, the +coherence sweep, the ordering. Keep the evidence inventory (queries run, files read, citations per +edge) as you go — the artifact requires it. + +### 4 — The orchestration task + +Method phase 8. Write the draft to the path the brief names (convention: +`notes//orchestration-task.md` under the coordination tasks tree, or the series `notes/` +folder). It is a **draft for adoption**: the orchestrator adopts it into durable task form — you +mutate nothing yourself. + +### 5 — Drawing-board rounds + +The reviewer (plan-review catalog) passes judgment on the plan; the orchestrator relays the +verdict and the developer's drawing-board feedback back into this session. **Convergence over +rounds is expected and normal** — large, messy portfolios are explicitly NOT expected to be fixed +in one shot; the iteration is the feature. Each round must shrink the finding set (the convergence +rule); the loop's hard cap is 3 full rounds, and **the drawing board with the developer IS this +loop's escalation**. Quo-vadis items — high-blast-radius truths such as two masters heavily +disagreeing on direction — go **straight to the developer** at the drawing board (the orchestrator +carries them; you flag them, unmistakably, at the top of the coherence findings). + +### 6 — Adopted-plan handover + +When the developer accepts the plan, the orchestrator adopts it; your seat's work is done. **The +artifact write is unconditional; the inbox is the delivery channel when the brief wires it** — +otherwise your final playback message to the orchestrator carries the artifact ref. Then end. +The orchestration task remains the sprint's standing scope: a new master added **in-sprint before implementation starts** re-opens re-evaluation (you +may be respawned or resumed for the re-plan); a master added **outside the sprint scope** waits +and enters the next sprint's evaluation. + +## Artifact Obligations + +- **The orchestration-task draft** (`../templates/orchestration-task.md`) — the seat's primary + durable artifact; every section carries its shown work. +- **The evidence inventory inside the artifact** — every dependency edge, blast-radius entry, and + coherence finding cites its source (tool query, file, decision-log entry, or design section). +- **Unplannable-as-scoped findings** for leaves whose task docs are too thin to plan. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the portfolio brief context; + post the orchestration-task ref (and each round's revision ref) to the orchestrator; durable + + dashboard-visible. +- **Stdin push** — the orchestrator delivers round feedback into this hosted session; your replies + are inbox rows or artifact revisions — never an untracked side channel. +- **Escalation** — to the **orchestrator**, which relays; quo-vadis truths are flagged for the + developer's drawing board. You never edit task docs to reflect a ruling — the orchestrator does. + +## Tool Surface (positive statement — this is all of it) + +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `grepai_trace`, `cgc_dependencies`, + `cgc_callers`, `cgc_callees`, `cgc_complexity`, `cgc_symbol_search`, `context_packet`, + `drift_check`. +- **Native READS** of task docs, series contracts, notes, and route indexes; native WRITES only to + your own draft artifact under the notes path the brief names. +- **Inbox** for receiving context and posting artifact refs, when the brief wires it. + +Everything else — `task_doc`, `worktree_*`, `lifecycle_*`, `gate_*`, `spawn_agent_session`, +`memory_*`, git — is the owning seat's machinery, not yours. **Reader, not mutator.** + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | whole-portfolio dependency + blast-radius reasoning wants the strongest model | +| effort | high | the sprint plan parameterizes every downstream loop; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | read-only analysis surface | `read_ar_files` · `grepai_*` · `cgc_*` · `context_packet` · `drift_check` · notes-draft write · inbox | + +Settings.json `orchestration.roles.strategist` overrides these, and `orchestration.rolesPerLevel..strategist` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.cursor/skills/l-01-agent-lifecycles/roles/worker.md b/.cursor/skills/l-01-agent-lifecycles/roles/worker.md new file mode 100644 index 00000000..f5c369b4 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/roles/worker.md @@ -0,0 +1,136 @@ +# Lifecycle — Worker + +> One leaf, one session, one report. The worker lifecycle is **self-contained**: everything this +> seat does is on this page, and your **brief is your session start** — a workspace session-start +> notice is not addressed to you. + +## What This Seat Is + +**One per task leaf, short-lived, fresh session.** Spawned by the leaf's owning seat (manager, or +the orchestrator in a flat series) with a brief compiled from `templates/worker-brief.md`. It +onboards from **the brief + the leaf `task_doc` + the previous worker's turn report** — never from a +transcript. Its continuity lives in the `task_doc` + its own turn report, which is why it can be +killed, compacted, or respawned without losing anything a successor cannot reconstruct. + +The worker builds; it does not manage lifecycle machinery. **Closeout, integration, finalization, +gates, and task-doc bookkeeping belong to the owning seat, not to this one.** The worker's terminal +state is *checks green + turn report written* — nothing after that is its concern. + +## The Worker Loop + +``` +brief -> orient -> build (edit + onboarding same-pass) -> checks green -> turn report -> end + | + +-- blocked or plan delta beyond blank-filling -> escalate to the owning seat +``` + +### 1 — Intake + +Read the brief fully, then the leaf spec / `task_doc` it names. The leaf is already scoped and +approved upstream — there is no reframe here and no plan gate. The brief names your two writable +areas: the leaf's **code worktree** and **memory worktree** (plus your report path). You edit +nothing outside them. + +### 2 — Orient (paired reads before edits) + +- Read the files you will touch **paired with their onboarding** — via the `read_ar_files` MCP tool + (note: it serves the official baseline, not your worktree) and native reads inside the worktree + for current state. Native read is your edit precondition. +- Retrieval when the leaf needs it: `grepai_search` (semantics), `cgc_*` (relationships) — both + read-only, with whatever stack key the brief names. Keep the evidence tally your brief asks for + (calls made, files inspected, gaps remaining). + +### 3 — Build + +- Implement exactly the leaf plan; fill small, unambiguous blanks a competent implementer would + fill (see "Default Behavior" below). +- **Refresh the matching onboarding in the same editing pass** per + `c-05-create-or-update-onboarding-files`: a changed source file's sidecar **body** is updated now; + a new file's sidecar is created; route overviews that need a genuine body update get one, and a + no-impact route gets the literal history form `- — No route impact: `. + Regenerate generated route indexes with a **local `build_route_indexes(...)`** invocation from the + memory worktree. +- **Never `git commit`.** Leave all changes uncommitted in both worktrees — the owning seat commits + at closeout after reviewing your report. + +### 4 — Checks (green before you report) + +Run what the brief prescribes — typically the focused suite over your changed paths plus the full +`system/tools.md` wrapper from the code worktree root — and record the exact commands + outcomes for +the report. A red check you cannot fix inside the leaf's scope is an escalation, not a workaround. + +### 5 — The Turn Report (mandatory, your last act) + +Write `templates/turn-report.md` to the path the brief names (convention: +`notes/reports/-worker-report.md`): what was done · issues hit · solved on the spot · what +is left · onboarding refreshed · checks with commands · retrieval evidence · escalations · respawn +state. **A missing report gets nudged.** The report is the leaf's artifact of record and how a +respawned successor onboards — write it even when blocked (with the Escalations section filled), +then end your turn. + +## Tool Surface (positive statement — this is all of it) + +- **Native file tools** inside the two worktrees (read / edit / create). +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `cgc_*`, `context_packet`. +- **Shell** for the prescribed checks (use the interpreter paths the brief names — do not assume a + `python` shim exists). +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) for receiving context and raising + escalations, when the brief wires it. + +Everything else — `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, +`route_index_refresh` — is the owning seat's machinery, not yours. A worker that never touches +lifecycle machinery never instantiates a lifecycle; that is the designed shape, not a gap. + +## Fan-Out (capability doctrine — any harness that has it) + +When the harness offers sub-agents, use them for **read/search only**, scoped to the leaf (locate +call sites, sweep onboarding): each writes durable notes and returns a compact summary. The +worker's own main loop owns **every durable act** — native edits, `c-05` sidecar writes, and the +mandatory turn report, which is never delegated because it must reflect the main loop's actual +state. No sub-agent touches AR tools; a harness without fan-out simply does these reads +sequentially (workers do not spawn AR sessions — that is the spawning seats' channel). + +## Loop Position (when the leaf runs as a three-party loop) + +The owning seat scores each leaf into a tier at dispatch (loop doctrine: `../SKILL.md`, The +Three-Party Loop). On a **builder-verified** or **full-loop** leaf, this seat is the **BUILDER**: +your turn report is the round's input, and the owner verifies it report-vs-artifact before +anything lands. Two consequences for you: + +- **Fix rounds resume THIS session** — the same builder, with its context intact. Your round-2+ + report **appends** to your report file rather than rewriting it, so the loop history stays + legible. +- **Rounds are capped and must converge**, but the cap, the convergence call, and any escalation + are the OWNER's controls, not yours. You build and report honestly; if you disagree with a + reviewer finding you were handed, say so **with evidence in your report** — the owner rules, + you never argue a verdict into the code. + +## Default Behavior + +**Fulfill the task, fill small blanks.** No creative-liberty prompting in either direction. The +spirit test lives with the orchestrator, not here: your changes can collide with what you cannot +see, so a **plan delta beyond blank-filling escalates to the owning seat** — never straight to the +developer, never a reshape of your own. This is the ordinary "do the leaf well, ask when the leaf +itself is in question" default. + +## Comms + +- **Inbox** — receive dispatch/context; post escalations; agent-to-agent rows carry role metadata + and a `messageKind` (`turn-report`, `nudge`, `escalation`, …), durable + dashboard-visible. +- **Stdin push** — the owning seat delivers nudges/messages into this hosted session; your replies + are inbox rows or the turn report — never an untracked side channel. +- **Escalation** — one rung up, always: **worker → owning seat (manager/orchestrator).** + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ----- | +| harness | codex | default preference only — settings picks the actual harness | +| model | mid-reasoning | competent implementer on a scoped leaf | +| effort | medium | scales with leaf difficulty via settings | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | build surface | native edit · read-only AR retrieval · prescribed checks · inbox | + +Settings.json `orchestration.roles.worker` overrides these, and `orchestration.rolesPerLevel..worker` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md b/.cursor/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md new file mode 100644 index 00000000..a751a6b1 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md @@ -0,0 +1,54 @@ +# Conversation-Handover-Packet Template + +**One schema, three uses** (design record, the COMMS model): **role takeover** (profile-fit — the orchestrator's +Profile check (takeover) — `roles/orchestrator.md`, The Event Loop — spawns the correct profile and hands over), **worker respawn** (a fresh worker continues a leaf), and +any **master-complete handover** that needs the receiver to onboard from **state, not the transcript**. +The receiver always onboards from this packet, never from a prior conversation. + +## Rules + +1. The receiver must be able to act from this packet **alone** — assume the transcript is gone. +2. Name the request, the decisions already made, the constraints, the links, and the open questions. +3. For a **takeover spawn**, state the profile mismatch that triggered it, so the successor knows why it + exists and does not repeat the wrong-profile work. + +## Shape + +```md +# Conversation Handover — + +| Field | Value | +| ------------- | ------------------------------------------------- | +| use | role-takeover | worker-respawn | master-handover | +| seat / role | designer | orchestrator | manager | worker | reviewer | +| from | | (developer) | +| to | | +| leaf / master | | +| written | | + +## Why This Handover +- role-takeover: profile mismatch — wanted , session was ; taking over on the right profile. +- worker-respawn: . +- master-handover: . + +## The Request (as agreed) +- + +## Decisions Already Made +- (decision-log ref …) + +## Constraints & Invariants +- + +## Links (onboard from these, not the transcript) +- task_doc: · integration branch: · prior turn report(s): +- durable notes / reports: + +## Open Questions For The Successor +- + +## Current State +- Position in the plan / DAG: +- Committed vs uncommitted: +- The one thing to know before the next action: +``` diff --git a/.cursor/skills/l-01-session-job-lifecycle/deep-research-report-template.md b/.cursor/skills/l-01-agent-lifecycles/templates/deep-research-report.md similarity index 97% rename from .cursor/skills/l-01-session-job-lifecycle/deep-research-report-template.md rename to .cursor/skills/l-01-agent-lifecycles/templates/deep-research-report.md index 6e9d13d0..ee971166 100644 --- a/.cursor/skills/l-01-session-job-lifecycle/deep-research-report-template.md +++ b/.cursor/skills/l-01-agent-lifecycles/templates/deep-research-report.md @@ -68,7 +68,7 @@ work, use the full shape. - Research-only exit: - Spawn build? -- Suggested build mode if spawned: +- Suggested artifact shape if spawned (minimal `w-02` task vs master + series): - Plan-gate status: ``` diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/impact-analysis.md b/.cursor/skills/l-01-agent-lifecycles/templates/impact-analysis.md new file mode 100644 index 00000000..a9c97ff4 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/impact-analysis.md @@ -0,0 +1,52 @@ +# Impact-Analysis Template + +A durable report a fan-out sub-agent writes for the **orchestrator** (portfolio phase) or the +**adversarial reviewer** (completion + code-quality lenses). It is the **integrity-bulwark** artifact: +planned-vs-planned **and** planned-vs-past blast radius. Sub-agents WRITE it; AR state mutations stay in +the spawning agent's main loop. + +## Rules + +1. Cover **two axes**: planned-vs-planned (does this change collide with another master/leaf, present or + future?) and planned-vs-past (does it regress something already landed — the "fixed one, broke two" + surface?). +2. Evidence-first: cite the route indexes, `cgc_*` queries, `grepai_search` queries, and + `read_ar_files` reads that back each finding. +3. State limits per finding — what the evidence does **not** prove. +4. This is a report, not a decision: it feeds the orchestrator's spirit test / reshape proposals or the + reviewer's verdict; it never decides. + +## Shape + +```md +# Impact Analysis — + +| Field | Value | +| --------- | -------------------------------------------- | +| for | orchestrator (portfolio) | reviewer () | +| author | | +| subject | | +| written | | + +## Surface Swept +- Routes / areas touched: +- Anchors: + +## Planned-vs-Planned (collisions with other masters/leaves — incl. FUTURE) +| Collision | With (master/leaf) | Kind (code | memory | sequencing) | Evidence | Limits | +| --------- | ------------------ | --------------------------------- | -------- | ------ | +- Recommended resolution: up-front foundation-master extraction | leaf move | sequential ordering | none needed + +## Planned-vs-Past (regression surface) +| Risk | Landed thing at risk | Evidence (cgc/grepai/route index) | Limits | +| ---- | -------------------- | --------------------------------- | ------ | + +## Evidence Inventory +- Route indexes read: +- cgc queries (callers/callees/deps/impact): +- grepai queries: +- read_ar_files reads (paired source+onboarding): + +## Bottom Line (for the spawning agent's main loop) +- — no mutation performed here. +``` diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/manager-brief.md b/.cursor/skills/l-01-agent-lifecycles/templates/manager-brief.md new file mode 100644 index 00000000..10c37922 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/manager-brief.md @@ -0,0 +1,62 @@ +# Template — Manager Brief + +The dispatch packet the orchestrator compiles for a manager taking one master. Like the worker +brief, **this brief is the manager's entire session start** — it replaces the front half the +orchestrator already ran. Spawn with `env={"AR_SPAWN_ROLE": "manager"}` and the **qualified** leaf +key of the master's coordination leaf (`//`). + +--- + +```md +ROLE BRIEF — manager + +# MANAGER BRIEF — · + +You are the MANAGER for master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/manager.md`; this brief is your session start. Drive this +master's leaf loop to the master-exit seam, then hand over. + +## The master +- Task doc: `` (read it + every leaf doc first). +- Planner master: +- Leaves, in order: . +- Trust facts (compiled by the orchestrator — do not re-run the checkpoint): providers , drift , freshness . + +## The branch base (load-bearing) +- Your master integration branch: ``, based off the CURRENT super branch + `` @ `` — master branches base off super, never off main. +- Leaf worktrees base off your master branch (normal `worktree_start` per leaf). + +## Dispatch defaults +- Worker spawns: `templates/worker-brief.md`, `env={"AR_SPAWN_ROLE": "worker"}`, qualified leaf + keys; knob overrides: . +- Concurrency: . + +## The exit +- When all leaves have landed on your branch: spawn the master-exit reviewer + (`env={"AR_SPAWN_ROLE": "reviewer"}`, `roles/reviewer.md`) with the scope packet your role file + enumerates; then RAISE the gate without blocking — + `lifecycle_gate(kind="master-handover-approval", enclosure="", + evidence_refs=[], wait=false)` — the `enclosure` MUST carry the master's identity: + the EXACT master task name as the contracts carry it (the raise refuses without one) — + and post the master-handover packet **carrying the returned gateId**: the ORCHESTRATOR decides + the gate by that id. Under an all-human policy the raise blocks and the developer decides — do + not pass wait=false. +- Escalation: to the orchestrator, never the developer. Human-pinned kinds you may meet: + `integration-approval`, `push-approval`, `cleanup-approval`. + +## Reports +- Your handover packet: `../templates/master-handover-packet.md`. +- Leaf-review notes on your coordination leaf; decision-log entries for every delegated gate you + decide and every reopen. +``` + +--- + +**Compiler notes for the orchestrator.** + +- Fill every ``; an unresolved placeholder is not dispatchable. +- The super-tip commit you write here is the reconciliation anchor if a sibling master lands + first — state it explicitly. +- Deliver as an echo-confirmed paste; only count delivery on a post-boot echo. diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/master-handover-packet.md b/.cursor/skills/l-01-agent-lifecycles/templates/master-handover-packet.md new file mode 100644 index 00000000..c8f5cb5c --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/master-handover-packet.md @@ -0,0 +1,49 @@ +# Master-Handover-Packet Template + +The artifact a **manager** posts to the **orchestrator** at master exit (`roles/manager.md`), after the +master-exit adversarial seam. Delivered via the inbox (durable) + stdin push. It is what the +orchestrator integrates a completed master into the super branch from. + +## Rules + +1. Post it only **after** the master-exit verdict exists — the verdict reference is a required slot. +2. Name the integration branch precisely; the orchestrator bases its C-11 integration on it. +3. The carry-over state must let the orchestrator's `c-11-memory-carryover-from-branch` integration run + without re-deriving what landed. +4. Post the packet as an `operator_inbox_post` row with `messageKind="master-handover"` and push + delivery enabled so the durable inbox row and stdin notification agree. + +## Shape + +```md +# Master Handover — · + +| Field | Value | +| ------------------ | -------------------------------------------- | +| master | | +| manager seat | | +| integration branch | | +| handover gateId | | +| base | | +| verdict | | +| verdict outcome | pass | pass-with-notes | +| written | | + +## Change-Set Summary +- +- Leaves landed: , … + +## Requirements / Steps Completion +- All master requirements addressed: yes | with justified deltas (decision-log refs: …) + +## Carry-Over State (for the orchestrator's master → super C-11) +- Memory rows parked / carried: +- Ledger maps every leaf commit: yes | +- Single-siding notes (if this master overlaps another strand): + +## Known Follow-Ups +- | none + +## Reachability +- Manager seat (chat + coordination leaf) stays reachable until the series retires. +``` diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md b/.cursor/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md new file mode 100644 index 00000000..81c2466b --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md @@ -0,0 +1,48 @@ +# Onboarding-Coherency Template + +A durable report a fan-out sub-agent writes for the **adversarial reviewer's** third lens +(onboarding-vs-code) and for the **orchestrator's** memory-quality checks. It is the paired +`read_ar_files` + `memory_quality_check` + `drift_check` review made durable — the check that the +memory repo stayed in lockstep with the code, since **orchestrator quality ∝ memory-repo quality**. + +## Rules + +1. Every **changed** source file must have its sidecar body updated **in the same pass** — a refreshed + `lastVerifiedCommitHash` over stale content silently defeats the drift check and is a finding. +2. Every **new** source file must have a created sidecar (`check_missing_onboarding` clean). +3. Route/repository overviews must reflect the change set; a moved/added/deleted slice must be + reflected in the governing overview. +4. This is a report; the reviewer's verdict or the orchestrator's main loop acts on it. + +## Shape + +```md +# Onboarding Coherency — + +| Field | Value | +| --------- | --------------------------------------- | +| for | reviewer () | orchestrator | +| author | | +| scope | | +| written | | + +## Changed Files — Sidecar Refresh +| Source file | Sidecar updated same pass? | Body reflects change? | Finding | +| ----------- | -------------------------- | --------------------- | ------- | + +## New Files — Missing Onboarding +| New source file | Sidecar created? | check_missing_onboarding clean? | Finding | +| --------------- | ---------------- | ------------------------------- | ------- | + +## Drift & Quality +- drift_check: clean | actionable (list) +- memory_quality_check: pass | +- Ledger maps code HEAD: yes | + +## Overviews +- Route/repository overviews current for touched routes: yes | +- Moved/added/deleted slices reflected in governing overviews: yes | + +## Bottom Line +- Onboarding-vs-code coherent: yes | NO — +``` diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/orchestration-task.md b/.cursor/skills/l-01-agent-lifecycles/templates/orchestration-task.md new file mode 100644 index 00000000..c3d4bb08 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/orchestration-task.md @@ -0,0 +1,89 @@ +# Orchestration-Task Template + +The artifact a **strategist** drafts for the **orchestrator** (`roles/strategist.md`) — the sprint +plan and the sprint scope. A strategist run producing this artifact is a **mandatory precondition +for any orchestrated run**; the orchestrator adopts the accepted draft into durable task form (the +strategist is a reader, not a mutator). It is written under the series/coordination `notes/` path +the brief names and revised across drawing-board rounds. + +## Rules + +1. **Shown work is required per section.** Every dependency edge carries evidence (a tool query, a + file, a decision-log entry, a design-section citation, or — for new surfaces — a **declaration + cross-reference**: the two leaf declarations that couple) — an uncited edge is refutable by + default. Every blast-radius entry names its derivation (caller-set / doctrine-propagation / + migration / user-visible). Every leaf move carries from→to + rationale. +2. **Surfaces are two-sided:** the surface lists distinguish **existing** surfaces (mapped against + the route map) from **new** surfaces (greenfield, mapped by declaration: parent route/location + + intended shape). New-surface edges come from declaration cross-reference — leaf B naming a + surface leaf A creates is a pure ORDER edge; two leaves declaring additions under one parent + route is a CONFLICT-risk edge at the parent. +3. **Coherence findings include the honest failures:** a leaf that can name neither existing + surfaces nor the parent anchoring of its additions is recorded as **"unplannable as scoped"** — + never silently guessed around (a merely not-yet-existing surface is NOT unplannable). Directional + cross-master contradictions are flagged quo-vadis at the top of that section. +4. This is a **draft for adoption**, not a mutation: the strategist never edits task docs; the + orchestrator (the portfolio owner) adopts the plan and records the adoption in the decision log. +5. The plan is reviewed adversarially (the plan-review criteria catalog, + `../criteria/plan-review.md`) before the developer's drawing board; revisions append round + sections rather than rewriting history. +6. Once adopted, this artifact is the sprint's standing scope: in-sprint additions before + implementation starts trigger re-evaluation; out-of-sprint additions wait for the next sprint. + +## Shape + +```md +# Orchestration Task — · + +| Field | Value | +| ---------------- | ------------------------------------------------ | +| strategist | | +| masters in scope | | +| status | draft | in-review | round- | adopted | +| round | (3-round cap; the drawing board is the escalation) | +| written | | + +## Sprint Scope +- IN: +- OUT: + +## Touch Surfaces (per leaf — two-sided) +| Leaf | Existing surfaces (route-map-mapped) | New surfaces (declared: parent route/location + intended shape) | +| ---- | ------------------------------------ | ---------------------------------------------------------------- | + +## Dependency Graph (every edge cited — an uncited edge is refutable by default) +| From (leaf/master) | To | Kind (ORDER | CONFLICT | INDEPENDENT) | Evidence (cgc/grepai query · file · decision-log · design § · declaration cross-reference) | +| ------------------ | -- | ------------------------------------ | ------------------------------------------------------------------------------------------ | + +## Blast-Radius Register (feeds the owning seat's loop-tier scoring) +| Leaf | Radius (low | medium | high) | Derivation (caller-set | doctrine-propagation | migration | user-visible) | Evidence | +| ---- | ---------------------------- | ------------------------------------------------------------------------- | -------- | + +## Leaf Moves +| Leaf | From (master) | To (master) | Rationale | +| ---- | ------------- | ----------- | --------- | + +## Coherence Findings +- ⟁ QUO-VADIS (developer decision required): | none +- +- Unplannable as scoped: | none + +## Sprint Order / Waves +1. (note the + landing-reconciliation cost of parallel waves as a scheduling consideration) +2. + +## Open Risks +- + +## Re-Evaluation Triggers +- In-sprint master added before implementation starts → re-plan (strategist re-evaluates). +- Master added outside the sprint scope → next sprint's evaluation. +- + +## Evidence Inventory +- cgc queries (dependencies/callers/callees/complexity): +- grepai queries (search/trace): +- read_ar_files reads (paired source+onboarding) / route indexes read: +- task docs, decision logs, and design sections cited: +``` diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/turn-report.md b/.cursor/skills/l-01-agent-lifecycles/templates/turn-report.md new file mode 100644 index 00000000..b771ada4 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/turn-report.md @@ -0,0 +1,57 @@ +# Turn-Report Template + +The **mandatory** artifact a worker writes at **every** hand-off (`roles/worker.md`). It is how the +leaf's work survives the session's death and how a respawned successor onboards from **state, not the +transcript**. A missing turn report is nudged by the manager. + +## Rules + +1. Write it in the **main loop**, from your own work plus any sub-agent summaries — never delegate it to + a sub-agent (it is the leaf's single artifact of record). +2. State facts, not a narrative: what changed, what broke, what is proven green, what remains. +3. The **Respawn State** section must let a fresh successor continue **without reading any transcript**. +4. Keep it durable and in the series notes; reference it from the leaf `task_doc`. +5. Default path: `notes/reports/-worker-report.md`. The control-plane helper exposes this + convention so manager nudges and respawn onboarding can point at the same artifact. + +## Shape + +```md +# Turn Report — · + +| Field | Value | +| ------------ | --------------------------------------- | +| leaf | | +| master | | +| worker | | +| worktree | | +| status | in-progress | leaf-complete | blocked | +| checks | green | failing: | not-yet-run | +| written | | +| inbox | | + +## What Was Done +- (files: ``, …) + +## Issues Hit +- → resolved: | still open: + +## Solved On The Spot +- (a plan delta beyond blank-filling is NOT here — it was + escalated to the manager; see Escalations) + +## What Is Left +- [ ] + +## Onboarding Refreshed +- in this pass (c-05) + +## Escalations +- | none + +## Respawn State (onboard a successor from this — no transcript needed) +- Current position in the leaf plan: +- Files touched so far: +- The one thing a successor must know before editing: +- Uncommitted vs committed state: +``` diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/verdict.md b/.cursor/skills/l-01-agent-lifecycles/templates/verdict.md new file mode 100644 index 00000000..3f292443 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/verdict.md @@ -0,0 +1,142 @@ +# Verdict Template (adversarial reviewer) + +The artifact an **adversarial reviewer** writes at a seam (`roles/reviewer.md`). It lands +under the series `notes/reports/` directory and attaches to the handover gate as **judge evidence**. +There are two variants: **master-exit** (before a manager hands over to the orchestrator) and +**super-exit** (before the orchestrator hands over to the developer) — plus a loop-review +adaptation of the master-exit shape (see Loop-Review Adaptation below). + +## Rules + +1. **A verdict is evidence, not a decision.** State an explicit pass/block **recommendation**; the gate's + decider decides. Never write the verdict as if it were the gate outcome. +2. **A block must decompose into fix leaves** — concrete, leaf-shaped findings the owning + manager/orchestrator can dispatch. A block that cannot be named as fix leaves is not yet a block. +3. **Refute-or-confirm:** every finding must survive an attempt to refute it. Rank findings and cite + the backing evidence file. +4. Cover all three lenses (completion · code quality · onboarding-vs-code) explicitly, even to say a + lens is clean. +5. Record the gate evidence reference exactly: `kind=reviewer-verdict`, `ref=`, and + `verdict=`. +6. **Report every bound catalog criterion** in the Criteria Catalog Results table (the catalogs the + binding table in `roles/reviewer.md` assigns this review type, `../criteria/`) — one row per + standing criterion even when it found nothing, candidate rows when run — and carry any proposed + catalog amendments (the promotion ratchet) in that section. + +## Master-Exit Variant + +```md +# Adversarial Verdict — master-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | master-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | orchestrator (delegated `master-handover-approval`; serious issues escalate → developer) | +| artifact path | notes/reports/-master-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Task Docs +- Master requirement/substep coverage: addressed | delta justified | MISSING +- Leaf task docs and worker reports reconcile with the master task_doc: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite: green | failing: +- regressions vs the past (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- master-side route overviews current: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Manager Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the master-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Super-Exit Variant + +```md +# Adversarial Verdict — super-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | super-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | developer (human review concentrates at the super gate) | +| artifact path | notes/reports/-super-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Portfolio Task Docs +- Portfolio objective and dependency order satisfied: yes | +- Master handover packets and prior master-exit verdicts reconciled: yes | +- Cross-master conflicts, duplicate implementations, and deferred follow-ups surfaced: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite for the accumulated super branch: green | failing: +- branch-wide regressions vs the past and across masters (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- route overviews describe the accumulated behavior: yes | +- C-11 carry-over and ledger mapping coherent for the final super branch: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Orchestrator Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the super-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Loop-Review Adaptation (leaf full-loop · plan review) + +A three-party-loop review (a full-loop leaf round, or the plan review over an orchestration task) +uses the **master-exit variant's shape minus the gate machinery**: drop the `gate evidence` header +row and the Judge-Evidence Note (a loop review attaches to no gate), set `decider` to the **loop +owner** (the leaf's owning seat, or the orchestrator for the plan review), scope to the round's +change set (or the orchestration-task draft), and keep everything else — recommendation, Criteria +Catalog Results (the loop's bound catalogs, e.g. `plan-review` + `report-verification` for a plan +review), ranked refute-tested findings, and fix decomposition. The verdict remains **evidence to +the loop owner, never a decision**; a delta-verify appends a dated delta section to this same +artifact rather than opening a new one. diff --git a/.cursor/skills/l-01-agent-lifecycles/templates/worker-brief.md b/.cursor/skills/l-01-agent-lifecycles/templates/worker-brief.md new file mode 100644 index 00000000..db8f44d0 --- /dev/null +++ b/.cursor/skills/l-01-agent-lifecycles/templates/worker-brief.md @@ -0,0 +1,72 @@ +# Template — Worker Brief + +The dispatch packet a spawning seat (manager / orchestrator) compiles for a worker. **The brief is +the worker's entire session start** — it replaces the front half the spawner already ran (trust +checkpoint, reframe, plan). Compile it fresh per leaf from this shape; the proven form below +absorbed a series of real dispatch frictions (route-index leaks, attestation format, provider-stack +keying, missing `python` shim), so deviate knowingly or not at all. + +Spawn with `env={"AR_SPAWN_ROLE": "worker"}` and the **qualified** leaf key +`//` so the session-start router and the dashboard leaf rail both engage. + +--- + +```md +ROLE BRIEF — worker + +# WORKER BRIEF — · + +You are a WORKER for leaf `` of master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/worker.md`; this brief is your session start. Execute the leaf +completely, write your turn report, then stop. + +## Worktrees (your ONLY writable areas) +- Code: `` (branch ``, base ``) +- Memory: `` +- Plus your turn report at the path below. Nothing else. NEVER `git commit` — the owning seat + closes out after reviewing your report. + +## Tool surface +- Native file tools inside the two worktrees; shell for the checks below. +- Read-only AR retrieval: `read_ar_files` (serves the OFFICIAL baseline, never your worktree — + final verification uses native reads), `grepai_search` / `cgc_*` (provider stack key: + ``), `context_packet`. +- No `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, or `route_index_refresh` — + generated route indexes are regenerated with a local `build_route_indexes(...)` from the memory + worktree. +- Interpreter: `` with `PYTHONPATH=/mcp/src` — there is no + `python` shim in this environment. + +## The task +Leaf spec: `` (read it first). + +## Checks (green before you report) +- Focused: . +- Full: — must exit 0. +- `git diff --check` in both worktrees. + +## Onboarding (same editing pass, per c-05) +- Changed source files: update the sidecar BODY now; new files: create the sidecar. +- Route overviews: genuine body update where routes changed; otherwise the newest history entry + uses the LITERAL form `- — No route impact: ` (timestamp first). +- Pin idiom for verification metadata: "Verification metadata pinned until closeout stamps the + commit." + +## Turn report (mandatory, last act) +Write `/-worker-report.md` following +`skills/l-01-agent-lifecycles/templates/turn-report.md` — including exact check commands + +outcomes, the retrieval-evidence tally, and the respawn state. If blocked: fill Escalations and +stop — escalate to , never to the developer. +``` + +--- + +**Compiler notes for the spawning seat.** + +- Fill every ``; a brief with an unresolved placeholder is not dispatchable. +- Verify the provider stack actually answers before naming it; write `NONE (native reads only)` + when it does not — a worker discovering dead providers mid-leaf wastes its turn. +- Deliver as an echo-confirmed paste; verify the harness's paste chip (`[Pasted Content N chars]`) + before submitting, and only count delivery on a post-boot echo. +- The report path lives under the series `notes/reports/` — the same folder the seam verdicts use. diff --git a/.cursor/skills/l-01-session-job-lifecycle/SKILL.md b/.cursor/skills/l-01-session-job-lifecycle/SKILL.md deleted file mode 100644 index 9b3cc6d6..00000000 --- a/.cursor/skills/l-01-session-job-lifecycle/SKILL.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -name: l-01-session-job-lifecycle -description: "The session job lifecycle the coordinator routes every session into: request -> context/trust checkpoint -> developer-agreed reframe -> deeper research -> decide build mode -> build -> close. Owns research-only exits, the build-mode decision (chat build vs durable w-02-light-task-workflow task), and the job lens (bug/feature/triage/research). Supersedes the retired chat workflow by migrating and modernizing its doctrine." ---- - -# l-01-session-job-lifecycle Session Job Lifecycle - -The `l-01-session-job-lifecycle` skill is the **canvas** the coordinator routes into at the start of every session. -It is not a task format. A task format is one outcome of a single step inside it. - -The lifecycle is one shared spine with thin per-job lenses. Its front half is a -developer/model collaboration loop: the developer states the request, the model -runs mandatory MCP grounding checks, the model presents an evidence-backed -reframe, and the developer agrees or revises that reframe before deeper research -or build-mode decisions proceed. - -## Companion Files - -1. `job-variants.md` — the four thin job lenses (bug / feature / triage / research). -2. `deep-research-report-template.md` — the reusable report and evidence-ledger shape for deeper research. - -``` -0 Request -> 1 Trust Checkpoint -> 2 Reframe + Research -> 3 Decide -> 4 Build -> 5 Close - | - +-- research-only (e.g. investigation, code questions...) -``` - -## Hand-off Protocol — Dry-run action => "Notify-and-stop" Action => "Report" Action - -Every developer hand-off / gate moment — reframe agreement, plan gate, worktree intent, commit -approval, push approval, integration, cleanup/finalization, regular turn-end — is **notify-and-continue**: -surface an attention item, present the result, and **end your turn**; the developer responds and your -**next** turn picks up automatically. It is **three actions, never one**: - -1. **Dry-run action.** Run applicable MCP tools in `dry-run` for the hand-off. If dry run succeeds, - proceed with the notify-and-stop action. If dry run fails, try to ammend the issue first before reporting failure. -2. **Notify-and-stop action.** Call `lifecycle_turn_end_notification(summary=…)`. It sets the new - **`awaiting-developer`** lifecycle state, surfaces a dashboard attention item, and **returns - immediately — no wait, no inbox.** This is the **last tool call of the turn** — the report prose - still follows it; do not STOP here. The developer responds on the - dashboard or in the leaf's attached chat, and the **first AR tool call of your next turn** - automatically resumes the lifecycle (`running`) and clears the attention item — you send **no** - explicit resume. -3. **Report action.** Deliver the complete hand-off report as plain assistant output - (the reframe, the plan, the intent packet, or the closeout relay with - preview facts, quality results, proposed commit messages, and - attestations), and make the decision you are handing to the developer the last - line of prose. **The report is the last thing in the turn — then STOP / end your turn.** - -Use the `dry-run` step to verify that the planned tool call (for example the closeout apply) will -succeed before you hand off, and self-fix any failure before reporting it. - -`lifecycle_turn_end_notification` returns immediately and does **not** render a prompt over your prose, -so the report you deliver after it is exactly what the developer sees — call the -notification, then deliver the report as your final prose, then stop. Keep the report turn free of any mutating or permission-triggering operation so -nothing obscures the report. - -Junction → Dry-run → notify (`lifecycle_turn_end_notification`) → Report. Every junction below now hands -off through that one notification; the named `kind` is the **parked** durable-gate label the fallback -would use (see "Parked fallback" below), kept so the dashboard can still classify each hand-off: - -| Junction | Parked durable gate `kind` | Skill that hands off | -| -------------------------------- | -------------------------- | ---------------------------------------------------------- | -| plan gate | `plan-approval` | `l-01-session-job-lifecycle` | -| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | -| commit / closeout | `closeout-approval` | `c-12-closeout` | -| push | `push-approval` | `l-01-session-job-lifecycle` / `c-09-git-worktree-manager` | -| integration | `integration-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| cleanup / lifecycle finalization | `cleanup-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| any other dev-wait | `agent-question` | `l-01-session-job-lifecycle` | - -`closeout-approval` **is** the commit hand-off — there is no separate -`commit-approval`. Closeout is the single commit-of-record for code, memory, and -ledger, so every commit (including a singular one) routes through the closeout -hand-off. `agent-question` is the non-exhaustive catch-all so any dev-wait that is -not a structured junction is still observable. - -### Parked fallback — block-and-wait `lifecycle_gate` - -The block-and-wait `lifecycle_gate(kind=…)` junction (which creates a durable gate and waits for a -developer decision), the operator inbox, and the dashboard GateResponder **still exist and still work** -when explicitly raised — but they are **no longer the active path**, and nothing routes toward them: -`next_step.py` repoints every gate moment to `lifecycle_turn_end_notification`. Reach for the -server-enforced `lifecycle_gate` (followed by `lifecycle_resume` after the developer decides) only when -you deliberately need a durable, developer-attributed, mutation-blocking approval record; its `kind` -values are the table above. If you ever do raise it, it renders an approval prompt **over** your prose, -so the report must land in an earlier turn — which is exactly why notify-and-stop is preferred. - -## Lifecycle Signals — Making The Session Observable - -Every session in a managed repo is a **lifecycle**: the six `lifecycle_*` signals -record where it is and what it is waiting on, so the work is observable and -resumable across chat deaths (design `docs/design/observable-lifecycle.md`). The -model **never handles a lifecycle id** — identity is server-side, anchored in the -worktree contract. - -| When (phase) | Signal | Why | -| ---------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Trust Checkpoint passes (managed repo) | `lifecycle_start` | Begin a **fleeting** lifecycle (guarded: one per session; takes no id). | -| Entering each phase | `lifecycle_phase` | Move the orthogonal phase axis (`request`/`trust-checkpoint`/`reframe-research`/`decide`/`build`/`close`). | -| At a hand-off (reframe, plan, commit, …) | `lifecycle_turn_end_notification(summary=…)` (last tool call), then the report prose, then **STOP** | Set `awaiting-developer`, surface the dashboard attention item, and return immediately (no wait, no inbox); the next turn's first AR tool call auto-resumes (`running`) and clears the item. Block-and-wait `lifecycle_gate(kind=, ask=…, packet=…)` + `lifecycle_resume` is the parked fallback. | -| `worktree_start` (Decide → Build) | _(promotion — automatic)_ | The fleeting lifecycle becomes **persistent**, anchored in the contract; no separate signal. | -| Resuming an existing task | `worktree_attach` | Re-adopts the contract's lifecycle (contract-resolved); the model passes no id. | -| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | The save gate: promote it or abandon it — never dropped silently. | -| Close | `lifecycle_end` (`completed`\|`abandoned`) | The terminal record. | - -Rules: `lifecycle_start` is guarded (one active lifecycle, no id). `paused` is -**system-owned** — there is no pause signal. `awaiting-developer` is set by -`lifecycle_turn_end_notification` and auto-cleared back to `running` by the next -turn's first AR tool call — you never resume it by hand. A tool call outside any -lifecycle is **dropped, never misattributed**. `worktree_start` **promotes** the current -lifecycle (fleeting → persistent); `worktree_attach` **resumes** the contract's -lifecycle; both keep identity server-side. - -## 0 — Request - -Receive the developer's raw request and identify the active repository. - -1. Treat the developer's statement as raw input, not yet as an implementation plan. -2. Infer the target code repository from the request and local context. Ask the - developer if the target is unclear. - -Request intake changes nothing. It only establishes which repository the next -checkpoint must inspect. - -The upcoming `Trust Checkpoint` reveals whether or not the request is related to repositories managed by Agents Remember. If not, then the lifecycle exits early and the agent can work as usual. - -However, if later work is to enter the boundary of repositories being managed by Agents Remember, -the lifecycle must be re-entered. - ---- - -## 1 — Trust Checkpoint - -Establish whether memory and providers are trustworthy enough to use. - -1. For the target repository, resolve coordination/memory context with - the MCP tool call: - - ```text - context_packet(repo_id="", include_providers=true, include_drift=true, include_freshness=true) - ``` - -2. Report the packet facts before relying on memory or providers: - - repository, branch, and dirty state - - memory root and onboarding root - - provider state - - drift status and actionable drift count - - branch freshness: whether the code and memory checkouts are current with - their upstreams (`behind`/`diverged` means the local official line is - stale — fast-forward it before trusting analysis or basing work on it) - and whether the ledger maps code HEAD (`ledgerMapsCodeHead=false` means - the memory checkout does not match the code state; run carryover or - check out the right memory branch first) -3. If onboarding for committed source is drifted, missing verification, or - orphaned, and the corresponding source file is not dirty in the code - worktree, stop and ask the developer whether or not to refresh it through - `c-05-create-or-update-onboarding-files`. Drift handling is approval-gated! -4. If drift is tied to dirty source, report it as active work-in-progress. Do - not adopt it as maintenance or silently trust it as current state unless the - developer explicitly says this job owns it. -5. If providers are stopped or degraded, use the matching MCP provider/runtime - operations, then re-run the provider check. If providers are ready, report - readiness and continue. If issues persist, report it to the developer and - wait for instructions. If the packet's providers summary lists `indexing` - targets, report them to the developer: those providers are healthy but - busy, and their results may be partial until the scan completes. -6. After the trust checkpoint passes, read committed-state onboarding for the - in-scope anchors as needed. A file dirty in another chat is still valid for - HEAD and worth comparing, but its dirty-source drift remains active work. - ---- - -## 2 — Reframe And Research - -Turn the developer's raw request into an agreed piece of work, then perform the -deeper research that the agreed frame requires. The `tasks/AGENTS.md` -collaboration doctrine applies here in plain chat, before any task file or task -format exists. - -**Read tool for this phase.** Until the build-mode decision (Phase 3), read managed-repo source -through the `read_ar_files` MCP tool, not the harness's native read — it returns paired -source+onboarding plus the repository/route overviews in one observable, lifecycle-attributed -call, and you keep a running count of those calls as evidence. Native read is the edit -precondition in Phase 4. - -1. **Gather evidence for the reframe** through reading the - `c-04-retrieval-strategy-router` skill. Pick the strategy by the question: - - _Semantics_ (grepai over onboarding) — "where does X live / what handles Y." - - _Relationship_ (cgc) — callers/callees/dependencies/impact. - - _Intent_ (onboarding + bounded source confirmation) — hidden contracts, invariants, - branch-valid truths, behavioral expectations. This is a workflow of paired - source+onboarding reads via the `read_ar_files` MCP tool: one call pairs each source - file with its verified onboarding and auto-attaches the repository overview + governing - route-overview chain (the bird's-eye view). -2. **Reframe** the request through `tasks/AGENTS.md`: distinguish the surface - request, deeper objective, highest-leverage framing, assumptions, boundaries, - invariants, and truth gaps. Do not rush a statement into a plan. -3. Present the reframe to the developer. If the developer disagrees, discuss and - revise the reframe. If the developer agrees, proceed to deeper research. -4. **Perform deeper research** for the agreed frame. This research still uses - `c-04-retrieval-strategy-router`, but it is now scoped by the developer-agreed - frame rather than by the model's first guess. Use - `deep-research-report-template.md` for the report shape; the lifecycle owns - the required proof categories, while the template owns evidence formatting. -5. The deeper research report must list its proof and tie evidence to the claim it supports: - - `read_ar_files` calls (paired source+onboarding reads — the running count) - - onboarding docs read - - semantic queries performed - - code graph queries performed - - source files inspected - - remaining truth gaps -6. Run the **job opening move** for the job lens (see `job-variants.md`) and use - the deeper research to name the truth gaps that remain. -7. Continue until the developer agrees the design is defined well enough to write - down, then produce the **plan**: the steps, and a **code example for every - distinct change** you intend to make. - -**Plan gate:** **hand off** before changing any code. No implementation begins -before the developer approves. Call -`lifecycle_turn_end_notification(summary={…the plan + the developer-facing approval ask…})` as the -**last tool call**, then present the plan as your final prose and **STOP**; -the developer approves on the dashboard or in chat and your next turn auto-resumes to begin -implementation. (Parked fallback: the server-enforced -`lifecycle_gate(kind="plan-approval", ask=…, packet=…)` + `lifecycle_resume` still exist if you -deliberately need a mutation-blocking approval record.) - ---- - -## 3 — Decide (build mode) - -One decision: does this job change code? - -- **No -> research-only exit.** Deliver the answer/assessment. No worktree, no task artifact, no closeout. - A research-only job may recommend or spawn a follow-up build job; it does not perform one itself. -- **Yes -> worktree intent hand-off, then always a worktree.** Read `c-09-git-worktree-manager` - and `system/git-workflow.md`, call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the worktree - intent packet as your final prose and **STOP**. The developer approves and your next turn - auto-resumes to `worktree_start`. Then open it with - `c-09-git-worktree-manager` and pick the build mode: - - **Chat build** — small enough to carry inline this session: worktree-backed, **no** `task.md`. - - **Durable task build** — hand off to `w-02-light-task-workflow`: `task.md`, checklist, decision - log, proposed code examples. Escalate to a master + light sub-task series when the work outgrows a - single-page plan. - -The worktree intent packet names the target repo, build mode, discovered branch policy, proposed -`source_branch`, proposed work branch/worktree name, memory mode, landing path, and material risks. -On PR-gated repos, the packet must prove that the recorded `source_branch` is pushable and that -protected targets are reached later through the repo's PR flow. - -Worktree granularity = the leaf task unit. A single task gets its own leaf enclosure/worktree. A -master multi-task owns a root `series-contract.md` and integration branch, while each active leaf -sub-task gets its own `enclosures//series-contract.md`, branch, and worktree. A chat build -gets its own leaf worktree without a task artifact. The git-landing decision (direct vs PR-gated) is -deferred to the repo's `system/git-workflow.md` — read it before landing on a gated branch. - ---- - -## 4 — Build - -Implement inside the worktree, keeping memory and tests in lockstep with the code. - -1. Apply the approved code changes. -2. **Refresh the matching onboarding in the same editing pass**, per completed plan-section — never - deferred to the end of the job. When a change affects durable current-state knowledge, the sidecar - is updated alongside it through `c-05-create-or-update-onboarding-files`. - - For **changed** (already-onboarded) source files, update the sidecar **body** now: the closeout - gate rejects a changed source file whose existing sidecar was not modified this job, because - refreshing `lastVerifiedCommitHash` over stale content silently defeats the drift check. - - For **new** source files, run `check_missing_onboarding` before the commit and create the - reported missing sidecars through the `c-05-create-or-update-onboarding-files` skill; the post-code-commit memory refresh stamps them with - the real code commit hash and date. -3. Run the checks from the `c-08-ar-coordination-context-resolver` resolved `system/tools.md` (lint, typecheck, complexity, tests) and - get them **green before each incremental commit**. Testing is never deferred to a final task; the - pre-commit/pre-push hooks enforce it. -4. **Watch the official line and sync early.** `worktree_status`'s `freshness` block reports when the - recorded base pair fell behind the local source branch tips (a parallel cycle landed). Pull the - moved official line in with `worktree_sync` — preferably **before memories are written**: with - parked memory the sync is a pure fast-forward, the other cycle's sidecars and ledger rows end up - beneath this task's future work, and end-of-series integration stays `ff-only` with no carryover - reconciliation. - -Incremental, pushable commits keep the work-loss window small. Each closeout below is one such commit. - ---- - -## 5 — Close - -Land the work. **Implementation approval is not commit approval.** - -1. Run the `c-09-git-worktree-manager` closeout **preview** for the worktree (`worktree_closeout_preview`). - Every build closes through its worktree — there is no direct-checkout closeout. - Relay the proposed code, memory, and ledger commit messages. -2. **Commit gate:** run the closeout **preview** (dry-run), then **hand off** before any real commit or closeout - apply. If required onboarding is missing, run the `c-05-create-or-update-onboarding-files` skill for the affected file and re-run the preview. - Call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the - **last tool call**, then deliver the preview facts as your final prose and **STOP**; - the developer approves on the dashboard or in chat and your next turn auto-resumes to - `worktree_closeout_apply`. The `c-12-closeout` skill owns this hand-off. Parked fallback: when you - deliberately raise the durable `closeout-approval` `lifecycle_gate`, it is enforced **server-side** — - `worktree_closeout_apply` refuses unless it is approved by the developer, and an agent self-approval - never satisfies it. -3. On approval, the `c-09-git-worktree-manager` skill owns the external-memory invariant in order: commit code → refresh affected - onboarding metadata to the new code commit → run memory quality control → commit memory content → - update and commit the ledger. -4. **Integrate + land** per `c-09-git-worktree-manager` and `system/git-workflow.md`: integrate the - worktree branch into the approved source/integration branch, then on a PR-gated repo push that - source branch, open the PR, wait for green checks, and merge per the repo convention. Never push a - protected branch directly. The agent does not push on its own authority — call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the push intent - as your final prose, and **STOP**; push only after the developer - approves and your next turn auto-resumes. The `c-09-git-worktree-manager` skill makes the matching - integration and cleanup/finalization hand-offs at its landing tail (parked durable kinds - `integration-approval` / `cleanup-approval`). -5. **Map the ledger to the landed commit.** A PR merge usually lands a **merge commit** on top of the - work — tree-identical to the verified tip but a new SHA the ledger does not yet map. Ensure the - ledger maps that merge commit so the next worktree can base off the merged branch without a manual - reconciliation. `system/git-workflow.md` owns this step. -6. **Finalize the lifecycle:** run `lifecycle_finalize_task(..., dry_run=true)` once the local parent - branch contains the landed commit and memory carryover is done. Call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then relay its landed-commit - proof, cleanup plan, and task-document updates as your final prose, and - **STOP**. The developer approves cleanup/finalization and your next turn auto-resumes to run the real - finalizer. The tool proves one parent-child branch edge, - reclaims the worktrees, and marks the leaf task plus immediate parent row `Completed` when those - task-doc paths are supplied. It does not recursively complete ancestors; repeat the edge at the next - parent level when that parent task lands. -7. **Keep squash out of the normal path.** A PR-gated edge is structurally the same as a direct edge - after the model finishes the PR merge and pulls the target branch locally. Do not use squash-merge - equivalence as a default finalization proof; squash is an emergency/manual recovery path because it - erases commit lineage and can make memory lookup history wrong. - -A research-only exit skips this phase entirely. - -## Relationship To Other Instructions - -This skill extends the coordinator `AGENTS.md` and the repository memory layer; it does not replace -them. Read `job-variants.md` for the per-job lenses, and `deep-research-report-template.md` for the -deeper research report shape. diff --git a/.cursor/skills/w-02-light-task-workflow/SKILL.md b/.cursor/skills/w-02-light-task-workflow/SKILL.md index 248e6f3c..b34f3017 100644 --- a/.cursor/skills/w-02-light-task-workflow/SKILL.md +++ b/.cursor/skills/w-02-light-task-workflow/SKILL.md @@ -40,7 +40,7 @@ Light-task artifacts use minute-precision timestamps in `YYYY-MM-DDTHH:MM` forma The task document is **JSON-primary**: an `ar-task-document/v1` JSON file is the source of truth, and the `task.md` (or `.md` for a sub-task) is a deterministic **render** of it. Author and update it with the `task_doc` MCP tool — `create`, `set_status`, `set_step`, `append_decision`, `set_field` — which writes the JSON and re-renders the markdown on every write. Do not hand-edit a tool-managed `task.md`; edit through the tool and let it re-render. `template.md` and `master-template.md` document the **render spec** (the shape the renderer produces), not a separate hand-authored format. When a planning slice defers its code examples to the plan gate, record that with `codeExamplesNote` (a `set_field` value, e.g. "Drafted at the plan gate.") so the rendered "Proposed Code Examples" section reads as *deferred* rather than as if none are needed. A leaf doc may also carry a descriptive `statusNote` (a suffix beside the strict status enum), `headerNotes` (extra `**Key:** value` header lines such as Verified/Source), and freeform `sections` appended after References — the escape hatch for bespoke prose (e.g. a Status history) while the standard template sections stay the backbone. Pass `dry_run=true` to any op to **preview** — it builds + validates and returns the rendered markdown, a unified `diff` vs the on-disk `.md`, and a `wouldLose` flag, **without writing**; use it before adopting a hand-authored `.md` into JSON-primary (author the JSON → dry-run → confirm `wouldLose` is false → then write). -Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for a chat build (a thin doc: title plus a few steps, so even a no-`task.md` session is legible) and a *full* one for a durable task; the difference is content completeness, not a separate format. +Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for the smallest single-session build (a THIN doc: title plus a few steps — chat is never a build route, so even micro-work gets this thin doc and stays legible on the dashboard) and a *full* one for a durable task; the difference is content completeness, not a separate format. Scope and transition: the tool manages **`light` and `subTask`** documents, and the format also covers a series **master** (`kind:"master"`: a structured `subTasks` index + ordered `sections` that preserve a master's bespoke prose, so a re-render is lossless). Masters and existing markdown task files stay hand-authored markdown until the runtime ships `task_doc` and they are intentionally migrated — new tasks adopt the JSON-primary format going forward. diff --git a/.cursor/skills/w-02-light-task-workflow/master-template.md b/.cursor/skills/w-02-light-task-workflow/master-template.md index 7cb4e85a..42738c16 100644 --- a/.cursor/skills/w-02-light-task-workflow/master-template.md +++ b/.cursor/skills/w-02-light-task-workflow/master-template.md @@ -7,7 +7,7 @@ built to grow as the work unfolds. ## When to escalate to a series -The `l-01-session-job-lifecycle` skill's `decide` build-mode step escalates a single task to a series once its size is apparent — the +The `l-01-agent-lifecycles` orchestrator lifecycle's `decide` step escalates a single task to a series once its size is apparent — the implementation plan no longer fits on a single page, or the work splits into distinct slices that each deserve their own checklist and commit. You can also start single and escalate later: drop in the master `task.md` and move the existing plan into the first `NN_.md`. diff --git a/.github-vscode/copilot-instructions.md b/.github-vscode/copilot-instructions.md index a0f19f8f..0d2055f4 100644 --- a/.github-vscode/copilot-instructions.md +++ b/.github-vscode/copilot-instructions.md @@ -1,13 +1,15 @@ -MANDATORY FIRST ACTION for this workspace +**Agents Remember — session start.** -You are not allowed to read, write, or execute code on any repository -until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure. +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** -Read and follow `/ar-coordination/AGENTS.md` -before working in any sibling project. Treat those rules as workspace -instructions. +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`ar-coordination/AGENTS.md`, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent). -Include the onboarding files inspected and every CGC and GrepAI query made as -evidence. +`ar-coordination/AGENTS.md` resolves under the workspace root: +`/ar-coordination/AGENTS.md`. diff --git a/.github-vscode/hooks/agents-remember-session-start.md b/.github-vscode/hooks/agents-remember-session-start.md index 427c30f3..cd999a73 100644 --- a/.github-vscode/hooks/agents-remember-session-start.md +++ b/.github-vscode/hooks/agents-remember-session-start.md @@ -1,14 +1,12 @@ -MANDATORY FIRST ACTION for this workspace +**Agents Remember — session start.** -You are not allowed to read, write, or execute code on any repository -until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure! +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** -Until the build/job decision is made, read managed-repo source with the -`read_ar_files` MCP tool — not the harness's native read tool. One call returns -each file paired with its onboarding plus the repository and governing route -overviews. Native read is reserved as the edit precondition once building begins. - -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent), and -keep a running count of your `read_ar_files` calls. Include the onboarding files -inspected and every CGC, GrepAI, and `read_ar_files` call made as evidence. +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`ar-coordination/AGENTS.md`, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. diff --git a/.github-vscode/skills/c-01-findings-capture/SKILL.md b/.github-vscode/skills/c-01-findings-capture/SKILL.md index e145d7ee..d413e8fe 100644 --- a/.github-vscode/skills/c-01-findings-capture/SKILL.md +++ b/.github-vscode/skills/c-01-findings-capture/SKILL.md @@ -13,7 +13,7 @@ Companion file: ## Operating Modes -1. Inside a task workflow (an `l-01-session-job-lifecycle` build job or a `w-02-light-task-workflow` task, including a master + light sub-task series). +1. Inside a task workflow (an `l-01-agent-lifecycles` orchestrator build phase or a `w-02-light-task-workflow` task, including a master + light sub-task series). 2. Standalone during direct clarification. ## Durable Destinations diff --git a/.github-vscode/skills/c-03-repo-bootstrap/SKILL.md b/.github-vscode/skills/c-03-repo-bootstrap/SKILL.md index 40148918..44f14f78 100644 --- a/.github-vscode/skills/c-03-repo-bootstrap/SKILL.md +++ b/.github-vscode/skills/c-03-repo-bootstrap/SKILL.md @@ -1240,7 +1240,7 @@ The orchestrator remains thin throughout. | `c-05-create-or-update-onboarding-files` | Owns final file-level onboarding semantics and routes structural slice maintenance back to the `c-03-repo-bootstrap` skill. The `c-03-repo-bootstrap` skill creates cards/waves and delegates file output rules to the `c-05-create-or-update-onboarding-files` skill. | | `c-04-retrieval-strategy-router` | Consumes bootstrapped overviews and file maps as the Intent substrate and can route to semantic/relationship providers first. | | `c-02-memory-quality-control` | Becomes relevant after bootstrap; touched files can be promoted from deferred to covered. | -| `l-01-session-job-lifecycle` | May trigger targeted bootstrap when an active job enters an uncovered area. | +| `l-01-agent-lifecycles` | May trigger targeted bootstrap when an active job enters an uncovered area. | | `confluence-search` / documentation search skills | Feed the docs evidence pass through approved sources from the input ledger. | --- diff --git a/.github-vscode/skills/c-04-retrieval-strategy-router/SKILL.md b/.github-vscode/skills/c-04-retrieval-strategy-router/SKILL.md index 01434c77..e226f8c0 100644 --- a/.github-vscode/skills/c-04-retrieval-strategy-router/SKILL.md +++ b/.github-vscode/skills/c-04-retrieval-strategy-router/SKILL.md @@ -160,7 +160,7 @@ names an unresolved source question. ### Rules: -- During the research phase (the lifecycle up to the build/job decision), read managed-repo +- During the research phase (the lifecycle up to the build decision), read managed-repo source with `read_ar_files`, not the native read tool — one call returns each file paired with its onboarding plus the repository and governing route overviews (the recipe above, batched and observable). diff --git a/.github-vscode/skills/c-09-git-worktree-manager/SKILL.md b/.github-vscode/skills/c-09-git-worktree-manager/SKILL.md index e19c7902..692dec19 100644 --- a/.github-vscode/skills/c-09-git-worktree-manager/SKILL.md +++ b/.github-vscode/skills/c-09-git-worktree-manager/SKILL.md @@ -7,7 +7,7 @@ description: "Create, attach to, report on, integrate, finalize, and clean up Ag Use this skill when a task should run through an explicit code/memory worktree wrapper. -The `c-09-git-worktree-manager` skill wraps the existing chat-build, light-task, or external workflow. It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. +The `c-09-git-worktree-manager` skill wraps the existing light-task or external workflow (a build that fits one session still rides a THIN `w-02-light-task-workflow` doc — chat is never a build route, per the `l-01-agent-lifecycles` invariant). It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. For closeout, use the `c-12-closeout` skill. The `c-09-git-worktree-manager` skill only supplies the worktree-specific contract path and integration/finalization follow-up rules. @@ -67,7 +67,7 @@ The intended order is: 1. run the `c-08-ar-coordination-context-resolver` skill for the target repository 2. run the `c-02-memory-quality-control` skill's task-start drift check and follow the existing AGENTS Gate 3/4 choice point 3. when onboarding is refreshed, commit the memory content and ledger before starting any worktree -4. decide whether the work is a chat build, a `w-02-light-task-workflow` light task (or master + light sub-task series), or external workflow +4. decide whether the work is a `w-02-light-task-workflow` light task — possibly a THIN one for single-session work; chat never builds — a master + light sub-task series, or external workflow 5. read the repository's `system/git-workflow.md` and identify the parent branch edge. For a standalone task, the leaf worktree branches from the approved source branch. For a master series, the master owns a root `series-contract.md` @@ -198,7 +198,9 @@ moved since task start. ## Integration -Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. +Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. Orchestrated-run carve-out (ruled 2026-07-06): dependency-ordered leaf→master and master→super integrations ride the series' standing approval (the developer's portfolio-gate approval recorded in the planner master) — the developer hand-off concentrates at the super PR/carry-over gate per the `l-01-agent-lifecycles` loop/orchestrator doctrine; a raised durable `integration-approval` gate still awaits the developer. + +On an orchestrated master's exit (master → super integration) the integrate step additionally enforces the delegated `master-handover-approval` seam: an undecided or policy-invalid handover gate addressed to the master (by `enclosure` = master task name) returns `handover-gate-blocked` instead of landing — decide the gate per the `l-01-agent-lifecycles` seam doctrine, then rerun. When no gate addresses the integrating master but open `master-handover-approval` gates exist elsewhere, integrate still proceeds and its result carries a `handover_gate_warning` naming them — treat it as a spelling check on the raised gate's `enclosure`. Run `worktree_integrate(..., dry_run=true)` first, then **hand off**: call `lifecycle_turn_end_notification(summary={…the integration plan…})` as the **last tool call**, then diff --git a/.github-vscode/skills/c-12-closeout/SKILL.md b/.github-vscode/skills/c-12-closeout/SKILL.md index f83071d9..2c7fe3ff 100644 --- a/.github-vscode/skills/c-12-closeout/SKILL.md +++ b/.github-vscode/skills/c-12-closeout/SKILL.md @@ -40,7 +40,7 @@ records the developer's explicit commit approval. Agents must not treat implementation approval, a previous "looks good", or their own judgment as commit approval. -The relay follows the `l-01-session-job-lifecycle` skill hand-off protocol: run the +The relay follows the `l-01-agent-lifecycles` orchestrator hand-off protocol: run the preview/dry-run first, then call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the **last tool call**, then deliver the preview facts and proposed messages as plain diff --git a/.github-vscode/skills/c-13-install-and-onboard/SKILL.md b/.github-vscode/skills/c-13-install-and-onboard/SKILL.md index 6515ae46..d583fd13 100644 --- a/.github-vscode/skills/c-13-install-and-onboard/SKILL.md +++ b/.github-vscode/skills/c-13-install-and-onboard/SKILL.md @@ -52,10 +52,12 @@ Run this sequence in order: 0. Preflight: verify the copied package and MCP setup are usable enough to continue. 1. Runtime scaffold: run or verify `runtime_install()`. -2. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. -3. Bootstrap: when a new memory repo was scaffolded, hand off to +2. Agentic settings: walk the developer through the orchestration defaults in + the seeded global settings file. +3. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. +4. Bootstrap: when a new memory repo was scaffolded, hand off to `c-03-repo-bootstrap`. -4. Providers: when providers are enabled, start/refresh indexing and verify +5. Providers: when providers are enabled, start/refresh indexing and verify readiness. This skill orchestrates and delegates. It does not reimplement @@ -79,7 +81,9 @@ Check, in order: 3. **Settings sane.** Confirm `server_info` reports the expected `coordinationRoot`, `workspaceRoot`, allowed repositories, and providers. Surface the resolved absolute paths because wrong paths are the common cause - of resolver failures. + of resolver failures. Also report whether the global agentic settings file + (`/system/settings.json`) exists yet; Stage 1 seeds it + when missing and Stage 2 configures it. 4. **Runtime state.** Check whether the coordinator scaffold already exists under `coordinationRoot` (`AGENTS.md`, `skills/`, `tasks/`, `memory-repos/`, `system/` as applicable). If it is missing or stale, Stage 1 will run @@ -118,7 +122,61 @@ Do not run `skills_install()` as part of first-run setup. The harness starter package already carries the skills. `skills_install()` remains available for manual maintenance or non-package setups, but it is not the default path. -## Stage 2 - Memory Repo: Ask Scaffold Vs Existing +## Stage 2 - Agentic Settings: Interview The Developer + +`runtime_install()` seeds the GLOBAL agentic settings file at +`/system/settings.json` copy-if-missing, with every knob at +its documented default: all-human gate delegation, the standard three-party-loop +defaults, no concurrency caps, no spawn harness preference. This stage turns +those defaults into the developer's actual posture so the intended workflows +run on ANY harness. The schema reference is `docs/reference/settings-json.md` +(Agentic Settings); unknown `orchestration.*` keys fail loud, so write only +documented keys. + +Walk the developer through the four knob families and edit the global file with +their answers (leave a family at its seeded default when they have no +preference): + +1. **Gate delegation posture** (`orchestration.gateDelegation`; GLOBAL file only - the + loader refuses it repo-locally and the boot snapshot reads the coordinator file) - keep every + gate human (`all-human`, the default), or delegate leaf gates with the + `manager-decides-leaf-gates` policy, optional per-kind `kinds` overrides, + and `requireReviewerVerdictAtSeams`. Say explicitly that this one key is + boot-snapshot: a change needs an MCP/harness restart. +2. **Loop defaults** (`orchestration.loops`) - the review-round cap + (`defaults.maxRounds`), reviewer reuse (`defaults.reviewerReuse`), + complexity thresholds (`defaults.complexity`), and per-level loop postures + (`perLevel`). Read per-use; edits apply on the next use, no restart. +3. **Concurrency caps** (`orchestration.concurrency`) - `maxParallelMasters`, + `maxParallelLeaves`, `maxSubAgents`. Default: uncapped. +4. **Harness preference + role knobs** (`orchestration.spawn.harness`, + per-role `orchestration.roles.`, per-level + `orchestration.rolesPerLevel..`) - which installed harness + `spawn_agent_session` uses when the spawning seat passes none, per-role + harness/model/effort overrides, and per-LEVEL overrides + (leaf|master|portfolio) for tiered economics (e.g. a cheap leaf reviewer, + a smarter master-seam reviewer). Harness values must be known ids: the + builtin registry (`claude`, `codex`, `pi`) or an `orchestration.harnesses` + entry the developer defines (new TUIs, or a pre-customized launch argv for + a builtin). `effort` is validated per-harness at dispatch (claude: + `low|medium|high|xhigh|max` on the `--effort` flag plus the session-level + `ultracode`); mention the FREE-FORM escape hatch for anything outside the + vocabularies - `launchArgs` (verbatim argv), `sessionCommands` (pasted + before the brief), `promptKeywords` (prepended to the brief) - never + validated, recorded in spawn provenance. Default: detection-gated (the + first detected harness). The full spawn-surface manual is + `docs/reference/harnesses.md`. + +If the developer wants to skip the interview, confirm the seeded defaults +apply and continue; tell them the file can be edited any time (picked up +per-use, except the gateDelegation restart note above). + +Per-repo overrides: a code repo may carry its own `/system/settings.json` +with the same `orchestration.*` shape; repo-local leaf values override the +global file (arrays replace). Offer this only when the developer asks for +repo-specific behavior; do not create the file unprompted. + +## Stage 3 - Memory Repo: Ask Scaffold Vs Existing Do not assume the developer wants a fresh memory repo. Ask which case applies, unless a memory repo is already present and resolvable: @@ -126,10 +184,10 @@ unless a memory repo is already present and resolvable: 1. **Scaffold a new memory repo** - they have no existing memory for this code repo. Run `c-00-initialize-memory-repo` (internal by default; external only if the developer asks or the configured topology requires it). Continue to Stage - 3. + 4. 2. **Use an existing memory repo** - they already have one. Clone or checkout it to the resolved memory location, then adopt it as the ledgered baseline with - `c-10-adopt-memory-baseline`. Skip Stage 3 because its onboarding already + `c-10-adopt-memory-baseline`. Skip Stage 4 because its onboarding already exists. Internal-memory note: pre-existing internal memory lives inside the code repo @@ -137,9 +195,9 @@ Internal-memory note: pre-existing internal memory lives inside the code repo `c-08-ar-coordination-context-resolver` and skip the question when the memory layer is already there. -## Stage 3 - Bootstrap +## Stage 4 - Bootstrap -Run this stage only when Stage 2 scaffolded a new memory repo. +Run this stage only when Stage 3 scaffolded a new memory repo. Hand off to `c-03-repo-bootstrap` to generate initial onboarding. A thin `overview.md` is enough to start; deeper route-local overviews and file-level @@ -147,7 +205,7 @@ onboarding should grow as work touches new areas. Skip this stage when an existing memory repo was adopted. -## Stage 4 - Configure Providers To Index +## Stage 5 - Configure Providers To Index If providers are enabled, make them index the configured code and memory: @@ -177,10 +235,12 @@ Summarize: step the developer must perform; 2. runtime scaffold: `runtime_install()` run or already current, with the resolved coordination root; -3. memory repo: scaffolded, existing-adopted, or already present, with the +3. agentic settings: interviewed and written, or left at the seeded defaults, + with the global file path; +4. memory repo: scaffolded, existing-adopted, or already present, with the resolved memory root; -4. bootstrap: run via `c-03-repo-bootstrap` or skipped; -5. providers: indexing status and any deferred/degraded state. +5. bootstrap: run via `c-03-repo-bootstrap` or skipped; +6. providers: indexing status and any deferred/degraded state. End by telling the developer whether the project is ready for normal work. Do not tell them to restart for hooks installed by this skill, because this skill no diff --git a/.github-vscode/skills/l-01-agent-lifecycles/SKILL.md b/.github-vscode/skills/l-01-agent-lifecycles/SKILL.md new file mode 100644 index 00000000..1d390618 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/SKILL.md @@ -0,0 +1,259 @@ +--- +name: l-01-agent-lifecycles +description: "The agent lifecycles: one lifecycle per agent type, under one roof. Routes every session by exactly three conditions (spawn-role env -> role brief -> otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator, designer, strategist, manager, worker, adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. A developer-facing session IS the orchestrator; solo work is the degenerate portfolio. Supersedes and replaces both l-01-session-job-lifecycle and l-02-agent-orchestration." +--- + +# l-01-agent-lifecycles — The Agent Lifecycles + +Lifecycle and job are **one entity**: each agent type runs its own, self-contained lifecycle. This +skill is the single roof over all of them — a thin router, the minimal frame every session shares, +and the role lifecycles as the payload files. No role is defined by reference to another role's +lifecycle, and no role reads another role's file. + +## Which Lifecycle Am I? (the router — exactly three conditions, in order) + +1. **`AR_SPAWN_ROLE` is set** (spawn env, injected by `spawn_agent_session`) → run + `roles/.md`. Nothing else in this file's "developer session" material applies to you. + (`designer` here means the same design hat in a separate chair — see `roles/designer.md`.) +2. **Else: the first user message is a role brief** — a `templates/*-brief.md`-shaped dispatch or + a first line of the form `ROLE BRIEF — ` from an orchestrating agent → run that role's + lifecycle. The brief is your session start; a workspace session-start notice is not addressed + to you. +3. **Else** (a developer opened this session) → you are the **orchestrator**: run + `roles/orchestrator.md`. Solo work is the degenerate portfolio — the same three jobs with hats + collapsed (the orchestrator wears the manager hat in flat runs and builds hands-on at session + scale); the task doc still comes first. + +There is no fourth entry, and the edge cases are decided: an **unresolvable `AR_SPAWN_ROLE` +value** (no matching `roles/.md`) falls through to condition 2 (the brief); a role-env +session **whose brief never arrives** announces itself on the inbox and waits — it never +improvises a task; `AR_SPAWN_ROLE=orchestrator` is valid only as a takeover chair (the Profile +check (takeover) in `roles/orchestrator.md`, The Event Loop) — the developer still talks to **one** orchestrator. Orchestrated +fan-out (spawning managers/workers at scale) begins only on an explicit developer request (e.g. +*"orchestrate these masters"*) — no agent promotes itself into a spawning seat. + +One exception to the no-cross-reading rule above: **a seat that WEARS a hat runs that hat's file +as its own** — the orchestrator always for `roles/designer.md`, and in flat runs for +`roles/manager.md` (the hat-collapse rule). + +## The Role Registry + +| Role | Seat | Lifecycle file | +| --- | --- | --- | +| **orchestrator** | the developer-facing session; first coordination leaf of an orchestrated series | `roles/orchestrator.md` | +| **designer** | a HAT the orchestrator pulls inline (front of the pipeline or mid-flight; separate chair optional) | `roles/designer.md` | +| **strategist** | the sprint planner, SPAWN-FIRST; a strategist run is a **mandatory precondition for any orchestrated run** — its deliverable is the orchestration task (sprint plan + scope); spawn value `strategist` | `roles/strategist.md` | +| **manager** | one coordination leaf per master; drives that master's leaf loop | `roles/manager.md` | +| **worker** | one leaf worktree, short-lived, fresh session | `roles/worker.md` | +| **adversarial reviewer** | short-lived, spawned at the two seams (master-exit, super-exit) and as any three-party loop's reviewer seat (criteria catalogs bound per review type); spawn value `reviewer` | `roles/reviewer.md` | + +The **lenses** (bug · feature · triage · research — `lenses.md`) are how the scoping seats +(orchestrator, designer) read a piece of work; a dispatched role never picks a lens — its brief +already carries the flavor. + +## The Minimal Frame (the only machinery every session shares) + +Every session in a managed repo may be a **lifecycle**: six signals — `lifecycle_start` · +`lifecycle_phase` · `lifecycle_turn_end_notification` · `worktree_attach` · `switch_lifecycle` · +`lifecycle_end` (plus the automatic `worktree_start` promotion) — record where it +is and what it waits on, so work is observable and resumable across chat deaths. The model **never +handles a lifecycle id** — identity is server-side, anchored in the worktree contract. + +| When | Signal | Effect | +| --- | --- | --- | +| Trust checkpoint passes (managed repo) | `lifecycle_start` | begin a **fleeting** lifecycle (guarded: one per session; no id) | +| Entering a phase | `lifecycle_phase` | move the phase axis (`request` / `trust-checkpoint` / `reframe-research` / `decide` / `build` / `close`) | +| A developer hand-off | `lifecycle_turn_end_notification(summary=…)` | set `awaiting-developer`, surface the attention item, return immediately; the **next turn's first AR call auto-resumes** — never resume by hand | +| `worktree_start` | *(automatic promotion)* | the fleeting lifecycle becomes **persistent**, anchored in the contract | +| Resuming an existing task | `worktree_attach` | re-adopts the contract's lifecycle (contract-resolved) | +| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | the save gate — never dropped silently | +| Close | `lifecycle_end` (`completed`\|`abandoned`) | the terminal record | + +Rules: a tool call outside any lifecycle is **dropped, never misattributed**; `paused` is +system-owned. **A spawned role that never touches mutating AR tools simply never instantiates a +lifecycle — that is correct, not a violation.** A spawned role runs its **own** lifecycle when it +runs one; it never adopts its spawner's. The session↔leaf association is the catalog binding made +at spawn (the **qualified** leaf key `//`), not lifecycle adoption. + +## Shared Invariants (every role can count on these) + +- **Continuity lives in the `task_doc` + durable artifacts, never in transcripts** — which is why + short-lived workers and reviewers are safe, and why every seat writes its artifact of record. +- **Escalation ladder: worker → manager → orchestrator → developer.** No rung is skipped, ever. + Each role file states only its own rung. +- **Observability:** coordination seats are `task_doc` leaves with attached chats; the developer + can walk into any seat at any level. +- **Decision-needing questions land in the task doc's `openQuestions`** — the rendered decision + surface; `notes/` carries the analysis behind them. + +## The Three-Party Loop (one home — this section owns the loop doctrine) + +**OWNER → BUILDER → REVIEWER → owner, at every level that owns work.** The owner never +self-approves; the builder never lands; the reviewer never decides — verdicts are evidence. The +owner checks the verdict and either redispatches a builder or escalates. Role files reference this +section; they do not restate it. + +| Level | Owner (holds the deliverable, rules, lands) | Builder | Reviewer | +| --- | --- | --- | --- | +| Leaf | the leaf's owning seat (manager; orchestrator in tight/flat mode) | spawned worker (no-commit contract) | spawned reviewer, criteria catalog + liberty | +| Master | the manager | the leaf workers | the master-exit seam reviewer (verdict rides `master-handover-approval`) | +| Portfolio | the orchestrator | the STRATEGIST (spawn-first) | reviewer with the plan-review catalog | + +**Complexity-scored tiers (per leaf, at dispatch).** The owning seat scores three axes — blast +radius (doctrine/enforcement/public surface vs leaf-local) · novelty (new subsystem vs +pattern-following) · size (files × steps) — into three tiers: **direct** (no loop +machinery — the level's ordinary build channel implements: hands-on at session scale, the leaf's +worker under a manager; self-check + checks ladder only), **builder-verified** (builder +implements; owner verifies report-vs-artifact; no reviewer), **full loop** (builder + independent +reviewer rounds). The +strategist's blast-radius register is the scoring input when an orchestration task exists. A +leaf's loop mark (tier + scope: manager | orchestrator — the owning level runs the loop with ITS +agent set) is recorded on the leaf doc with a decision-log entry. **A master whose leaves all +score `direct` is a workflow-free manager** — no loop machinery; the knobs make every loop +optional per level, never mandatory ceremony. + +**Rounds and the HARD cap.** A round = implement → review. **Hard cap: 3 rounds per loop — and +ONLY full end-to-end rounds count against it.** Residuals of a passing round are landed and +**delta-verified by the SAME reviewer via a follow-up message** (it retains everything it already +verified, at a fraction of a fresh round's cost); **fix rounds resume the SAME builder**. A fresh +reviewer is spawned only for a full round or when new scope opens. Delta-verifies close rounds; +they do not open them. + +**The convergence rule (the real control; the cap is the backstop).** Every round must SHRINK the +open finding set. A round that does not shrink it escalates immediately, regardless of the count; +a monotonically converging loop may never hit the cap at all. At the cap, or on non-convergence, +the owner does not spin another round — it **escalates one seat up the ladder (worker → manager → +orchestrator → developer) with the full round history attached**; the escalation packet IS the +upper seat's visibility. + +**Quo-vadis (the written developer-escalation criterion).** A question is developer-worthy when it +is a **high-blast-radius truth** — answered wrong it means big rewrites later (architecture +direction, security posture, doctrine contradictions, irreversible data/branch operations, where +agent settings live). Quo-vadis questions escalate IMMEDIATELY, regardless of round count. +Presentation-grade choices (2px vs 3px) never do — the owner rules and logs. + +**Criteria catalogs (the reviewer as test bench).** Criteria are never made up on the spot: every +review runs its type's standing catalog from `criteria/` (code-seam · doctrine · +onboarding-memory · report-verification · plan-review) plus an exploratory mandate, under the +promotion ratchet (each catalog carries it). `roles/reviewer.md` binds them. + +**Per-level agent sets.** Each level runs its loop with its own harness/model/effort set — the +orchestrator-level set (the strongest models) and the manager-level set (cheaper, possibly +workflow-free) are configured per level in the `orchestration.loops` settings block (schema in +`docs/reference/settings-json.md`; stored in the global agentic settings file with repo-local +override, parsed by the kernel agentic-settings loader — L13, landed). The strategist's mandatory +pre-run is doctrine, not a knob — it is unconditional. + +## Knob Block & Capability Doctrine (no per-harness files) + +Role files are **model-interpreted markdown, never an executor**. Each carries a portable **knob +block** (harness / model / effort / tools) — the defaults the terminal host injects at spawn. +Resolution: **role-file defaults < settings.json orchestration block.** There are deliberately +**no per-harness role files** (developer decision 2026-07-05): harness-specific ABILITIES — +sub-agent fan-out and the like — are covered inside the portable files as capability-conditional +doctrine any coding agent can apply, and harness PREFERENCE is deployment configuration +(settings), not doctrine. Hard-coding a vendor would fork the doctrine per harness. For spawning +seats, `spawn_agent_session` is itself the harness-independent fan-out: a harness with no +sub-agent facility still dispatches seats through the framework (a chat, no leaf attachment +required) — the DBMS principle: one behavior, any engine. + +## settings.json Orchestration Block + +Machine/user overrides layer over the role-file defaults, in the **global agentic settings file** +(`/system/settings.json`), with `/system/settings.json` as the +repo-local override layer (leaf-key deep merge, arrays replace, unknown `orchestration.*` keys +fail loud — schema in `docs/reference/settings-json.md`, Agentic Settings). Precedence: role-file +defaults < global settings < repo-local settings. + +```jsonc +{ + "orchestration": { + "roles": { // role → knob override; validated: harness/model/effort · free-form: launchArgs/promptKeywords/sessionCommands + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { // per-LEVEL agent sets (leaf|master|portfolio), deep-merged over roles + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" }, // spawn_agent_session default when the seat passes none + "gateDelegation": { + "policy": "manager-decides-leaf-gates", + "requireReviewerVerdictAtSeams": true + } + } +} +``` + +**As-built (L13 + L16):** the whole block is parsed by the kernel agentic-settings loader +(`kernel/agentic_settings.py`) — typed models for `roles` / `rolesPerLevel` / `concurrency` / +`spawn` / `harnesses` / `loops`, +read PER-USE (an edit applies on the next use, no restart). `orchestration.gateDelegation` is +parsed and **enforced** (`controlplane/gate_policy.py` — all-human default, opt-in delegation, +human-pinned kinds `integration-approval` / `push-approval` / `cleanup-approval`, owner never +self-approves); it is the ONE boot-snapshot key — read from the global file at MCP boot, a change +needs a restart (an authority-file value is a one-cycle legacy fallback with a boot warning). +`requireReviewerVerdictAtSeams` **binds delegated seam decisions** (`master-handover-approval`) to +attached reviewer-verdict evidence; the named policy `manager-decides-leaf-gates` routes leaf gates +to the manager and the master-exit handover to the **orchestrator** (human review concentrates at +the super gate). `spawn_agent_session` resolves its knobs (260703-L16) as explicit args > +repo-local level override > global level override > repo-local role default > global role default +> detection-gated default — the dispatcher declares its `level` (leaf|master|portfolio, default +leaf) and the resolved level rides spawn provenance — and **applies** them at the harness +boundary: model/effort ride as `AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` env AND map onto the launch argv +per-harness via the effective registry (claude `--model`/`--effort`; a mapping-less harness stays +env-only; a session-vocabulary effort like claude's `ultracode` is delivered as a post-launch +`/effort` paste). Unknown effort values REFUSE at dispatch naming the harness's vocabulary — the +CLI would warn-and-silently-degrade. The free-form escape hatch (`launchArgs` verbatim argv, +`promptKeywords` riding the brief paste, `sessionCommands` pasted before the brief) is never +validated, only recorded in spawn provenance; `orchestration.harnesses` teaches the framework new +TUIs or pre-customizes builtin launches (manual: `docs/reference/harnesses.md`). +`orchestration.loops` (the three-party-loop knobs: per-level loop sets, round cap, reviewer +reuse, complexity thresholds) lives in the same block — meaning in +`docs/reference/settings-json.md`; no knob touches the master-exit seam gate. + +## Companion Files + +- `lenses.md` — the four job lenses for the scoping seats. +- `roles/…` — the six self-contained role lifecycles (the registry above). +- `templates/…` — turn-report · worker-brief · manager-brief (`ROLE BRIEF — manager`; the + orchestrator compiles a manager's session start from it) · master-handover-packet · + conversation-handover-packet · verdict · impact-analysis · onboarding-coherency · + deep-research-report · orchestration-task (the strategist's sprint plan). Spawning seats compile + briefs FROM these; sub-agents fan out and fill them, so analysis survives compaction. +- `criteria/…` — the reviewer criteria catalogs (code-seam · doctrine · onboarding-memory · + report-verification · plan-review), the review test bench the three-party loop binds; maintained + through the promotion ratchet, never made up on the spot. + +## The Super Integration Branch (orientation only — the doctrine lives with its owner) + +``` +main + └── super-integration (orchestrator-owned, off main) + ├── master-A branch (off super) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, C-11) + ├── master-B branch (off the moved super — sees A) + └── … final: super → main PR + memory carry-over + push +``` + +The full topology — dependency-ordered dispatch, the integration-duty procedure, the two +conflict-resolution modes, leaf moves — lives in **`roles/orchestrator.md`** and only there. + +## Credits + +This skill absorbs and supersedes `l-01-session-job-lifecycle` and `l-02-agent-orchestration` +(converged 2026-07-05: lifecycle and job are one entity — one lifecycle per agent type). The +orchestration vocabulary adopts the parked `260619_agentic-control-plane` spec — jobs as +model-interpreted markdown (D6), the knob block (D7), role + lens in one file (D10), the +ambient-singleton rule (D11), per-harness variants (D12), the judge rung, short-lived workers with +structured handoff, dev-talks-to-one-orchestrator (D15) — which in turn credits **Archon** and the +**agent-control-plane** project (D14); that credit carries forward. + +## Relationship To Other Instructions + +This skill extends — never replaces — the coordinator `AGENTS.md`, the `w-02-light-task-workflow` +task format, and the memory layer (`c-…` skills). Each `roles/.md` is self-contained for its +seat; read exactly the one the router selects. diff --git a/.github-vscode/skills/l-01-agent-lifecycles/criteria/code-seam.md b/.github-vscode/skills/l-01-agent-lifecycles/criteria/code-seam.md new file mode 100644 index 00000000..053feb1b --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/criteria/code-seam.md @@ -0,0 +1,85 @@ +# Criteria Catalog — Code-Seam Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review wires code seams: consumers, enforcement points, gates, addresses, tool contracts. +Binds at the master-exit and super-exit seams and in any loop review whose change set touches code +(see the binding table in `../roles/reviewer.md`). Criteria are never made up on the spot: the +standing list below is the regression floor, run every time; the exploratory mandate and the +promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### CS-1 — Production-wiring walk + +**Trace the real call path, never a hand-aligned harness.** A claim that a consumer or an +enforcement point exists must be walked through the PRODUCTION call path — the controller, the +tool registration, the store fold — not through a test that hand-assembles the pieces into +alignment. A test can pass while the production consumer is inert. + +- Catching evidence: 260703-L8 review 3 (AR3-1) — the integrate consumer was proven **inert**: the + policy was omitted at the controller and the gate was looked up on the wrong lifecycle, while a + hand-aligned test passed (L8 decision log, cycle-6 entry). + +### CS-2 — Fail-open hunt + +**What happens when the address/config is absent or mistyped?** For every identity, address, key, +or config the seam matches on: feed it nothing, feed it a near-miss, and confirm the seam fails +CLOSED (refuses) rather than open (silently proceeds unmatched). + +- Catching evidence: 260703-L8 review 4 (AR4-1) — the seam's `enclosure` address had to be pinned + as an exact-string contract and the enclosure-less raise made a refusal (L8 decision log, + cycle-7 entry). + +### CS-3 — Validate-then-mutate + +**Every raise/write validates before it mutates.** A call that records state (a gate raise, a +store append, a contract write) must perform its refusal checks before any durable effect; a +mutation that precedes validation leaves half-states behind on refusal. + +- Catching evidence: 260703-L8 cycle 6 — the `wait=false` raise was reworked to be + validate-then-mutate and seam-kind-restricted (L8 decision log, cycle-6 entry). + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### CS-4 — Reused-primitive affordance parity *(candidate — 1 catch)* + +**When a screen reuses a shared content primitive, verify every branch of the ORIGINAL's +affordances (banners, status chips, truncation notices, error states) still fires on the reuse +path.** A dropped affordance is a silent regression the reuse's own tests won't catch — they +assert the new screen's happy paths, not the primitive's full surface. + +- Catching evidence (single engagement): 260703-L17 review (L17R-2) — the notes reader's + `DualPane` reuse drops the "first 2 MiB" truncation banner on the markdown path (the banner + lives in `CodeSide`, which markdown never reaches); text and binary keep it. + +### CS-5 — Cross-repo side-effect safety *(candidate — seeded from a clean exemplar, 0 catches)* + +**Any step that writes to a repository OTHER than the one it operates in gets the full +validate-then-mutate treatment plus partial-failure and dirty-target analysis.** Check the order +of validation vs the foreign write, the state left behind when the write lands but the caller +fails afterward, behavior against a dirty target repo, and an exact format round-trip with the +foreign artifact's consumer. + +- Seeding evidence: 260703-L18 finding 7 (`_reconcile_missing_mapping` writing the official + memory repo's ledger mid-`worktree_start`) PASSED all four lenses under this analysis — the + clean exemplar that defined the class. A catch in a later engagement promotes. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS change set the catalog does not name yet. Every novel finding-class that survives +refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.github-vscode/skills/l-01-agent-lifecycles/criteria/doctrine.md b/.github-vscode/skills/l-01-agent-lifecycles/criteria/doctrine.md new file mode 100644 index 00000000..9b9ccae1 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/criteria/doctrine.md @@ -0,0 +1,58 @@ +# Criteria Catalog — Doctrine Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review is doctrine: skill files, role lifecycles, templates, instruction surfaces, docs +that agents obey. Binds whenever doctrine/skill files are in the change set (see the binding table +in `../roles/reviewer.md`). Criteria are never made up on the spot: the standing list below is the +regression floor, run every time; the exploratory mandate and the promotion ratchet keep the +catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### D-1 — Doctrine-vs-code anchoring + +**Every "X enforces Y" needs a code anchor.** A doctrine sentence claiming enforcement, refusal, +or automatic behavior must resolve to the code that does it (file + mechanism). Doctrine that +narrates enforcement which does not exist is a defect, not an aspiration. + +- Catching evidence: 260703-L8 review 1 (AR-5) — `requireReviewerVerdictAtSeams` was documented as + binding while the flag was **inert**; the finding forced the wiring (L8 decision log, AR-1 + entry: "closing AR-5's inert flag"). + +### D-2 — Cross-file contradiction sweep + +**Sweep sibling doctrine for statements the change set now contradicts.** A doctrine change is +reviewed against the whole doctrine surface (skills, role files, templates, docs, hooks, canvas +prose), not just the edited files — one file's new invariant is another file's stale sentence. + +- Catching evidence: 260703-L10 — the landed "chat is never a build route" invariant contradicted + surviving chat-build wording inside `c-09` / `w-02` (builder escalation 1, owner-sanctioned + sweep; L10 builder report). + +### D-3 — Stuck-state walk + +**Can an agent following the prose deadlock?** Walk the doctrine as the obeying agent: at every +wait, gate, and handover, ask who unblocks it and through which channel. Prose in which two seats +each wait on the other — or a seat waits on a channel nobody is told to serve — is a blocking +finding. + +- Catching evidence: 260703-L8 review 2 — the seam deadlock: the manager's blocking raise and the + orchestrator's decide path could not meet as written; the ruled `wait=false` + + packet-carried-gateId channel resolved it (L8 rounds 2/4b history). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS doctrine change the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.github-vscode/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md b/.github-vscode/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md new file mode 100644 index 00000000..e47783e3 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md @@ -0,0 +1,67 @@ +# Criteria Catalog — Onboarding/Memory Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run over the +memory side of a change set: sidecars, route overviews, route indexes, update histories. Binds at +the master-exit and super-exit seams (the onboarding-vs-code lens) and in loop reviews whose change +set carries onboarding (see the binding table in `../roles/reviewer.md`). Criteria are never made +up on the spot: the standing list below is the regression floor, run every time; the exploratory +mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### OM-1 — Staleness diff vs as-landed code + +**Diff every body claim about current behavior against the as-landed code.** A sidecar or overview +body that describes the present tense is checked against what the branch actually ships — deleted +things still described, renamed things under old names, duplicated rows. + +- Catching evidence, two separate engagements: 260703-L8 cycle 6 (owner follow-up pass) — route + overview bodies still described **deleted canvas models** (the panels overview's build-job/frame + tail) and carried **duplicated table rows** (the tools and controlplane overviews' Layout + tables), durably recorded in those overviews' own 2026-07-05T19:25 Update History entries; + 260703-L10 — the flowModels sidecar body was still the pre-convergence 8-model census and its + references row still said "8 models" (the sidecar's 2026-07-06T12:05 history entry + L10R-3). + +### OM-2 — History-only-update detection + +**"Refreshed" must mean a genuine body edit.** An onboarding file whose only change is a new +Update History line has NOT been refreshed — the body still asserts the old truth. Check that +every claimed refresh touched body sentences, not just the history list. + +- Catching evidence: 260703-L8 cycle 6 — the builder reported route overviews as refreshed when + they were **history-only**; the closeout body gate caught it (L8 decision log, cycle-6 entry: + "report-vs-artifact verification belongs in the reviewer criteria catalog"). + +## Candidate Criteria (seeded exploratory — one catching engagement; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### OM-3 — Newest-first with the checker's own semantics *(candidate — 1 catch)* + +**Update History sorts newest-first under the CHECKER's datetime parse, not lexicographically.** +The quality checker compares naive timestamps as-is and folds tz-aware stamps to UTC; a merge or +mechanical insert that sorts by string can pass the eye and fail the gate (or worse, pass the gate +in the wrong order). Verify ordering with the checker's semantics. + +- Catching evidence (single engagement): 260703-L11 — four onboarding history collisions from the + parallel wave had to be re-sorted **with the checker's own datetime semantics** (naive compare + as-is, tz-aware folds to UTC); the quality gates caught the owner's wrong sort key (L11 decision + log). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS memory delta the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate is the working example, and it is THIS catalog's own OM-2 mechanized: the gate catches + history-only "refreshes" at commit time, where prose requests did not. diff --git a/.github-vscode/skills/l-01-agent-lifecycles/criteria/plan-review.md b/.github-vscode/skills/l-01-agent-lifecycles/criteria/plan-review.md new file mode 100644 index 00000000..ef4d2d90 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/criteria/plan-review.md @@ -0,0 +1,69 @@ +# Criteria Catalog — Plan Review (the strategist loop) + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run against an +**orchestration task** (`../templates/orchestration-task.md`) — the strategist's sprint plan — +before the developer's drawing board. This is the portfolio loop's review type: owner = +orchestrator, builder = strategist, reviewer = this catalog. The reviewer holds the same read-only +analysis tools the strategist used (`cgc_*`, `grepai_*`, `read_ar_files`), so the plan's mechanical +claims are re-derivable, not just readable. Criteria are never made up on the spot: the standing +list below is the regression floor, run every time; the exploratory mandate and the promotion +ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### PR-1 — Refute uncited edges + +**An uncited dependency edge is refutable by default.** Every edge in the dependency graph must +carry evidence — a cgc/grepai query, a file, a decision-log entry, a design-section citation, or +(for new surfaces) a declaration cross-reference naming both leaf declarations. An edge with no +evidence is challenged as a finding; so is evidence that does not actually support the edge's +direction or kind. + +### PR-2 — Missed-shared-surface hunt (class-completeness on intersections) + +**Re-intersect the surface lists independently.** Take the plan's per-leaf touch surfaces (both +existing and declared-new), recompute the pairwise intersections, and hunt pairs the edge list +omits — including CONFLICT-risk at a shared parent route where two leaves declare additions +(wiring points, shared registries). A plan that lists surfaces but misses one of their +intersections has a hole exactly where collisions happen. + +### PR-3 — Blast-radius re-derivation + +**Re-derive at least the HIGH-blast-radius entries with the cgc tools** (`cgc_dependencies` / +`cgc_callers` / `cgc_callees`, capped depth) — and spot-check a sample of the low/medium entries. +A register entry whose derivation cannot be reproduced, or whose classification drops the doctrine +propagation / migration / user-visible unions, is a finding; the register parameterizes every +downstream loop tier, so an understated radius under-reviews a leaf. + +### PR-4 — Order-respects-edges + +**Check the sprint order/waves against the edge list, mechanically.** No ORDER edge may run +backwards across the proposed sequence; every CONFLICT edge must be resolved by serialization or a +recorded leaf move (from→to + rationale); parallel waves may contain only INDEPENDENT pairs, and +the wave plan must acknowledge the landing-reconciliation cost. + +### PR-5 — Honesty of the findings section + +**Verify the plan's failure claims both ways.** Every "unplannable as scoped" finding must be +genuine (the leaf can name neither existing surfaces nor the parent anchoring of its additions — +a merely not-yet-existing surface is NOT unplannable); and thin leaf scopes the plan silently +guessed around instead of flagging are themselves findings. Quo-vadis contradictions must be +flagged at the top of the coherence findings, not buried. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS plan could be wrong that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example; PR-4 is this catalog's mechanization candidate (a topological check over + a structured edge list). diff --git a/.github-vscode/skills/l-01-agent-lifecycles/criteria/report-verification.md b/.github-vscode/skills/l-01-agent-lifecycles/criteria/report-verification.md new file mode 100644 index 00000000..fb3bdda8 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/criteria/report-verification.md @@ -0,0 +1,95 @@ +# Criteria Catalog — Report Verification + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) — and the loop OWNER +verifying a builder round — MUST run over every report, claim, and summary in the change set: +builder reports, owner claims, handover packets. **Standing from day one** in every review type: +report-vs-artifact caught real defects in three separate engagements before this catalog existed. +Criteria are never made up on the spot: the standing list below is the regression floor, run every +time; the exploratory mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### RV-1 — Report-vs-artifact on EVERY claim + +**Open the artifact behind every claim.** A report sentence asserting "X was done / is green / +was refreshed" is verified against the artifact itself, not trusted — claim by claim, no sampling +of the load-bearing ones. + +- Catching evidence, three separate engagements (260703-L8): review 3 caught a **hand-aligned + test** behind a wiring claim; cycle 6's closeout gate caught **"refreshed" overviews that were + history-only**; review 4 caught the **OWNER's own canvas overclaim** (L8 decision log, cycle-7 + entry) — builder reports and owner claims fail the same way. + +### RV-2 — CLASS-completeness *(promoted to standing at 260703-L18 — 2 catches)* + +**Hunt the siblings of every found instance.** A finding or a fix names an instance of a CLASS +(a directive surface, a census count, a vocabulary token). Enumerate the class — every sibling +surface, not just the instances the report names — and check each one. + +- Catching evidence: (1) 260703-L10 round 1 — the reviewer's completeness sweep found **six of + ten first-action surfaces** still shipping the retired directive when the report claimed the + flip done (L10 decision log). (2) 260703-L18 review (L18R-3) — the fix for + advertised-but-unimplemented recovery choices named the `cli.py` `custom` residual but missed + the SIBLING `_load_memory_ledger` block still advertising an inert `reconciliation`; the + sibling hunt found it. + +### RV-4 — Decision-log completeness for scope-expanding disclosures *(promoted to standing at 260703-L18 — 2 catches)* + +**A scope-expanding owner supplement or load-bearing builder disclosure must be verifiable in +the task-doc decision log, not only the builder report.** Continuity lives in the task_doc + +durable artifacts, never in transcripts; a ruling or environment finding that exists only in a +report is one lost file away from unrecoverable. Cross-check every supplement and disclosure the +builder report carries against the decision log. + +- Catching evidence: (1) 260703-L17 review (L17R-1) — supplement 2 (the wait-loop-era remnant + sweep with per-hit verdicts and two named follow-ups) was recorded only in the builder report. + (2) 260703-L18 review (L18R-4) — the load-bearing editable-install/PYTHONPATH environment + finding + named follow-ups lived only in the builder report; the leaf's `decisions[]` was + empty. Both folded by the owner at closeout. + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### RV-3 — Partial-fix-creates-falsehoods *(candidate — 1 catch)* + +**Verify claims ABOUT the changed artifacts, not only the artifacts.** A partial fix can turn +previously-true sentences elsewhere false (docs describing the artifact, install guides quoting +it, counts referencing it). Sweep for statements about what changed and re-verify their truth +after the change. + +- Catching evidence (single engagement): 260703-L10 round 1 — the partial hook flip made **two + install-doc claims false** ("injects the same startup directive" no longer held); round 2 + restored byte-identity so the claims became true again (L10 decision log + builder report). + +### RV-5 — Worktree-shadowed regression pins *(candidate — 1 catch)* + +**A regression test must bite under the invocation the owner actually runs.** An editable +install pointing at another checkout can shadow the worktree's sources, making a mutation-tested +pin pass vacuously under the canonical invocation while failing only under a hand-set +`PYTHONPATH`. Verify sensitivity by mutating the target and running the CANONICAL invocation; +a pin that only bites under a nonstandard environment is not yet a pin. + +- Catching evidence (single engagement): 260703-L18 review (L18R-1) — the inbox + delivered/unconfirmed pin failed its mutation check only under `PYTHONPATH=src`; under the + canonical `pytest mcp/tests` the main-repo editable install shadowed the worktree and the + mutated code still passed. Remedy: the `sys.path` pin idiom the sibling suites carry. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS report could mislead that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests (RV-1 is itself the precedent: promoted on three catches). Promotion is proposed in the + verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.github-vscode/skills/l-01-agent-lifecycles/lenses.md b/.github-vscode/skills/l-01-agent-lifecycles/lenses.md new file mode 100644 index 00000000..0f277b06 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/lenses.md @@ -0,0 +1,45 @@ +# Lenses — How the Scoping Seats Read a Job + +Read by the **scoping seats** (orchestrator, designer); a dispatched role never picks a lens — its +brief already carries the flavor. The job type is a **lens**, picked during `reframe-research` and +re-pickable at any time. It is not a gate and it never changes the orchestrator phase axis +(`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three +things only: + +- **Opening move** — the first concrete thing `reframe-research` does for this kind of job. +- **Retrieval lean** — which `c-04-retrieval-strategy-router` strategy leads (others are still available). +- **Decide default** — where this job usually lands at `decide` (still a real decision, not automatic). + +| Job | Opening move (in `reframe-research`) | Retrieval lean (`c-04-retrieval-strategy-router`) | `decide` default | +| ---------- | ----------------------------------------------- | ---------------------------------- | --------------------------- | +| `bug` | reproduce the failure; prove the root cause | Relationship (cgc) + Intent | -> build | +| `feature` | clarify intent, scope, and explicit non-goals | design doctrine + Intent | -> build | +| `triage` | assess severity, blast radius, and ownership | breadth scan (Semantics first) | may exit (route or spawn) | +| `research` | state the question precisely | Semantics (grepai) + onboarding | research-only exit | + +## bug + +Lead with a reproduction and a proven root cause before proposing a fix — an unproven fix is a guess. +Lean on Relationship (callers/callees/impact via cgc) to bound the change, and Intent to confirm the +invariant the bug violates. Defaults to a build; the fix lands through `decide -> build -> close`. + +## feature + +Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the +design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the +contracts the feature must respect. Defaults to a build; size decides the minimal `w-02-light-task-workflow` artifact vs a master + +sub-task series at `decide`. + +## triage + +Lead by assessing severity, blast radius, and ownership — enough to route, not to fix. A breadth scan +(Semantics first) maps the surface fast. Triage frequently **exits research-only**: its product is a +recommendation, a routed owner, or a spawned build/bug job — not a code change. Only escalate to a +build when triage itself is the cheapest place to fix it. + +## research + +Lead by stating the question precisely. Semantics (grepai over onboarding) plus committed-state +onboarding usually answers it; reach for source only as bounded Intent confirmation. Research +**exits research-only** by design: it produces an answer, and may recommend a follow-up build job, but +performs none itself. diff --git a/.github-vscode/skills/l-01-agent-lifecycles/roles/designer.md b/.github-vscode/skills/l-01-agent-lifecycles/roles/designer.md new file mode 100644 index 00000000..c67cec40 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/roles/designer.md @@ -0,0 +1,91 @@ +# Lifecycle — Designer (the hat) + +> The design lifecycle the **orchestrator pulls inline** whenever design is needed — front of the +> pipeline or mid-flight. **A hat, not a seat**: it cannot sit in a coordination leaf because the +> task is what it exists to create — no leaf, no worktree, no branch, no spawn required. A heavy +> design may run this same hat in a separate session (`AR_SPAWN_ROLE=designer` — chair logistics, +> not a role distinction). +> +> Drawn as the **DESIGNER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Hat Is + +Task design is **its own job** (developer decision 2026-07-04). Before orchestration one implicit +do-it-all role did design, features, and fixes; the roles now diversify, and design routes +**through the orchestrator, which wears this hat** — at the front of the pipeline AND mid-flight +(most leaves of a live series are designed mid-flight). It is the `tasks/AGENTS.md` collaboration +doctrine (meta-questioning, reframe-before-execution, evidence-first) given a distinct, optimized +shape as a job. Nothing here assumes a master exists yet — producing one is the point. + +The designer shares the orchestrator's **bird's-eye toolkit** — route indexes, onboarding, the +`grepai_search` MCP tool, the code-graph (`cgc_*`) MCP tools, blast-radius analysis — but is **scoped +to one master**. Collisions with *other* — especially **future** — masters can slip past a +single-master view. That residual risk is **owned downstream, not here**: at portfolio streamlining the +**orchestrator doubles as the designer's adversarial reviewer** (planned-vs-planned and +planned-vs-past). The designer's duty is to *declare* the limit, not to close it. + +## Lens + +- **Opening move:** meta-question the ask. Surface the request, the deeper objective, and the + highest-leverage framing before any structure exists — do not jump from the developer's first + phrasing to a plan. +- **Retrieval lean:** evidence-first, within the master's scope. Route indexes and onboarding for the + map; `grepai_search` for semantics; `cgc_*` for relationships/impact; bounded `read_ar_files` for + intent confirmation. Sub-agents fan out and write durable reports. +- **Decide default:** a `w-02-light-task-workflow`-shaped master + leaf task_doc, handed into the + portfolio — **not** a build. The designer designs; it does not implement. + +## Duties + +1. **Reframe with `tasks/AGENTS.md`.** Distinguish surface request · deeper objective · highest-leverage + framing · assumptions · boundaries · invariants · truth gaps. Material scope/intent/sequencing + changes are **played back and wait for confirmation**; a pure clarification may be presented and + continued. +2. **Evidence-first, master-scoped.** Make the evidence model visible before or alongside the plan + (external · repo-internal · cross-repo · executable). Gather it through the + `c-04-retrieval-strategy-router` skill, not ad-hoc reads. +3. **Blast-radius WITHIN the master.** Routes touched · invariants at risk · regressions — bounded to + this master's scope. Cross-master and future-master reasoning is explicitly out of the designer's + reach. +4. **Author the task_doc.** Master + leaves (requirements · steps · code examples per distinct change, + the `w-02-light-task-workflow` shape), leaves scoped around routes/areas, via the `task_doc` MCP + tool. Include a **code example for every distinct change** when code is in scope. + Decision-needing questions land in the task doc's `openQuestions` — the rendered decision + surface; `notes/` carries the analysis behind them. +5. **Declare the designer limit.** Record on the doc that this is a **master-scoped bird's-eye**: + cross-master and future-master collisions can slip and are owned downstream at streamlining. Never + hide the limit. +6. **Ask, never fill silently.** Assumptions and truth gaps only the developer can resolve are asked as + a short, high-leverage list — never filled silently. + +## Artifact Obligations + +- The **task_doc** (master + leaves) is the durable artifact of the designer job. +- A **designer-limits note** on the doc — the declared master-scoped blind spot, for the orchestrator's + later adversarial pass. +- Evidence reports from fan-out sub-agents (durable), so the framing survives into streamlining. + +## Comms Protocol + +- **Primary channel:** the developer, directly, in the designer's attached chat — this seat is a + co-thinking loop, so the developer is the standing interlocutor here (unlike the deeper seats, which + relay through the ladder). +- **Handover:** the finished design **joins the portfolio**. At streamlining the orchestrator + adversarially reviews it; hand the task_doc + the designer-limits note over via the inbox + (`operator_inbox_post`) and, for a hosted orchestrator, stdin push. +- **Escalation:** the hat's "escalation" is simply the handover into the portfolio job — the + orchestrator that wears it is already the last resolver before the developer. + +## Knobs + +| Knob | Default | Notes | +| ------- | ------------------ | --------------------------------------------------------------------- | +| harness | (the wearer's) | the hat runs inside the orchestrator session, or a spawned design chair | +| model | high-reasoning | reframe + blast-radius reasoning wants a strong model | +| effort | high | design leverage justifies the thinking budget | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | bird's-eye toolkit | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · inbox | + +Settings.json `orchestration.roles.designer` overrides these, and `orchestration.rolesPerLevel..designer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.github-vscode/skills/l-01-agent-lifecycles/roles/manager.md b/.github-vscode/skills/l-01-agent-lifecycles/roles/manager.md new file mode 100644 index 00000000..0b42124a --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/roles/manager.md @@ -0,0 +1,168 @@ +# Lifecycle — Manager + +> One master, one seat, self-contained. The manager lifecycle drives exactly one master series: +> spawn a fresh worker per leaf, review turn reports, decide the delegated leaf gates, close out and +> integrate each leaf, hand the completed master to the orchestrator through the master-exit seam. +> Your **brief is your session start**. +> +> Drawn as the **MANAGER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**One per master task.** Spawned by the orchestrator with the master's context packet. It owns its own +coordination leaf + chat (**no worktree**) and drives exactly one master series: spawns/respawns a fresh +worker per leaf, reviews turn-report artifacts, decides **delegated** leaf gates, integrates leaves into +the master integration branch via the `c-11-memory-carryover-from-branch` skill, and hands the completed +master to the orchestrator through the master-exit adversarial seam. + +The manager owns the leaf lifecycle machinery **end-to-end**: `worktree_start` → (the worker +builds) → closeout preview/apply (deciding the delegated gates per the gate policy) → +`worktree_integrate` → finalize — task-doc statuses via the finalizer, **steps checked by this +seat by hand** (the tool does not reconcile checkboxes). The worker's terminal +state is checks-green + turn report; everything after that is this seat's. + +**Flat-run note:** in a flat series (no managers spawned) the **orchestrator wears this hat** — +same duties, same artifacts, one chair. + +A manager has **no bird's-eye view** — it sees one master, not the portfolio. That boundary shapes +everything below. + +## Lens + +- **Opening move:** read the master `task_doc` + its leaf docs; order the leaves (parallel where safe — + the C-11 reconcile absorbs a moved base). +- **Retrieval lean:** intent-confirmation on the master's own routes (paired `read_ar_files`); the + breadth/blast-radius reasoning belongs to the orchestrator, not here. +- **Decide default:** dispatch the next ready leaf; the master exits through the master-exit seam. + +## The Default-Behavior Rule (read this before anything else) + +The **default agent behavior stands**: **fulfill the task, fill small blanks.** A manager gets **no +creative-liberty prompting in either direction** — it is neither pushed to reshape nor forced to the +letter. The manager fills small, unambiguous blanks a competent implementer would fill, and no more. + +> **The spirit test does NOT apply to this seat.** It is orchestrator-only. A manager's changes can +> collide with what it cannot see, so a **plan delta beyond blank-filling escalates to the +> orchestrator** — the manager does not reshape plans. This is not a licence to be timid and it is not a +> licence to be creative; it is the ordinary "do the task well, ask when the task itself is in +> question" default, with the ask routed **up the ladder to the orchestrator**, never to the developer. + +## Duties + +### 1 — Seat & intake + +Take the master's own coordination leaf (`task_doc`, no enclosure); the chat is attached so the +developer can walk in any time. Read the master + leaf docs; order the leaves. + +### 2 — Leaf dispatch loop (per leaf) + +- **Score the leaf's loop tier at dispatch** (loop doctrine: `../SKILL.md`, The Three-Party Loop): + blast radius · novelty · size → **direct** (NO loop machinery: the leaf's worker implements as + usual — worker self-check + checks ladder + this seat's ordinary artifact review; this seat + still dispatches per leaf and never grows a build surface) | **builder-verified** (the worker + implements; this seat additionally verifies its report claim-by-claim against the artifacts; no + reviewer) | **full loop** (worker + independent reviewer rounds). When an orchestration task + exists, its **blast-radius register is the scoring input**. Record the mark (tier + scope: + manager | orchestrator — the owning level runs the loop with ITS agent set) on the leaf doc with + a decision-log entry. **A master whose leaves all score `direct` is a workflow-free manager** — + no loop machinery, just the dispatch-review-integrate spine below. +- On a full-loop leaf, run the loop with this level's controls: a round = implement → review; + **hard cap 3 full rounds** (delta-verifies by the SAME reviewer close rounds, they do not count; + fix rounds resume the SAME builder); **every round must shrink the finding set** — a + non-shrinking round escalates to the orchestrator immediately, with the full round history + attached, regardless of the count. +- `spawn_agent_session(worker)` — a **fresh session** on the leaf: the brief (compiled from + `../templates/worker-brief.md`) is pasted + submitted, with `env={"AR_SPAWN_ROLE": "worker"}` and + the **qualified** leaf key `//`; the worker edits inside the leaf + worktrees the brief names. +- **Monitor the worker** — a turn-report artifact is expected at **every** hand-off. Inactivity or a + missing artifact → a **rate-limited stdin nudge** (logged as an event, never spammy). Escalation + intake via the inbox. +- **Review artifact vs `task_doc`** — completion vs requirements/steps · checks green · + onboarding refreshed in the same pass (the manager's own leaf-level review; **this is not an + adversarial seam**). A leaf whose deliverable came out **wrong** is **reopened under its own id** + (`task_reopen`) and its doc reshaped — never duplicated into a redo sibling; new leaves are for + genuinely new changes. +- **Delegated leaf gates (plan · closeout)** — decide the leaf's delegated gates, **attributed** + (`decidedBy: `, `decidedVia: orchestration`), appended and dashboard-visible. The + **owning agent never self-approves; a distinct configured role may** — that configured role is the + manager. (Enforced as-built by the gate policy: `orchestration.gateDelegation` in settings, + `controlplane/gate_policy.py` — human-pinned kinds stay human, decisions attributed.) + Your own hand-off idiom, this seat only: durable gates + inbox posts — you never call the + developer-facing notification; your counterparty is the orchestrator. +- **Integrate leaf → master branch** via the `c-11-memory-carryover-from-branch` skill (ff-only / replay + per the `c-09-git-worktree-manager` skill). Know the human-pinned gate kinds by name: + `integration-approval`, `push-approval`, `cleanup-approval` — none is ever delegable. When a + durable `integration-approval` gate is raised on this step it awaits the **developer** (via the + dashboard GateResponder or your attached chat — you do not relay; if the wait blocks the loop, + escalate to the orchestrator). Absent a durable gate, the **series' standing approval** governs: + the developer's portfolio-gate approval of this series, recorded in the planner master's + decision log, covers dependency-ordered leaf integrations. Loop until the master's leaves are + done. + +### 3 — Master-exit seam + +When all leaves have landed on the master integration branch, spawn the **adversarial reviewer** +(master-exit) via `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "reviewer"}` and the reviewer +role file (`roles/reviewer.md`), passing the master branch ref, +master/leaf task docs, worker turn reports, decision logs, changed paths, resolved +`system/tools.md` evidence, and carry-over state. The verdict lands at +`notes/reports/-master-exit-verdict.md` and attaches to the handover gate as +`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"pass|pass-with-notes|block"}]` +— a verdict over completion vs task docs · `system/tools.md` quality · onboarding-vs-code. **Blocked? → the verdict decomposes into fix leaves** the manager dispatches (loop +back to the leaf loop). Verdicts are **evidence, not decisions**. The seam channel, exactly: +**raise without blocking** — `lifecycle_gate(kind="master-handover-approval", +enclosure="", evidence_refs=[], wait=false)` (raise-and-continue +is allowed precisely because the kind is a delegated seam kind; the `enclosure` MUST carry the +master's identity — it is the address integration enforcement matches the gate by, and the match +is exact-string: pass the EXACT master task name as the contracts carry it (`worktree_start`'s +`task_name`) — the raise refuses without an enclosure; the call +returns the **gateId**); then **carry that gateId in the handover +packet** (§4) — the packet is the orchestrator's trigger AND its address for the gate. Under an +all-human policy the raise blocks and the developer decides — do not pass wait=false. Identity +truth, as-built: the gate pins to your ambient lifecycle when you raise it; the deciding +orchestrator resolves the gate **by the packet-carried gate id** (gate ids are model-visible — +only LIFECYCLE ids stay server-side) and its own ambient identity becomes `decidedBy`; +owner-never-self-approves holds by construction. A handover carrying serious issues the +orchestrator cannot answer on its own escalates up the ladder (orchestrator → developer). + +### 4 — Handover to the orchestrator + +Post the **master-handover packet** (`../templates/master-handover-packet.md`) — inbox (durable) + stdin +push — integration branch ref · change-set summary · verdict ref · **handover gateId** · +carry-over state. The seat (chat + coordination leaf) **stays reachable** until the series +retires; your raised gate stays open until the orchestrator decides it (poll `gate_list` on your +own lifecycle if you need its state). + +## Artifact Obligations + +- The **master-handover packet** at master exit (the manager's primary durable artifact). +- Leaf-review notes (completion vs task_doc) — lightweight, on the master's coordination leaf. +- Delegated-gate decision records (attributed). + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down to workers, escalation + intake up from workers, handover up to the orchestrator; all durable + dashboard-visible. +- **Stdin push** — nudges and messages delivered into hosted worker sessions; poll is the fallback. +- **Escalation** — **up to the orchestrator, never straight to the developer.** A stumped manager, and + any plan delta beyond blank-filling, raises to the orchestrator. The manager resolves within its own + master's view first. A loop that hits the 3-round cap or stops converging escalates **with the + full round history attached**. **Quo-vadis test:** a question that is a **high-blast-radius + truth** — answered wrong it means big rewrites later, not a cosmetic choice — is flagged as + quo-vadis when raised, so the orchestrator relays it to the developer immediately instead of + absorbing it; presentation-grade choices are never escalated — decide and log. + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ---------------------------------------------------------------- | +| harness | claude | default preference only — settings picks the actual harness | +| model | mid-reasoning | leaf review + coordination; strong but below the orchestrator | +| effort | medium | one master's scope, not the portfolio | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | coordination + review + leaf lifecycle | `task_doc` · `read_ar_files` · gates · `spawn_agent_session` · worktree lifecycle (start · closeout · integrate · finalize) · C-11/`c-09` · inbox | + +Settings.json `orchestration.roles.manager` overrides these, and `orchestration.rolesPerLevel..manager` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.github-vscode/skills/l-01-agent-lifecycles/roles/orchestrator.md b/.github-vscode/skills/l-01-agent-lifecycles/roles/orchestrator.md new file mode 100644 index 00000000..90a5e06a --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/roles/orchestrator.md @@ -0,0 +1,377 @@ +# Lifecycle — Orchestrator + +> The developer-facing lifecycle: an **event loop over durable portfolio state**, not a +> request-to-close pipeline. Each turn routes the incoming event — a developer message, a worker +> report, a verdict, the orchestrator's own finding — into one of **three jobs** (Design · +> Portfolio · Orchestrate) under one roof, with solo work as the same jobs run with hats collapsed. + +## What This Seat Is + +The developer's single point of contact and the only seat with a standing developer relay +(managers/workers stay reachable via their attached chats). It owns the design conversation, the +portfolio bird's-eye, dependency-ordered dispatch, the super integration branch, the **spirit +test**, and the **integrity bulwark** against "fixed one thing, broke two others." + +Its real state is the **task tree** — masters, leaves, statuses, decision logs, `openQuestions`, +contracts — never the transcript. That is why sessions can die, compact, and resume without losing +the run. Its analysis substrate is the **memory system** (route indexes, onboarding, +`grepai_search`, `cgc_*`); **orchestrator quality ∝ memory-repo quality**. Its durable notes and +reports are the most important artifacts in the system: only this seat sees the whole picture. + +## The Event Loop + +**Opening move, every session — new or resumed** (resumption is the common case, not the +exception): + +1. **Trust checkpoint** (below), then `lifecycle_start` (the frame's fleeting lifecycle). +2. **Portfolio orientation:** read the portfolio state — what exists, what is in flight, what is + blocked on whom, what awaits the developer — and **say it back**. +3. **Route the event** by what exists and what is asked: + +| Condition | Job | +| --- | --- | +| No task doc exists for the ask (or a planning-status doc needs reshaping before work) | **D — Design** | +| Designed masters exist; coherence/conflicts/order in question, or "orchestrate these" | **P — Portfolio** | +| An approved task/series is ready for implementation | **O — Orchestrate** | +| The ask changes no code (a question, an investigation) | **research-only exit** — deliver the answer; chat is the right medium; no worktree, no task artifact | + +**Profile check (takeover).** Before heavy work in any job: if this session's harness/model/ +effort is wrong for the run (resolved: role file < settings), spawn the right chair — +`spawn_agent_session` with `AR_SPAWN_ROLE=orchestrator` + a conversation-handover packet +(`../templates/conversation-handover-packet.md`) — and hand over; the developer still talks to +ONE orchestrator at a time. + +Several jobs can be active across a day; the loop routes per event. The frame's phase axis stays +the observable `lifecycle_phase` vocabulary (`reframe-research` ≈ D, `decide` ≈ P, `build`/`close` +≈ O); the jobs are the decision structure. + +## The Invariant Ladder + +``` +task doc (approved) → branch (intent) → worktree (only where something is built) +``` + +- **Design and Portfolio never touch git.** Nothing is being built there. +- **Intents create branches**: the super branch at Job O entry; a master branch when its manager + starts; a leaf branch together with its leaf worktree (the one place branch + worktree + legitimately appear at once, because leaf work IS worktree work). +- **Worktrees exist per build/integration edge** and are reclaimed after. +- **Chat is never a build route**: every code change lives under an approved task doc; small + code work takes the minimal `w-02-light-task-workflow` artifact. Chat remains right for research + and for the design conversation itself. + +## Trust Checkpoint (shared opening detail) + +1. `context_packet(repo_id="", include_providers=true, include_drift=true, + include_freshness=true)`. +2. Report the packet facts before relying on memory or providers: repository/branch/dirty state; + memory + onboarding roots; provider state; drift status and actionable count; branch freshness + (`behind`/`diverged` → fast-forward the local official line first; + `ledgerMapsCodeHead=false` → carryover or the right memory branch first). +3. Drifted/missing/orphaned onboarding on committed, non-dirty source: **ask the developer** before + refreshing via `c-05-create-or-update-onboarding-files` — drift handling is approval-gated. + Drift tied to dirty source is active work-in-progress, not maintenance. +4. Providers stopped/degraded: run the matching provider/runtime operations, re-check, report; + `indexing` means healthy-but-busy (partial results). + +When this seat spawns a role it compiles the trust facts into the brief — a spawned role does not +repeat this checkpoint. + +## Hand-Off Protocol — Dry-Run → Notify-And-Stop → Report + +Every developer hand-off (design acceptance, portfolio plan, worktree intent, commit, push, +integration, cleanup/finalization, any dev-wait) is three actions, never one. Carve-out (ruled +2026-07-06): in an orchestrated run, leaf→master and master→super integrations ride the series' +**standing approval** — no per-edge developer hand-off; the developer hand-off concentrates at the +super PR/carry-over gate (see Super exit & landing tail). The table's integration row governs when +a hand-off DOES happen (solo runs; a raised durable gate): + +1. **Dry-run** the pending mutation and self-fix failures before reporting. +2. **Notify:** `lifecycle_turn_end_notification(summary=…)` as the **last tool call**. +3. **Report:** the complete packet as final prose, the decision handed over as the last line — + then STOP. The next turn's first AR call auto-resumes. + +| Junction | Parked durable gate `kind` | Hands off via | +| --- | --- | --- | +| design acceptance / plan gate | `plan-approval` | this lifecycle | +| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | +| commit / closeout | `closeout-approval` | `c-12-closeout` | +| push | `push-approval` | this lifecycle / `c-09` | +| integration | `integration-approval` | `c-09` / `c-12` | +| cleanup / finalization | `cleanup-approval` | `c-09` / `c-12` | +| any other dev-wait | `agent-question` | this lifecycle | + +`closeout-approval` **is** the commit hand-off. The block-and-wait `lifecycle_gate` + +`lifecycle_resume` pair remains the parked fallback for a durable, mutation-blocking approval +record; it renders a prompt over your prose, which is exactly why notify-and-stop is the path. + +## Job D — Design (pull the designer hat) + +**Entry:** an intent/problem with no task doc — or a planning-status doc that needs reshaping +before work starts. Fires at the front of the pipeline AND mid-flight; most leaves of a live +series are designed mid-flight. + +Run `roles/designer.md` **inline — the designer is a hat, not a seat**: it cannot sit in a +coordination leaf because the task is what it exists to create. No worktree, no branch, no spawn +required; a heavy design may run the same hat in a separate session (chair logistics, not a role +distinction — spawn with `AR_SPAWN_ROLE=designer`). + +- The co-think loop, evidence model, blast-radius-within-the-master, and designer-limits + declaration are the hat's own file. The orchestrator remains accountable for what the hat + produces: **bulwark-check the design against the portfolio and the past before acceptance** + (planned-vs-planned AND planned-vs-past — a designed change that collides with another master's + standing order is caught here or shipped broken). +- **Output:** master/leaf task docs (requirements · steps · code examples), `openQuestions` for + the developer (the rendered decision surface; `notes/` carries the analysis), the limits note. +- **Gate:** the developer accepts the design — or parks it. **No git surface.** + +## Job P — Portfolio (streamline + plan) + +**Entry:** designed masters exist and coherence/order is the question, or the developer says +"orchestrate these." + +- **Route-coherence scan** across the set (route indexes · onboarding · grepai · cgc); fan-out + sub-agents write durable reports (`../templates/impact-analysis.md`). +- **Integrity bulwark** — planned-vs-planned AND planned-vs-past, every time. +- **Reshape** — foundation-master extraction; leaf **moves** for planning-status leaves (real + moves, never tombstones), each with decision-log entries on both masters. **The sub-task list is + an ORDERED LIST with word-processor semantics:** numbers ARE positions; moving an item renumbers + the list; the list stays contiguous while the series is unlanded; every renumber map lands in + the decision log; numbers freeze when the series lands on main. +- **Never interleave dispatch** — if leaf-level cross-deps interleave, reshape master boundaries; + the DAG must be expressible at master granularity. +- **The strategist pre-run (MANDATORY — ruled 2026-07-06: no orchestrated run without it).** After + 1..N masters are designed and BEFORE implementation starts on any of them, dispatch the + **strategist** — `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "strategist"}` + (`roles/strategist.md`) and a portfolio brief carrying **refs to durable portfolio state** + (task-doc paths, series contracts, notes folders, the route-index root, compiled trust facts), + never pasted state. Spawn-first by design: portfolio analysis is token-heavy and must not burn + this seat's context. **Even a single master gets the pass.** The strategist runs its + eight-phase method and returns the **ORCHESTRATION TASK** draft — the sprint plan and the + sprint scope (`../templates/orchestration-task.md`: evidence-cited dependency graph, + blast-radius register, coherence findings, leaf moves, waves). This is the portfolio + three-party loop (owner = this seat · builder = strategist · reviewer with + `../criteria/plan-review.md`), followed by **drawing-board rounds with the developer** — this + seat relays, multi-round convergence is expected and normal, and quo-vadis items (e.g. two + masters heavily disagreeing) go straight to the developer. On acceptance **this seat adopts the + draft into durable task form** (the strategist is a reader, not a mutator) with a decision-log + entry. +- **Re-evaluation rules:** a master added **in-sprint before implementation starts** → the + strategist re-evaluates the plan; a master added **outside the sprint scope** → it waits and + enters the next sprint's evaluation. +- **Output: the planner master task + the adopted orchestration task** — the run's durable home: + subTasks = the coordination leaves (orchestrator seat first, one per manager); body = the DAG + + dispatch order + conflict decisions + (once Job O starts) the super branch name; decision log = + every spirit-test act and reshape; `openQuestions` = the standing decision surface; the + orchestration task = the sprint scope the run executes. Its durable form is a `kind:"master"` + task doc carrying a top-level `orchestrates` list naming the master tasks it commands — the + dashboard derives the orchestration > master > leaf hierarchy (and the rank insignia) from that + field, so setting it is part of adoption. +- **Gate:** the portfolio plan gate — one wholesale developer review of the reshaped portfolio + + the orchestration task (sprint scope + DAG + dispatch order). **No git surface** — not even the + super branch exists yet. + +## Job O — Orchestrate (execute the plan) + +**Entry:** an approved planner master — or a single approved master for a flat run. Either way, +**the adopted orchestration task must exist**: the strategist pre-run (Job P) is the +unconditional precondition for any orchestrated run — even one master. It is doctrine, not a +knob. + +**First act — the super-branch intent:** create the super integration branch off `main` so +masters can base off it. **A branch, not a worktree** — this seat has nothing to build at creation +time. (Interim: until a branch-without-worktree primitive lands, the manual git + contract edge is +acceptable and recorded in durable notes.) + +**Dispatch loop**, dependency-ordered — for each ready master (dependencies integrated into +super): `spawn_agent_session(manager)` with a brief compiled from +`../templates/manager-brief.md` (`env={"AR_SPAWN_ROLE": "manager"}`, the **qualified** leaf key +`//`; the brief carries the load-bearing base fact: master branches +off the **current super**, never off main); +monitor turn-report artifacts, nudges, escalation intake; apply the **spirit test** to escalated +deltas. A manager escalation may carry a **loop's full round history** (3-round cap hit, or a +round that failed to shrink the finding set — the convergence rule, `../SKILL.md` The Three-Party +Loop): this seat either re-runs the loop at ITS level (the orchestrator-level agent set — the +strongest models) or, when the blocker is a quo-vadis truth, takes it to the developer. In a +**flat run, wear the manager hat yourself** (see The Hat-Collapse Rule). + +**Failed-deliverable rule (reopen-and-reshape):** a leaf whose deliverable came out wrong is +**REOPENED under its own id** (`task_reopen`) and its doc reshaped to the intended form — the +decision log preserves the journey. New leaves are only for genuinely **new** changes discovered +(a fix leaf ≠ a redo leaf). Spawning a sibling per failed attempt hides what went down, breaks +task order, and splits the change-set. + +**Master exit:** consume the manager's handover packet +(`../templates/master-handover-packet.md`); check the master-exit verdict (evidence, never a +decision); then **decide the manager's gate by its packet-carried id** — the exact call: +`gate_decide(gate_id=, decision="approve", +deciding_role="orchestrator")`. The server resolves the gate across lifecycles by id (you never +handle a LIFECYCLE id; gate ids are the sanctioned hand-off), your ambient identity becomes the +attributed decider (owner-never-self-approves holds because the raiser was the manager), and the +policy may require the attached reviewer verdict (`requireReviewerVerdictAtSeams`). Integration +enforces it: `worktree_integrate` refuses while a `master-handover-approval` gate addressed to +this master (its `enclosure`) is undecided or policy-invalid. A blocking verdict decomposes into +fix leaves dispatched before integration; a +handover you cannot honestly decide escalates to the developer. + +**Integration duty (master → super) — the worktree moment.** Per completed master: + +1. Consume the handover packet: branch ref, change-set summary, checks, verdict, carry-over + state, risks, next dependencies. +2. Check the verdict (pass/accepted proceeds; block → fix leaves first). +3. Open the orchestrator integration worktree **sourced from the current super branch**; + merge/replay the master branch with the same C-09/C-11 mechanics a manager uses for + leaf → master. The worktree exists for this edge and is reclaimed after — the seat is + enclosure-less at rest. +4. Carry memory + map the ledger (C-11; duplicate memory single-sided; memory quality before the + memory edge lands). +5. Record the new super tips in durable notes; mark next masters ready. + +**The topology (single home — this section owns it):** + +``` +main + └── super-integration (orchestrator-owned, branch off main — created at Job O entry) + ├── master-A integration branch (off super @ t0) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, source = super, C-11) @ t1 + ├── master-B integration branch (off super @ t1 → sees A's results) + ├── integrate B → super @ t2 + └── … final: super → main PR (remote merge) + memory carry-over to main + push +``` + +Strict stack: super off main; master branches off the **current super** (never off main); leaf +branches off their master. **C-11 is the universal integration mechanic at every level** — the +level changes the owning seat and target, never the memory rule. The final super → main landing +follows `system/git-workflow.md`: PR to gated main, remote merge, memory carry-over so the ledger +maps the actual merge commit, then push — **push only after the developer approves**. + +**Conflict resolution — exactly two modes:** *Up-front (preferred):* an overlap found during +streamlining → extract shared logic into a foundation master implemented first (leaf moves + +decision-log entries + renumbered lists). *Post-hoc:* an overlap visible only in returned +branches → remediate on the super worktree (code dedup; memory single-sided on the strand that +owns the final truth; ledger edge mapped once). + +**Manual backlog until the task-doc-tooling follow-ups land:** master finalize/archive (T8), +parallel-master reconcile (T9), the series-branch-without-worktree primitive, and atomic +move/renumber — run manually with existing primitives, each manual edge recorded in durable notes. + +**Super exit & landing tail — the developer's SINGLE review point (ruled 2026-07-06, resolves +L8-Q9):** all leaf→master and master→super integrations are **orchestrator-delegated** — on the +happy path they proceed under the series' standing approval (the developer's portfolio-gate +approval, recorded in the planner master's decision log); a durable `integration-approval` gate, +when one is raised, still awaits the developer — the kind stays human-pinned as-built. The +developer reviews ONCE, at the **fully integrated super branch on the PR/carry-over gate**. When +the DAG drains, spawn the super-exit adversarial reviewer (`roles/reviewer.md`, spawned with +`env={"AR_SPAWN_ROLE": "reviewer"}`) over the whole super branch; attach its verdict as judge +evidence (`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"…"}]`). +The handover to the developer **MUST offer a REVIEWABLE ENVIRONMENT** — for agents-remember: the +dashboard running on the super branch — because the review is **visible-behavior-first** (a +broken visual pass fails the handover fast, before anyone reads a diff), code review second. The +handover carries **demo notes — "what changed visibly"**: per master, the user-visible behavior +to walk (panels, flows, outputs, how to reach them), so the developer drives the environment +without archaeology. Rejections decompose into fix leaves. On approval: PR + memory carry-over + +push (developer-gated), then finalization +(`lifecycle_finalize_task` per edge — statuses via the tool, steps checked by hand), then the **self-improvement close**: +proposals for future runs grounded in the run's own ledger ("did x/y/z; hit a/b/c; a and b solved +on the spot; c needs this change") — proposals only, never automated self-modification. +`lifecycle_end` records the terminal state. + +## The Hat-Collapse Rule (solo and flat runs) + +Solo work is **not a fourth route** — it is the same three jobs collapsed: + +- **Design** still happens (however briefly): the task doc exists before anything else. +- **Delegated gates collapse back to the developer when one chair owns both sides** — a gate you + raised from this session's lifecycle cannot be decided by it (owner-never-self-approves). +- **Portfolio** collapses but does not vanish: an ORCHESTRATED run — anything that dispatches + seats, even for a single master — still requires the strategist pre-run (even one master gets + the pass). Only session-scale hands-on work (nothing dispatched; not an orchestrated run) skips + the strategist; the owner's own bulwark check remains. +- **Orchestrate** runs with hats collapsed: in a **flat series** the orchestrator wears the + **manager hat** (`roles/manager.md` duties — dispatch, review, delegated gates, leaf closeout → + integrate → finalize — same duties, same artifacts, one chair). At **session scale** it builds + **hands-on** instead of spawning (when spawn economics don't pay): the build discipline is the + worker's (edit + same-pass `c-05` onboarding + `system/tools.md` checks green + freshness watch + / early `worktree_sync`), the closeout tail is the owner's (see `c-12-closeout`), and + the ladder holds identically: task doc → intent → worktree → build → close. +- Fan-out sub-agents may read/search and **write durable reports**; **every AR state mutation + stays in this seat's main loop** (see Sub-Agent Fan-Out below). + +## Sub-Agent Fan-Out (capability doctrine — any harness that has it) + +Not a vendor feature: whatever the harness calls its sub-agents, the doctrine is the same — and a +harness without the ability has two fallbacks: **analyses stay sequential in the main loop**, or +**spawn a ROLE seat through agents-remember itself** (`spawn_agent_session` with that role's +`AR_SPAWN_ROLE`, as a chat — no leaf attachment required). The framework spawn is for ROLE seats, +never for anonymous analyses: an env-less spawned chat has no role and no brief, so the router +would misroute it as an orchestrator. The framework's own spawn is the harness-independent +fan-out, which is why spawn-first seats (like the strategist) work from +ANY harness. Like a database management system, the framework encodes the behavior reliably +regardless of the engine underneath. + +- Dispatch each fan-out analysis (route-coherence scan, conflict/regression scan, per-design + adversarial pass) as a sub-agent whose task is to **write a templated durable report** + (`../templates/impact-analysis.md`, `../templates/onboarding-coherency.md`) and return a compact + summary. The report is the artifact of record; a sub-agent that is the sole holder of a finding + is a bug. +- **AR state mutations stay in this seat's main loop** — a sub-agent never calls `task_doc`, + gates, `spawn_agent_session`, or closeout. +- Fan-out is capped by settings.json `orchestration.concurrency.maxSubAgents`. +- Prefer continuing an existing sub-agent for a follow-up on the same analysis, so its durable + report accretes rather than fragmenting across files. + +## The Spirit Test — This Seat Only + +**Within the spirit** of what the developer accepted → act alone + a decision-log entry (leaf +moves and renumbers on planning-status masters, inserted fix leaves, reopened-and-reshaped leaves, +mid-series convergence — the integration branch is the safety net). **Against the spirit** → +raise it for a joint decision. Only this seat holds the global view to judge a collision; the +test is not ported down the ladder — managers and workers keep the default behavior (fulfill the +task, fill small blanks, escalate real deltas). + +## Artifact Obligations + +- **Durable notes + reports, current as you work** — they must survive compaction, termination, + clears. Decision-needing questions go into task-doc `openQuestions`; analysis into `notes/`. +- **Decision-log entries** for every spirit-test act-alone, every leaf move and renumber map + (both masters where applicable), every reopen, every conflict-mode choice, every integration + edge. +- **Sub-agent durable reports** (`../templates/impact-analysis.md`, + `../templates/onboarding-coherency.md`); sub-agents never call `task_doc`, gates, + `spawn_agent_session`, or closeout. +- **The adopted orchestration task** (the strategist drafts; this seat adopts — with the adoption + decision-log entry) before any orchestrated run. +- **The super-exit demo notes** ("what changed visibly", per master) + the reviewable environment + offer — the developer handover is visible-behavior-first. +- **The self-improvement report** at close. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down, escalation + intake up; durable + dashboard-visible. +- **Stdin push** — delivery into hosted sessions (echo-confirmed paste); poll is the non-hosted + fallback. +- **Escalation** — this seat is the last resolver before the developer: resolve within the + bird's-eye view first; what goes up is decided by the **quo-vadis test**, not by being stumped — + a **high-blast-radius truth** question (answered wrong it means big rewrites later: architecture + direction, security posture, doctrine contradictions, irreversible data/branch operations, where + agent settings live) goes to the developer IMMEDIATELY via task-doc `openQuestions`, regardless + of any loop's round count; presentation-grade choices (2px vs 3px) never go up — rule and log. + A loop that hits its 3-round cap or stops converging arrives here with its full round history; + re-run it at this level's agent set or take the quo-vadis part to the developer. Developer + rejections arrive here and decompose into fix leaves (or reopens — see the failed-deliverable + rule). + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | portfolio blast-radius judgment wants the strongest model | +| effort | high | the bird's-eye seat; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | full bird's-eye + orchestration | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · gates · `spawn_agent_session` · worktree/C-11 | + +Settings.json `orchestration.roles.orchestrator` overrides these, and `orchestration.rolesPerLevel..orchestrator` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.github-vscode/skills/l-01-agent-lifecycles/roles/reviewer.md b/.github-vscode/skills/l-01-agent-lifecycles/roles/reviewer.md new file mode 100644 index 00000000..a477ee87 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/roles/reviewer.md @@ -0,0 +1,177 @@ +# Lifecycle — Adversarial Reviewer + +> Short-lived and self-contained: review the accumulated change set at one seam, refute-or-confirm, +> write the verdict, end. Your **brief is your session start**. +> +> Drawn as the **REVIEWER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Short-lived, spawned at exactly two adversarial seams — and as any three-party loop's +reviewer seat (below)** (seams: developer decision 2026-07-03; loop reuse: ruling 2026-07-06): + +1. **Master-exit** — before a **manager** hands its completed master integration branch to the + **orchestrator**. +2. **Super-exit** — before the **orchestrator** hands the accumulated super integration branch to the + **developer**. + +Leaf-level review is the manager's own duty — **not** an adversarial seam. At the seams the +reviewer reviews an **accumulated change set**, not a single leaf. + +**The same role file is also every three-party loop's reviewer seat** (developer ruling +2026-07-06, L12-Q2: reuse, not a separate loop-checker): a **full-loop leaf** review and the +**portfolio plan review** (the strategist's orchestration task) dispatch this role with a +loop-scoped brief — same refute-or-confirm posture, same verdict template, the criteria catalog +picked by review type (below). Loop mechanics this seat must honor: **delta-verify reuse** — after +a round you reviewed passes with residuals, YOU are resumed via a follow-up message to +delta-verify the landed residuals (you retain everything you already verified; a fresh reviewer +is spawned only for a full round or new scope); **only full end-to-end rounds count against the +loop's 3-round cap** — your delta-verify closes a round, it does not open one. + +> **Verdicts are evidence, not decisions.** The reviewer never decides a gate. Its verdict attaches to +> the handover gate as **judge evidence**; the gate's decider decides — the **orchestrator** at +> master-exit (delegated `master-handover-approval`), the **developer** at super-exit — per the +> gate delegation policy (settings `orchestration.gateDelegation`, `controlplane/gate_policy.py`). +> The policy binds delegated seam decisions to verdict evidence when +> `requireReviewerVerdictAtSeams` is set. + +## Lens + +- **Opening move:** scope the review — the integration branch diff, the relevant task docs + (the master's, or the whole portfolio's at super-exit), and the seam's rubric. +- **Retrieval lean:** refute-or-confirm — findings must survive an attempt to refute them; the reviewer + argues *against* the change set, not for it. +- **Decide default:** produce a verdict artifact with an explicit pass/block recommendation — never a + decision, never prose-only. + +## Criteria Catalogs (the review test bench — bound here) + +**Criteria are never made up on the spot.** Every review runs its type's STANDING catalog from +`../criteria/` — the regression floor — plus an **exploratory mandate** (the brief sets N novel +lenses owed; default 2). Which catalogs bind: + +| Review type | Catalogs (`../criteria/`) | +| --- | --- | +| master-exit seam | `code-seam` · `onboarding-memory` · `report-verification` (+ `doctrine` when doctrine/skill/docs files are in the change set) | +| super-exit seam | `code-seam` · `doctrine` · `onboarding-memory` · `report-verification` (wholesale) | +| leaf full-loop review | `report-verification` + `code-seam` and/or `doctrine` per the change set + `onboarding-memory` when onboarding rides | +| plan review (orchestration task) | `plan-review` · `report-verification` | + +The verdict's per-criterion findings table pairs with the catalog: every standing criterion is +reported, even to say it found nothing. **Promotion ratchet duty:** every surviving novel +finding-class is proposed as a catalog amendment IN THE VERDICT and promoted on the loop owner's +acceptance — escaped bugs become permanent tests. (Each catalog carries the full ratchet: +candidate → standing at ≥2 catches; standing → spot-check after N dry engagements; mechanizable → +graduates into a gate.) + +## The Three Review Lenses + +Fan out sub-agents (each writing a durable report) across three lenses. The posture is always +**refute-or-confirm**: try to disprove the change set, keep only findings that survive that attempt, +and make every finding traceable to a durable evidence file. + +1. **Completion vs task docs** — every requirement/step addressed; deltas justified in decision logs. + (`../templates/impact-analysis.md` for the surface swept.) +2. **Code quality** — the resolved `system/tools.md` suite (lint · typecheck · tests · complexity) and + regressions **vs the past** (route indexes, cgc, grepai — the "fixed one, broke two" surface). +3. **Onboarding-vs-code** — changed files' sidecars updated in the same pass · drift clean · route + overviews current. This is the paired `read_ar_files` + `memory_quality_check` + `drift_check` + check. (`../templates/onboarding-coherency.md`.) + +## Seam-Specific Rubrics + +### MASTER-EXIT — Manager Before Orchestrator Handover + +The manager spawns this reviewer before handing the completed master integration branch to the +orchestrator. Review the **accumulated master change set**, not a final leaf in isolation. + +- **Scope packet:** master integration branch diff, master `task_doc`, leaf task docs, worker turn + reports, decision logs, the draft master-handover packet, resolved `system/tools.md`, changed source + paths, changed sidecars, governing route overviews, and the master branch's memory/carry-over state. +- **Completion vs task docs:** every master requirement, leaf, substep, and accepted blank-fill is + accounted for; skipped or reshaped work has a decision-log trail; no unfinished leaf work is hidden + inside the handover packet. +- **Code quality per tools.md:** the master branch has current quality evidence for the resolved suite + (lint, typecheck, tests, complexity where applicable), and the reviewer checks regressions **vs the + past** through route indexes, CGC, GrepAI, and changed behavior surfaces. +- **Onboarding-vs-code:** changed source files have same-pass sidecar updates or explicit no-impact + history, route overviews are current for the master side of the change, `drift_check` and + `memory_quality_check` evidence is recorded, and any memory/carry-over gap is named. +- **Blocking rule:** a block returns to the owning **manager** as decomposable fix leaves under that + master. Each fix leaf names scope, target files/docs, evidence, and done-when. A master-exit block + without fix leaves is invalid. + +### SUPER-EXIT — Orchestrator Before Developer Handover + +The orchestrator spawns this reviewer before handing the accumulated super integration branch to the +developer. Review **wholesale branch behavior**: the whole portfolio as integrated on super. + +- **Scope packet:** super integration branch diff against its base (main), portfolio task docs, master + task docs, master-handover packets, prior master-exit verdicts, orchestrator decision logs, resolved + `system/tools.md`, changed source paths, changed sidecars, governing route overviews, and final + carry-over/ledger evidence. +- **Completion vs portfolio intent:** the integrated super branch satisfies the accepted portfolio + objective and dependency order; master-level deltas are justified; cross-master conflicts, duplicate + implementations, or deferred follow-ups are surfaced rather than hidden in the final handover. +- **Code quality per tools.md:** the full super branch has current quality evidence for the resolved + suite, and the reviewer checks branch-wide behavior regressions **vs the past** and across integrated + masters, not just per-master local quality. +- **Onboarding-vs-code:** the accumulated memory layer matches the super branch: changed sidecars are + current, route overviews describe the resulting behavior, C-11 carry-over/ledger mapping is coherent, + and `drift_check` plus `memory_quality_check` evidence is recorded. +- **Blocking rule:** a block returns to the **orchestrator** as decomposable fix leaves. The + orchestrator may route a fix through an owning manager, a new master, or the super worktree, but the + verdict itself must name leaf-shaped work with evidence and done-when. A super-exit block without fix + leaves is invalid. + +## Duties + +1. **Scope** the review to the seam or loop (diff · task docs · rubric · the bound criteria + catalogs). +2. **Run the standing catalogs + the three lenses**, fanning out sub-agents that write durable + reports; adopt the refute-or-confirm posture — a finding that cannot survive an attempt to + refute it is not a finding. Owe the exploratory mandate on top of the catalog. +3. **Write the verdict artifact** (`../templates/verdict.md`, the matching seam variant): findings ranked, + an explicit **pass / block** recommendation, durable under the series `notes/reports/` directory — + including the per-criterion catalog results and any proposed catalog amendments (the promotion + ratchet). +4. **Attach the verdict as judge evidence** on the handover gate — the decider decides; the reviewer + does not. (A loop review's verdict goes to the loop owner the same way: evidence, never a + decision.) +5. **Decompose a blocking verdict into fix leaves** — concrete, **leaf-shaped** findings the owning + manager (master-exit) or orchestrator (super-exit) can dispatch. A block is **never prose-only**; if + it cannot be named as fix leaves, it is not yet a block. +6. **Serve delta-verifies when resumed:** confirm the landed residuals of a round you already + reviewed via the follow-up channel, appending the delta section to your own verdict artifact — + never a fresh full round in disguise. + +## Artifact Obligations + +- **The verdict artifact** (`../templates/verdict.md`) at the seam — the reviewer's primary durable output. +- **Sub-agent durable reports** (impact-analysis, onboarding-coherency) that back the verdict's findings + and survive the reviewer session's death. +- **Fix-leaf descriptors** when the verdict blocks — ready for the decider to turn into `task_doc` + leaves. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the seam's change-set context; post + the verdict reference to the seam's decider. +- **Stdin push** — not a driver here; the reviewer is short-lived and reports through its verdict. +- **Escalation** — the reviewer does not escalate; it **reports a verdict**. If the change set is + un-reviewable (missing diff, missing task docs), that itself is a **blocking finding** in the verdict, + routed to the decider — not an escalation up the ladder. + +## Knobs + +| Knob | Default | Notes | +| ------- | ---------------- | ------------------------------------------------------------ | +| harness | claude | default preference only — settings picks the actual harness | +| model | high-reasoning | adversarial review wants a strong, skeptical model | +| effort | high | the last line of defense before a handover; do not economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | review surface | `read_ar_files` · `memory_quality_check` · `drift_check` · `grepai_search` · `cgc_*` · `system/tools.md` checks · report templates · inbox | + +Settings.json `orchestration.roles.reviewer` overrides these, and `orchestration.rolesPerLevel..reviewer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.github-vscode/skills/l-01-agent-lifecycles/roles/strategist.md b/.github-vscode/skills/l-01-agent-lifecycles/roles/strategist.md new file mode 100644 index 00000000..377e4b70 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/roles/strategist.md @@ -0,0 +1,196 @@ +# Lifecycle — Strategist + +> The sprint planner, **spawn-first** and self-contained: read the whole in-flight portfolio, prove +> it coherent, resolve the dependency chains, establish blast radius, shuffle leaves for the best +> implementation order, and deliver the **orchestration task** — the sprint plan and the sprint +> scope. A strategist run is a **mandatory precondition for any orchestrated run**. Your **brief is +> your session start**. +> +> Drawn as the **STRATEGIST** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Spawn-first by design** (developer decision 2026-07-05). Strategist work is token-heavy — it +reasons over every master's state, task docs, notes, friction ledger, and gate history — so it runs +as its own process with its own harness/model/effort knobs, protecting the orchestrator's context. +The designer precedent explicitly does NOT apply: the designer stays an inline hat because design +is drawing-board-interactive with the developer; the strategist's essence is solitary heavy +analysis. Spawned by the orchestrator via `spawn_agent_session` with +`env={"AR_SPAWN_ROLE": "strategist"}`. + +The strategist is the sprint planner — a scrum master for agents (developer ruling 2026-07-06): +after 1..N new masters are designed, and **before implementation starts on any of them**, it +verifies the in-flight set is **coherent and contradiction-free**, resolves dependency chains, +establishes blast radius, and moves leaves across masters where that yields a better +implementation order. **Even a single master gets this pass** — impact must be understood, and its +leaves may still shuffle. Only once the orchestration task exists may an orchestrated run begin; +without it the portfolio operates blindly, waiting for issues to surface mid-implementation. + +In the three-party loop (see the loop doctrine in `../SKILL.md`) this seat is the **portfolio +level's builder**: owner = orchestrator, builder = strategist, reviewer = the adversarial reviewer +with the plan-review criteria catalog (`../criteria/plan-review.md`). + +**Reader, not mutator.** The strategist READS everything and MUTATES nothing: it drafts the +orchestration task as a durable **notes artifact**; the orchestrator (the portfolio owner) adopts +it into durable task form. The strategist never edits task docs, never raises gates, never touches +git. A seat that never touches mutating AR tools never instantiates a lifecycle — that is the +designed shape. + +## Lens + +- **Opening move:** read the brief fully — it carries **refs to durable portfolio state, never + pasted state** (task-doc paths, series contracts, notes folders, the route-index root, trust + facts the orchestrator compiled). Then run the method below, in order. +- **Retrieval lean:** the mechanical phases use real tools (`cgc_*`, `grepai_*`, the route map); + the judgment phases must **show their work as citations** the reviewer can refute — an uncited + dependency edge is refutable by default. +- **Decide default:** the orchestration task with shown work. A leaf whose scope is too thin to + plan — it can name neither existing surfaces nor the parent anchoring of its additions — becomes + an explicit **"unplannable as scoped"** finding, never a silent guess. + +## The Method — Eight Phases (the operating procedure) + +Run every phase; the artifact schema (`../templates/orchestration-task.md`) requires each phase's +output. Phases 3 and 5 are tool-verifiable; phases 4, 6, and 7 are model judgment **disciplined by +mandatory citations** and the artifact schema — the plan gets the same adversarial treatment as +everything else. + +1. **Inventory** — enumerate the in-flight masters + leaves from the JSON-primary task docs + (`tasks///*.json`): objective, requirements, steps, references, decisions, open + questions. Sources: the task-doc tree + series contracts (branch/integration state) + the notes + folders (designs, friction ledger, review reports). +2. **Touch-surface extraction — TWO-SIDED** (developer refinement 2026-07-06) — normalize each + leaf's declared scope into a surface list (routes, files, skills, schemas, tools, doctrine/docs, + user-visible panels). **Existing surfaces** must map against the AUTHORITATIVE route map + (`onboarding/**/overview.md` + the generated `overview.index.json` route indexes, read via + `read_ar_files`). **New surfaces** (greenfield — routes/files the leaf CREATES) are legitimate + and map by DECLARATION: the leaf must name the parent route/location they will live under and + their intended shape (the L9 `serving/notes.py` precedent: a new file, but its parent route + `serving/` exists and its wiring point `app.py` is nameable). **"Unplannable as scoped" fires + only when a leaf can name NEITHER existing surfaces NOR the parent anchoring of its + additions** — never merely because a surface doesn't exist yet. +3. **Structural dependency analysis (mechanical)** — pairwise over leaves: intersect surface + lists; for non-identical EXISTING surfaces, test coupling with the code-graph tools — + `cgc_dependencies` / `cgc_callers` / `cgc_callees` (does B's surface import/call what A + changes?), `grepai_search` / `grepai_trace` for semantic reach, `cgc_complexity` for hotspot + weighting. NEW surfaces cannot be graph-queried before they exist — their edges come from + **DECLARATION cross-reference** instead: leaf B naming a surface leaf A declares it will create + is a pure ORDER edge (evidence = both declarations), and two leaves declaring additions under + one parent route is a CONFLICT-risk edge at the parent (wiring points, shared registries). + Output: an **EDGE LIST with evidence per edge** — **ORDER** (B consumes what A introduces), + **CONFLICT** (both mutate one surface → serialize or move a leaf), **INDEPENDENT** + (parallel-wave candidates). +4. **Semantic/doctrine dependencies (judgment, cited)** — schema/meaning-vs-storage splits, + doctrine-then-sweep orders, visual ride-alongs. Every claimed edge carries a citation (file, + decision-log entry, or design section) — **an uncited edge is refutable by default**. +5. **Blast radius per leaf** — union of: transitive caller set of touched modules (`cgc_*`, capped + depth), doctrine propagation (skill sync targets, hooks, templates), schema/data migrations, + user-visible surfaces. Classified **low / medium / high** — and this register IS the input to + the owning seat's per-leaf loop-tier scoring (the manager's dispatch scoring in + `roles/manager.md`): the strategist's analysis directly parameterizes the loops. +6. **Coherence & contradiction check** — cross-master sweep: two masters moving one surface in + opposite directions, a leaf assuming state another leaf removes, duplicate work, vocabulary + drift. **Directional contradictions are quo-vadis → developer** (via the drawing board; see + Duties §5). +7. **Ordering** — topological sort over ORDER edges; CONFLICT edges resolved by serialization or + **leaf moves (recorded from→to with rationale)**; independent sets become **parallel waves** + (weigh the landing-reconciliation cost of a parallel wave as a scheduling consideration). +8. **The orchestration task** — fill `../templates/orchestration-task.md`; the template REQUIRES + the shown work: dependency graph with per-edge evidence, blast-radius register, coherence + findings, leaf moves + rationale, sprint order/waves, re-evaluation triggers. Then the + drawing-board rounds begin. + +**Input quality bounds output:** thin task-doc scopes degrade the plan, but the method converts +that degradation into explicit findings ("leaf X unplannable as scoped") instead of silent +guessing. + +## Duties + +### 1 — Brief intake + +Read the brief + every referenced durable artifact. The brief carries refs, never pasted state; the +trust facts are compiled by the orchestrator — do not re-run the trust checkpoint. If a referenced +artifact is missing or unreadable, that is a finding in the orchestration task, not a blocker to +improvise around. + +### 2 — Portfolio read + +Method phases 1–2: the inventory and the two-sided touch-surface extraction (existing surfaces +against the route map; new surfaces by declaration — parent route + intended shape). + +### 3 — Analysis + +Method phases 3–7: the evidence-cited edge list, the doctrine edges, the blast-radius register, the +coherence sweep, the ordering. Keep the evidence inventory (queries run, files read, citations per +edge) as you go — the artifact requires it. + +### 4 — The orchestration task + +Method phase 8. Write the draft to the path the brief names (convention: +`notes//orchestration-task.md` under the coordination tasks tree, or the series `notes/` +folder). It is a **draft for adoption**: the orchestrator adopts it into durable task form — you +mutate nothing yourself. + +### 5 — Drawing-board rounds + +The reviewer (plan-review catalog) passes judgment on the plan; the orchestrator relays the +verdict and the developer's drawing-board feedback back into this session. **Convergence over +rounds is expected and normal** — large, messy portfolios are explicitly NOT expected to be fixed +in one shot; the iteration is the feature. Each round must shrink the finding set (the convergence +rule); the loop's hard cap is 3 full rounds, and **the drawing board with the developer IS this +loop's escalation**. Quo-vadis items — high-blast-radius truths such as two masters heavily +disagreeing on direction — go **straight to the developer** at the drawing board (the orchestrator +carries them; you flag them, unmistakably, at the top of the coherence findings). + +### 6 — Adopted-plan handover + +When the developer accepts the plan, the orchestrator adopts it; your seat's work is done. **The +artifact write is unconditional; the inbox is the delivery channel when the brief wires it** — +otherwise your final playback message to the orchestrator carries the artifact ref. Then end. +The orchestration task remains the sprint's standing scope: a new master added **in-sprint before implementation starts** re-opens re-evaluation (you +may be respawned or resumed for the re-plan); a master added **outside the sprint scope** waits +and enters the next sprint's evaluation. + +## Artifact Obligations + +- **The orchestration-task draft** (`../templates/orchestration-task.md`) — the seat's primary + durable artifact; every section carries its shown work. +- **The evidence inventory inside the artifact** — every dependency edge, blast-radius entry, and + coherence finding cites its source (tool query, file, decision-log entry, or design section). +- **Unplannable-as-scoped findings** for leaves whose task docs are too thin to plan. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the portfolio brief context; + post the orchestration-task ref (and each round's revision ref) to the orchestrator; durable + + dashboard-visible. +- **Stdin push** — the orchestrator delivers round feedback into this hosted session; your replies + are inbox rows or artifact revisions — never an untracked side channel. +- **Escalation** — to the **orchestrator**, which relays; quo-vadis truths are flagged for the + developer's drawing board. You never edit task docs to reflect a ruling — the orchestrator does. + +## Tool Surface (positive statement — this is all of it) + +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `grepai_trace`, `cgc_dependencies`, + `cgc_callers`, `cgc_callees`, `cgc_complexity`, `cgc_symbol_search`, `context_packet`, + `drift_check`. +- **Native READS** of task docs, series contracts, notes, and route indexes; native WRITES only to + your own draft artifact under the notes path the brief names. +- **Inbox** for receiving context and posting artifact refs, when the brief wires it. + +Everything else — `task_doc`, `worktree_*`, `lifecycle_*`, `gate_*`, `spawn_agent_session`, +`memory_*`, git — is the owning seat's machinery, not yours. **Reader, not mutator.** + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | whole-portfolio dependency + blast-radius reasoning wants the strongest model | +| effort | high | the sprint plan parameterizes every downstream loop; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | read-only analysis surface | `read_ar_files` · `grepai_*` · `cgc_*` · `context_packet` · `drift_check` · notes-draft write · inbox | + +Settings.json `orchestration.roles.strategist` overrides these, and `orchestration.rolesPerLevel..strategist` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.github-vscode/skills/l-01-agent-lifecycles/roles/worker.md b/.github-vscode/skills/l-01-agent-lifecycles/roles/worker.md new file mode 100644 index 00000000..f5c369b4 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/roles/worker.md @@ -0,0 +1,136 @@ +# Lifecycle — Worker + +> One leaf, one session, one report. The worker lifecycle is **self-contained**: everything this +> seat does is on this page, and your **brief is your session start** — a workspace session-start +> notice is not addressed to you. + +## What This Seat Is + +**One per task leaf, short-lived, fresh session.** Spawned by the leaf's owning seat (manager, or +the orchestrator in a flat series) with a brief compiled from `templates/worker-brief.md`. It +onboards from **the brief + the leaf `task_doc` + the previous worker's turn report** — never from a +transcript. Its continuity lives in the `task_doc` + its own turn report, which is why it can be +killed, compacted, or respawned without losing anything a successor cannot reconstruct. + +The worker builds; it does not manage lifecycle machinery. **Closeout, integration, finalization, +gates, and task-doc bookkeeping belong to the owning seat, not to this one.** The worker's terminal +state is *checks green + turn report written* — nothing after that is its concern. + +## The Worker Loop + +``` +brief -> orient -> build (edit + onboarding same-pass) -> checks green -> turn report -> end + | + +-- blocked or plan delta beyond blank-filling -> escalate to the owning seat +``` + +### 1 — Intake + +Read the brief fully, then the leaf spec / `task_doc` it names. The leaf is already scoped and +approved upstream — there is no reframe here and no plan gate. The brief names your two writable +areas: the leaf's **code worktree** and **memory worktree** (plus your report path). You edit +nothing outside them. + +### 2 — Orient (paired reads before edits) + +- Read the files you will touch **paired with their onboarding** — via the `read_ar_files` MCP tool + (note: it serves the official baseline, not your worktree) and native reads inside the worktree + for current state. Native read is your edit precondition. +- Retrieval when the leaf needs it: `grepai_search` (semantics), `cgc_*` (relationships) — both + read-only, with whatever stack key the brief names. Keep the evidence tally your brief asks for + (calls made, files inspected, gaps remaining). + +### 3 — Build + +- Implement exactly the leaf plan; fill small, unambiguous blanks a competent implementer would + fill (see "Default Behavior" below). +- **Refresh the matching onboarding in the same editing pass** per + `c-05-create-or-update-onboarding-files`: a changed source file's sidecar **body** is updated now; + a new file's sidecar is created; route overviews that need a genuine body update get one, and a + no-impact route gets the literal history form `- — No route impact: `. + Regenerate generated route indexes with a **local `build_route_indexes(...)`** invocation from the + memory worktree. +- **Never `git commit`.** Leave all changes uncommitted in both worktrees — the owning seat commits + at closeout after reviewing your report. + +### 4 — Checks (green before you report) + +Run what the brief prescribes — typically the focused suite over your changed paths plus the full +`system/tools.md` wrapper from the code worktree root — and record the exact commands + outcomes for +the report. A red check you cannot fix inside the leaf's scope is an escalation, not a workaround. + +### 5 — The Turn Report (mandatory, your last act) + +Write `templates/turn-report.md` to the path the brief names (convention: +`notes/reports/-worker-report.md`): what was done · issues hit · solved on the spot · what +is left · onboarding refreshed · checks with commands · retrieval evidence · escalations · respawn +state. **A missing report gets nudged.** The report is the leaf's artifact of record and how a +respawned successor onboards — write it even when blocked (with the Escalations section filled), +then end your turn. + +## Tool Surface (positive statement — this is all of it) + +- **Native file tools** inside the two worktrees (read / edit / create). +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `cgc_*`, `context_packet`. +- **Shell** for the prescribed checks (use the interpreter paths the brief names — do not assume a + `python` shim exists). +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) for receiving context and raising + escalations, when the brief wires it. + +Everything else — `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, +`route_index_refresh` — is the owning seat's machinery, not yours. A worker that never touches +lifecycle machinery never instantiates a lifecycle; that is the designed shape, not a gap. + +## Fan-Out (capability doctrine — any harness that has it) + +When the harness offers sub-agents, use them for **read/search only**, scoped to the leaf (locate +call sites, sweep onboarding): each writes durable notes and returns a compact summary. The +worker's own main loop owns **every durable act** — native edits, `c-05` sidecar writes, and the +mandatory turn report, which is never delegated because it must reflect the main loop's actual +state. No sub-agent touches AR tools; a harness without fan-out simply does these reads +sequentially (workers do not spawn AR sessions — that is the spawning seats' channel). + +## Loop Position (when the leaf runs as a three-party loop) + +The owning seat scores each leaf into a tier at dispatch (loop doctrine: `../SKILL.md`, The +Three-Party Loop). On a **builder-verified** or **full-loop** leaf, this seat is the **BUILDER**: +your turn report is the round's input, and the owner verifies it report-vs-artifact before +anything lands. Two consequences for you: + +- **Fix rounds resume THIS session** — the same builder, with its context intact. Your round-2+ + report **appends** to your report file rather than rewriting it, so the loop history stays + legible. +- **Rounds are capped and must converge**, but the cap, the convergence call, and any escalation + are the OWNER's controls, not yours. You build and report honestly; if you disagree with a + reviewer finding you were handed, say so **with evidence in your report** — the owner rules, + you never argue a verdict into the code. + +## Default Behavior + +**Fulfill the task, fill small blanks.** No creative-liberty prompting in either direction. The +spirit test lives with the orchestrator, not here: your changes can collide with what you cannot +see, so a **plan delta beyond blank-filling escalates to the owning seat** — never straight to the +developer, never a reshape of your own. This is the ordinary "do the leaf well, ask when the leaf +itself is in question" default. + +## Comms + +- **Inbox** — receive dispatch/context; post escalations; agent-to-agent rows carry role metadata + and a `messageKind` (`turn-report`, `nudge`, `escalation`, …), durable + dashboard-visible. +- **Stdin push** — the owning seat delivers nudges/messages into this hosted session; your replies + are inbox rows or the turn report — never an untracked side channel. +- **Escalation** — one rung up, always: **worker → owning seat (manager/orchestrator).** + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ----- | +| harness | codex | default preference only — settings picks the actual harness | +| model | mid-reasoning | competent implementer on a scoped leaf | +| effort | medium | scales with leaf difficulty via settings | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | build surface | native edit · read-only AR retrieval · prescribed checks · inbox | + +Settings.json `orchestration.roles.worker` overrides these, and `orchestration.rolesPerLevel..worker` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md new file mode 100644 index 00000000..a751a6b1 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md @@ -0,0 +1,54 @@ +# Conversation-Handover-Packet Template + +**One schema, three uses** (design record, the COMMS model): **role takeover** (profile-fit — the orchestrator's +Profile check (takeover) — `roles/orchestrator.md`, The Event Loop — spawns the correct profile and hands over), **worker respawn** (a fresh worker continues a leaf), and +any **master-complete handover** that needs the receiver to onboard from **state, not the transcript**. +The receiver always onboards from this packet, never from a prior conversation. + +## Rules + +1. The receiver must be able to act from this packet **alone** — assume the transcript is gone. +2. Name the request, the decisions already made, the constraints, the links, and the open questions. +3. For a **takeover spawn**, state the profile mismatch that triggered it, so the successor knows why it + exists and does not repeat the wrong-profile work. + +## Shape + +```md +# Conversation Handover — + +| Field | Value | +| ------------- | ------------------------------------------------- | +| use | role-takeover | worker-respawn | master-handover | +| seat / role | designer | orchestrator | manager | worker | reviewer | +| from | | (developer) | +| to | | +| leaf / master | | +| written | | + +## Why This Handover +- role-takeover: profile mismatch — wanted , session was ; taking over on the right profile. +- worker-respawn: . +- master-handover: . + +## The Request (as agreed) +- + +## Decisions Already Made +- (decision-log ref …) + +## Constraints & Invariants +- + +## Links (onboard from these, not the transcript) +- task_doc: · integration branch: · prior turn report(s): +- durable notes / reports: + +## Open Questions For The Successor +- + +## Current State +- Position in the plan / DAG: +- Committed vs uncommitted: +- The one thing to know before the next action: +``` diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/deep-research-report.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/deep-research-report.md new file mode 100644 index 00000000..ee971166 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/deep-research-report.md @@ -0,0 +1,123 @@ +# Deep Research Report Template + +Use this template after the developer-agreed reframe and before the lifecycle's +`decide` step. The lifecycle owns when deeper research happens and which proof +categories are required; this template owns the report shape, evidence IDs, and +optional sections. + +For small research-only answers, use the compact shape. For ambiguous, +architectural, taxonomy-heavy, bug-root-cause, triage-routing, or build-spawning +work, use the full shape. + +## Report Rules + +1. Keep the report claim-first: findings state what is now believed to be true. +2. Treat evidence rows as proof records, not activity logs. +3. Every finding cites evidence IDs, and every evidence row names the claim it proves. +4. Mark inference separately when the report reasons across multiple evidence rows. +5. Keep limits visible: every evidence row should say what it does not prove. +6. End with the lifecycle decision: research-only exit or recommended follow-up build. + +## Full Shape + +```md +# Deep Research Report: + +## Frame + +- Surface request: +- Deeper objective: +- Agreed scope: +- Non-goals: +- Invariants: +- Truth gaps before research: + +## Short Answer + + + +## Findings + +- F-01: [E-01, E-03] +- F-02: [E-02] + +## Evidence Ledger + +| ID | Kind | Source / Query | Claim Proven | Limits | +|----|------|----------------|--------------|--------| +| E-01 | Semantics | query: "" | F-01 | Does not prove runtime behavior. | +| E-02 | Intent | onboarding: ``; source: `` | F-02 | Covers committed HEAD only. | +| E-03 | Relationship | cgc callees/deps: `` | F-01 | Does not prove hidden business intent. | + +## Proof Inventory + +- Onboarding docs read: +- Semantic queries performed: +- Code graph queries performed: +- Source files inspected: +- External references checked: +- Executable validations run: + +## Remaining Truth Gaps + +| Gap | Why It Matters | Blocks Build? | +|-----|----------------|---------------| +| | | yes/no | + +## Decision + +- Research-only exit: +- Spawn build? +- Suggested artifact shape if spawned (minimal `w-02` task vs master + series): +- Plan-gate status: +``` + +## Compact Shape + +```md +## Short Answer + + + +## Evidence + +- E-01 (): proves ; limits: . + +## Proof Inventory + +- Onboarding docs read: +- Semantic queries performed: +- Code graph queries performed: +- Source files inspected: + +## Remaining Truth Gaps + +- + +## Decision + + +``` + +## Evidence Kinds + +- `Semantics`: fuzzy routing through GrepAI or onboarding search. +- `Relationship`: CodeGraphContext callers, callees, dependencies, impact, or neighboring structure. +- `Intent`: paired onboarding plus bounded source confirmation for contracts, invariants, behavioral expectations, or branch-valid truths. +- `External`: domain documentation, standards, issues, PRs, release notes, or other non-repo references. +- `Executable`: reproduction steps, tests, scripts, command output, or generated validation artifacts. +- `Developer`: explicit clarification from the developer; verify against source before treating it as durable current-state knowledge. +- `Inference`: reasoning across evidence rows. Cite the input evidence IDs in `Source / Query` and state the remaining uncertainty. + +## Evidence Ledger Guidance + +The evidence ledger should be precise enough that another agent can tell why a +claim is supported without rerunning the entire investigation. Prefer concrete +paths, query strings, anchors, and command names over prose summaries. + +Use `Limits` to prevent overclaiming. Examples: + +- `Routes the feature area but does not prove current source behavior.` +- `Confirms the source contract at HEAD, not dirty work-in-progress.` +- `Shows the call path but not whether the path is user-facing.` +- `Explains the documented intent but needs executable validation before build.` diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/impact-analysis.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/impact-analysis.md new file mode 100644 index 00000000..a9c97ff4 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/impact-analysis.md @@ -0,0 +1,52 @@ +# Impact-Analysis Template + +A durable report a fan-out sub-agent writes for the **orchestrator** (portfolio phase) or the +**adversarial reviewer** (completion + code-quality lenses). It is the **integrity-bulwark** artifact: +planned-vs-planned **and** planned-vs-past blast radius. Sub-agents WRITE it; AR state mutations stay in +the spawning agent's main loop. + +## Rules + +1. Cover **two axes**: planned-vs-planned (does this change collide with another master/leaf, present or + future?) and planned-vs-past (does it regress something already landed — the "fixed one, broke two" + surface?). +2. Evidence-first: cite the route indexes, `cgc_*` queries, `grepai_search` queries, and + `read_ar_files` reads that back each finding. +3. State limits per finding — what the evidence does **not** prove. +4. This is a report, not a decision: it feeds the orchestrator's spirit test / reshape proposals or the + reviewer's verdict; it never decides. + +## Shape + +```md +# Impact Analysis — + +| Field | Value | +| --------- | -------------------------------------------- | +| for | orchestrator (portfolio) | reviewer () | +| author | | +| subject | | +| written | | + +## Surface Swept +- Routes / areas touched: +- Anchors: + +## Planned-vs-Planned (collisions with other masters/leaves — incl. FUTURE) +| Collision | With (master/leaf) | Kind (code | memory | sequencing) | Evidence | Limits | +| --------- | ------------------ | --------------------------------- | -------- | ------ | +- Recommended resolution: up-front foundation-master extraction | leaf move | sequential ordering | none needed + +## Planned-vs-Past (regression surface) +| Risk | Landed thing at risk | Evidence (cgc/grepai/route index) | Limits | +| ---- | -------------------- | --------------------------------- | ------ | + +## Evidence Inventory +- Route indexes read: +- cgc queries (callers/callees/deps/impact): +- grepai queries: +- read_ar_files reads (paired source+onboarding): + +## Bottom Line (for the spawning agent's main loop) +- — no mutation performed here. +``` diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/manager-brief.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/manager-brief.md new file mode 100644 index 00000000..10c37922 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/manager-brief.md @@ -0,0 +1,62 @@ +# Template — Manager Brief + +The dispatch packet the orchestrator compiles for a manager taking one master. Like the worker +brief, **this brief is the manager's entire session start** — it replaces the front half the +orchestrator already ran. Spawn with `env={"AR_SPAWN_ROLE": "manager"}` and the **qualified** leaf +key of the master's coordination leaf (`//`). + +--- + +```md +ROLE BRIEF — manager + +# MANAGER BRIEF — · + +You are the MANAGER for master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/manager.md`; this brief is your session start. Drive this +master's leaf loop to the master-exit seam, then hand over. + +## The master +- Task doc: `` (read it + every leaf doc first). +- Planner master: +- Leaves, in order: . +- Trust facts (compiled by the orchestrator — do not re-run the checkpoint): providers , drift , freshness . + +## The branch base (load-bearing) +- Your master integration branch: ``, based off the CURRENT super branch + `` @ `` — master branches base off super, never off main. +- Leaf worktrees base off your master branch (normal `worktree_start` per leaf). + +## Dispatch defaults +- Worker spawns: `templates/worker-brief.md`, `env={"AR_SPAWN_ROLE": "worker"}`, qualified leaf + keys; knob overrides: . +- Concurrency: . + +## The exit +- When all leaves have landed on your branch: spawn the master-exit reviewer + (`env={"AR_SPAWN_ROLE": "reviewer"}`, `roles/reviewer.md`) with the scope packet your role file + enumerates; then RAISE the gate without blocking — + `lifecycle_gate(kind="master-handover-approval", enclosure="", + evidence_refs=[], wait=false)` — the `enclosure` MUST carry the master's identity: + the EXACT master task name as the contracts carry it (the raise refuses without one) — + and post the master-handover packet **carrying the returned gateId**: the ORCHESTRATOR decides + the gate by that id. Under an all-human policy the raise blocks and the developer decides — do + not pass wait=false. +- Escalation: to the orchestrator, never the developer. Human-pinned kinds you may meet: + `integration-approval`, `push-approval`, `cleanup-approval`. + +## Reports +- Your handover packet: `../templates/master-handover-packet.md`. +- Leaf-review notes on your coordination leaf; decision-log entries for every delegated gate you + decide and every reopen. +``` + +--- + +**Compiler notes for the orchestrator.** + +- Fill every ``; an unresolved placeholder is not dispatchable. +- The super-tip commit you write here is the reconciliation anchor if a sibling master lands + first — state it explicitly. +- Deliver as an echo-confirmed paste; only count delivery on a post-boot echo. diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/master-handover-packet.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/master-handover-packet.md new file mode 100644 index 00000000..c8f5cb5c --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/master-handover-packet.md @@ -0,0 +1,49 @@ +# Master-Handover-Packet Template + +The artifact a **manager** posts to the **orchestrator** at master exit (`roles/manager.md`), after the +master-exit adversarial seam. Delivered via the inbox (durable) + stdin push. It is what the +orchestrator integrates a completed master into the super branch from. + +## Rules + +1. Post it only **after** the master-exit verdict exists — the verdict reference is a required slot. +2. Name the integration branch precisely; the orchestrator bases its C-11 integration on it. +3. The carry-over state must let the orchestrator's `c-11-memory-carryover-from-branch` integration run + without re-deriving what landed. +4. Post the packet as an `operator_inbox_post` row with `messageKind="master-handover"` and push + delivery enabled so the durable inbox row and stdin notification agree. + +## Shape + +```md +# Master Handover — · + +| Field | Value | +| ------------------ | -------------------------------------------- | +| master | | +| manager seat | | +| integration branch | | +| handover gateId | | +| base | | +| verdict | | +| verdict outcome | pass | pass-with-notes | +| written | | + +## Change-Set Summary +- +- Leaves landed: , … + +## Requirements / Steps Completion +- All master requirements addressed: yes | with justified deltas (decision-log refs: …) + +## Carry-Over State (for the orchestrator's master → super C-11) +- Memory rows parked / carried: +- Ledger maps every leaf commit: yes | +- Single-siding notes (if this master overlaps another strand): + +## Known Follow-Ups +- | none + +## Reachability +- Manager seat (chat + coordination leaf) stays reachable until the series retires. +``` diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md new file mode 100644 index 00000000..81c2466b --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md @@ -0,0 +1,48 @@ +# Onboarding-Coherency Template + +A durable report a fan-out sub-agent writes for the **adversarial reviewer's** third lens +(onboarding-vs-code) and for the **orchestrator's** memory-quality checks. It is the paired +`read_ar_files` + `memory_quality_check` + `drift_check` review made durable — the check that the +memory repo stayed in lockstep with the code, since **orchestrator quality ∝ memory-repo quality**. + +## Rules + +1. Every **changed** source file must have its sidecar body updated **in the same pass** — a refreshed + `lastVerifiedCommitHash` over stale content silently defeats the drift check and is a finding. +2. Every **new** source file must have a created sidecar (`check_missing_onboarding` clean). +3. Route/repository overviews must reflect the change set; a moved/added/deleted slice must be + reflected in the governing overview. +4. This is a report; the reviewer's verdict or the orchestrator's main loop acts on it. + +## Shape + +```md +# Onboarding Coherency — + +| Field | Value | +| --------- | --------------------------------------- | +| for | reviewer () | orchestrator | +| author | | +| scope | | +| written | | + +## Changed Files — Sidecar Refresh +| Source file | Sidecar updated same pass? | Body reflects change? | Finding | +| ----------- | -------------------------- | --------------------- | ------- | + +## New Files — Missing Onboarding +| New source file | Sidecar created? | check_missing_onboarding clean? | Finding | +| --------------- | ---------------- | ------------------------------- | ------- | + +## Drift & Quality +- drift_check: clean | actionable (list) +- memory_quality_check: pass | +- Ledger maps code HEAD: yes | + +## Overviews +- Route/repository overviews current for touched routes: yes | +- Moved/added/deleted slices reflected in governing overviews: yes | + +## Bottom Line +- Onboarding-vs-code coherent: yes | NO — +``` diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/orchestration-task.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/orchestration-task.md new file mode 100644 index 00000000..c3d4bb08 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/orchestration-task.md @@ -0,0 +1,89 @@ +# Orchestration-Task Template + +The artifact a **strategist** drafts for the **orchestrator** (`roles/strategist.md`) — the sprint +plan and the sprint scope. A strategist run producing this artifact is a **mandatory precondition +for any orchestrated run**; the orchestrator adopts the accepted draft into durable task form (the +strategist is a reader, not a mutator). It is written under the series/coordination `notes/` path +the brief names and revised across drawing-board rounds. + +## Rules + +1. **Shown work is required per section.** Every dependency edge carries evidence (a tool query, a + file, a decision-log entry, a design-section citation, or — for new surfaces — a **declaration + cross-reference**: the two leaf declarations that couple) — an uncited edge is refutable by + default. Every blast-radius entry names its derivation (caller-set / doctrine-propagation / + migration / user-visible). Every leaf move carries from→to + rationale. +2. **Surfaces are two-sided:** the surface lists distinguish **existing** surfaces (mapped against + the route map) from **new** surfaces (greenfield, mapped by declaration: parent route/location + + intended shape). New-surface edges come from declaration cross-reference — leaf B naming a + surface leaf A creates is a pure ORDER edge; two leaves declaring additions under one parent + route is a CONFLICT-risk edge at the parent. +3. **Coherence findings include the honest failures:** a leaf that can name neither existing + surfaces nor the parent anchoring of its additions is recorded as **"unplannable as scoped"** — + never silently guessed around (a merely not-yet-existing surface is NOT unplannable). Directional + cross-master contradictions are flagged quo-vadis at the top of that section. +4. This is a **draft for adoption**, not a mutation: the strategist never edits task docs; the + orchestrator (the portfolio owner) adopts the plan and records the adoption in the decision log. +5. The plan is reviewed adversarially (the plan-review criteria catalog, + `../criteria/plan-review.md`) before the developer's drawing board; revisions append round + sections rather than rewriting history. +6. Once adopted, this artifact is the sprint's standing scope: in-sprint additions before + implementation starts trigger re-evaluation; out-of-sprint additions wait for the next sprint. + +## Shape + +```md +# Orchestration Task — · + +| Field | Value | +| ---------------- | ------------------------------------------------ | +| strategist | | +| masters in scope | | +| status | draft | in-review | round- | adopted | +| round | (3-round cap; the drawing board is the escalation) | +| written | | + +## Sprint Scope +- IN: +- OUT: + +## Touch Surfaces (per leaf — two-sided) +| Leaf | Existing surfaces (route-map-mapped) | New surfaces (declared: parent route/location + intended shape) | +| ---- | ------------------------------------ | ---------------------------------------------------------------- | + +## Dependency Graph (every edge cited — an uncited edge is refutable by default) +| From (leaf/master) | To | Kind (ORDER | CONFLICT | INDEPENDENT) | Evidence (cgc/grepai query · file · decision-log · design § · declaration cross-reference) | +| ------------------ | -- | ------------------------------------ | ------------------------------------------------------------------------------------------ | + +## Blast-Radius Register (feeds the owning seat's loop-tier scoring) +| Leaf | Radius (low | medium | high) | Derivation (caller-set | doctrine-propagation | migration | user-visible) | Evidence | +| ---- | ---------------------------- | ------------------------------------------------------------------------- | -------- | + +## Leaf Moves +| Leaf | From (master) | To (master) | Rationale | +| ---- | ------------- | ----------- | --------- | + +## Coherence Findings +- ⟁ QUO-VADIS (developer decision required): | none +- +- Unplannable as scoped: | none + +## Sprint Order / Waves +1. (note the + landing-reconciliation cost of parallel waves as a scheduling consideration) +2. + +## Open Risks +- + +## Re-Evaluation Triggers +- In-sprint master added before implementation starts → re-plan (strategist re-evaluates). +- Master added outside the sprint scope → next sprint's evaluation. +- + +## Evidence Inventory +- cgc queries (dependencies/callers/callees/complexity): +- grepai queries (search/trace): +- read_ar_files reads (paired source+onboarding) / route indexes read: +- task docs, decision logs, and design sections cited: +``` diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/turn-report.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/turn-report.md new file mode 100644 index 00000000..b771ada4 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/turn-report.md @@ -0,0 +1,57 @@ +# Turn-Report Template + +The **mandatory** artifact a worker writes at **every** hand-off (`roles/worker.md`). It is how the +leaf's work survives the session's death and how a respawned successor onboards from **state, not the +transcript**. A missing turn report is nudged by the manager. + +## Rules + +1. Write it in the **main loop**, from your own work plus any sub-agent summaries — never delegate it to + a sub-agent (it is the leaf's single artifact of record). +2. State facts, not a narrative: what changed, what broke, what is proven green, what remains. +3. The **Respawn State** section must let a fresh successor continue **without reading any transcript**. +4. Keep it durable and in the series notes; reference it from the leaf `task_doc`. +5. Default path: `notes/reports/-worker-report.md`. The control-plane helper exposes this + convention so manager nudges and respawn onboarding can point at the same artifact. + +## Shape + +```md +# Turn Report — · + +| Field | Value | +| ------------ | --------------------------------------- | +| leaf | | +| master | | +| worker | | +| worktree | | +| status | in-progress | leaf-complete | blocked | +| checks | green | failing: | not-yet-run | +| written | | +| inbox | | + +## What Was Done +- (files: ``, …) + +## Issues Hit +- → resolved: | still open: + +## Solved On The Spot +- (a plan delta beyond blank-filling is NOT here — it was + escalated to the manager; see Escalations) + +## What Is Left +- [ ] + +## Onboarding Refreshed +- in this pass (c-05) + +## Escalations +- | none + +## Respawn State (onboard a successor from this — no transcript needed) +- Current position in the leaf plan: +- Files touched so far: +- The one thing a successor must know before editing: +- Uncommitted vs committed state: +``` diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/verdict.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/verdict.md new file mode 100644 index 00000000..3f292443 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/verdict.md @@ -0,0 +1,142 @@ +# Verdict Template (adversarial reviewer) + +The artifact an **adversarial reviewer** writes at a seam (`roles/reviewer.md`). It lands +under the series `notes/reports/` directory and attaches to the handover gate as **judge evidence**. +There are two variants: **master-exit** (before a manager hands over to the orchestrator) and +**super-exit** (before the orchestrator hands over to the developer) — plus a loop-review +adaptation of the master-exit shape (see Loop-Review Adaptation below). + +## Rules + +1. **A verdict is evidence, not a decision.** State an explicit pass/block **recommendation**; the gate's + decider decides. Never write the verdict as if it were the gate outcome. +2. **A block must decompose into fix leaves** — concrete, leaf-shaped findings the owning + manager/orchestrator can dispatch. A block that cannot be named as fix leaves is not yet a block. +3. **Refute-or-confirm:** every finding must survive an attempt to refute it. Rank findings and cite + the backing evidence file. +4. Cover all three lenses (completion · code quality · onboarding-vs-code) explicitly, even to say a + lens is clean. +5. Record the gate evidence reference exactly: `kind=reviewer-verdict`, `ref=`, and + `verdict=`. +6. **Report every bound catalog criterion** in the Criteria Catalog Results table (the catalogs the + binding table in `roles/reviewer.md` assigns this review type, `../criteria/`) — one row per + standing criterion even when it found nothing, candidate rows when run — and carry any proposed + catalog amendments (the promotion ratchet) in that section. + +## Master-Exit Variant + +```md +# Adversarial Verdict — master-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | master-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | orchestrator (delegated `master-handover-approval`; serious issues escalate → developer) | +| artifact path | notes/reports/-master-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Task Docs +- Master requirement/substep coverage: addressed | delta justified | MISSING +- Leaf task docs and worker reports reconcile with the master task_doc: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite: green | failing: +- regressions vs the past (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- master-side route overviews current: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Manager Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the master-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Super-Exit Variant + +```md +# Adversarial Verdict — super-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | super-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | developer (human review concentrates at the super gate) | +| artifact path | notes/reports/-super-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Portfolio Task Docs +- Portfolio objective and dependency order satisfied: yes | +- Master handover packets and prior master-exit verdicts reconciled: yes | +- Cross-master conflicts, duplicate implementations, and deferred follow-ups surfaced: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite for the accumulated super branch: green | failing: +- branch-wide regressions vs the past and across masters (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- route overviews describe the accumulated behavior: yes | +- C-11 carry-over and ledger mapping coherent for the final super branch: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Orchestrator Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the super-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Loop-Review Adaptation (leaf full-loop · plan review) + +A three-party-loop review (a full-loop leaf round, or the plan review over an orchestration task) +uses the **master-exit variant's shape minus the gate machinery**: drop the `gate evidence` header +row and the Judge-Evidence Note (a loop review attaches to no gate), set `decider` to the **loop +owner** (the leaf's owning seat, or the orchestrator for the plan review), scope to the round's +change set (or the orchestration-task draft), and keep everything else — recommendation, Criteria +Catalog Results (the loop's bound catalogs, e.g. `plan-review` + `report-verification` for a plan +review), ranked refute-tested findings, and fix decomposition. The verdict remains **evidence to +the loop owner, never a decision**; a delta-verify appends a dated delta section to this same +artifact rather than opening a new one. diff --git a/.github-vscode/skills/l-01-agent-lifecycles/templates/worker-brief.md b/.github-vscode/skills/l-01-agent-lifecycles/templates/worker-brief.md new file mode 100644 index 00000000..db8f44d0 --- /dev/null +++ b/.github-vscode/skills/l-01-agent-lifecycles/templates/worker-brief.md @@ -0,0 +1,72 @@ +# Template — Worker Brief + +The dispatch packet a spawning seat (manager / orchestrator) compiles for a worker. **The brief is +the worker's entire session start** — it replaces the front half the spawner already ran (trust +checkpoint, reframe, plan). Compile it fresh per leaf from this shape; the proven form below +absorbed a series of real dispatch frictions (route-index leaks, attestation format, provider-stack +keying, missing `python` shim), so deviate knowingly or not at all. + +Spawn with `env={"AR_SPAWN_ROLE": "worker"}` and the **qualified** leaf key +`//` so the session-start router and the dashboard leaf rail both engage. + +--- + +```md +ROLE BRIEF — worker + +# WORKER BRIEF — · + +You are a WORKER for leaf `` of master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/worker.md`; this brief is your session start. Execute the leaf +completely, write your turn report, then stop. + +## Worktrees (your ONLY writable areas) +- Code: `` (branch ``, base ``) +- Memory: `` +- Plus your turn report at the path below. Nothing else. NEVER `git commit` — the owning seat + closes out after reviewing your report. + +## Tool surface +- Native file tools inside the two worktrees; shell for the checks below. +- Read-only AR retrieval: `read_ar_files` (serves the OFFICIAL baseline, never your worktree — + final verification uses native reads), `grepai_search` / `cgc_*` (provider stack key: + ``), `context_packet`. +- No `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, or `route_index_refresh` — + generated route indexes are regenerated with a local `build_route_indexes(...)` from the memory + worktree. +- Interpreter: `` with `PYTHONPATH=/mcp/src` — there is no + `python` shim in this environment. + +## The task +Leaf spec: `` (read it first). + +## Checks (green before you report) +- Focused: . +- Full: — must exit 0. +- `git diff --check` in both worktrees. + +## Onboarding (same editing pass, per c-05) +- Changed source files: update the sidecar BODY now; new files: create the sidecar. +- Route overviews: genuine body update where routes changed; otherwise the newest history entry + uses the LITERAL form `- — No route impact: ` (timestamp first). +- Pin idiom for verification metadata: "Verification metadata pinned until closeout stamps the + commit." + +## Turn report (mandatory, last act) +Write `/-worker-report.md` following +`skills/l-01-agent-lifecycles/templates/turn-report.md` — including exact check commands + +outcomes, the retrieval-evidence tally, and the respawn state. If blocked: fill Escalations and +stop — escalate to , never to the developer. +``` + +--- + +**Compiler notes for the spawning seat.** + +- Fill every ``; a brief with an unresolved placeholder is not dispatchable. +- Verify the provider stack actually answers before naming it; write `NONE (native reads only)` + when it does not — a worker discovering dead providers mid-leaf wastes its turn. +- Deliver as an echo-confirmed paste; verify the harness's paste chip (`[Pasted Content N chars]`) + before submitting, and only count delivery on a post-boot echo. +- The report path lives under the series `notes/reports/` — the same folder the seam verdicts use. diff --git a/.github-vscode/skills/l-01-session-job-lifecycle/SKILL.md b/.github-vscode/skills/l-01-session-job-lifecycle/SKILL.md deleted file mode 100644 index 9b3cc6d6..00000000 --- a/.github-vscode/skills/l-01-session-job-lifecycle/SKILL.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -name: l-01-session-job-lifecycle -description: "The session job lifecycle the coordinator routes every session into: request -> context/trust checkpoint -> developer-agreed reframe -> deeper research -> decide build mode -> build -> close. Owns research-only exits, the build-mode decision (chat build vs durable w-02-light-task-workflow task), and the job lens (bug/feature/triage/research). Supersedes the retired chat workflow by migrating and modernizing its doctrine." ---- - -# l-01-session-job-lifecycle Session Job Lifecycle - -The `l-01-session-job-lifecycle` skill is the **canvas** the coordinator routes into at the start of every session. -It is not a task format. A task format is one outcome of a single step inside it. - -The lifecycle is one shared spine with thin per-job lenses. Its front half is a -developer/model collaboration loop: the developer states the request, the model -runs mandatory MCP grounding checks, the model presents an evidence-backed -reframe, and the developer agrees or revises that reframe before deeper research -or build-mode decisions proceed. - -## Companion Files - -1. `job-variants.md` — the four thin job lenses (bug / feature / triage / research). -2. `deep-research-report-template.md` — the reusable report and evidence-ledger shape for deeper research. - -``` -0 Request -> 1 Trust Checkpoint -> 2 Reframe + Research -> 3 Decide -> 4 Build -> 5 Close - | - +-- research-only (e.g. investigation, code questions...) -``` - -## Hand-off Protocol — Dry-run action => "Notify-and-stop" Action => "Report" Action - -Every developer hand-off / gate moment — reframe agreement, plan gate, worktree intent, commit -approval, push approval, integration, cleanup/finalization, regular turn-end — is **notify-and-continue**: -surface an attention item, present the result, and **end your turn**; the developer responds and your -**next** turn picks up automatically. It is **three actions, never one**: - -1. **Dry-run action.** Run applicable MCP tools in `dry-run` for the hand-off. If dry run succeeds, - proceed with the notify-and-stop action. If dry run fails, try to ammend the issue first before reporting failure. -2. **Notify-and-stop action.** Call `lifecycle_turn_end_notification(summary=…)`. It sets the new - **`awaiting-developer`** lifecycle state, surfaces a dashboard attention item, and **returns - immediately — no wait, no inbox.** This is the **last tool call of the turn** — the report prose - still follows it; do not STOP here. The developer responds on the - dashboard or in the leaf's attached chat, and the **first AR tool call of your next turn** - automatically resumes the lifecycle (`running`) and clears the attention item — you send **no** - explicit resume. -3. **Report action.** Deliver the complete hand-off report as plain assistant output - (the reframe, the plan, the intent packet, or the closeout relay with - preview facts, quality results, proposed commit messages, and - attestations), and make the decision you are handing to the developer the last - line of prose. **The report is the last thing in the turn — then STOP / end your turn.** - -Use the `dry-run` step to verify that the planned tool call (for example the closeout apply) will -succeed before you hand off, and self-fix any failure before reporting it. - -`lifecycle_turn_end_notification` returns immediately and does **not** render a prompt over your prose, -so the report you deliver after it is exactly what the developer sees — call the -notification, then deliver the report as your final prose, then stop. Keep the report turn free of any mutating or permission-triggering operation so -nothing obscures the report. - -Junction → Dry-run → notify (`lifecycle_turn_end_notification`) → Report. Every junction below now hands -off through that one notification; the named `kind` is the **parked** durable-gate label the fallback -would use (see "Parked fallback" below), kept so the dashboard can still classify each hand-off: - -| Junction | Parked durable gate `kind` | Skill that hands off | -| -------------------------------- | -------------------------- | ---------------------------------------------------------- | -| plan gate | `plan-approval` | `l-01-session-job-lifecycle` | -| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | -| commit / closeout | `closeout-approval` | `c-12-closeout` | -| push | `push-approval` | `l-01-session-job-lifecycle` / `c-09-git-worktree-manager` | -| integration | `integration-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| cleanup / lifecycle finalization | `cleanup-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| any other dev-wait | `agent-question` | `l-01-session-job-lifecycle` | - -`closeout-approval` **is** the commit hand-off — there is no separate -`commit-approval`. Closeout is the single commit-of-record for code, memory, and -ledger, so every commit (including a singular one) routes through the closeout -hand-off. `agent-question` is the non-exhaustive catch-all so any dev-wait that is -not a structured junction is still observable. - -### Parked fallback — block-and-wait `lifecycle_gate` - -The block-and-wait `lifecycle_gate(kind=…)` junction (which creates a durable gate and waits for a -developer decision), the operator inbox, and the dashboard GateResponder **still exist and still work** -when explicitly raised — but they are **no longer the active path**, and nothing routes toward them: -`next_step.py` repoints every gate moment to `lifecycle_turn_end_notification`. Reach for the -server-enforced `lifecycle_gate` (followed by `lifecycle_resume` after the developer decides) only when -you deliberately need a durable, developer-attributed, mutation-blocking approval record; its `kind` -values are the table above. If you ever do raise it, it renders an approval prompt **over** your prose, -so the report must land in an earlier turn — which is exactly why notify-and-stop is preferred. - -## Lifecycle Signals — Making The Session Observable - -Every session in a managed repo is a **lifecycle**: the six `lifecycle_*` signals -record where it is and what it is waiting on, so the work is observable and -resumable across chat deaths (design `docs/design/observable-lifecycle.md`). The -model **never handles a lifecycle id** — identity is server-side, anchored in the -worktree contract. - -| When (phase) | Signal | Why | -| ---------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Trust Checkpoint passes (managed repo) | `lifecycle_start` | Begin a **fleeting** lifecycle (guarded: one per session; takes no id). | -| Entering each phase | `lifecycle_phase` | Move the orthogonal phase axis (`request`/`trust-checkpoint`/`reframe-research`/`decide`/`build`/`close`). | -| At a hand-off (reframe, plan, commit, …) | `lifecycle_turn_end_notification(summary=…)` (last tool call), then the report prose, then **STOP** | Set `awaiting-developer`, surface the dashboard attention item, and return immediately (no wait, no inbox); the next turn's first AR tool call auto-resumes (`running`) and clears the item. Block-and-wait `lifecycle_gate(kind=, ask=…, packet=…)` + `lifecycle_resume` is the parked fallback. | -| `worktree_start` (Decide → Build) | _(promotion — automatic)_ | The fleeting lifecycle becomes **persistent**, anchored in the contract; no separate signal. | -| Resuming an existing task | `worktree_attach` | Re-adopts the contract's lifecycle (contract-resolved); the model passes no id. | -| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | The save gate: promote it or abandon it — never dropped silently. | -| Close | `lifecycle_end` (`completed`\|`abandoned`) | The terminal record. | - -Rules: `lifecycle_start` is guarded (one active lifecycle, no id). `paused` is -**system-owned** — there is no pause signal. `awaiting-developer` is set by -`lifecycle_turn_end_notification` and auto-cleared back to `running` by the next -turn's first AR tool call — you never resume it by hand. A tool call outside any -lifecycle is **dropped, never misattributed**. `worktree_start` **promotes** the current -lifecycle (fleeting → persistent); `worktree_attach` **resumes** the contract's -lifecycle; both keep identity server-side. - -## 0 — Request - -Receive the developer's raw request and identify the active repository. - -1. Treat the developer's statement as raw input, not yet as an implementation plan. -2. Infer the target code repository from the request and local context. Ask the - developer if the target is unclear. - -Request intake changes nothing. It only establishes which repository the next -checkpoint must inspect. - -The upcoming `Trust Checkpoint` reveals whether or not the request is related to repositories managed by Agents Remember. If not, then the lifecycle exits early and the agent can work as usual. - -However, if later work is to enter the boundary of repositories being managed by Agents Remember, -the lifecycle must be re-entered. - ---- - -## 1 — Trust Checkpoint - -Establish whether memory and providers are trustworthy enough to use. - -1. For the target repository, resolve coordination/memory context with - the MCP tool call: - - ```text - context_packet(repo_id="", include_providers=true, include_drift=true, include_freshness=true) - ``` - -2. Report the packet facts before relying on memory or providers: - - repository, branch, and dirty state - - memory root and onboarding root - - provider state - - drift status and actionable drift count - - branch freshness: whether the code and memory checkouts are current with - their upstreams (`behind`/`diverged` means the local official line is - stale — fast-forward it before trusting analysis or basing work on it) - and whether the ledger maps code HEAD (`ledgerMapsCodeHead=false` means - the memory checkout does not match the code state; run carryover or - check out the right memory branch first) -3. If onboarding for committed source is drifted, missing verification, or - orphaned, and the corresponding source file is not dirty in the code - worktree, stop and ask the developer whether or not to refresh it through - `c-05-create-or-update-onboarding-files`. Drift handling is approval-gated! -4. If drift is tied to dirty source, report it as active work-in-progress. Do - not adopt it as maintenance or silently trust it as current state unless the - developer explicitly says this job owns it. -5. If providers are stopped or degraded, use the matching MCP provider/runtime - operations, then re-run the provider check. If providers are ready, report - readiness and continue. If issues persist, report it to the developer and - wait for instructions. If the packet's providers summary lists `indexing` - targets, report them to the developer: those providers are healthy but - busy, and their results may be partial until the scan completes. -6. After the trust checkpoint passes, read committed-state onboarding for the - in-scope anchors as needed. A file dirty in another chat is still valid for - HEAD and worth comparing, but its dirty-source drift remains active work. - ---- - -## 2 — Reframe And Research - -Turn the developer's raw request into an agreed piece of work, then perform the -deeper research that the agreed frame requires. The `tasks/AGENTS.md` -collaboration doctrine applies here in plain chat, before any task file or task -format exists. - -**Read tool for this phase.** Until the build-mode decision (Phase 3), read managed-repo source -through the `read_ar_files` MCP tool, not the harness's native read — it returns paired -source+onboarding plus the repository/route overviews in one observable, lifecycle-attributed -call, and you keep a running count of those calls as evidence. Native read is the edit -precondition in Phase 4. - -1. **Gather evidence for the reframe** through reading the - `c-04-retrieval-strategy-router` skill. Pick the strategy by the question: - - _Semantics_ (grepai over onboarding) — "where does X live / what handles Y." - - _Relationship_ (cgc) — callers/callees/dependencies/impact. - - _Intent_ (onboarding + bounded source confirmation) — hidden contracts, invariants, - branch-valid truths, behavioral expectations. This is a workflow of paired - source+onboarding reads via the `read_ar_files` MCP tool: one call pairs each source - file with its verified onboarding and auto-attaches the repository overview + governing - route-overview chain (the bird's-eye view). -2. **Reframe** the request through `tasks/AGENTS.md`: distinguish the surface - request, deeper objective, highest-leverage framing, assumptions, boundaries, - invariants, and truth gaps. Do not rush a statement into a plan. -3. Present the reframe to the developer. If the developer disagrees, discuss and - revise the reframe. If the developer agrees, proceed to deeper research. -4. **Perform deeper research** for the agreed frame. This research still uses - `c-04-retrieval-strategy-router`, but it is now scoped by the developer-agreed - frame rather than by the model's first guess. Use - `deep-research-report-template.md` for the report shape; the lifecycle owns - the required proof categories, while the template owns evidence formatting. -5. The deeper research report must list its proof and tie evidence to the claim it supports: - - `read_ar_files` calls (paired source+onboarding reads — the running count) - - onboarding docs read - - semantic queries performed - - code graph queries performed - - source files inspected - - remaining truth gaps -6. Run the **job opening move** for the job lens (see `job-variants.md`) and use - the deeper research to name the truth gaps that remain. -7. Continue until the developer agrees the design is defined well enough to write - down, then produce the **plan**: the steps, and a **code example for every - distinct change** you intend to make. - -**Plan gate:** **hand off** before changing any code. No implementation begins -before the developer approves. Call -`lifecycle_turn_end_notification(summary={…the plan + the developer-facing approval ask…})` as the -**last tool call**, then present the plan as your final prose and **STOP**; -the developer approves on the dashboard or in chat and your next turn auto-resumes to begin -implementation. (Parked fallback: the server-enforced -`lifecycle_gate(kind="plan-approval", ask=…, packet=…)` + `lifecycle_resume` still exist if you -deliberately need a mutation-blocking approval record.) - ---- - -## 3 — Decide (build mode) - -One decision: does this job change code? - -- **No -> research-only exit.** Deliver the answer/assessment. No worktree, no task artifact, no closeout. - A research-only job may recommend or spawn a follow-up build job; it does not perform one itself. -- **Yes -> worktree intent hand-off, then always a worktree.** Read `c-09-git-worktree-manager` - and `system/git-workflow.md`, call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the worktree - intent packet as your final prose and **STOP**. The developer approves and your next turn - auto-resumes to `worktree_start`. Then open it with - `c-09-git-worktree-manager` and pick the build mode: - - **Chat build** — small enough to carry inline this session: worktree-backed, **no** `task.md`. - - **Durable task build** — hand off to `w-02-light-task-workflow`: `task.md`, checklist, decision - log, proposed code examples. Escalate to a master + light sub-task series when the work outgrows a - single-page plan. - -The worktree intent packet names the target repo, build mode, discovered branch policy, proposed -`source_branch`, proposed work branch/worktree name, memory mode, landing path, and material risks. -On PR-gated repos, the packet must prove that the recorded `source_branch` is pushable and that -protected targets are reached later through the repo's PR flow. - -Worktree granularity = the leaf task unit. A single task gets its own leaf enclosure/worktree. A -master multi-task owns a root `series-contract.md` and integration branch, while each active leaf -sub-task gets its own `enclosures//series-contract.md`, branch, and worktree. A chat build -gets its own leaf worktree without a task artifact. The git-landing decision (direct vs PR-gated) is -deferred to the repo's `system/git-workflow.md` — read it before landing on a gated branch. - ---- - -## 4 — Build - -Implement inside the worktree, keeping memory and tests in lockstep with the code. - -1. Apply the approved code changes. -2. **Refresh the matching onboarding in the same editing pass**, per completed plan-section — never - deferred to the end of the job. When a change affects durable current-state knowledge, the sidecar - is updated alongside it through `c-05-create-or-update-onboarding-files`. - - For **changed** (already-onboarded) source files, update the sidecar **body** now: the closeout - gate rejects a changed source file whose existing sidecar was not modified this job, because - refreshing `lastVerifiedCommitHash` over stale content silently defeats the drift check. - - For **new** source files, run `check_missing_onboarding` before the commit and create the - reported missing sidecars through the `c-05-create-or-update-onboarding-files` skill; the post-code-commit memory refresh stamps them with - the real code commit hash and date. -3. Run the checks from the `c-08-ar-coordination-context-resolver` resolved `system/tools.md` (lint, typecheck, complexity, tests) and - get them **green before each incremental commit**. Testing is never deferred to a final task; the - pre-commit/pre-push hooks enforce it. -4. **Watch the official line and sync early.** `worktree_status`'s `freshness` block reports when the - recorded base pair fell behind the local source branch tips (a parallel cycle landed). Pull the - moved official line in with `worktree_sync` — preferably **before memories are written**: with - parked memory the sync is a pure fast-forward, the other cycle's sidecars and ledger rows end up - beneath this task's future work, and end-of-series integration stays `ff-only` with no carryover - reconciliation. - -Incremental, pushable commits keep the work-loss window small. Each closeout below is one such commit. - ---- - -## 5 — Close - -Land the work. **Implementation approval is not commit approval.** - -1. Run the `c-09-git-worktree-manager` closeout **preview** for the worktree (`worktree_closeout_preview`). - Every build closes through its worktree — there is no direct-checkout closeout. - Relay the proposed code, memory, and ledger commit messages. -2. **Commit gate:** run the closeout **preview** (dry-run), then **hand off** before any real commit or closeout - apply. If required onboarding is missing, run the `c-05-create-or-update-onboarding-files` skill for the affected file and re-run the preview. - Call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the - **last tool call**, then deliver the preview facts as your final prose and **STOP**; - the developer approves on the dashboard or in chat and your next turn auto-resumes to - `worktree_closeout_apply`. The `c-12-closeout` skill owns this hand-off. Parked fallback: when you - deliberately raise the durable `closeout-approval` `lifecycle_gate`, it is enforced **server-side** — - `worktree_closeout_apply` refuses unless it is approved by the developer, and an agent self-approval - never satisfies it. -3. On approval, the `c-09-git-worktree-manager` skill owns the external-memory invariant in order: commit code → refresh affected - onboarding metadata to the new code commit → run memory quality control → commit memory content → - update and commit the ledger. -4. **Integrate + land** per `c-09-git-worktree-manager` and `system/git-workflow.md`: integrate the - worktree branch into the approved source/integration branch, then on a PR-gated repo push that - source branch, open the PR, wait for green checks, and merge per the repo convention. Never push a - protected branch directly. The agent does not push on its own authority — call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the push intent - as your final prose, and **STOP**; push only after the developer - approves and your next turn auto-resumes. The `c-09-git-worktree-manager` skill makes the matching - integration and cleanup/finalization hand-offs at its landing tail (parked durable kinds - `integration-approval` / `cleanup-approval`). -5. **Map the ledger to the landed commit.** A PR merge usually lands a **merge commit** on top of the - work — tree-identical to the verified tip but a new SHA the ledger does not yet map. Ensure the - ledger maps that merge commit so the next worktree can base off the merged branch without a manual - reconciliation. `system/git-workflow.md` owns this step. -6. **Finalize the lifecycle:** run `lifecycle_finalize_task(..., dry_run=true)` once the local parent - branch contains the landed commit and memory carryover is done. Call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then relay its landed-commit - proof, cleanup plan, and task-document updates as your final prose, and - **STOP**. The developer approves cleanup/finalization and your next turn auto-resumes to run the real - finalizer. The tool proves one parent-child branch edge, - reclaims the worktrees, and marks the leaf task plus immediate parent row `Completed` when those - task-doc paths are supplied. It does not recursively complete ancestors; repeat the edge at the next - parent level when that parent task lands. -7. **Keep squash out of the normal path.** A PR-gated edge is structurally the same as a direct edge - after the model finishes the PR merge and pulls the target branch locally. Do not use squash-merge - equivalence as a default finalization proof; squash is an emergency/manual recovery path because it - erases commit lineage and can make memory lookup history wrong. - -A research-only exit skips this phase entirely. - -## Relationship To Other Instructions - -This skill extends the coordinator `AGENTS.md` and the repository memory layer; it does not replace -them. Read `job-variants.md` for the per-job lenses, and `deep-research-report-template.md` for the -deeper research report shape. diff --git a/.github-vscode/skills/l-01-session-job-lifecycle/deep-research-report-template.md b/.github-vscode/skills/l-01-session-job-lifecycle/deep-research-report-template.md deleted file mode 100644 index 6e9d13d0..00000000 --- a/.github-vscode/skills/l-01-session-job-lifecycle/deep-research-report-template.md +++ /dev/null @@ -1,123 +0,0 @@ -# Deep Research Report Template - -Use this template after the developer-agreed reframe and before the lifecycle's -`decide` step. The lifecycle owns when deeper research happens and which proof -categories are required; this template owns the report shape, evidence IDs, and -optional sections. - -For small research-only answers, use the compact shape. For ambiguous, -architectural, taxonomy-heavy, bug-root-cause, triage-routing, or build-spawning -work, use the full shape. - -## Report Rules - -1. Keep the report claim-first: findings state what is now believed to be true. -2. Treat evidence rows as proof records, not activity logs. -3. Every finding cites evidence IDs, and every evidence row names the claim it proves. -4. Mark inference separately when the report reasons across multiple evidence rows. -5. Keep limits visible: every evidence row should say what it does not prove. -6. End with the lifecycle decision: research-only exit or recommended follow-up build. - -## Full Shape - -```md -# Deep Research Report: - -## Frame - -- Surface request: -- Deeper objective: -- Agreed scope: -- Non-goals: -- Invariants: -- Truth gaps before research: - -## Short Answer - - - -## Findings - -- F-01: [E-01, E-03] -- F-02: [E-02] - -## Evidence Ledger - -| ID | Kind | Source / Query | Claim Proven | Limits | -|----|------|----------------|--------------|--------| -| E-01 | Semantics | query: "" | F-01 | Does not prove runtime behavior. | -| E-02 | Intent | onboarding: ``; source: `` | F-02 | Covers committed HEAD only. | -| E-03 | Relationship | cgc callees/deps: `` | F-01 | Does not prove hidden business intent. | - -## Proof Inventory - -- Onboarding docs read: -- Semantic queries performed: -- Code graph queries performed: -- Source files inspected: -- External references checked: -- Executable validations run: - -## Remaining Truth Gaps - -| Gap | Why It Matters | Blocks Build? | -|-----|----------------|---------------| -| | | yes/no | - -## Decision - -- Research-only exit: -- Spawn build? -- Suggested build mode if spawned: -- Plan-gate status: -``` - -## Compact Shape - -```md -## Short Answer - - - -## Evidence - -- E-01 (): proves ; limits: . - -## Proof Inventory - -- Onboarding docs read: -- Semantic queries performed: -- Code graph queries performed: -- Source files inspected: - -## Remaining Truth Gaps - -- - -## Decision - - -``` - -## Evidence Kinds - -- `Semantics`: fuzzy routing through GrepAI or onboarding search. -- `Relationship`: CodeGraphContext callers, callees, dependencies, impact, or neighboring structure. -- `Intent`: paired onboarding plus bounded source confirmation for contracts, invariants, behavioral expectations, or branch-valid truths. -- `External`: domain documentation, standards, issues, PRs, release notes, or other non-repo references. -- `Executable`: reproduction steps, tests, scripts, command output, or generated validation artifacts. -- `Developer`: explicit clarification from the developer; verify against source before treating it as durable current-state knowledge. -- `Inference`: reasoning across evidence rows. Cite the input evidence IDs in `Source / Query` and state the remaining uncertainty. - -## Evidence Ledger Guidance - -The evidence ledger should be precise enough that another agent can tell why a -claim is supported without rerunning the entire investigation. Prefer concrete -paths, query strings, anchors, and command names over prose summaries. - -Use `Limits` to prevent overclaiming. Examples: - -- `Routes the feature area but does not prove current source behavior.` -- `Confirms the source contract at HEAD, not dirty work-in-progress.` -- `Shows the call path but not whether the path is user-facing.` -- `Explains the documented intent but needs executable validation before build.` diff --git a/.github-vscode/skills/l-01-session-job-lifecycle/job-variants.md b/.github-vscode/skills/l-01-session-job-lifecycle/job-variants.md deleted file mode 100644 index 48f032c6..00000000 --- a/.github-vscode/skills/l-01-session-job-lifecycle/job-variants.md +++ /dev/null @@ -1,43 +0,0 @@ -# l-01-session-job-lifecycle Job Variants — The Lenses - -The job type is a **lens**, picked during `reframe-research` and re-pickable at any time. It is not a gate and it -never changes the spine (`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three -things only: - -- **Opening move** — the first concrete thing `reframe-research` does for this kind of job. -- **Retrieval lean** — which `c-04-retrieval-strategy-router` strategy leads (others are still available). -- **Decide default** — where this job usually lands at `decide` (still a real decision, not automatic). - -| Job | Opening move (in `reframe-research`) | Retrieval lean (`c-04-retrieval-strategy-router`) | `decide` default | -| ---------- | ----------------------------------------------- | ---------------------------------- | --------------------------- | -| `bug` | reproduce the failure; prove the root cause | Relationship (cgc) + Intent | -> build | -| `feature` | clarify intent, scope, and explicit non-goals | design doctrine + Intent | -> build | -| `triage` | assess severity, blast radius, and ownership | breadth scan (Semantics first) | may exit (route or spawn) | -| `research` | state the question precisely | Semantics (grepai) + onboarding | research-only exit | - -## bug - -Lead with a reproduction and a proven root cause before proposing a fix — an unproven fix is a guess. -Lean on Relationship (callers/callees/impact via cgc) to bound the change, and Intent to confirm the -invariant the bug violates. Defaults to a build; the fix lands through `decide -> build -> close`. - -## feature - -Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the -design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the -contracts the feature must respect. Defaults to a build; size decides chat vs durable `w-02-light-task-workflow` task at -`decide`. - -## triage - -Lead by assessing severity, blast radius, and ownership — enough to route, not to fix. A breadth scan -(Semantics first) maps the surface fast. Triage frequently **exits research-only**: its product is a -recommendation, a routed owner, or a spawned build/bug job — not a code change. Only escalate to a -build when triage itself is the cheapest place to fix it. - -## research - -Lead by stating the question precisely. Semantics (grepai over onboarding) plus committed-state -onboarding usually answers it; reach for source only as bounded Intent confirmation. Research -**exits research-only** by design: it produces an answer, and may recommend a follow-up build job, but -performs none itself. diff --git a/.github-vscode/skills/w-02-light-task-workflow/SKILL.md b/.github-vscode/skills/w-02-light-task-workflow/SKILL.md index 248e6f3c..b34f3017 100644 --- a/.github-vscode/skills/w-02-light-task-workflow/SKILL.md +++ b/.github-vscode/skills/w-02-light-task-workflow/SKILL.md @@ -40,7 +40,7 @@ Light-task artifacts use minute-precision timestamps in `YYYY-MM-DDTHH:MM` forma The task document is **JSON-primary**: an `ar-task-document/v1` JSON file is the source of truth, and the `task.md` (or `.md` for a sub-task) is a deterministic **render** of it. Author and update it with the `task_doc` MCP tool — `create`, `set_status`, `set_step`, `append_decision`, `set_field` — which writes the JSON and re-renders the markdown on every write. Do not hand-edit a tool-managed `task.md`; edit through the tool and let it re-render. `template.md` and `master-template.md` document the **render spec** (the shape the renderer produces), not a separate hand-authored format. When a planning slice defers its code examples to the plan gate, record that with `codeExamplesNote` (a `set_field` value, e.g. "Drafted at the plan gate.") so the rendered "Proposed Code Examples" section reads as *deferred* rather than as if none are needed. A leaf doc may also carry a descriptive `statusNote` (a suffix beside the strict status enum), `headerNotes` (extra `**Key:** value` header lines such as Verified/Source), and freeform `sections` appended after References — the escape hatch for bespoke prose (e.g. a Status history) while the standard template sections stay the backbone. Pass `dry_run=true` to any op to **preview** — it builds + validates and returns the rendered markdown, a unified `diff` vs the on-disk `.md`, and a `wouldLose` flag, **without writing**; use it before adopting a hand-authored `.md` into JSON-primary (author the JSON → dry-run → confirm `wouldLose` is false → then write). -Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for a chat build (a thin doc: title plus a few steps, so even a no-`task.md` session is legible) and a *full* one for a durable task; the difference is content completeness, not a separate format. +Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for the smallest single-session build (a THIN doc: title plus a few steps — chat is never a build route, so even micro-work gets this thin doc and stays legible on the dashboard) and a *full* one for a durable task; the difference is content completeness, not a separate format. Scope and transition: the tool manages **`light` and `subTask`** documents, and the format also covers a series **master** (`kind:"master"`: a structured `subTasks` index + ordered `sections` that preserve a master's bespoke prose, so a re-render is lossless). Masters and existing markdown task files stay hand-authored markdown until the runtime ships `task_doc` and they are intentionally migrated — new tasks adopt the JSON-primary format going forward. diff --git a/.github-vscode/skills/w-02-light-task-workflow/master-template.md b/.github-vscode/skills/w-02-light-task-workflow/master-template.md index 7cb4e85a..42738c16 100644 --- a/.github-vscode/skills/w-02-light-task-workflow/master-template.md +++ b/.github-vscode/skills/w-02-light-task-workflow/master-template.md @@ -7,7 +7,7 @@ built to grow as the work unfolds. ## When to escalate to a series -The `l-01-session-job-lifecycle` skill's `decide` build-mode step escalates a single task to a series once its size is apparent — the +The `l-01-agent-lifecycles` orchestrator lifecycle's `decide` step escalates a single task to a series once its size is apparent — the implementation plan no longer fits on a single page, or the work splits into distinct slices that each deserve their own checklist and commit. You can also start single and escalate later: drop in the master `task.md` and move the existing plan into the first `NN_.md`. diff --git a/.hermes/HERMES.md b/.hermes/HERMES.md index 80c471a0..98580af1 100644 --- a/.hermes/HERMES.md +++ b/.hermes/HERMES.md @@ -1,18 +1,13 @@ -MANDATORY FIRST ACTION for this workspace - -You are not allowed to read, write, or execute code on any repository -until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure. - -Read and follow `/ar-coordination/AGENTS.md` -before working in any sibling project. Treat those rules as workspace -instructions. - -Until the build/job decision is made, read managed-repo source with the -`read_ar_files` MCP tool — not the harness's native read tool. One call returns -each file paired with its onboarding plus the repository and governing route -overviews. Native read is reserved as the edit precondition once building begins. - -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent), and -keep a running count of your `read_ar_files` calls. Include the onboarding files -inspected and every CGC, GrepAI, and `read_ar_files` call made as evidence. +**Agents Remember — session start.** + +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** + +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`/ar-coordination/AGENTS.md` and treat those rules +as workspace instructions, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. diff --git a/.hermes/skills/c-01-findings-capture/SKILL.md b/.hermes/skills/c-01-findings-capture/SKILL.md index e145d7ee..d413e8fe 100644 --- a/.hermes/skills/c-01-findings-capture/SKILL.md +++ b/.hermes/skills/c-01-findings-capture/SKILL.md @@ -13,7 +13,7 @@ Companion file: ## Operating Modes -1. Inside a task workflow (an `l-01-session-job-lifecycle` build job or a `w-02-light-task-workflow` task, including a master + light sub-task series). +1. Inside a task workflow (an `l-01-agent-lifecycles` orchestrator build phase or a `w-02-light-task-workflow` task, including a master + light sub-task series). 2. Standalone during direct clarification. ## Durable Destinations diff --git a/.hermes/skills/c-03-repo-bootstrap/SKILL.md b/.hermes/skills/c-03-repo-bootstrap/SKILL.md index 40148918..44f14f78 100644 --- a/.hermes/skills/c-03-repo-bootstrap/SKILL.md +++ b/.hermes/skills/c-03-repo-bootstrap/SKILL.md @@ -1240,7 +1240,7 @@ The orchestrator remains thin throughout. | `c-05-create-or-update-onboarding-files` | Owns final file-level onboarding semantics and routes structural slice maintenance back to the `c-03-repo-bootstrap` skill. The `c-03-repo-bootstrap` skill creates cards/waves and delegates file output rules to the `c-05-create-or-update-onboarding-files` skill. | | `c-04-retrieval-strategy-router` | Consumes bootstrapped overviews and file maps as the Intent substrate and can route to semantic/relationship providers first. | | `c-02-memory-quality-control` | Becomes relevant after bootstrap; touched files can be promoted from deferred to covered. | -| `l-01-session-job-lifecycle` | May trigger targeted bootstrap when an active job enters an uncovered area. | +| `l-01-agent-lifecycles` | May trigger targeted bootstrap when an active job enters an uncovered area. | | `confluence-search` / documentation search skills | Feed the docs evidence pass through approved sources from the input ledger. | --- diff --git a/.hermes/skills/c-04-retrieval-strategy-router/SKILL.md b/.hermes/skills/c-04-retrieval-strategy-router/SKILL.md index 01434c77..e226f8c0 100644 --- a/.hermes/skills/c-04-retrieval-strategy-router/SKILL.md +++ b/.hermes/skills/c-04-retrieval-strategy-router/SKILL.md @@ -160,7 +160,7 @@ names an unresolved source question. ### Rules: -- During the research phase (the lifecycle up to the build/job decision), read managed-repo +- During the research phase (the lifecycle up to the build decision), read managed-repo source with `read_ar_files`, not the native read tool — one call returns each file paired with its onboarding plus the repository and governing route overviews (the recipe above, batched and observable). diff --git a/.hermes/skills/c-09-git-worktree-manager/SKILL.md b/.hermes/skills/c-09-git-worktree-manager/SKILL.md index e19c7902..692dec19 100644 --- a/.hermes/skills/c-09-git-worktree-manager/SKILL.md +++ b/.hermes/skills/c-09-git-worktree-manager/SKILL.md @@ -7,7 +7,7 @@ description: "Create, attach to, report on, integrate, finalize, and clean up Ag Use this skill when a task should run through an explicit code/memory worktree wrapper. -The `c-09-git-worktree-manager` skill wraps the existing chat-build, light-task, or external workflow. It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. +The `c-09-git-worktree-manager` skill wraps the existing light-task or external workflow (a build that fits one session still rides a THIN `w-02-light-task-workflow` doc — chat is never a build route, per the `l-01-agent-lifecycles` invariant). It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. For closeout, use the `c-12-closeout` skill. The `c-09-git-worktree-manager` skill only supplies the worktree-specific contract path and integration/finalization follow-up rules. @@ -67,7 +67,7 @@ The intended order is: 1. run the `c-08-ar-coordination-context-resolver` skill for the target repository 2. run the `c-02-memory-quality-control` skill's task-start drift check and follow the existing AGENTS Gate 3/4 choice point 3. when onboarding is refreshed, commit the memory content and ledger before starting any worktree -4. decide whether the work is a chat build, a `w-02-light-task-workflow` light task (or master + light sub-task series), or external workflow +4. decide whether the work is a `w-02-light-task-workflow` light task — possibly a THIN one for single-session work; chat never builds — a master + light sub-task series, or external workflow 5. read the repository's `system/git-workflow.md` and identify the parent branch edge. For a standalone task, the leaf worktree branches from the approved source branch. For a master series, the master owns a root `series-contract.md` @@ -198,7 +198,9 @@ moved since task start. ## Integration -Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. +Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. Orchestrated-run carve-out (ruled 2026-07-06): dependency-ordered leaf→master and master→super integrations ride the series' standing approval (the developer's portfolio-gate approval recorded in the planner master) — the developer hand-off concentrates at the super PR/carry-over gate per the `l-01-agent-lifecycles` loop/orchestrator doctrine; a raised durable `integration-approval` gate still awaits the developer. + +On an orchestrated master's exit (master → super integration) the integrate step additionally enforces the delegated `master-handover-approval` seam: an undecided or policy-invalid handover gate addressed to the master (by `enclosure` = master task name) returns `handover-gate-blocked` instead of landing — decide the gate per the `l-01-agent-lifecycles` seam doctrine, then rerun. When no gate addresses the integrating master but open `master-handover-approval` gates exist elsewhere, integrate still proceeds and its result carries a `handover_gate_warning` naming them — treat it as a spelling check on the raised gate's `enclosure`. Run `worktree_integrate(..., dry_run=true)` first, then **hand off**: call `lifecycle_turn_end_notification(summary={…the integration plan…})` as the **last tool call**, then diff --git a/.hermes/skills/c-12-closeout/SKILL.md b/.hermes/skills/c-12-closeout/SKILL.md index f83071d9..2c7fe3ff 100644 --- a/.hermes/skills/c-12-closeout/SKILL.md +++ b/.hermes/skills/c-12-closeout/SKILL.md @@ -40,7 +40,7 @@ records the developer's explicit commit approval. Agents must not treat implementation approval, a previous "looks good", or their own judgment as commit approval. -The relay follows the `l-01-session-job-lifecycle` skill hand-off protocol: run the +The relay follows the `l-01-agent-lifecycles` orchestrator hand-off protocol: run the preview/dry-run first, then call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the **last tool call**, then deliver the preview facts and proposed messages as plain diff --git a/.hermes/skills/c-13-install-and-onboard/SKILL.md b/.hermes/skills/c-13-install-and-onboard/SKILL.md index 6515ae46..d583fd13 100644 --- a/.hermes/skills/c-13-install-and-onboard/SKILL.md +++ b/.hermes/skills/c-13-install-and-onboard/SKILL.md @@ -52,10 +52,12 @@ Run this sequence in order: 0. Preflight: verify the copied package and MCP setup are usable enough to continue. 1. Runtime scaffold: run or verify `runtime_install()`. -2. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. -3. Bootstrap: when a new memory repo was scaffolded, hand off to +2. Agentic settings: walk the developer through the orchestration defaults in + the seeded global settings file. +3. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. +4. Bootstrap: when a new memory repo was scaffolded, hand off to `c-03-repo-bootstrap`. -4. Providers: when providers are enabled, start/refresh indexing and verify +5. Providers: when providers are enabled, start/refresh indexing and verify readiness. This skill orchestrates and delegates. It does not reimplement @@ -79,7 +81,9 @@ Check, in order: 3. **Settings sane.** Confirm `server_info` reports the expected `coordinationRoot`, `workspaceRoot`, allowed repositories, and providers. Surface the resolved absolute paths because wrong paths are the common cause - of resolver failures. + of resolver failures. Also report whether the global agentic settings file + (`/system/settings.json`) exists yet; Stage 1 seeds it + when missing and Stage 2 configures it. 4. **Runtime state.** Check whether the coordinator scaffold already exists under `coordinationRoot` (`AGENTS.md`, `skills/`, `tasks/`, `memory-repos/`, `system/` as applicable). If it is missing or stale, Stage 1 will run @@ -118,7 +122,61 @@ Do not run `skills_install()` as part of first-run setup. The harness starter package already carries the skills. `skills_install()` remains available for manual maintenance or non-package setups, but it is not the default path. -## Stage 2 - Memory Repo: Ask Scaffold Vs Existing +## Stage 2 - Agentic Settings: Interview The Developer + +`runtime_install()` seeds the GLOBAL agentic settings file at +`/system/settings.json` copy-if-missing, with every knob at +its documented default: all-human gate delegation, the standard three-party-loop +defaults, no concurrency caps, no spawn harness preference. This stage turns +those defaults into the developer's actual posture so the intended workflows +run on ANY harness. The schema reference is `docs/reference/settings-json.md` +(Agentic Settings); unknown `orchestration.*` keys fail loud, so write only +documented keys. + +Walk the developer through the four knob families and edit the global file with +their answers (leave a family at its seeded default when they have no +preference): + +1. **Gate delegation posture** (`orchestration.gateDelegation`; GLOBAL file only - the + loader refuses it repo-locally and the boot snapshot reads the coordinator file) - keep every + gate human (`all-human`, the default), or delegate leaf gates with the + `manager-decides-leaf-gates` policy, optional per-kind `kinds` overrides, + and `requireReviewerVerdictAtSeams`. Say explicitly that this one key is + boot-snapshot: a change needs an MCP/harness restart. +2. **Loop defaults** (`orchestration.loops`) - the review-round cap + (`defaults.maxRounds`), reviewer reuse (`defaults.reviewerReuse`), + complexity thresholds (`defaults.complexity`), and per-level loop postures + (`perLevel`). Read per-use; edits apply on the next use, no restart. +3. **Concurrency caps** (`orchestration.concurrency`) - `maxParallelMasters`, + `maxParallelLeaves`, `maxSubAgents`. Default: uncapped. +4. **Harness preference + role knobs** (`orchestration.spawn.harness`, + per-role `orchestration.roles.`, per-level + `orchestration.rolesPerLevel..`) - which installed harness + `spawn_agent_session` uses when the spawning seat passes none, per-role + harness/model/effort overrides, and per-LEVEL overrides + (leaf|master|portfolio) for tiered economics (e.g. a cheap leaf reviewer, + a smarter master-seam reviewer). Harness values must be known ids: the + builtin registry (`claude`, `codex`, `pi`) or an `orchestration.harnesses` + entry the developer defines (new TUIs, or a pre-customized launch argv for + a builtin). `effort` is validated per-harness at dispatch (claude: + `low|medium|high|xhigh|max` on the `--effort` flag plus the session-level + `ultracode`); mention the FREE-FORM escape hatch for anything outside the + vocabularies - `launchArgs` (verbatim argv), `sessionCommands` (pasted + before the brief), `promptKeywords` (prepended to the brief) - never + validated, recorded in spawn provenance. Default: detection-gated (the + first detected harness). The full spawn-surface manual is + `docs/reference/harnesses.md`. + +If the developer wants to skip the interview, confirm the seeded defaults +apply and continue; tell them the file can be edited any time (picked up +per-use, except the gateDelegation restart note above). + +Per-repo overrides: a code repo may carry its own `/system/settings.json` +with the same `orchestration.*` shape; repo-local leaf values override the +global file (arrays replace). Offer this only when the developer asks for +repo-specific behavior; do not create the file unprompted. + +## Stage 3 - Memory Repo: Ask Scaffold Vs Existing Do not assume the developer wants a fresh memory repo. Ask which case applies, unless a memory repo is already present and resolvable: @@ -126,10 +184,10 @@ unless a memory repo is already present and resolvable: 1. **Scaffold a new memory repo** - they have no existing memory for this code repo. Run `c-00-initialize-memory-repo` (internal by default; external only if the developer asks or the configured topology requires it). Continue to Stage - 3. + 4. 2. **Use an existing memory repo** - they already have one. Clone or checkout it to the resolved memory location, then adopt it as the ledgered baseline with - `c-10-adopt-memory-baseline`. Skip Stage 3 because its onboarding already + `c-10-adopt-memory-baseline`. Skip Stage 4 because its onboarding already exists. Internal-memory note: pre-existing internal memory lives inside the code repo @@ -137,9 +195,9 @@ Internal-memory note: pre-existing internal memory lives inside the code repo `c-08-ar-coordination-context-resolver` and skip the question when the memory layer is already there. -## Stage 3 - Bootstrap +## Stage 4 - Bootstrap -Run this stage only when Stage 2 scaffolded a new memory repo. +Run this stage only when Stage 3 scaffolded a new memory repo. Hand off to `c-03-repo-bootstrap` to generate initial onboarding. A thin `overview.md` is enough to start; deeper route-local overviews and file-level @@ -147,7 +205,7 @@ onboarding should grow as work touches new areas. Skip this stage when an existing memory repo was adopted. -## Stage 4 - Configure Providers To Index +## Stage 5 - Configure Providers To Index If providers are enabled, make them index the configured code and memory: @@ -177,10 +235,12 @@ Summarize: step the developer must perform; 2. runtime scaffold: `runtime_install()` run or already current, with the resolved coordination root; -3. memory repo: scaffolded, existing-adopted, or already present, with the +3. agentic settings: interviewed and written, or left at the seeded defaults, + with the global file path; +4. memory repo: scaffolded, existing-adopted, or already present, with the resolved memory root; -4. bootstrap: run via `c-03-repo-bootstrap` or skipped; -5. providers: indexing status and any deferred/degraded state. +5. bootstrap: run via `c-03-repo-bootstrap` or skipped; +6. providers: indexing status and any deferred/degraded state. End by telling the developer whether the project is ready for normal work. Do not tell them to restart for hooks installed by this skill, because this skill no diff --git a/.hermes/skills/l-01-agent-lifecycles/SKILL.md b/.hermes/skills/l-01-agent-lifecycles/SKILL.md new file mode 100644 index 00000000..1d390618 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/SKILL.md @@ -0,0 +1,259 @@ +--- +name: l-01-agent-lifecycles +description: "The agent lifecycles: one lifecycle per agent type, under one roof. Routes every session by exactly three conditions (spawn-role env -> role brief -> otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator, designer, strategist, manager, worker, adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. A developer-facing session IS the orchestrator; solo work is the degenerate portfolio. Supersedes and replaces both l-01-session-job-lifecycle and l-02-agent-orchestration." +--- + +# l-01-agent-lifecycles — The Agent Lifecycles + +Lifecycle and job are **one entity**: each agent type runs its own, self-contained lifecycle. This +skill is the single roof over all of them — a thin router, the minimal frame every session shares, +and the role lifecycles as the payload files. No role is defined by reference to another role's +lifecycle, and no role reads another role's file. + +## Which Lifecycle Am I? (the router — exactly three conditions, in order) + +1. **`AR_SPAWN_ROLE` is set** (spawn env, injected by `spawn_agent_session`) → run + `roles/.md`. Nothing else in this file's "developer session" material applies to you. + (`designer` here means the same design hat in a separate chair — see `roles/designer.md`.) +2. **Else: the first user message is a role brief** — a `templates/*-brief.md`-shaped dispatch or + a first line of the form `ROLE BRIEF — ` from an orchestrating agent → run that role's + lifecycle. The brief is your session start; a workspace session-start notice is not addressed + to you. +3. **Else** (a developer opened this session) → you are the **orchestrator**: run + `roles/orchestrator.md`. Solo work is the degenerate portfolio — the same three jobs with hats + collapsed (the orchestrator wears the manager hat in flat runs and builds hands-on at session + scale); the task doc still comes first. + +There is no fourth entry, and the edge cases are decided: an **unresolvable `AR_SPAWN_ROLE` +value** (no matching `roles/.md`) falls through to condition 2 (the brief); a role-env +session **whose brief never arrives** announces itself on the inbox and waits — it never +improvises a task; `AR_SPAWN_ROLE=orchestrator` is valid only as a takeover chair (the Profile +check (takeover) in `roles/orchestrator.md`, The Event Loop) — the developer still talks to **one** orchestrator. Orchestrated +fan-out (spawning managers/workers at scale) begins only on an explicit developer request (e.g. +*"orchestrate these masters"*) — no agent promotes itself into a spawning seat. + +One exception to the no-cross-reading rule above: **a seat that WEARS a hat runs that hat's file +as its own** — the orchestrator always for `roles/designer.md`, and in flat runs for +`roles/manager.md` (the hat-collapse rule). + +## The Role Registry + +| Role | Seat | Lifecycle file | +| --- | --- | --- | +| **orchestrator** | the developer-facing session; first coordination leaf of an orchestrated series | `roles/orchestrator.md` | +| **designer** | a HAT the orchestrator pulls inline (front of the pipeline or mid-flight; separate chair optional) | `roles/designer.md` | +| **strategist** | the sprint planner, SPAWN-FIRST; a strategist run is a **mandatory precondition for any orchestrated run** — its deliverable is the orchestration task (sprint plan + scope); spawn value `strategist` | `roles/strategist.md` | +| **manager** | one coordination leaf per master; drives that master's leaf loop | `roles/manager.md` | +| **worker** | one leaf worktree, short-lived, fresh session | `roles/worker.md` | +| **adversarial reviewer** | short-lived, spawned at the two seams (master-exit, super-exit) and as any three-party loop's reviewer seat (criteria catalogs bound per review type); spawn value `reviewer` | `roles/reviewer.md` | + +The **lenses** (bug · feature · triage · research — `lenses.md`) are how the scoping seats +(orchestrator, designer) read a piece of work; a dispatched role never picks a lens — its brief +already carries the flavor. + +## The Minimal Frame (the only machinery every session shares) + +Every session in a managed repo may be a **lifecycle**: six signals — `lifecycle_start` · +`lifecycle_phase` · `lifecycle_turn_end_notification` · `worktree_attach` · `switch_lifecycle` · +`lifecycle_end` (plus the automatic `worktree_start` promotion) — record where it +is and what it waits on, so work is observable and resumable across chat deaths. The model **never +handles a lifecycle id** — identity is server-side, anchored in the worktree contract. + +| When | Signal | Effect | +| --- | --- | --- | +| Trust checkpoint passes (managed repo) | `lifecycle_start` | begin a **fleeting** lifecycle (guarded: one per session; no id) | +| Entering a phase | `lifecycle_phase` | move the phase axis (`request` / `trust-checkpoint` / `reframe-research` / `decide` / `build` / `close`) | +| A developer hand-off | `lifecycle_turn_end_notification(summary=…)` | set `awaiting-developer`, surface the attention item, return immediately; the **next turn's first AR call auto-resumes** — never resume by hand | +| `worktree_start` | *(automatic promotion)* | the fleeting lifecycle becomes **persistent**, anchored in the contract | +| Resuming an existing task | `worktree_attach` | re-adopts the contract's lifecycle (contract-resolved) | +| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | the save gate — never dropped silently | +| Close | `lifecycle_end` (`completed`\|`abandoned`) | the terminal record | + +Rules: a tool call outside any lifecycle is **dropped, never misattributed**; `paused` is +system-owned. **A spawned role that never touches mutating AR tools simply never instantiates a +lifecycle — that is correct, not a violation.** A spawned role runs its **own** lifecycle when it +runs one; it never adopts its spawner's. The session↔leaf association is the catalog binding made +at spawn (the **qualified** leaf key `//`), not lifecycle adoption. + +## Shared Invariants (every role can count on these) + +- **Continuity lives in the `task_doc` + durable artifacts, never in transcripts** — which is why + short-lived workers and reviewers are safe, and why every seat writes its artifact of record. +- **Escalation ladder: worker → manager → orchestrator → developer.** No rung is skipped, ever. + Each role file states only its own rung. +- **Observability:** coordination seats are `task_doc` leaves with attached chats; the developer + can walk into any seat at any level. +- **Decision-needing questions land in the task doc's `openQuestions`** — the rendered decision + surface; `notes/` carries the analysis behind them. + +## The Three-Party Loop (one home — this section owns the loop doctrine) + +**OWNER → BUILDER → REVIEWER → owner, at every level that owns work.** The owner never +self-approves; the builder never lands; the reviewer never decides — verdicts are evidence. The +owner checks the verdict and either redispatches a builder or escalates. Role files reference this +section; they do not restate it. + +| Level | Owner (holds the deliverable, rules, lands) | Builder | Reviewer | +| --- | --- | --- | --- | +| Leaf | the leaf's owning seat (manager; orchestrator in tight/flat mode) | spawned worker (no-commit contract) | spawned reviewer, criteria catalog + liberty | +| Master | the manager | the leaf workers | the master-exit seam reviewer (verdict rides `master-handover-approval`) | +| Portfolio | the orchestrator | the STRATEGIST (spawn-first) | reviewer with the plan-review catalog | + +**Complexity-scored tiers (per leaf, at dispatch).** The owning seat scores three axes — blast +radius (doctrine/enforcement/public surface vs leaf-local) · novelty (new subsystem vs +pattern-following) · size (files × steps) — into three tiers: **direct** (no loop +machinery — the level's ordinary build channel implements: hands-on at session scale, the leaf's +worker under a manager; self-check + checks ladder only), **builder-verified** (builder +implements; owner verifies report-vs-artifact; no reviewer), **full loop** (builder + independent +reviewer rounds). The +strategist's blast-radius register is the scoring input when an orchestration task exists. A +leaf's loop mark (tier + scope: manager | orchestrator — the owning level runs the loop with ITS +agent set) is recorded on the leaf doc with a decision-log entry. **A master whose leaves all +score `direct` is a workflow-free manager** — no loop machinery; the knobs make every loop +optional per level, never mandatory ceremony. + +**Rounds and the HARD cap.** A round = implement → review. **Hard cap: 3 rounds per loop — and +ONLY full end-to-end rounds count against it.** Residuals of a passing round are landed and +**delta-verified by the SAME reviewer via a follow-up message** (it retains everything it already +verified, at a fraction of a fresh round's cost); **fix rounds resume the SAME builder**. A fresh +reviewer is spawned only for a full round or when new scope opens. Delta-verifies close rounds; +they do not open them. + +**The convergence rule (the real control; the cap is the backstop).** Every round must SHRINK the +open finding set. A round that does not shrink it escalates immediately, regardless of the count; +a monotonically converging loop may never hit the cap at all. At the cap, or on non-convergence, +the owner does not spin another round — it **escalates one seat up the ladder (worker → manager → +orchestrator → developer) with the full round history attached**; the escalation packet IS the +upper seat's visibility. + +**Quo-vadis (the written developer-escalation criterion).** A question is developer-worthy when it +is a **high-blast-radius truth** — answered wrong it means big rewrites later (architecture +direction, security posture, doctrine contradictions, irreversible data/branch operations, where +agent settings live). Quo-vadis questions escalate IMMEDIATELY, regardless of round count. +Presentation-grade choices (2px vs 3px) never do — the owner rules and logs. + +**Criteria catalogs (the reviewer as test bench).** Criteria are never made up on the spot: every +review runs its type's standing catalog from `criteria/` (code-seam · doctrine · +onboarding-memory · report-verification · plan-review) plus an exploratory mandate, under the +promotion ratchet (each catalog carries it). `roles/reviewer.md` binds them. + +**Per-level agent sets.** Each level runs its loop with its own harness/model/effort set — the +orchestrator-level set (the strongest models) and the manager-level set (cheaper, possibly +workflow-free) are configured per level in the `orchestration.loops` settings block (schema in +`docs/reference/settings-json.md`; stored in the global agentic settings file with repo-local +override, parsed by the kernel agentic-settings loader — L13, landed). The strategist's mandatory +pre-run is doctrine, not a knob — it is unconditional. + +## Knob Block & Capability Doctrine (no per-harness files) + +Role files are **model-interpreted markdown, never an executor**. Each carries a portable **knob +block** (harness / model / effort / tools) — the defaults the terminal host injects at spawn. +Resolution: **role-file defaults < settings.json orchestration block.** There are deliberately +**no per-harness role files** (developer decision 2026-07-05): harness-specific ABILITIES — +sub-agent fan-out and the like — are covered inside the portable files as capability-conditional +doctrine any coding agent can apply, and harness PREFERENCE is deployment configuration +(settings), not doctrine. Hard-coding a vendor would fork the doctrine per harness. For spawning +seats, `spawn_agent_session` is itself the harness-independent fan-out: a harness with no +sub-agent facility still dispatches seats through the framework (a chat, no leaf attachment +required) — the DBMS principle: one behavior, any engine. + +## settings.json Orchestration Block + +Machine/user overrides layer over the role-file defaults, in the **global agentic settings file** +(`/system/settings.json`), with `/system/settings.json` as the +repo-local override layer (leaf-key deep merge, arrays replace, unknown `orchestration.*` keys +fail loud — schema in `docs/reference/settings-json.md`, Agentic Settings). Precedence: role-file +defaults < global settings < repo-local settings. + +```jsonc +{ + "orchestration": { + "roles": { // role → knob override; validated: harness/model/effort · free-form: launchArgs/promptKeywords/sessionCommands + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { // per-LEVEL agent sets (leaf|master|portfolio), deep-merged over roles + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" }, // spawn_agent_session default when the seat passes none + "gateDelegation": { + "policy": "manager-decides-leaf-gates", + "requireReviewerVerdictAtSeams": true + } + } +} +``` + +**As-built (L13 + L16):** the whole block is parsed by the kernel agentic-settings loader +(`kernel/agentic_settings.py`) — typed models for `roles` / `rolesPerLevel` / `concurrency` / +`spawn` / `harnesses` / `loops`, +read PER-USE (an edit applies on the next use, no restart). `orchestration.gateDelegation` is +parsed and **enforced** (`controlplane/gate_policy.py` — all-human default, opt-in delegation, +human-pinned kinds `integration-approval` / `push-approval` / `cleanup-approval`, owner never +self-approves); it is the ONE boot-snapshot key — read from the global file at MCP boot, a change +needs a restart (an authority-file value is a one-cycle legacy fallback with a boot warning). +`requireReviewerVerdictAtSeams` **binds delegated seam decisions** (`master-handover-approval`) to +attached reviewer-verdict evidence; the named policy `manager-decides-leaf-gates` routes leaf gates +to the manager and the master-exit handover to the **orchestrator** (human review concentrates at +the super gate). `spawn_agent_session` resolves its knobs (260703-L16) as explicit args > +repo-local level override > global level override > repo-local role default > global role default +> detection-gated default — the dispatcher declares its `level` (leaf|master|portfolio, default +leaf) and the resolved level rides spawn provenance — and **applies** them at the harness +boundary: model/effort ride as `AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` env AND map onto the launch argv +per-harness via the effective registry (claude `--model`/`--effort`; a mapping-less harness stays +env-only; a session-vocabulary effort like claude's `ultracode` is delivered as a post-launch +`/effort` paste). Unknown effort values REFUSE at dispatch naming the harness's vocabulary — the +CLI would warn-and-silently-degrade. The free-form escape hatch (`launchArgs` verbatim argv, +`promptKeywords` riding the brief paste, `sessionCommands` pasted before the brief) is never +validated, only recorded in spawn provenance; `orchestration.harnesses` teaches the framework new +TUIs or pre-customizes builtin launches (manual: `docs/reference/harnesses.md`). +`orchestration.loops` (the three-party-loop knobs: per-level loop sets, round cap, reviewer +reuse, complexity thresholds) lives in the same block — meaning in +`docs/reference/settings-json.md`; no knob touches the master-exit seam gate. + +## Companion Files + +- `lenses.md` — the four job lenses for the scoping seats. +- `roles/…` — the six self-contained role lifecycles (the registry above). +- `templates/…` — turn-report · worker-brief · manager-brief (`ROLE BRIEF — manager`; the + orchestrator compiles a manager's session start from it) · master-handover-packet · + conversation-handover-packet · verdict · impact-analysis · onboarding-coherency · + deep-research-report · orchestration-task (the strategist's sprint plan). Spawning seats compile + briefs FROM these; sub-agents fan out and fill them, so analysis survives compaction. +- `criteria/…` — the reviewer criteria catalogs (code-seam · doctrine · onboarding-memory · + report-verification · plan-review), the review test bench the three-party loop binds; maintained + through the promotion ratchet, never made up on the spot. + +## The Super Integration Branch (orientation only — the doctrine lives with its owner) + +``` +main + └── super-integration (orchestrator-owned, off main) + ├── master-A branch (off super) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, C-11) + ├── master-B branch (off the moved super — sees A) + └── … final: super → main PR + memory carry-over + push +``` + +The full topology — dependency-ordered dispatch, the integration-duty procedure, the two +conflict-resolution modes, leaf moves — lives in **`roles/orchestrator.md`** and only there. + +## Credits + +This skill absorbs and supersedes `l-01-session-job-lifecycle` and `l-02-agent-orchestration` +(converged 2026-07-05: lifecycle and job are one entity — one lifecycle per agent type). The +orchestration vocabulary adopts the parked `260619_agentic-control-plane` spec — jobs as +model-interpreted markdown (D6), the knob block (D7), role + lens in one file (D10), the +ambient-singleton rule (D11), per-harness variants (D12), the judge rung, short-lived workers with +structured handoff, dev-talks-to-one-orchestrator (D15) — which in turn credits **Archon** and the +**agent-control-plane** project (D14); that credit carries forward. + +## Relationship To Other Instructions + +This skill extends — never replaces — the coordinator `AGENTS.md`, the `w-02-light-task-workflow` +task format, and the memory layer (`c-…` skills). Each `roles/.md` is self-contained for its +seat; read exactly the one the router selects. diff --git a/.hermes/skills/l-01-agent-lifecycles/criteria/code-seam.md b/.hermes/skills/l-01-agent-lifecycles/criteria/code-seam.md new file mode 100644 index 00000000..053feb1b --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/criteria/code-seam.md @@ -0,0 +1,85 @@ +# Criteria Catalog — Code-Seam Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review wires code seams: consumers, enforcement points, gates, addresses, tool contracts. +Binds at the master-exit and super-exit seams and in any loop review whose change set touches code +(see the binding table in `../roles/reviewer.md`). Criteria are never made up on the spot: the +standing list below is the regression floor, run every time; the exploratory mandate and the +promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### CS-1 — Production-wiring walk + +**Trace the real call path, never a hand-aligned harness.** A claim that a consumer or an +enforcement point exists must be walked through the PRODUCTION call path — the controller, the +tool registration, the store fold — not through a test that hand-assembles the pieces into +alignment. A test can pass while the production consumer is inert. + +- Catching evidence: 260703-L8 review 3 (AR3-1) — the integrate consumer was proven **inert**: the + policy was omitted at the controller and the gate was looked up on the wrong lifecycle, while a + hand-aligned test passed (L8 decision log, cycle-6 entry). + +### CS-2 — Fail-open hunt + +**What happens when the address/config is absent or mistyped?** For every identity, address, key, +or config the seam matches on: feed it nothing, feed it a near-miss, and confirm the seam fails +CLOSED (refuses) rather than open (silently proceeds unmatched). + +- Catching evidence: 260703-L8 review 4 (AR4-1) — the seam's `enclosure` address had to be pinned + as an exact-string contract and the enclosure-less raise made a refusal (L8 decision log, + cycle-7 entry). + +### CS-3 — Validate-then-mutate + +**Every raise/write validates before it mutates.** A call that records state (a gate raise, a +store append, a contract write) must perform its refusal checks before any durable effect; a +mutation that precedes validation leaves half-states behind on refusal. + +- Catching evidence: 260703-L8 cycle 6 — the `wait=false` raise was reworked to be + validate-then-mutate and seam-kind-restricted (L8 decision log, cycle-6 entry). + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### CS-4 — Reused-primitive affordance parity *(candidate — 1 catch)* + +**When a screen reuses a shared content primitive, verify every branch of the ORIGINAL's +affordances (banners, status chips, truncation notices, error states) still fires on the reuse +path.** A dropped affordance is a silent regression the reuse's own tests won't catch — they +assert the new screen's happy paths, not the primitive's full surface. + +- Catching evidence (single engagement): 260703-L17 review (L17R-2) — the notes reader's + `DualPane` reuse drops the "first 2 MiB" truncation banner on the markdown path (the banner + lives in `CodeSide`, which markdown never reaches); text and binary keep it. + +### CS-5 — Cross-repo side-effect safety *(candidate — seeded from a clean exemplar, 0 catches)* + +**Any step that writes to a repository OTHER than the one it operates in gets the full +validate-then-mutate treatment plus partial-failure and dirty-target analysis.** Check the order +of validation vs the foreign write, the state left behind when the write lands but the caller +fails afterward, behavior against a dirty target repo, and an exact format round-trip with the +foreign artifact's consumer. + +- Seeding evidence: 260703-L18 finding 7 (`_reconcile_missing_mapping` writing the official + memory repo's ledger mid-`worktree_start`) PASSED all four lenses under this analysis — the + clean exemplar that defined the class. A catch in a later engagement promotes. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS change set the catalog does not name yet. Every novel finding-class that survives +refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.hermes/skills/l-01-agent-lifecycles/criteria/doctrine.md b/.hermes/skills/l-01-agent-lifecycles/criteria/doctrine.md new file mode 100644 index 00000000..9b9ccae1 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/criteria/doctrine.md @@ -0,0 +1,58 @@ +# Criteria Catalog — Doctrine Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review is doctrine: skill files, role lifecycles, templates, instruction surfaces, docs +that agents obey. Binds whenever doctrine/skill files are in the change set (see the binding table +in `../roles/reviewer.md`). Criteria are never made up on the spot: the standing list below is the +regression floor, run every time; the exploratory mandate and the promotion ratchet keep the +catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### D-1 — Doctrine-vs-code anchoring + +**Every "X enforces Y" needs a code anchor.** A doctrine sentence claiming enforcement, refusal, +or automatic behavior must resolve to the code that does it (file + mechanism). Doctrine that +narrates enforcement which does not exist is a defect, not an aspiration. + +- Catching evidence: 260703-L8 review 1 (AR-5) — `requireReviewerVerdictAtSeams` was documented as + binding while the flag was **inert**; the finding forced the wiring (L8 decision log, AR-1 + entry: "closing AR-5's inert flag"). + +### D-2 — Cross-file contradiction sweep + +**Sweep sibling doctrine for statements the change set now contradicts.** A doctrine change is +reviewed against the whole doctrine surface (skills, role files, templates, docs, hooks, canvas +prose), not just the edited files — one file's new invariant is another file's stale sentence. + +- Catching evidence: 260703-L10 — the landed "chat is never a build route" invariant contradicted + surviving chat-build wording inside `c-09` / `w-02` (builder escalation 1, owner-sanctioned + sweep; L10 builder report). + +### D-3 — Stuck-state walk + +**Can an agent following the prose deadlock?** Walk the doctrine as the obeying agent: at every +wait, gate, and handover, ask who unblocks it and through which channel. Prose in which two seats +each wait on the other — or a seat waits on a channel nobody is told to serve — is a blocking +finding. + +- Catching evidence: 260703-L8 review 2 — the seam deadlock: the manager's blocking raise and the + orchestrator's decide path could not meet as written; the ruled `wait=false` + + packet-carried-gateId channel resolved it (L8 rounds 2/4b history). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS doctrine change the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.hermes/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md b/.hermes/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md new file mode 100644 index 00000000..e47783e3 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md @@ -0,0 +1,67 @@ +# Criteria Catalog — Onboarding/Memory Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run over the +memory side of a change set: sidecars, route overviews, route indexes, update histories. Binds at +the master-exit and super-exit seams (the onboarding-vs-code lens) and in loop reviews whose change +set carries onboarding (see the binding table in `../roles/reviewer.md`). Criteria are never made +up on the spot: the standing list below is the regression floor, run every time; the exploratory +mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### OM-1 — Staleness diff vs as-landed code + +**Diff every body claim about current behavior against the as-landed code.** A sidecar or overview +body that describes the present tense is checked against what the branch actually ships — deleted +things still described, renamed things under old names, duplicated rows. + +- Catching evidence, two separate engagements: 260703-L8 cycle 6 (owner follow-up pass) — route + overview bodies still described **deleted canvas models** (the panels overview's build-job/frame + tail) and carried **duplicated table rows** (the tools and controlplane overviews' Layout + tables), durably recorded in those overviews' own 2026-07-05T19:25 Update History entries; + 260703-L10 — the flowModels sidecar body was still the pre-convergence 8-model census and its + references row still said "8 models" (the sidecar's 2026-07-06T12:05 history entry + L10R-3). + +### OM-2 — History-only-update detection + +**"Refreshed" must mean a genuine body edit.** An onboarding file whose only change is a new +Update History line has NOT been refreshed — the body still asserts the old truth. Check that +every claimed refresh touched body sentences, not just the history list. + +- Catching evidence: 260703-L8 cycle 6 — the builder reported route overviews as refreshed when + they were **history-only**; the closeout body gate caught it (L8 decision log, cycle-6 entry: + "report-vs-artifact verification belongs in the reviewer criteria catalog"). + +## Candidate Criteria (seeded exploratory — one catching engagement; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### OM-3 — Newest-first with the checker's own semantics *(candidate — 1 catch)* + +**Update History sorts newest-first under the CHECKER's datetime parse, not lexicographically.** +The quality checker compares naive timestamps as-is and folds tz-aware stamps to UTC; a merge or +mechanical insert that sorts by string can pass the eye and fail the gate (or worse, pass the gate +in the wrong order). Verify ordering with the checker's semantics. + +- Catching evidence (single engagement): 260703-L11 — four onboarding history collisions from the + parallel wave had to be re-sorted **with the checker's own datetime semantics** (naive compare + as-is, tz-aware folds to UTC); the quality gates caught the owner's wrong sort key (L11 decision + log). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS memory delta the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate is the working example, and it is THIS catalog's own OM-2 mechanized: the gate catches + history-only "refreshes" at commit time, where prose requests did not. diff --git a/.hermes/skills/l-01-agent-lifecycles/criteria/plan-review.md b/.hermes/skills/l-01-agent-lifecycles/criteria/plan-review.md new file mode 100644 index 00000000..ef4d2d90 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/criteria/plan-review.md @@ -0,0 +1,69 @@ +# Criteria Catalog — Plan Review (the strategist loop) + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run against an +**orchestration task** (`../templates/orchestration-task.md`) — the strategist's sprint plan — +before the developer's drawing board. This is the portfolio loop's review type: owner = +orchestrator, builder = strategist, reviewer = this catalog. The reviewer holds the same read-only +analysis tools the strategist used (`cgc_*`, `grepai_*`, `read_ar_files`), so the plan's mechanical +claims are re-derivable, not just readable. Criteria are never made up on the spot: the standing +list below is the regression floor, run every time; the exploratory mandate and the promotion +ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### PR-1 — Refute uncited edges + +**An uncited dependency edge is refutable by default.** Every edge in the dependency graph must +carry evidence — a cgc/grepai query, a file, a decision-log entry, a design-section citation, or +(for new surfaces) a declaration cross-reference naming both leaf declarations. An edge with no +evidence is challenged as a finding; so is evidence that does not actually support the edge's +direction or kind. + +### PR-2 — Missed-shared-surface hunt (class-completeness on intersections) + +**Re-intersect the surface lists independently.** Take the plan's per-leaf touch surfaces (both +existing and declared-new), recompute the pairwise intersections, and hunt pairs the edge list +omits — including CONFLICT-risk at a shared parent route where two leaves declare additions +(wiring points, shared registries). A plan that lists surfaces but misses one of their +intersections has a hole exactly where collisions happen. + +### PR-3 — Blast-radius re-derivation + +**Re-derive at least the HIGH-blast-radius entries with the cgc tools** (`cgc_dependencies` / +`cgc_callers` / `cgc_callees`, capped depth) — and spot-check a sample of the low/medium entries. +A register entry whose derivation cannot be reproduced, or whose classification drops the doctrine +propagation / migration / user-visible unions, is a finding; the register parameterizes every +downstream loop tier, so an understated radius under-reviews a leaf. + +### PR-4 — Order-respects-edges + +**Check the sprint order/waves against the edge list, mechanically.** No ORDER edge may run +backwards across the proposed sequence; every CONFLICT edge must be resolved by serialization or a +recorded leaf move (from→to + rationale); parallel waves may contain only INDEPENDENT pairs, and +the wave plan must acknowledge the landing-reconciliation cost. + +### PR-5 — Honesty of the findings section + +**Verify the plan's failure claims both ways.** Every "unplannable as scoped" finding must be +genuine (the leaf can name neither existing surfaces nor the parent anchoring of its additions — +a merely not-yet-existing surface is NOT unplannable); and thin leaf scopes the plan silently +guessed around instead of flagging are themselves findings. Quo-vadis contradictions must be +flagged at the top of the coherence findings, not buried. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS plan could be wrong that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example; PR-4 is this catalog's mechanization candidate (a topological check over + a structured edge list). diff --git a/.hermes/skills/l-01-agent-lifecycles/criteria/report-verification.md b/.hermes/skills/l-01-agent-lifecycles/criteria/report-verification.md new file mode 100644 index 00000000..fb3bdda8 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/criteria/report-verification.md @@ -0,0 +1,95 @@ +# Criteria Catalog — Report Verification + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) — and the loop OWNER +verifying a builder round — MUST run over every report, claim, and summary in the change set: +builder reports, owner claims, handover packets. **Standing from day one** in every review type: +report-vs-artifact caught real defects in three separate engagements before this catalog existed. +Criteria are never made up on the spot: the standing list below is the regression floor, run every +time; the exploratory mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### RV-1 — Report-vs-artifact on EVERY claim + +**Open the artifact behind every claim.** A report sentence asserting "X was done / is green / +was refreshed" is verified against the artifact itself, not trusted — claim by claim, no sampling +of the load-bearing ones. + +- Catching evidence, three separate engagements (260703-L8): review 3 caught a **hand-aligned + test** behind a wiring claim; cycle 6's closeout gate caught **"refreshed" overviews that were + history-only**; review 4 caught the **OWNER's own canvas overclaim** (L8 decision log, cycle-7 + entry) — builder reports and owner claims fail the same way. + +### RV-2 — CLASS-completeness *(promoted to standing at 260703-L18 — 2 catches)* + +**Hunt the siblings of every found instance.** A finding or a fix names an instance of a CLASS +(a directive surface, a census count, a vocabulary token). Enumerate the class — every sibling +surface, not just the instances the report names — and check each one. + +- Catching evidence: (1) 260703-L10 round 1 — the reviewer's completeness sweep found **six of + ten first-action surfaces** still shipping the retired directive when the report claimed the + flip done (L10 decision log). (2) 260703-L18 review (L18R-3) — the fix for + advertised-but-unimplemented recovery choices named the `cli.py` `custom` residual but missed + the SIBLING `_load_memory_ledger` block still advertising an inert `reconciliation`; the + sibling hunt found it. + +### RV-4 — Decision-log completeness for scope-expanding disclosures *(promoted to standing at 260703-L18 — 2 catches)* + +**A scope-expanding owner supplement or load-bearing builder disclosure must be verifiable in +the task-doc decision log, not only the builder report.** Continuity lives in the task_doc + +durable artifacts, never in transcripts; a ruling or environment finding that exists only in a +report is one lost file away from unrecoverable. Cross-check every supplement and disclosure the +builder report carries against the decision log. + +- Catching evidence: (1) 260703-L17 review (L17R-1) — supplement 2 (the wait-loop-era remnant + sweep with per-hit verdicts and two named follow-ups) was recorded only in the builder report. + (2) 260703-L18 review (L18R-4) — the load-bearing editable-install/PYTHONPATH environment + finding + named follow-ups lived only in the builder report; the leaf's `decisions[]` was + empty. Both folded by the owner at closeout. + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### RV-3 — Partial-fix-creates-falsehoods *(candidate — 1 catch)* + +**Verify claims ABOUT the changed artifacts, not only the artifacts.** A partial fix can turn +previously-true sentences elsewhere false (docs describing the artifact, install guides quoting +it, counts referencing it). Sweep for statements about what changed and re-verify their truth +after the change. + +- Catching evidence (single engagement): 260703-L10 round 1 — the partial hook flip made **two + install-doc claims false** ("injects the same startup directive" no longer held); round 2 + restored byte-identity so the claims became true again (L10 decision log + builder report). + +### RV-5 — Worktree-shadowed regression pins *(candidate — 1 catch)* + +**A regression test must bite under the invocation the owner actually runs.** An editable +install pointing at another checkout can shadow the worktree's sources, making a mutation-tested +pin pass vacuously under the canonical invocation while failing only under a hand-set +`PYTHONPATH`. Verify sensitivity by mutating the target and running the CANONICAL invocation; +a pin that only bites under a nonstandard environment is not yet a pin. + +- Catching evidence (single engagement): 260703-L18 review (L18R-1) — the inbox + delivered/unconfirmed pin failed its mutation check only under `PYTHONPATH=src`; under the + canonical `pytest mcp/tests` the main-repo editable install shadowed the worktree and the + mutated code still passed. Remedy: the `sys.path` pin idiom the sibling suites carry. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS report could mislead that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests (RV-1 is itself the precedent: promoted on three catches). Promotion is proposed in the + verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.hermes/skills/l-01-agent-lifecycles/lenses.md b/.hermes/skills/l-01-agent-lifecycles/lenses.md new file mode 100644 index 00000000..0f277b06 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/lenses.md @@ -0,0 +1,45 @@ +# Lenses — How the Scoping Seats Read a Job + +Read by the **scoping seats** (orchestrator, designer); a dispatched role never picks a lens — its +brief already carries the flavor. The job type is a **lens**, picked during `reframe-research` and +re-pickable at any time. It is not a gate and it never changes the orchestrator phase axis +(`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three +things only: + +- **Opening move** — the first concrete thing `reframe-research` does for this kind of job. +- **Retrieval lean** — which `c-04-retrieval-strategy-router` strategy leads (others are still available). +- **Decide default** — where this job usually lands at `decide` (still a real decision, not automatic). + +| Job | Opening move (in `reframe-research`) | Retrieval lean (`c-04-retrieval-strategy-router`) | `decide` default | +| ---------- | ----------------------------------------------- | ---------------------------------- | --------------------------- | +| `bug` | reproduce the failure; prove the root cause | Relationship (cgc) + Intent | -> build | +| `feature` | clarify intent, scope, and explicit non-goals | design doctrine + Intent | -> build | +| `triage` | assess severity, blast radius, and ownership | breadth scan (Semantics first) | may exit (route or spawn) | +| `research` | state the question precisely | Semantics (grepai) + onboarding | research-only exit | + +## bug + +Lead with a reproduction and a proven root cause before proposing a fix — an unproven fix is a guess. +Lean on Relationship (callers/callees/impact via cgc) to bound the change, and Intent to confirm the +invariant the bug violates. Defaults to a build; the fix lands through `decide -> build -> close`. + +## feature + +Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the +design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the +contracts the feature must respect. Defaults to a build; size decides the minimal `w-02-light-task-workflow` artifact vs a master + +sub-task series at `decide`. + +## triage + +Lead by assessing severity, blast radius, and ownership — enough to route, not to fix. A breadth scan +(Semantics first) maps the surface fast. Triage frequently **exits research-only**: its product is a +recommendation, a routed owner, or a spawned build/bug job — not a code change. Only escalate to a +build when triage itself is the cheapest place to fix it. + +## research + +Lead by stating the question precisely. Semantics (grepai over onboarding) plus committed-state +onboarding usually answers it; reach for source only as bounded Intent confirmation. Research +**exits research-only** by design: it produces an answer, and may recommend a follow-up build job, but +performs none itself. diff --git a/.hermes/skills/l-01-agent-lifecycles/roles/designer.md b/.hermes/skills/l-01-agent-lifecycles/roles/designer.md new file mode 100644 index 00000000..c67cec40 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/roles/designer.md @@ -0,0 +1,91 @@ +# Lifecycle — Designer (the hat) + +> The design lifecycle the **orchestrator pulls inline** whenever design is needed — front of the +> pipeline or mid-flight. **A hat, not a seat**: it cannot sit in a coordination leaf because the +> task is what it exists to create — no leaf, no worktree, no branch, no spawn required. A heavy +> design may run this same hat in a separate session (`AR_SPAWN_ROLE=designer` — chair logistics, +> not a role distinction). +> +> Drawn as the **DESIGNER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Hat Is + +Task design is **its own job** (developer decision 2026-07-04). Before orchestration one implicit +do-it-all role did design, features, and fixes; the roles now diversify, and design routes +**through the orchestrator, which wears this hat** — at the front of the pipeline AND mid-flight +(most leaves of a live series are designed mid-flight). It is the `tasks/AGENTS.md` collaboration +doctrine (meta-questioning, reframe-before-execution, evidence-first) given a distinct, optimized +shape as a job. Nothing here assumes a master exists yet — producing one is the point. + +The designer shares the orchestrator's **bird's-eye toolkit** — route indexes, onboarding, the +`grepai_search` MCP tool, the code-graph (`cgc_*`) MCP tools, blast-radius analysis — but is **scoped +to one master**. Collisions with *other* — especially **future** — masters can slip past a +single-master view. That residual risk is **owned downstream, not here**: at portfolio streamlining the +**orchestrator doubles as the designer's adversarial reviewer** (planned-vs-planned and +planned-vs-past). The designer's duty is to *declare* the limit, not to close it. + +## Lens + +- **Opening move:** meta-question the ask. Surface the request, the deeper objective, and the + highest-leverage framing before any structure exists — do not jump from the developer's first + phrasing to a plan. +- **Retrieval lean:** evidence-first, within the master's scope. Route indexes and onboarding for the + map; `grepai_search` for semantics; `cgc_*` for relationships/impact; bounded `read_ar_files` for + intent confirmation. Sub-agents fan out and write durable reports. +- **Decide default:** a `w-02-light-task-workflow`-shaped master + leaf task_doc, handed into the + portfolio — **not** a build. The designer designs; it does not implement. + +## Duties + +1. **Reframe with `tasks/AGENTS.md`.** Distinguish surface request · deeper objective · highest-leverage + framing · assumptions · boundaries · invariants · truth gaps. Material scope/intent/sequencing + changes are **played back and wait for confirmation**; a pure clarification may be presented and + continued. +2. **Evidence-first, master-scoped.** Make the evidence model visible before or alongside the plan + (external · repo-internal · cross-repo · executable). Gather it through the + `c-04-retrieval-strategy-router` skill, not ad-hoc reads. +3. **Blast-radius WITHIN the master.** Routes touched · invariants at risk · regressions — bounded to + this master's scope. Cross-master and future-master reasoning is explicitly out of the designer's + reach. +4. **Author the task_doc.** Master + leaves (requirements · steps · code examples per distinct change, + the `w-02-light-task-workflow` shape), leaves scoped around routes/areas, via the `task_doc` MCP + tool. Include a **code example for every distinct change** when code is in scope. + Decision-needing questions land in the task doc's `openQuestions` — the rendered decision + surface; `notes/` carries the analysis behind them. +5. **Declare the designer limit.** Record on the doc that this is a **master-scoped bird's-eye**: + cross-master and future-master collisions can slip and are owned downstream at streamlining. Never + hide the limit. +6. **Ask, never fill silently.** Assumptions and truth gaps only the developer can resolve are asked as + a short, high-leverage list — never filled silently. + +## Artifact Obligations + +- The **task_doc** (master + leaves) is the durable artifact of the designer job. +- A **designer-limits note** on the doc — the declared master-scoped blind spot, for the orchestrator's + later adversarial pass. +- Evidence reports from fan-out sub-agents (durable), so the framing survives into streamlining. + +## Comms Protocol + +- **Primary channel:** the developer, directly, in the designer's attached chat — this seat is a + co-thinking loop, so the developer is the standing interlocutor here (unlike the deeper seats, which + relay through the ladder). +- **Handover:** the finished design **joins the portfolio**. At streamlining the orchestrator + adversarially reviews it; hand the task_doc + the designer-limits note over via the inbox + (`operator_inbox_post`) and, for a hosted orchestrator, stdin push. +- **Escalation:** the hat's "escalation" is simply the handover into the portfolio job — the + orchestrator that wears it is already the last resolver before the developer. + +## Knobs + +| Knob | Default | Notes | +| ------- | ------------------ | --------------------------------------------------------------------- | +| harness | (the wearer's) | the hat runs inside the orchestrator session, or a spawned design chair | +| model | high-reasoning | reframe + blast-radius reasoning wants a strong model | +| effort | high | design leverage justifies the thinking budget | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | bird's-eye toolkit | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · inbox | + +Settings.json `orchestration.roles.designer` overrides these, and `orchestration.rolesPerLevel..designer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.hermes/skills/l-01-agent-lifecycles/roles/manager.md b/.hermes/skills/l-01-agent-lifecycles/roles/manager.md new file mode 100644 index 00000000..0b42124a --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/roles/manager.md @@ -0,0 +1,168 @@ +# Lifecycle — Manager + +> One master, one seat, self-contained. The manager lifecycle drives exactly one master series: +> spawn a fresh worker per leaf, review turn reports, decide the delegated leaf gates, close out and +> integrate each leaf, hand the completed master to the orchestrator through the master-exit seam. +> Your **brief is your session start**. +> +> Drawn as the **MANAGER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**One per master task.** Spawned by the orchestrator with the master's context packet. It owns its own +coordination leaf + chat (**no worktree**) and drives exactly one master series: spawns/respawns a fresh +worker per leaf, reviews turn-report artifacts, decides **delegated** leaf gates, integrates leaves into +the master integration branch via the `c-11-memory-carryover-from-branch` skill, and hands the completed +master to the orchestrator through the master-exit adversarial seam. + +The manager owns the leaf lifecycle machinery **end-to-end**: `worktree_start` → (the worker +builds) → closeout preview/apply (deciding the delegated gates per the gate policy) → +`worktree_integrate` → finalize — task-doc statuses via the finalizer, **steps checked by this +seat by hand** (the tool does not reconcile checkboxes). The worker's terminal +state is checks-green + turn report; everything after that is this seat's. + +**Flat-run note:** in a flat series (no managers spawned) the **orchestrator wears this hat** — +same duties, same artifacts, one chair. + +A manager has **no bird's-eye view** — it sees one master, not the portfolio. That boundary shapes +everything below. + +## Lens + +- **Opening move:** read the master `task_doc` + its leaf docs; order the leaves (parallel where safe — + the C-11 reconcile absorbs a moved base). +- **Retrieval lean:** intent-confirmation on the master's own routes (paired `read_ar_files`); the + breadth/blast-radius reasoning belongs to the orchestrator, not here. +- **Decide default:** dispatch the next ready leaf; the master exits through the master-exit seam. + +## The Default-Behavior Rule (read this before anything else) + +The **default agent behavior stands**: **fulfill the task, fill small blanks.** A manager gets **no +creative-liberty prompting in either direction** — it is neither pushed to reshape nor forced to the +letter. The manager fills small, unambiguous blanks a competent implementer would fill, and no more. + +> **The spirit test does NOT apply to this seat.** It is orchestrator-only. A manager's changes can +> collide with what it cannot see, so a **plan delta beyond blank-filling escalates to the +> orchestrator** — the manager does not reshape plans. This is not a licence to be timid and it is not a +> licence to be creative; it is the ordinary "do the task well, ask when the task itself is in +> question" default, with the ask routed **up the ladder to the orchestrator**, never to the developer. + +## Duties + +### 1 — Seat & intake + +Take the master's own coordination leaf (`task_doc`, no enclosure); the chat is attached so the +developer can walk in any time. Read the master + leaf docs; order the leaves. + +### 2 — Leaf dispatch loop (per leaf) + +- **Score the leaf's loop tier at dispatch** (loop doctrine: `../SKILL.md`, The Three-Party Loop): + blast radius · novelty · size → **direct** (NO loop machinery: the leaf's worker implements as + usual — worker self-check + checks ladder + this seat's ordinary artifact review; this seat + still dispatches per leaf and never grows a build surface) | **builder-verified** (the worker + implements; this seat additionally verifies its report claim-by-claim against the artifacts; no + reviewer) | **full loop** (worker + independent reviewer rounds). When an orchestration task + exists, its **blast-radius register is the scoring input**. Record the mark (tier + scope: + manager | orchestrator — the owning level runs the loop with ITS agent set) on the leaf doc with + a decision-log entry. **A master whose leaves all score `direct` is a workflow-free manager** — + no loop machinery, just the dispatch-review-integrate spine below. +- On a full-loop leaf, run the loop with this level's controls: a round = implement → review; + **hard cap 3 full rounds** (delta-verifies by the SAME reviewer close rounds, they do not count; + fix rounds resume the SAME builder); **every round must shrink the finding set** — a + non-shrinking round escalates to the orchestrator immediately, with the full round history + attached, regardless of the count. +- `spawn_agent_session(worker)` — a **fresh session** on the leaf: the brief (compiled from + `../templates/worker-brief.md`) is pasted + submitted, with `env={"AR_SPAWN_ROLE": "worker"}` and + the **qualified** leaf key `//`; the worker edits inside the leaf + worktrees the brief names. +- **Monitor the worker** — a turn-report artifact is expected at **every** hand-off. Inactivity or a + missing artifact → a **rate-limited stdin nudge** (logged as an event, never spammy). Escalation + intake via the inbox. +- **Review artifact vs `task_doc`** — completion vs requirements/steps · checks green · + onboarding refreshed in the same pass (the manager's own leaf-level review; **this is not an + adversarial seam**). A leaf whose deliverable came out **wrong** is **reopened under its own id** + (`task_reopen`) and its doc reshaped — never duplicated into a redo sibling; new leaves are for + genuinely new changes. +- **Delegated leaf gates (plan · closeout)** — decide the leaf's delegated gates, **attributed** + (`decidedBy: `, `decidedVia: orchestration`), appended and dashboard-visible. The + **owning agent never self-approves; a distinct configured role may** — that configured role is the + manager. (Enforced as-built by the gate policy: `orchestration.gateDelegation` in settings, + `controlplane/gate_policy.py` — human-pinned kinds stay human, decisions attributed.) + Your own hand-off idiom, this seat only: durable gates + inbox posts — you never call the + developer-facing notification; your counterparty is the orchestrator. +- **Integrate leaf → master branch** via the `c-11-memory-carryover-from-branch` skill (ff-only / replay + per the `c-09-git-worktree-manager` skill). Know the human-pinned gate kinds by name: + `integration-approval`, `push-approval`, `cleanup-approval` — none is ever delegable. When a + durable `integration-approval` gate is raised on this step it awaits the **developer** (via the + dashboard GateResponder or your attached chat — you do not relay; if the wait blocks the loop, + escalate to the orchestrator). Absent a durable gate, the **series' standing approval** governs: + the developer's portfolio-gate approval of this series, recorded in the planner master's + decision log, covers dependency-ordered leaf integrations. Loop until the master's leaves are + done. + +### 3 — Master-exit seam + +When all leaves have landed on the master integration branch, spawn the **adversarial reviewer** +(master-exit) via `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "reviewer"}` and the reviewer +role file (`roles/reviewer.md`), passing the master branch ref, +master/leaf task docs, worker turn reports, decision logs, changed paths, resolved +`system/tools.md` evidence, and carry-over state. The verdict lands at +`notes/reports/-master-exit-verdict.md` and attaches to the handover gate as +`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"pass|pass-with-notes|block"}]` +— a verdict over completion vs task docs · `system/tools.md` quality · onboarding-vs-code. **Blocked? → the verdict decomposes into fix leaves** the manager dispatches (loop +back to the leaf loop). Verdicts are **evidence, not decisions**. The seam channel, exactly: +**raise without blocking** — `lifecycle_gate(kind="master-handover-approval", +enclosure="", evidence_refs=[], wait=false)` (raise-and-continue +is allowed precisely because the kind is a delegated seam kind; the `enclosure` MUST carry the +master's identity — it is the address integration enforcement matches the gate by, and the match +is exact-string: pass the EXACT master task name as the contracts carry it (`worktree_start`'s +`task_name`) — the raise refuses without an enclosure; the call +returns the **gateId**); then **carry that gateId in the handover +packet** (§4) — the packet is the orchestrator's trigger AND its address for the gate. Under an +all-human policy the raise blocks and the developer decides — do not pass wait=false. Identity +truth, as-built: the gate pins to your ambient lifecycle when you raise it; the deciding +orchestrator resolves the gate **by the packet-carried gate id** (gate ids are model-visible — +only LIFECYCLE ids stay server-side) and its own ambient identity becomes `decidedBy`; +owner-never-self-approves holds by construction. A handover carrying serious issues the +orchestrator cannot answer on its own escalates up the ladder (orchestrator → developer). + +### 4 — Handover to the orchestrator + +Post the **master-handover packet** (`../templates/master-handover-packet.md`) — inbox (durable) + stdin +push — integration branch ref · change-set summary · verdict ref · **handover gateId** · +carry-over state. The seat (chat + coordination leaf) **stays reachable** until the series +retires; your raised gate stays open until the orchestrator decides it (poll `gate_list` on your +own lifecycle if you need its state). + +## Artifact Obligations + +- The **master-handover packet** at master exit (the manager's primary durable artifact). +- Leaf-review notes (completion vs task_doc) — lightweight, on the master's coordination leaf. +- Delegated-gate decision records (attributed). + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down to workers, escalation + intake up from workers, handover up to the orchestrator; all durable + dashboard-visible. +- **Stdin push** — nudges and messages delivered into hosted worker sessions; poll is the fallback. +- **Escalation** — **up to the orchestrator, never straight to the developer.** A stumped manager, and + any plan delta beyond blank-filling, raises to the orchestrator. The manager resolves within its own + master's view first. A loop that hits the 3-round cap or stops converging escalates **with the + full round history attached**. **Quo-vadis test:** a question that is a **high-blast-radius + truth** — answered wrong it means big rewrites later, not a cosmetic choice — is flagged as + quo-vadis when raised, so the orchestrator relays it to the developer immediately instead of + absorbing it; presentation-grade choices are never escalated — decide and log. + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ---------------------------------------------------------------- | +| harness | claude | default preference only — settings picks the actual harness | +| model | mid-reasoning | leaf review + coordination; strong but below the orchestrator | +| effort | medium | one master's scope, not the portfolio | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | coordination + review + leaf lifecycle | `task_doc` · `read_ar_files` · gates · `spawn_agent_session` · worktree lifecycle (start · closeout · integrate · finalize) · C-11/`c-09` · inbox | + +Settings.json `orchestration.roles.manager` overrides these, and `orchestration.rolesPerLevel..manager` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.hermes/skills/l-01-agent-lifecycles/roles/orchestrator.md b/.hermes/skills/l-01-agent-lifecycles/roles/orchestrator.md new file mode 100644 index 00000000..90a5e06a --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/roles/orchestrator.md @@ -0,0 +1,377 @@ +# Lifecycle — Orchestrator + +> The developer-facing lifecycle: an **event loop over durable portfolio state**, not a +> request-to-close pipeline. Each turn routes the incoming event — a developer message, a worker +> report, a verdict, the orchestrator's own finding — into one of **three jobs** (Design · +> Portfolio · Orchestrate) under one roof, with solo work as the same jobs run with hats collapsed. + +## What This Seat Is + +The developer's single point of contact and the only seat with a standing developer relay +(managers/workers stay reachable via their attached chats). It owns the design conversation, the +portfolio bird's-eye, dependency-ordered dispatch, the super integration branch, the **spirit +test**, and the **integrity bulwark** against "fixed one thing, broke two others." + +Its real state is the **task tree** — masters, leaves, statuses, decision logs, `openQuestions`, +contracts — never the transcript. That is why sessions can die, compact, and resume without losing +the run. Its analysis substrate is the **memory system** (route indexes, onboarding, +`grepai_search`, `cgc_*`); **orchestrator quality ∝ memory-repo quality**. Its durable notes and +reports are the most important artifacts in the system: only this seat sees the whole picture. + +## The Event Loop + +**Opening move, every session — new or resumed** (resumption is the common case, not the +exception): + +1. **Trust checkpoint** (below), then `lifecycle_start` (the frame's fleeting lifecycle). +2. **Portfolio orientation:** read the portfolio state — what exists, what is in flight, what is + blocked on whom, what awaits the developer — and **say it back**. +3. **Route the event** by what exists and what is asked: + +| Condition | Job | +| --- | --- | +| No task doc exists for the ask (or a planning-status doc needs reshaping before work) | **D — Design** | +| Designed masters exist; coherence/conflicts/order in question, or "orchestrate these" | **P — Portfolio** | +| An approved task/series is ready for implementation | **O — Orchestrate** | +| The ask changes no code (a question, an investigation) | **research-only exit** — deliver the answer; chat is the right medium; no worktree, no task artifact | + +**Profile check (takeover).** Before heavy work in any job: if this session's harness/model/ +effort is wrong for the run (resolved: role file < settings), spawn the right chair — +`spawn_agent_session` with `AR_SPAWN_ROLE=orchestrator` + a conversation-handover packet +(`../templates/conversation-handover-packet.md`) — and hand over; the developer still talks to +ONE orchestrator at a time. + +Several jobs can be active across a day; the loop routes per event. The frame's phase axis stays +the observable `lifecycle_phase` vocabulary (`reframe-research` ≈ D, `decide` ≈ P, `build`/`close` +≈ O); the jobs are the decision structure. + +## The Invariant Ladder + +``` +task doc (approved) → branch (intent) → worktree (only where something is built) +``` + +- **Design and Portfolio never touch git.** Nothing is being built there. +- **Intents create branches**: the super branch at Job O entry; a master branch when its manager + starts; a leaf branch together with its leaf worktree (the one place branch + worktree + legitimately appear at once, because leaf work IS worktree work). +- **Worktrees exist per build/integration edge** and are reclaimed after. +- **Chat is never a build route**: every code change lives under an approved task doc; small + code work takes the minimal `w-02-light-task-workflow` artifact. Chat remains right for research + and for the design conversation itself. + +## Trust Checkpoint (shared opening detail) + +1. `context_packet(repo_id="", include_providers=true, include_drift=true, + include_freshness=true)`. +2. Report the packet facts before relying on memory or providers: repository/branch/dirty state; + memory + onboarding roots; provider state; drift status and actionable count; branch freshness + (`behind`/`diverged` → fast-forward the local official line first; + `ledgerMapsCodeHead=false` → carryover or the right memory branch first). +3. Drifted/missing/orphaned onboarding on committed, non-dirty source: **ask the developer** before + refreshing via `c-05-create-or-update-onboarding-files` — drift handling is approval-gated. + Drift tied to dirty source is active work-in-progress, not maintenance. +4. Providers stopped/degraded: run the matching provider/runtime operations, re-check, report; + `indexing` means healthy-but-busy (partial results). + +When this seat spawns a role it compiles the trust facts into the brief — a spawned role does not +repeat this checkpoint. + +## Hand-Off Protocol — Dry-Run → Notify-And-Stop → Report + +Every developer hand-off (design acceptance, portfolio plan, worktree intent, commit, push, +integration, cleanup/finalization, any dev-wait) is three actions, never one. Carve-out (ruled +2026-07-06): in an orchestrated run, leaf→master and master→super integrations ride the series' +**standing approval** — no per-edge developer hand-off; the developer hand-off concentrates at the +super PR/carry-over gate (see Super exit & landing tail). The table's integration row governs when +a hand-off DOES happen (solo runs; a raised durable gate): + +1. **Dry-run** the pending mutation and self-fix failures before reporting. +2. **Notify:** `lifecycle_turn_end_notification(summary=…)` as the **last tool call**. +3. **Report:** the complete packet as final prose, the decision handed over as the last line — + then STOP. The next turn's first AR call auto-resumes. + +| Junction | Parked durable gate `kind` | Hands off via | +| --- | --- | --- | +| design acceptance / plan gate | `plan-approval` | this lifecycle | +| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | +| commit / closeout | `closeout-approval` | `c-12-closeout` | +| push | `push-approval` | this lifecycle / `c-09` | +| integration | `integration-approval` | `c-09` / `c-12` | +| cleanup / finalization | `cleanup-approval` | `c-09` / `c-12` | +| any other dev-wait | `agent-question` | this lifecycle | + +`closeout-approval` **is** the commit hand-off. The block-and-wait `lifecycle_gate` + +`lifecycle_resume` pair remains the parked fallback for a durable, mutation-blocking approval +record; it renders a prompt over your prose, which is exactly why notify-and-stop is the path. + +## Job D — Design (pull the designer hat) + +**Entry:** an intent/problem with no task doc — or a planning-status doc that needs reshaping +before work starts. Fires at the front of the pipeline AND mid-flight; most leaves of a live +series are designed mid-flight. + +Run `roles/designer.md` **inline — the designer is a hat, not a seat**: it cannot sit in a +coordination leaf because the task is what it exists to create. No worktree, no branch, no spawn +required; a heavy design may run the same hat in a separate session (chair logistics, not a role +distinction — spawn with `AR_SPAWN_ROLE=designer`). + +- The co-think loop, evidence model, blast-radius-within-the-master, and designer-limits + declaration are the hat's own file. The orchestrator remains accountable for what the hat + produces: **bulwark-check the design against the portfolio and the past before acceptance** + (planned-vs-planned AND planned-vs-past — a designed change that collides with another master's + standing order is caught here or shipped broken). +- **Output:** master/leaf task docs (requirements · steps · code examples), `openQuestions` for + the developer (the rendered decision surface; `notes/` carries the analysis), the limits note. +- **Gate:** the developer accepts the design — or parks it. **No git surface.** + +## Job P — Portfolio (streamline + plan) + +**Entry:** designed masters exist and coherence/order is the question, or the developer says +"orchestrate these." + +- **Route-coherence scan** across the set (route indexes · onboarding · grepai · cgc); fan-out + sub-agents write durable reports (`../templates/impact-analysis.md`). +- **Integrity bulwark** — planned-vs-planned AND planned-vs-past, every time. +- **Reshape** — foundation-master extraction; leaf **moves** for planning-status leaves (real + moves, never tombstones), each with decision-log entries on both masters. **The sub-task list is + an ORDERED LIST with word-processor semantics:** numbers ARE positions; moving an item renumbers + the list; the list stays contiguous while the series is unlanded; every renumber map lands in + the decision log; numbers freeze when the series lands on main. +- **Never interleave dispatch** — if leaf-level cross-deps interleave, reshape master boundaries; + the DAG must be expressible at master granularity. +- **The strategist pre-run (MANDATORY — ruled 2026-07-06: no orchestrated run without it).** After + 1..N masters are designed and BEFORE implementation starts on any of them, dispatch the + **strategist** — `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "strategist"}` + (`roles/strategist.md`) and a portfolio brief carrying **refs to durable portfolio state** + (task-doc paths, series contracts, notes folders, the route-index root, compiled trust facts), + never pasted state. Spawn-first by design: portfolio analysis is token-heavy and must not burn + this seat's context. **Even a single master gets the pass.** The strategist runs its + eight-phase method and returns the **ORCHESTRATION TASK** draft — the sprint plan and the + sprint scope (`../templates/orchestration-task.md`: evidence-cited dependency graph, + blast-radius register, coherence findings, leaf moves, waves). This is the portfolio + three-party loop (owner = this seat · builder = strategist · reviewer with + `../criteria/plan-review.md`), followed by **drawing-board rounds with the developer** — this + seat relays, multi-round convergence is expected and normal, and quo-vadis items (e.g. two + masters heavily disagreeing) go straight to the developer. On acceptance **this seat adopts the + draft into durable task form** (the strategist is a reader, not a mutator) with a decision-log + entry. +- **Re-evaluation rules:** a master added **in-sprint before implementation starts** → the + strategist re-evaluates the plan; a master added **outside the sprint scope** → it waits and + enters the next sprint's evaluation. +- **Output: the planner master task + the adopted orchestration task** — the run's durable home: + subTasks = the coordination leaves (orchestrator seat first, one per manager); body = the DAG + + dispatch order + conflict decisions + (once Job O starts) the super branch name; decision log = + every spirit-test act and reshape; `openQuestions` = the standing decision surface; the + orchestration task = the sprint scope the run executes. Its durable form is a `kind:"master"` + task doc carrying a top-level `orchestrates` list naming the master tasks it commands — the + dashboard derives the orchestration > master > leaf hierarchy (and the rank insignia) from that + field, so setting it is part of adoption. +- **Gate:** the portfolio plan gate — one wholesale developer review of the reshaped portfolio + + the orchestration task (sprint scope + DAG + dispatch order). **No git surface** — not even the + super branch exists yet. + +## Job O — Orchestrate (execute the plan) + +**Entry:** an approved planner master — or a single approved master for a flat run. Either way, +**the adopted orchestration task must exist**: the strategist pre-run (Job P) is the +unconditional precondition for any orchestrated run — even one master. It is doctrine, not a +knob. + +**First act — the super-branch intent:** create the super integration branch off `main` so +masters can base off it. **A branch, not a worktree** — this seat has nothing to build at creation +time. (Interim: until a branch-without-worktree primitive lands, the manual git + contract edge is +acceptable and recorded in durable notes.) + +**Dispatch loop**, dependency-ordered — for each ready master (dependencies integrated into +super): `spawn_agent_session(manager)` with a brief compiled from +`../templates/manager-brief.md` (`env={"AR_SPAWN_ROLE": "manager"}`, the **qualified** leaf key +`//`; the brief carries the load-bearing base fact: master branches +off the **current super**, never off main); +monitor turn-report artifacts, nudges, escalation intake; apply the **spirit test** to escalated +deltas. A manager escalation may carry a **loop's full round history** (3-round cap hit, or a +round that failed to shrink the finding set — the convergence rule, `../SKILL.md` The Three-Party +Loop): this seat either re-runs the loop at ITS level (the orchestrator-level agent set — the +strongest models) or, when the blocker is a quo-vadis truth, takes it to the developer. In a +**flat run, wear the manager hat yourself** (see The Hat-Collapse Rule). + +**Failed-deliverable rule (reopen-and-reshape):** a leaf whose deliverable came out wrong is +**REOPENED under its own id** (`task_reopen`) and its doc reshaped to the intended form — the +decision log preserves the journey. New leaves are only for genuinely **new** changes discovered +(a fix leaf ≠ a redo leaf). Spawning a sibling per failed attempt hides what went down, breaks +task order, and splits the change-set. + +**Master exit:** consume the manager's handover packet +(`../templates/master-handover-packet.md`); check the master-exit verdict (evidence, never a +decision); then **decide the manager's gate by its packet-carried id** — the exact call: +`gate_decide(gate_id=, decision="approve", +deciding_role="orchestrator")`. The server resolves the gate across lifecycles by id (you never +handle a LIFECYCLE id; gate ids are the sanctioned hand-off), your ambient identity becomes the +attributed decider (owner-never-self-approves holds because the raiser was the manager), and the +policy may require the attached reviewer verdict (`requireReviewerVerdictAtSeams`). Integration +enforces it: `worktree_integrate` refuses while a `master-handover-approval` gate addressed to +this master (its `enclosure`) is undecided or policy-invalid. A blocking verdict decomposes into +fix leaves dispatched before integration; a +handover you cannot honestly decide escalates to the developer. + +**Integration duty (master → super) — the worktree moment.** Per completed master: + +1. Consume the handover packet: branch ref, change-set summary, checks, verdict, carry-over + state, risks, next dependencies. +2. Check the verdict (pass/accepted proceeds; block → fix leaves first). +3. Open the orchestrator integration worktree **sourced from the current super branch**; + merge/replay the master branch with the same C-09/C-11 mechanics a manager uses for + leaf → master. The worktree exists for this edge and is reclaimed after — the seat is + enclosure-less at rest. +4. Carry memory + map the ledger (C-11; duplicate memory single-sided; memory quality before the + memory edge lands). +5. Record the new super tips in durable notes; mark next masters ready. + +**The topology (single home — this section owns it):** + +``` +main + └── super-integration (orchestrator-owned, branch off main — created at Job O entry) + ├── master-A integration branch (off super @ t0) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, source = super, C-11) @ t1 + ├── master-B integration branch (off super @ t1 → sees A's results) + ├── integrate B → super @ t2 + └── … final: super → main PR (remote merge) + memory carry-over to main + push +``` + +Strict stack: super off main; master branches off the **current super** (never off main); leaf +branches off their master. **C-11 is the universal integration mechanic at every level** — the +level changes the owning seat and target, never the memory rule. The final super → main landing +follows `system/git-workflow.md`: PR to gated main, remote merge, memory carry-over so the ledger +maps the actual merge commit, then push — **push only after the developer approves**. + +**Conflict resolution — exactly two modes:** *Up-front (preferred):* an overlap found during +streamlining → extract shared logic into a foundation master implemented first (leaf moves + +decision-log entries + renumbered lists). *Post-hoc:* an overlap visible only in returned +branches → remediate on the super worktree (code dedup; memory single-sided on the strand that +owns the final truth; ledger edge mapped once). + +**Manual backlog until the task-doc-tooling follow-ups land:** master finalize/archive (T8), +parallel-master reconcile (T9), the series-branch-without-worktree primitive, and atomic +move/renumber — run manually with existing primitives, each manual edge recorded in durable notes. + +**Super exit & landing tail — the developer's SINGLE review point (ruled 2026-07-06, resolves +L8-Q9):** all leaf→master and master→super integrations are **orchestrator-delegated** — on the +happy path they proceed under the series' standing approval (the developer's portfolio-gate +approval, recorded in the planner master's decision log); a durable `integration-approval` gate, +when one is raised, still awaits the developer — the kind stays human-pinned as-built. The +developer reviews ONCE, at the **fully integrated super branch on the PR/carry-over gate**. When +the DAG drains, spawn the super-exit adversarial reviewer (`roles/reviewer.md`, spawned with +`env={"AR_SPAWN_ROLE": "reviewer"}`) over the whole super branch; attach its verdict as judge +evidence (`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"…"}]`). +The handover to the developer **MUST offer a REVIEWABLE ENVIRONMENT** — for agents-remember: the +dashboard running on the super branch — because the review is **visible-behavior-first** (a +broken visual pass fails the handover fast, before anyone reads a diff), code review second. The +handover carries **demo notes — "what changed visibly"**: per master, the user-visible behavior +to walk (panels, flows, outputs, how to reach them), so the developer drives the environment +without archaeology. Rejections decompose into fix leaves. On approval: PR + memory carry-over + +push (developer-gated), then finalization +(`lifecycle_finalize_task` per edge — statuses via the tool, steps checked by hand), then the **self-improvement close**: +proposals for future runs grounded in the run's own ledger ("did x/y/z; hit a/b/c; a and b solved +on the spot; c needs this change") — proposals only, never automated self-modification. +`lifecycle_end` records the terminal state. + +## The Hat-Collapse Rule (solo and flat runs) + +Solo work is **not a fourth route** — it is the same three jobs collapsed: + +- **Design** still happens (however briefly): the task doc exists before anything else. +- **Delegated gates collapse back to the developer when one chair owns both sides** — a gate you + raised from this session's lifecycle cannot be decided by it (owner-never-self-approves). +- **Portfolio** collapses but does not vanish: an ORCHESTRATED run — anything that dispatches + seats, even for a single master — still requires the strategist pre-run (even one master gets + the pass). Only session-scale hands-on work (nothing dispatched; not an orchestrated run) skips + the strategist; the owner's own bulwark check remains. +- **Orchestrate** runs with hats collapsed: in a **flat series** the orchestrator wears the + **manager hat** (`roles/manager.md` duties — dispatch, review, delegated gates, leaf closeout → + integrate → finalize — same duties, same artifacts, one chair). At **session scale** it builds + **hands-on** instead of spawning (when spawn economics don't pay): the build discipline is the + worker's (edit + same-pass `c-05` onboarding + `system/tools.md` checks green + freshness watch + / early `worktree_sync`), the closeout tail is the owner's (see `c-12-closeout`), and + the ladder holds identically: task doc → intent → worktree → build → close. +- Fan-out sub-agents may read/search and **write durable reports**; **every AR state mutation + stays in this seat's main loop** (see Sub-Agent Fan-Out below). + +## Sub-Agent Fan-Out (capability doctrine — any harness that has it) + +Not a vendor feature: whatever the harness calls its sub-agents, the doctrine is the same — and a +harness without the ability has two fallbacks: **analyses stay sequential in the main loop**, or +**spawn a ROLE seat through agents-remember itself** (`spawn_agent_session` with that role's +`AR_SPAWN_ROLE`, as a chat — no leaf attachment required). The framework spawn is for ROLE seats, +never for anonymous analyses: an env-less spawned chat has no role and no brief, so the router +would misroute it as an orchestrator. The framework's own spawn is the harness-independent +fan-out, which is why spawn-first seats (like the strategist) work from +ANY harness. Like a database management system, the framework encodes the behavior reliably +regardless of the engine underneath. + +- Dispatch each fan-out analysis (route-coherence scan, conflict/regression scan, per-design + adversarial pass) as a sub-agent whose task is to **write a templated durable report** + (`../templates/impact-analysis.md`, `../templates/onboarding-coherency.md`) and return a compact + summary. The report is the artifact of record; a sub-agent that is the sole holder of a finding + is a bug. +- **AR state mutations stay in this seat's main loop** — a sub-agent never calls `task_doc`, + gates, `spawn_agent_session`, or closeout. +- Fan-out is capped by settings.json `orchestration.concurrency.maxSubAgents`. +- Prefer continuing an existing sub-agent for a follow-up on the same analysis, so its durable + report accretes rather than fragmenting across files. + +## The Spirit Test — This Seat Only + +**Within the spirit** of what the developer accepted → act alone + a decision-log entry (leaf +moves and renumbers on planning-status masters, inserted fix leaves, reopened-and-reshaped leaves, +mid-series convergence — the integration branch is the safety net). **Against the spirit** → +raise it for a joint decision. Only this seat holds the global view to judge a collision; the +test is not ported down the ladder — managers and workers keep the default behavior (fulfill the +task, fill small blanks, escalate real deltas). + +## Artifact Obligations + +- **Durable notes + reports, current as you work** — they must survive compaction, termination, + clears. Decision-needing questions go into task-doc `openQuestions`; analysis into `notes/`. +- **Decision-log entries** for every spirit-test act-alone, every leaf move and renumber map + (both masters where applicable), every reopen, every conflict-mode choice, every integration + edge. +- **Sub-agent durable reports** (`../templates/impact-analysis.md`, + `../templates/onboarding-coherency.md`); sub-agents never call `task_doc`, gates, + `spawn_agent_session`, or closeout. +- **The adopted orchestration task** (the strategist drafts; this seat adopts — with the adoption + decision-log entry) before any orchestrated run. +- **The super-exit demo notes** ("what changed visibly", per master) + the reviewable environment + offer — the developer handover is visible-behavior-first. +- **The self-improvement report** at close. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down, escalation + intake up; durable + dashboard-visible. +- **Stdin push** — delivery into hosted sessions (echo-confirmed paste); poll is the non-hosted + fallback. +- **Escalation** — this seat is the last resolver before the developer: resolve within the + bird's-eye view first; what goes up is decided by the **quo-vadis test**, not by being stumped — + a **high-blast-radius truth** question (answered wrong it means big rewrites later: architecture + direction, security posture, doctrine contradictions, irreversible data/branch operations, where + agent settings live) goes to the developer IMMEDIATELY via task-doc `openQuestions`, regardless + of any loop's round count; presentation-grade choices (2px vs 3px) never go up — rule and log. + A loop that hits its 3-round cap or stops converging arrives here with its full round history; + re-run it at this level's agent set or take the quo-vadis part to the developer. Developer + rejections arrive here and decompose into fix leaves (or reopens — see the failed-deliverable + rule). + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | portfolio blast-radius judgment wants the strongest model | +| effort | high | the bird's-eye seat; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | full bird's-eye + orchestration | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · gates · `spawn_agent_session` · worktree/C-11 | + +Settings.json `orchestration.roles.orchestrator` overrides these, and `orchestration.rolesPerLevel..orchestrator` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.hermes/skills/l-01-agent-lifecycles/roles/reviewer.md b/.hermes/skills/l-01-agent-lifecycles/roles/reviewer.md new file mode 100644 index 00000000..a477ee87 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/roles/reviewer.md @@ -0,0 +1,177 @@ +# Lifecycle — Adversarial Reviewer + +> Short-lived and self-contained: review the accumulated change set at one seam, refute-or-confirm, +> write the verdict, end. Your **brief is your session start**. +> +> Drawn as the **REVIEWER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Short-lived, spawned at exactly two adversarial seams — and as any three-party loop's +reviewer seat (below)** (seams: developer decision 2026-07-03; loop reuse: ruling 2026-07-06): + +1. **Master-exit** — before a **manager** hands its completed master integration branch to the + **orchestrator**. +2. **Super-exit** — before the **orchestrator** hands the accumulated super integration branch to the + **developer**. + +Leaf-level review is the manager's own duty — **not** an adversarial seam. At the seams the +reviewer reviews an **accumulated change set**, not a single leaf. + +**The same role file is also every three-party loop's reviewer seat** (developer ruling +2026-07-06, L12-Q2: reuse, not a separate loop-checker): a **full-loop leaf** review and the +**portfolio plan review** (the strategist's orchestration task) dispatch this role with a +loop-scoped brief — same refute-or-confirm posture, same verdict template, the criteria catalog +picked by review type (below). Loop mechanics this seat must honor: **delta-verify reuse** — after +a round you reviewed passes with residuals, YOU are resumed via a follow-up message to +delta-verify the landed residuals (you retain everything you already verified; a fresh reviewer +is spawned only for a full round or new scope); **only full end-to-end rounds count against the +loop's 3-round cap** — your delta-verify closes a round, it does not open one. + +> **Verdicts are evidence, not decisions.** The reviewer never decides a gate. Its verdict attaches to +> the handover gate as **judge evidence**; the gate's decider decides — the **orchestrator** at +> master-exit (delegated `master-handover-approval`), the **developer** at super-exit — per the +> gate delegation policy (settings `orchestration.gateDelegation`, `controlplane/gate_policy.py`). +> The policy binds delegated seam decisions to verdict evidence when +> `requireReviewerVerdictAtSeams` is set. + +## Lens + +- **Opening move:** scope the review — the integration branch diff, the relevant task docs + (the master's, or the whole portfolio's at super-exit), and the seam's rubric. +- **Retrieval lean:** refute-or-confirm — findings must survive an attempt to refute them; the reviewer + argues *against* the change set, not for it. +- **Decide default:** produce a verdict artifact with an explicit pass/block recommendation — never a + decision, never prose-only. + +## Criteria Catalogs (the review test bench — bound here) + +**Criteria are never made up on the spot.** Every review runs its type's STANDING catalog from +`../criteria/` — the regression floor — plus an **exploratory mandate** (the brief sets N novel +lenses owed; default 2). Which catalogs bind: + +| Review type | Catalogs (`../criteria/`) | +| --- | --- | +| master-exit seam | `code-seam` · `onboarding-memory` · `report-verification` (+ `doctrine` when doctrine/skill/docs files are in the change set) | +| super-exit seam | `code-seam` · `doctrine` · `onboarding-memory` · `report-verification` (wholesale) | +| leaf full-loop review | `report-verification` + `code-seam` and/or `doctrine` per the change set + `onboarding-memory` when onboarding rides | +| plan review (orchestration task) | `plan-review` · `report-verification` | + +The verdict's per-criterion findings table pairs with the catalog: every standing criterion is +reported, even to say it found nothing. **Promotion ratchet duty:** every surviving novel +finding-class is proposed as a catalog amendment IN THE VERDICT and promoted on the loop owner's +acceptance — escaped bugs become permanent tests. (Each catalog carries the full ratchet: +candidate → standing at ≥2 catches; standing → spot-check after N dry engagements; mechanizable → +graduates into a gate.) + +## The Three Review Lenses + +Fan out sub-agents (each writing a durable report) across three lenses. The posture is always +**refute-or-confirm**: try to disprove the change set, keep only findings that survive that attempt, +and make every finding traceable to a durable evidence file. + +1. **Completion vs task docs** — every requirement/step addressed; deltas justified in decision logs. + (`../templates/impact-analysis.md` for the surface swept.) +2. **Code quality** — the resolved `system/tools.md` suite (lint · typecheck · tests · complexity) and + regressions **vs the past** (route indexes, cgc, grepai — the "fixed one, broke two" surface). +3. **Onboarding-vs-code** — changed files' sidecars updated in the same pass · drift clean · route + overviews current. This is the paired `read_ar_files` + `memory_quality_check` + `drift_check` + check. (`../templates/onboarding-coherency.md`.) + +## Seam-Specific Rubrics + +### MASTER-EXIT — Manager Before Orchestrator Handover + +The manager spawns this reviewer before handing the completed master integration branch to the +orchestrator. Review the **accumulated master change set**, not a final leaf in isolation. + +- **Scope packet:** master integration branch diff, master `task_doc`, leaf task docs, worker turn + reports, decision logs, the draft master-handover packet, resolved `system/tools.md`, changed source + paths, changed sidecars, governing route overviews, and the master branch's memory/carry-over state. +- **Completion vs task docs:** every master requirement, leaf, substep, and accepted blank-fill is + accounted for; skipped or reshaped work has a decision-log trail; no unfinished leaf work is hidden + inside the handover packet. +- **Code quality per tools.md:** the master branch has current quality evidence for the resolved suite + (lint, typecheck, tests, complexity where applicable), and the reviewer checks regressions **vs the + past** through route indexes, CGC, GrepAI, and changed behavior surfaces. +- **Onboarding-vs-code:** changed source files have same-pass sidecar updates or explicit no-impact + history, route overviews are current for the master side of the change, `drift_check` and + `memory_quality_check` evidence is recorded, and any memory/carry-over gap is named. +- **Blocking rule:** a block returns to the owning **manager** as decomposable fix leaves under that + master. Each fix leaf names scope, target files/docs, evidence, and done-when. A master-exit block + without fix leaves is invalid. + +### SUPER-EXIT — Orchestrator Before Developer Handover + +The orchestrator spawns this reviewer before handing the accumulated super integration branch to the +developer. Review **wholesale branch behavior**: the whole portfolio as integrated on super. + +- **Scope packet:** super integration branch diff against its base (main), portfolio task docs, master + task docs, master-handover packets, prior master-exit verdicts, orchestrator decision logs, resolved + `system/tools.md`, changed source paths, changed sidecars, governing route overviews, and final + carry-over/ledger evidence. +- **Completion vs portfolio intent:** the integrated super branch satisfies the accepted portfolio + objective and dependency order; master-level deltas are justified; cross-master conflicts, duplicate + implementations, or deferred follow-ups are surfaced rather than hidden in the final handover. +- **Code quality per tools.md:** the full super branch has current quality evidence for the resolved + suite, and the reviewer checks branch-wide behavior regressions **vs the past** and across integrated + masters, not just per-master local quality. +- **Onboarding-vs-code:** the accumulated memory layer matches the super branch: changed sidecars are + current, route overviews describe the resulting behavior, C-11 carry-over/ledger mapping is coherent, + and `drift_check` plus `memory_quality_check` evidence is recorded. +- **Blocking rule:** a block returns to the **orchestrator** as decomposable fix leaves. The + orchestrator may route a fix through an owning manager, a new master, or the super worktree, but the + verdict itself must name leaf-shaped work with evidence and done-when. A super-exit block without fix + leaves is invalid. + +## Duties + +1. **Scope** the review to the seam or loop (diff · task docs · rubric · the bound criteria + catalogs). +2. **Run the standing catalogs + the three lenses**, fanning out sub-agents that write durable + reports; adopt the refute-or-confirm posture — a finding that cannot survive an attempt to + refute it is not a finding. Owe the exploratory mandate on top of the catalog. +3. **Write the verdict artifact** (`../templates/verdict.md`, the matching seam variant): findings ranked, + an explicit **pass / block** recommendation, durable under the series `notes/reports/` directory — + including the per-criterion catalog results and any proposed catalog amendments (the promotion + ratchet). +4. **Attach the verdict as judge evidence** on the handover gate — the decider decides; the reviewer + does not. (A loop review's verdict goes to the loop owner the same way: evidence, never a + decision.) +5. **Decompose a blocking verdict into fix leaves** — concrete, **leaf-shaped** findings the owning + manager (master-exit) or orchestrator (super-exit) can dispatch. A block is **never prose-only**; if + it cannot be named as fix leaves, it is not yet a block. +6. **Serve delta-verifies when resumed:** confirm the landed residuals of a round you already + reviewed via the follow-up channel, appending the delta section to your own verdict artifact — + never a fresh full round in disguise. + +## Artifact Obligations + +- **The verdict artifact** (`../templates/verdict.md`) at the seam — the reviewer's primary durable output. +- **Sub-agent durable reports** (impact-analysis, onboarding-coherency) that back the verdict's findings + and survive the reviewer session's death. +- **Fix-leaf descriptors** when the verdict blocks — ready for the decider to turn into `task_doc` + leaves. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the seam's change-set context; post + the verdict reference to the seam's decider. +- **Stdin push** — not a driver here; the reviewer is short-lived and reports through its verdict. +- **Escalation** — the reviewer does not escalate; it **reports a verdict**. If the change set is + un-reviewable (missing diff, missing task docs), that itself is a **blocking finding** in the verdict, + routed to the decider — not an escalation up the ladder. + +## Knobs + +| Knob | Default | Notes | +| ------- | ---------------- | ------------------------------------------------------------ | +| harness | claude | default preference only — settings picks the actual harness | +| model | high-reasoning | adversarial review wants a strong, skeptical model | +| effort | high | the last line of defense before a handover; do not economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | review surface | `read_ar_files` · `memory_quality_check` · `drift_check` · `grepai_search` · `cgc_*` · `system/tools.md` checks · report templates · inbox | + +Settings.json `orchestration.roles.reviewer` overrides these, and `orchestration.rolesPerLevel..reviewer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.hermes/skills/l-01-agent-lifecycles/roles/strategist.md b/.hermes/skills/l-01-agent-lifecycles/roles/strategist.md new file mode 100644 index 00000000..377e4b70 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/roles/strategist.md @@ -0,0 +1,196 @@ +# Lifecycle — Strategist + +> The sprint planner, **spawn-first** and self-contained: read the whole in-flight portfolio, prove +> it coherent, resolve the dependency chains, establish blast radius, shuffle leaves for the best +> implementation order, and deliver the **orchestration task** — the sprint plan and the sprint +> scope. A strategist run is a **mandatory precondition for any orchestrated run**. Your **brief is +> your session start**. +> +> Drawn as the **STRATEGIST** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Spawn-first by design** (developer decision 2026-07-05). Strategist work is token-heavy — it +reasons over every master's state, task docs, notes, friction ledger, and gate history — so it runs +as its own process with its own harness/model/effort knobs, protecting the orchestrator's context. +The designer precedent explicitly does NOT apply: the designer stays an inline hat because design +is drawing-board-interactive with the developer; the strategist's essence is solitary heavy +analysis. Spawned by the orchestrator via `spawn_agent_session` with +`env={"AR_SPAWN_ROLE": "strategist"}`. + +The strategist is the sprint planner — a scrum master for agents (developer ruling 2026-07-06): +after 1..N new masters are designed, and **before implementation starts on any of them**, it +verifies the in-flight set is **coherent and contradiction-free**, resolves dependency chains, +establishes blast radius, and moves leaves across masters where that yields a better +implementation order. **Even a single master gets this pass** — impact must be understood, and its +leaves may still shuffle. Only once the orchestration task exists may an orchestrated run begin; +without it the portfolio operates blindly, waiting for issues to surface mid-implementation. + +In the three-party loop (see the loop doctrine in `../SKILL.md`) this seat is the **portfolio +level's builder**: owner = orchestrator, builder = strategist, reviewer = the adversarial reviewer +with the plan-review criteria catalog (`../criteria/plan-review.md`). + +**Reader, not mutator.** The strategist READS everything and MUTATES nothing: it drafts the +orchestration task as a durable **notes artifact**; the orchestrator (the portfolio owner) adopts +it into durable task form. The strategist never edits task docs, never raises gates, never touches +git. A seat that never touches mutating AR tools never instantiates a lifecycle — that is the +designed shape. + +## Lens + +- **Opening move:** read the brief fully — it carries **refs to durable portfolio state, never + pasted state** (task-doc paths, series contracts, notes folders, the route-index root, trust + facts the orchestrator compiled). Then run the method below, in order. +- **Retrieval lean:** the mechanical phases use real tools (`cgc_*`, `grepai_*`, the route map); + the judgment phases must **show their work as citations** the reviewer can refute — an uncited + dependency edge is refutable by default. +- **Decide default:** the orchestration task with shown work. A leaf whose scope is too thin to + plan — it can name neither existing surfaces nor the parent anchoring of its additions — becomes + an explicit **"unplannable as scoped"** finding, never a silent guess. + +## The Method — Eight Phases (the operating procedure) + +Run every phase; the artifact schema (`../templates/orchestration-task.md`) requires each phase's +output. Phases 3 and 5 are tool-verifiable; phases 4, 6, and 7 are model judgment **disciplined by +mandatory citations** and the artifact schema — the plan gets the same adversarial treatment as +everything else. + +1. **Inventory** — enumerate the in-flight masters + leaves from the JSON-primary task docs + (`tasks///*.json`): objective, requirements, steps, references, decisions, open + questions. Sources: the task-doc tree + series contracts (branch/integration state) + the notes + folders (designs, friction ledger, review reports). +2. **Touch-surface extraction — TWO-SIDED** (developer refinement 2026-07-06) — normalize each + leaf's declared scope into a surface list (routes, files, skills, schemas, tools, doctrine/docs, + user-visible panels). **Existing surfaces** must map against the AUTHORITATIVE route map + (`onboarding/**/overview.md` + the generated `overview.index.json` route indexes, read via + `read_ar_files`). **New surfaces** (greenfield — routes/files the leaf CREATES) are legitimate + and map by DECLARATION: the leaf must name the parent route/location they will live under and + their intended shape (the L9 `serving/notes.py` precedent: a new file, but its parent route + `serving/` exists and its wiring point `app.py` is nameable). **"Unplannable as scoped" fires + only when a leaf can name NEITHER existing surfaces NOR the parent anchoring of its + additions** — never merely because a surface doesn't exist yet. +3. **Structural dependency analysis (mechanical)** — pairwise over leaves: intersect surface + lists; for non-identical EXISTING surfaces, test coupling with the code-graph tools — + `cgc_dependencies` / `cgc_callers` / `cgc_callees` (does B's surface import/call what A + changes?), `grepai_search` / `grepai_trace` for semantic reach, `cgc_complexity` for hotspot + weighting. NEW surfaces cannot be graph-queried before they exist — their edges come from + **DECLARATION cross-reference** instead: leaf B naming a surface leaf A declares it will create + is a pure ORDER edge (evidence = both declarations), and two leaves declaring additions under + one parent route is a CONFLICT-risk edge at the parent (wiring points, shared registries). + Output: an **EDGE LIST with evidence per edge** — **ORDER** (B consumes what A introduces), + **CONFLICT** (both mutate one surface → serialize or move a leaf), **INDEPENDENT** + (parallel-wave candidates). +4. **Semantic/doctrine dependencies (judgment, cited)** — schema/meaning-vs-storage splits, + doctrine-then-sweep orders, visual ride-alongs. Every claimed edge carries a citation (file, + decision-log entry, or design section) — **an uncited edge is refutable by default**. +5. **Blast radius per leaf** — union of: transitive caller set of touched modules (`cgc_*`, capped + depth), doctrine propagation (skill sync targets, hooks, templates), schema/data migrations, + user-visible surfaces. Classified **low / medium / high** — and this register IS the input to + the owning seat's per-leaf loop-tier scoring (the manager's dispatch scoring in + `roles/manager.md`): the strategist's analysis directly parameterizes the loops. +6. **Coherence & contradiction check** — cross-master sweep: two masters moving one surface in + opposite directions, a leaf assuming state another leaf removes, duplicate work, vocabulary + drift. **Directional contradictions are quo-vadis → developer** (via the drawing board; see + Duties §5). +7. **Ordering** — topological sort over ORDER edges; CONFLICT edges resolved by serialization or + **leaf moves (recorded from→to with rationale)**; independent sets become **parallel waves** + (weigh the landing-reconciliation cost of a parallel wave as a scheduling consideration). +8. **The orchestration task** — fill `../templates/orchestration-task.md`; the template REQUIRES + the shown work: dependency graph with per-edge evidence, blast-radius register, coherence + findings, leaf moves + rationale, sprint order/waves, re-evaluation triggers. Then the + drawing-board rounds begin. + +**Input quality bounds output:** thin task-doc scopes degrade the plan, but the method converts +that degradation into explicit findings ("leaf X unplannable as scoped") instead of silent +guessing. + +## Duties + +### 1 — Brief intake + +Read the brief + every referenced durable artifact. The brief carries refs, never pasted state; the +trust facts are compiled by the orchestrator — do not re-run the trust checkpoint. If a referenced +artifact is missing or unreadable, that is a finding in the orchestration task, not a blocker to +improvise around. + +### 2 — Portfolio read + +Method phases 1–2: the inventory and the two-sided touch-surface extraction (existing surfaces +against the route map; new surfaces by declaration — parent route + intended shape). + +### 3 — Analysis + +Method phases 3–7: the evidence-cited edge list, the doctrine edges, the blast-radius register, the +coherence sweep, the ordering. Keep the evidence inventory (queries run, files read, citations per +edge) as you go — the artifact requires it. + +### 4 — The orchestration task + +Method phase 8. Write the draft to the path the brief names (convention: +`notes//orchestration-task.md` under the coordination tasks tree, or the series `notes/` +folder). It is a **draft for adoption**: the orchestrator adopts it into durable task form — you +mutate nothing yourself. + +### 5 — Drawing-board rounds + +The reviewer (plan-review catalog) passes judgment on the plan; the orchestrator relays the +verdict and the developer's drawing-board feedback back into this session. **Convergence over +rounds is expected and normal** — large, messy portfolios are explicitly NOT expected to be fixed +in one shot; the iteration is the feature. Each round must shrink the finding set (the convergence +rule); the loop's hard cap is 3 full rounds, and **the drawing board with the developer IS this +loop's escalation**. Quo-vadis items — high-blast-radius truths such as two masters heavily +disagreeing on direction — go **straight to the developer** at the drawing board (the orchestrator +carries them; you flag them, unmistakably, at the top of the coherence findings). + +### 6 — Adopted-plan handover + +When the developer accepts the plan, the orchestrator adopts it; your seat's work is done. **The +artifact write is unconditional; the inbox is the delivery channel when the brief wires it** — +otherwise your final playback message to the orchestrator carries the artifact ref. Then end. +The orchestration task remains the sprint's standing scope: a new master added **in-sprint before implementation starts** re-opens re-evaluation (you +may be respawned or resumed for the re-plan); a master added **outside the sprint scope** waits +and enters the next sprint's evaluation. + +## Artifact Obligations + +- **The orchestration-task draft** (`../templates/orchestration-task.md`) — the seat's primary + durable artifact; every section carries its shown work. +- **The evidence inventory inside the artifact** — every dependency edge, blast-radius entry, and + coherence finding cites its source (tool query, file, decision-log entry, or design section). +- **Unplannable-as-scoped findings** for leaves whose task docs are too thin to plan. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the portfolio brief context; + post the orchestration-task ref (and each round's revision ref) to the orchestrator; durable + + dashboard-visible. +- **Stdin push** — the orchestrator delivers round feedback into this hosted session; your replies + are inbox rows or artifact revisions — never an untracked side channel. +- **Escalation** — to the **orchestrator**, which relays; quo-vadis truths are flagged for the + developer's drawing board. You never edit task docs to reflect a ruling — the orchestrator does. + +## Tool Surface (positive statement — this is all of it) + +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `grepai_trace`, `cgc_dependencies`, + `cgc_callers`, `cgc_callees`, `cgc_complexity`, `cgc_symbol_search`, `context_packet`, + `drift_check`. +- **Native READS** of task docs, series contracts, notes, and route indexes; native WRITES only to + your own draft artifact under the notes path the brief names. +- **Inbox** for receiving context and posting artifact refs, when the brief wires it. + +Everything else — `task_doc`, `worktree_*`, `lifecycle_*`, `gate_*`, `spawn_agent_session`, +`memory_*`, git — is the owning seat's machinery, not yours. **Reader, not mutator.** + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | whole-portfolio dependency + blast-radius reasoning wants the strongest model | +| effort | high | the sprint plan parameterizes every downstream loop; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | read-only analysis surface | `read_ar_files` · `grepai_*` · `cgc_*` · `context_packet` · `drift_check` · notes-draft write · inbox | + +Settings.json `orchestration.roles.strategist` overrides these, and `orchestration.rolesPerLevel..strategist` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.hermes/skills/l-01-agent-lifecycles/roles/worker.md b/.hermes/skills/l-01-agent-lifecycles/roles/worker.md new file mode 100644 index 00000000..f5c369b4 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/roles/worker.md @@ -0,0 +1,136 @@ +# Lifecycle — Worker + +> One leaf, one session, one report. The worker lifecycle is **self-contained**: everything this +> seat does is on this page, and your **brief is your session start** — a workspace session-start +> notice is not addressed to you. + +## What This Seat Is + +**One per task leaf, short-lived, fresh session.** Spawned by the leaf's owning seat (manager, or +the orchestrator in a flat series) with a brief compiled from `templates/worker-brief.md`. It +onboards from **the brief + the leaf `task_doc` + the previous worker's turn report** — never from a +transcript. Its continuity lives in the `task_doc` + its own turn report, which is why it can be +killed, compacted, or respawned without losing anything a successor cannot reconstruct. + +The worker builds; it does not manage lifecycle machinery. **Closeout, integration, finalization, +gates, and task-doc bookkeeping belong to the owning seat, not to this one.** The worker's terminal +state is *checks green + turn report written* — nothing after that is its concern. + +## The Worker Loop + +``` +brief -> orient -> build (edit + onboarding same-pass) -> checks green -> turn report -> end + | + +-- blocked or plan delta beyond blank-filling -> escalate to the owning seat +``` + +### 1 — Intake + +Read the brief fully, then the leaf spec / `task_doc` it names. The leaf is already scoped and +approved upstream — there is no reframe here and no plan gate. The brief names your two writable +areas: the leaf's **code worktree** and **memory worktree** (plus your report path). You edit +nothing outside them. + +### 2 — Orient (paired reads before edits) + +- Read the files you will touch **paired with their onboarding** — via the `read_ar_files` MCP tool + (note: it serves the official baseline, not your worktree) and native reads inside the worktree + for current state. Native read is your edit precondition. +- Retrieval when the leaf needs it: `grepai_search` (semantics), `cgc_*` (relationships) — both + read-only, with whatever stack key the brief names. Keep the evidence tally your brief asks for + (calls made, files inspected, gaps remaining). + +### 3 — Build + +- Implement exactly the leaf plan; fill small, unambiguous blanks a competent implementer would + fill (see "Default Behavior" below). +- **Refresh the matching onboarding in the same editing pass** per + `c-05-create-or-update-onboarding-files`: a changed source file's sidecar **body** is updated now; + a new file's sidecar is created; route overviews that need a genuine body update get one, and a + no-impact route gets the literal history form `- — No route impact: `. + Regenerate generated route indexes with a **local `build_route_indexes(...)`** invocation from the + memory worktree. +- **Never `git commit`.** Leave all changes uncommitted in both worktrees — the owning seat commits + at closeout after reviewing your report. + +### 4 — Checks (green before you report) + +Run what the brief prescribes — typically the focused suite over your changed paths plus the full +`system/tools.md` wrapper from the code worktree root — and record the exact commands + outcomes for +the report. A red check you cannot fix inside the leaf's scope is an escalation, not a workaround. + +### 5 — The Turn Report (mandatory, your last act) + +Write `templates/turn-report.md` to the path the brief names (convention: +`notes/reports/-worker-report.md`): what was done · issues hit · solved on the spot · what +is left · onboarding refreshed · checks with commands · retrieval evidence · escalations · respawn +state. **A missing report gets nudged.** The report is the leaf's artifact of record and how a +respawned successor onboards — write it even when blocked (with the Escalations section filled), +then end your turn. + +## Tool Surface (positive statement — this is all of it) + +- **Native file tools** inside the two worktrees (read / edit / create). +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `cgc_*`, `context_packet`. +- **Shell** for the prescribed checks (use the interpreter paths the brief names — do not assume a + `python` shim exists). +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) for receiving context and raising + escalations, when the brief wires it. + +Everything else — `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, +`route_index_refresh` — is the owning seat's machinery, not yours. A worker that never touches +lifecycle machinery never instantiates a lifecycle; that is the designed shape, not a gap. + +## Fan-Out (capability doctrine — any harness that has it) + +When the harness offers sub-agents, use them for **read/search only**, scoped to the leaf (locate +call sites, sweep onboarding): each writes durable notes and returns a compact summary. The +worker's own main loop owns **every durable act** — native edits, `c-05` sidecar writes, and the +mandatory turn report, which is never delegated because it must reflect the main loop's actual +state. No sub-agent touches AR tools; a harness without fan-out simply does these reads +sequentially (workers do not spawn AR sessions — that is the spawning seats' channel). + +## Loop Position (when the leaf runs as a three-party loop) + +The owning seat scores each leaf into a tier at dispatch (loop doctrine: `../SKILL.md`, The +Three-Party Loop). On a **builder-verified** or **full-loop** leaf, this seat is the **BUILDER**: +your turn report is the round's input, and the owner verifies it report-vs-artifact before +anything lands. Two consequences for you: + +- **Fix rounds resume THIS session** — the same builder, with its context intact. Your round-2+ + report **appends** to your report file rather than rewriting it, so the loop history stays + legible. +- **Rounds are capped and must converge**, but the cap, the convergence call, and any escalation + are the OWNER's controls, not yours. You build and report honestly; if you disagree with a + reviewer finding you were handed, say so **with evidence in your report** — the owner rules, + you never argue a verdict into the code. + +## Default Behavior + +**Fulfill the task, fill small blanks.** No creative-liberty prompting in either direction. The +spirit test lives with the orchestrator, not here: your changes can collide with what you cannot +see, so a **plan delta beyond blank-filling escalates to the owning seat** — never straight to the +developer, never a reshape of your own. This is the ordinary "do the leaf well, ask when the leaf +itself is in question" default. + +## Comms + +- **Inbox** — receive dispatch/context; post escalations; agent-to-agent rows carry role metadata + and a `messageKind` (`turn-report`, `nudge`, `escalation`, …), durable + dashboard-visible. +- **Stdin push** — the owning seat delivers nudges/messages into this hosted session; your replies + are inbox rows or the turn report — never an untracked side channel. +- **Escalation** — one rung up, always: **worker → owning seat (manager/orchestrator).** + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ----- | +| harness | codex | default preference only — settings picks the actual harness | +| model | mid-reasoning | competent implementer on a scoped leaf | +| effort | medium | scales with leaf difficulty via settings | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | build surface | native edit · read-only AR retrieval · prescribed checks · inbox | + +Settings.json `orchestration.roles.worker` overrides these, and `orchestration.rolesPerLevel..worker` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md b/.hermes/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md new file mode 100644 index 00000000..a751a6b1 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md @@ -0,0 +1,54 @@ +# Conversation-Handover-Packet Template + +**One schema, three uses** (design record, the COMMS model): **role takeover** (profile-fit — the orchestrator's +Profile check (takeover) — `roles/orchestrator.md`, The Event Loop — spawns the correct profile and hands over), **worker respawn** (a fresh worker continues a leaf), and +any **master-complete handover** that needs the receiver to onboard from **state, not the transcript**. +The receiver always onboards from this packet, never from a prior conversation. + +## Rules + +1. The receiver must be able to act from this packet **alone** — assume the transcript is gone. +2. Name the request, the decisions already made, the constraints, the links, and the open questions. +3. For a **takeover spawn**, state the profile mismatch that triggered it, so the successor knows why it + exists and does not repeat the wrong-profile work. + +## Shape + +```md +# Conversation Handover — + +| Field | Value | +| ------------- | ------------------------------------------------- | +| use | role-takeover | worker-respawn | master-handover | +| seat / role | designer | orchestrator | manager | worker | reviewer | +| from | | (developer) | +| to | | +| leaf / master | | +| written | | + +## Why This Handover +- role-takeover: profile mismatch — wanted , session was ; taking over on the right profile. +- worker-respawn: . +- master-handover: . + +## The Request (as agreed) +- + +## Decisions Already Made +- (decision-log ref …) + +## Constraints & Invariants +- + +## Links (onboard from these, not the transcript) +- task_doc: · integration branch: · prior turn report(s): +- durable notes / reports: + +## Open Questions For The Successor +- + +## Current State +- Position in the plan / DAG: +- Committed vs uncommitted: +- The one thing to know before the next action: +``` diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/deep-research-report.md b/.hermes/skills/l-01-agent-lifecycles/templates/deep-research-report.md new file mode 100644 index 00000000..ee971166 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/deep-research-report.md @@ -0,0 +1,123 @@ +# Deep Research Report Template + +Use this template after the developer-agreed reframe and before the lifecycle's +`decide` step. The lifecycle owns when deeper research happens and which proof +categories are required; this template owns the report shape, evidence IDs, and +optional sections. + +For small research-only answers, use the compact shape. For ambiguous, +architectural, taxonomy-heavy, bug-root-cause, triage-routing, or build-spawning +work, use the full shape. + +## Report Rules + +1. Keep the report claim-first: findings state what is now believed to be true. +2. Treat evidence rows as proof records, not activity logs. +3. Every finding cites evidence IDs, and every evidence row names the claim it proves. +4. Mark inference separately when the report reasons across multiple evidence rows. +5. Keep limits visible: every evidence row should say what it does not prove. +6. End with the lifecycle decision: research-only exit or recommended follow-up build. + +## Full Shape + +```md +# Deep Research Report: + +## Frame + +- Surface request: +- Deeper objective: +- Agreed scope: +- Non-goals: +- Invariants: +- Truth gaps before research: + +## Short Answer + + + +## Findings + +- F-01: [E-01, E-03] +- F-02: [E-02] + +## Evidence Ledger + +| ID | Kind | Source / Query | Claim Proven | Limits | +|----|------|----------------|--------------|--------| +| E-01 | Semantics | query: "" | F-01 | Does not prove runtime behavior. | +| E-02 | Intent | onboarding: ``; source: `` | F-02 | Covers committed HEAD only. | +| E-03 | Relationship | cgc callees/deps: `` | F-01 | Does not prove hidden business intent. | + +## Proof Inventory + +- Onboarding docs read: +- Semantic queries performed: +- Code graph queries performed: +- Source files inspected: +- External references checked: +- Executable validations run: + +## Remaining Truth Gaps + +| Gap | Why It Matters | Blocks Build? | +|-----|----------------|---------------| +| | | yes/no | + +## Decision + +- Research-only exit: +- Spawn build? +- Suggested artifact shape if spawned (minimal `w-02` task vs master + series): +- Plan-gate status: +``` + +## Compact Shape + +```md +## Short Answer + + + +## Evidence + +- E-01 (): proves ; limits: . + +## Proof Inventory + +- Onboarding docs read: +- Semantic queries performed: +- Code graph queries performed: +- Source files inspected: + +## Remaining Truth Gaps + +- + +## Decision + + +``` + +## Evidence Kinds + +- `Semantics`: fuzzy routing through GrepAI or onboarding search. +- `Relationship`: CodeGraphContext callers, callees, dependencies, impact, or neighboring structure. +- `Intent`: paired onboarding plus bounded source confirmation for contracts, invariants, behavioral expectations, or branch-valid truths. +- `External`: domain documentation, standards, issues, PRs, release notes, or other non-repo references. +- `Executable`: reproduction steps, tests, scripts, command output, or generated validation artifacts. +- `Developer`: explicit clarification from the developer; verify against source before treating it as durable current-state knowledge. +- `Inference`: reasoning across evidence rows. Cite the input evidence IDs in `Source / Query` and state the remaining uncertainty. + +## Evidence Ledger Guidance + +The evidence ledger should be precise enough that another agent can tell why a +claim is supported without rerunning the entire investigation. Prefer concrete +paths, query strings, anchors, and command names over prose summaries. + +Use `Limits` to prevent overclaiming. Examples: + +- `Routes the feature area but does not prove current source behavior.` +- `Confirms the source contract at HEAD, not dirty work-in-progress.` +- `Shows the call path but not whether the path is user-facing.` +- `Explains the documented intent but needs executable validation before build.` diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/impact-analysis.md b/.hermes/skills/l-01-agent-lifecycles/templates/impact-analysis.md new file mode 100644 index 00000000..a9c97ff4 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/impact-analysis.md @@ -0,0 +1,52 @@ +# Impact-Analysis Template + +A durable report a fan-out sub-agent writes for the **orchestrator** (portfolio phase) or the +**adversarial reviewer** (completion + code-quality lenses). It is the **integrity-bulwark** artifact: +planned-vs-planned **and** planned-vs-past blast radius. Sub-agents WRITE it; AR state mutations stay in +the spawning agent's main loop. + +## Rules + +1. Cover **two axes**: planned-vs-planned (does this change collide with another master/leaf, present or + future?) and planned-vs-past (does it regress something already landed — the "fixed one, broke two" + surface?). +2. Evidence-first: cite the route indexes, `cgc_*` queries, `grepai_search` queries, and + `read_ar_files` reads that back each finding. +3. State limits per finding — what the evidence does **not** prove. +4. This is a report, not a decision: it feeds the orchestrator's spirit test / reshape proposals or the + reviewer's verdict; it never decides. + +## Shape + +```md +# Impact Analysis — + +| Field | Value | +| --------- | -------------------------------------------- | +| for | orchestrator (portfolio) | reviewer () | +| author | | +| subject | | +| written | | + +## Surface Swept +- Routes / areas touched: +- Anchors: + +## Planned-vs-Planned (collisions with other masters/leaves — incl. FUTURE) +| Collision | With (master/leaf) | Kind (code | memory | sequencing) | Evidence | Limits | +| --------- | ------------------ | --------------------------------- | -------- | ------ | +- Recommended resolution: up-front foundation-master extraction | leaf move | sequential ordering | none needed + +## Planned-vs-Past (regression surface) +| Risk | Landed thing at risk | Evidence (cgc/grepai/route index) | Limits | +| ---- | -------------------- | --------------------------------- | ------ | + +## Evidence Inventory +- Route indexes read: +- cgc queries (callers/callees/deps/impact): +- grepai queries: +- read_ar_files reads (paired source+onboarding): + +## Bottom Line (for the spawning agent's main loop) +- — no mutation performed here. +``` diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/manager-brief.md b/.hermes/skills/l-01-agent-lifecycles/templates/manager-brief.md new file mode 100644 index 00000000..10c37922 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/manager-brief.md @@ -0,0 +1,62 @@ +# Template — Manager Brief + +The dispatch packet the orchestrator compiles for a manager taking one master. Like the worker +brief, **this brief is the manager's entire session start** — it replaces the front half the +orchestrator already ran. Spawn with `env={"AR_SPAWN_ROLE": "manager"}` and the **qualified** leaf +key of the master's coordination leaf (`//`). + +--- + +```md +ROLE BRIEF — manager + +# MANAGER BRIEF — · + +You are the MANAGER for master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/manager.md`; this brief is your session start. Drive this +master's leaf loop to the master-exit seam, then hand over. + +## The master +- Task doc: `` (read it + every leaf doc first). +- Planner master: +- Leaves, in order: . +- Trust facts (compiled by the orchestrator — do not re-run the checkpoint): providers , drift , freshness . + +## The branch base (load-bearing) +- Your master integration branch: ``, based off the CURRENT super branch + `` @ `` — master branches base off super, never off main. +- Leaf worktrees base off your master branch (normal `worktree_start` per leaf). + +## Dispatch defaults +- Worker spawns: `templates/worker-brief.md`, `env={"AR_SPAWN_ROLE": "worker"}`, qualified leaf + keys; knob overrides: . +- Concurrency: . + +## The exit +- When all leaves have landed on your branch: spawn the master-exit reviewer + (`env={"AR_SPAWN_ROLE": "reviewer"}`, `roles/reviewer.md`) with the scope packet your role file + enumerates; then RAISE the gate without blocking — + `lifecycle_gate(kind="master-handover-approval", enclosure="", + evidence_refs=[], wait=false)` — the `enclosure` MUST carry the master's identity: + the EXACT master task name as the contracts carry it (the raise refuses without one) — + and post the master-handover packet **carrying the returned gateId**: the ORCHESTRATOR decides + the gate by that id. Under an all-human policy the raise blocks and the developer decides — do + not pass wait=false. +- Escalation: to the orchestrator, never the developer. Human-pinned kinds you may meet: + `integration-approval`, `push-approval`, `cleanup-approval`. + +## Reports +- Your handover packet: `../templates/master-handover-packet.md`. +- Leaf-review notes on your coordination leaf; decision-log entries for every delegated gate you + decide and every reopen. +``` + +--- + +**Compiler notes for the orchestrator.** + +- Fill every ``; an unresolved placeholder is not dispatchable. +- The super-tip commit you write here is the reconciliation anchor if a sibling master lands + first — state it explicitly. +- Deliver as an echo-confirmed paste; only count delivery on a post-boot echo. diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/master-handover-packet.md b/.hermes/skills/l-01-agent-lifecycles/templates/master-handover-packet.md new file mode 100644 index 00000000..c8f5cb5c --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/master-handover-packet.md @@ -0,0 +1,49 @@ +# Master-Handover-Packet Template + +The artifact a **manager** posts to the **orchestrator** at master exit (`roles/manager.md`), after the +master-exit adversarial seam. Delivered via the inbox (durable) + stdin push. It is what the +orchestrator integrates a completed master into the super branch from. + +## Rules + +1. Post it only **after** the master-exit verdict exists — the verdict reference is a required slot. +2. Name the integration branch precisely; the orchestrator bases its C-11 integration on it. +3. The carry-over state must let the orchestrator's `c-11-memory-carryover-from-branch` integration run + without re-deriving what landed. +4. Post the packet as an `operator_inbox_post` row with `messageKind="master-handover"` and push + delivery enabled so the durable inbox row and stdin notification agree. + +## Shape + +```md +# Master Handover — · + +| Field | Value | +| ------------------ | -------------------------------------------- | +| master | | +| manager seat | | +| integration branch | | +| handover gateId | | +| base | | +| verdict | | +| verdict outcome | pass | pass-with-notes | +| written | | + +## Change-Set Summary +- +- Leaves landed: , … + +## Requirements / Steps Completion +- All master requirements addressed: yes | with justified deltas (decision-log refs: …) + +## Carry-Over State (for the orchestrator's master → super C-11) +- Memory rows parked / carried: +- Ledger maps every leaf commit: yes | +- Single-siding notes (if this master overlaps another strand): + +## Known Follow-Ups +- | none + +## Reachability +- Manager seat (chat + coordination leaf) stays reachable until the series retires. +``` diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md b/.hermes/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md new file mode 100644 index 00000000..81c2466b --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md @@ -0,0 +1,48 @@ +# Onboarding-Coherency Template + +A durable report a fan-out sub-agent writes for the **adversarial reviewer's** third lens +(onboarding-vs-code) and for the **orchestrator's** memory-quality checks. It is the paired +`read_ar_files` + `memory_quality_check` + `drift_check` review made durable — the check that the +memory repo stayed in lockstep with the code, since **orchestrator quality ∝ memory-repo quality**. + +## Rules + +1. Every **changed** source file must have its sidecar body updated **in the same pass** — a refreshed + `lastVerifiedCommitHash` over stale content silently defeats the drift check and is a finding. +2. Every **new** source file must have a created sidecar (`check_missing_onboarding` clean). +3. Route/repository overviews must reflect the change set; a moved/added/deleted slice must be + reflected in the governing overview. +4. This is a report; the reviewer's verdict or the orchestrator's main loop acts on it. + +## Shape + +```md +# Onboarding Coherency — + +| Field | Value | +| --------- | --------------------------------------- | +| for | reviewer () | orchestrator | +| author | | +| scope | | +| written | | + +## Changed Files — Sidecar Refresh +| Source file | Sidecar updated same pass? | Body reflects change? | Finding | +| ----------- | -------------------------- | --------------------- | ------- | + +## New Files — Missing Onboarding +| New source file | Sidecar created? | check_missing_onboarding clean? | Finding | +| --------------- | ---------------- | ------------------------------- | ------- | + +## Drift & Quality +- drift_check: clean | actionable (list) +- memory_quality_check: pass | +- Ledger maps code HEAD: yes | + +## Overviews +- Route/repository overviews current for touched routes: yes | +- Moved/added/deleted slices reflected in governing overviews: yes | + +## Bottom Line +- Onboarding-vs-code coherent: yes | NO — +``` diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/orchestration-task.md b/.hermes/skills/l-01-agent-lifecycles/templates/orchestration-task.md new file mode 100644 index 00000000..c3d4bb08 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/orchestration-task.md @@ -0,0 +1,89 @@ +# Orchestration-Task Template + +The artifact a **strategist** drafts for the **orchestrator** (`roles/strategist.md`) — the sprint +plan and the sprint scope. A strategist run producing this artifact is a **mandatory precondition +for any orchestrated run**; the orchestrator adopts the accepted draft into durable task form (the +strategist is a reader, not a mutator). It is written under the series/coordination `notes/` path +the brief names and revised across drawing-board rounds. + +## Rules + +1. **Shown work is required per section.** Every dependency edge carries evidence (a tool query, a + file, a decision-log entry, a design-section citation, or — for new surfaces — a **declaration + cross-reference**: the two leaf declarations that couple) — an uncited edge is refutable by + default. Every blast-radius entry names its derivation (caller-set / doctrine-propagation / + migration / user-visible). Every leaf move carries from→to + rationale. +2. **Surfaces are two-sided:** the surface lists distinguish **existing** surfaces (mapped against + the route map) from **new** surfaces (greenfield, mapped by declaration: parent route/location + + intended shape). New-surface edges come from declaration cross-reference — leaf B naming a + surface leaf A creates is a pure ORDER edge; two leaves declaring additions under one parent + route is a CONFLICT-risk edge at the parent. +3. **Coherence findings include the honest failures:** a leaf that can name neither existing + surfaces nor the parent anchoring of its additions is recorded as **"unplannable as scoped"** — + never silently guessed around (a merely not-yet-existing surface is NOT unplannable). Directional + cross-master contradictions are flagged quo-vadis at the top of that section. +4. This is a **draft for adoption**, not a mutation: the strategist never edits task docs; the + orchestrator (the portfolio owner) adopts the plan and records the adoption in the decision log. +5. The plan is reviewed adversarially (the plan-review criteria catalog, + `../criteria/plan-review.md`) before the developer's drawing board; revisions append round + sections rather than rewriting history. +6. Once adopted, this artifact is the sprint's standing scope: in-sprint additions before + implementation starts trigger re-evaluation; out-of-sprint additions wait for the next sprint. + +## Shape + +```md +# Orchestration Task — · + +| Field | Value | +| ---------------- | ------------------------------------------------ | +| strategist | | +| masters in scope | | +| status | draft | in-review | round- | adopted | +| round | (3-round cap; the drawing board is the escalation) | +| written | | + +## Sprint Scope +- IN: +- OUT: + +## Touch Surfaces (per leaf — two-sided) +| Leaf | Existing surfaces (route-map-mapped) | New surfaces (declared: parent route/location + intended shape) | +| ---- | ------------------------------------ | ---------------------------------------------------------------- | + +## Dependency Graph (every edge cited — an uncited edge is refutable by default) +| From (leaf/master) | To | Kind (ORDER | CONFLICT | INDEPENDENT) | Evidence (cgc/grepai query · file · decision-log · design § · declaration cross-reference) | +| ------------------ | -- | ------------------------------------ | ------------------------------------------------------------------------------------------ | + +## Blast-Radius Register (feeds the owning seat's loop-tier scoring) +| Leaf | Radius (low | medium | high) | Derivation (caller-set | doctrine-propagation | migration | user-visible) | Evidence | +| ---- | ---------------------------- | ------------------------------------------------------------------------- | -------- | + +## Leaf Moves +| Leaf | From (master) | To (master) | Rationale | +| ---- | ------------- | ----------- | --------- | + +## Coherence Findings +- ⟁ QUO-VADIS (developer decision required): | none +- +- Unplannable as scoped: | none + +## Sprint Order / Waves +1. (note the + landing-reconciliation cost of parallel waves as a scheduling consideration) +2. + +## Open Risks +- + +## Re-Evaluation Triggers +- In-sprint master added before implementation starts → re-plan (strategist re-evaluates). +- Master added outside the sprint scope → next sprint's evaluation. +- + +## Evidence Inventory +- cgc queries (dependencies/callers/callees/complexity): +- grepai queries (search/trace): +- read_ar_files reads (paired source+onboarding) / route indexes read: +- task docs, decision logs, and design sections cited: +``` diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/turn-report.md b/.hermes/skills/l-01-agent-lifecycles/templates/turn-report.md new file mode 100644 index 00000000..b771ada4 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/turn-report.md @@ -0,0 +1,57 @@ +# Turn-Report Template + +The **mandatory** artifact a worker writes at **every** hand-off (`roles/worker.md`). It is how the +leaf's work survives the session's death and how a respawned successor onboards from **state, not the +transcript**. A missing turn report is nudged by the manager. + +## Rules + +1. Write it in the **main loop**, from your own work plus any sub-agent summaries — never delegate it to + a sub-agent (it is the leaf's single artifact of record). +2. State facts, not a narrative: what changed, what broke, what is proven green, what remains. +3. The **Respawn State** section must let a fresh successor continue **without reading any transcript**. +4. Keep it durable and in the series notes; reference it from the leaf `task_doc`. +5. Default path: `notes/reports/-worker-report.md`. The control-plane helper exposes this + convention so manager nudges and respawn onboarding can point at the same artifact. + +## Shape + +```md +# Turn Report — · + +| Field | Value | +| ------------ | --------------------------------------- | +| leaf | | +| master | | +| worker | | +| worktree | | +| status | in-progress | leaf-complete | blocked | +| checks | green | failing: | not-yet-run | +| written | | +| inbox | | + +## What Was Done +- (files: ``, …) + +## Issues Hit +- → resolved: | still open: + +## Solved On The Spot +- (a plan delta beyond blank-filling is NOT here — it was + escalated to the manager; see Escalations) + +## What Is Left +- [ ] + +## Onboarding Refreshed +- in this pass (c-05) + +## Escalations +- | none + +## Respawn State (onboard a successor from this — no transcript needed) +- Current position in the leaf plan: +- Files touched so far: +- The one thing a successor must know before editing: +- Uncommitted vs committed state: +``` diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/verdict.md b/.hermes/skills/l-01-agent-lifecycles/templates/verdict.md new file mode 100644 index 00000000..3f292443 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/verdict.md @@ -0,0 +1,142 @@ +# Verdict Template (adversarial reviewer) + +The artifact an **adversarial reviewer** writes at a seam (`roles/reviewer.md`). It lands +under the series `notes/reports/` directory and attaches to the handover gate as **judge evidence**. +There are two variants: **master-exit** (before a manager hands over to the orchestrator) and +**super-exit** (before the orchestrator hands over to the developer) — plus a loop-review +adaptation of the master-exit shape (see Loop-Review Adaptation below). + +## Rules + +1. **A verdict is evidence, not a decision.** State an explicit pass/block **recommendation**; the gate's + decider decides. Never write the verdict as if it were the gate outcome. +2. **A block must decompose into fix leaves** — concrete, leaf-shaped findings the owning + manager/orchestrator can dispatch. A block that cannot be named as fix leaves is not yet a block. +3. **Refute-or-confirm:** every finding must survive an attempt to refute it. Rank findings and cite + the backing evidence file. +4. Cover all three lenses (completion · code quality · onboarding-vs-code) explicitly, even to say a + lens is clean. +5. Record the gate evidence reference exactly: `kind=reviewer-verdict`, `ref=`, and + `verdict=`. +6. **Report every bound catalog criterion** in the Criteria Catalog Results table (the catalogs the + binding table in `roles/reviewer.md` assigns this review type, `../criteria/`) — one row per + standing criterion even when it found nothing, candidate rows when run — and carry any proposed + catalog amendments (the promotion ratchet) in that section. + +## Master-Exit Variant + +```md +# Adversarial Verdict — master-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | master-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | orchestrator (delegated `master-handover-approval`; serious issues escalate → developer) | +| artifact path | notes/reports/-master-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Task Docs +- Master requirement/substep coverage: addressed | delta justified | MISSING +- Leaf task docs and worker reports reconcile with the master task_doc: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite: green | failing: +- regressions vs the past (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- master-side route overviews current: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Manager Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the master-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Super-Exit Variant + +```md +# Adversarial Verdict — super-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | super-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | developer (human review concentrates at the super gate) | +| artifact path | notes/reports/-super-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Portfolio Task Docs +- Portfolio objective and dependency order satisfied: yes | +- Master handover packets and prior master-exit verdicts reconciled: yes | +- Cross-master conflicts, duplicate implementations, and deferred follow-ups surfaced: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite for the accumulated super branch: green | failing: +- branch-wide regressions vs the past and across masters (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- route overviews describe the accumulated behavior: yes | +- C-11 carry-over and ledger mapping coherent for the final super branch: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Orchestrator Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the super-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Loop-Review Adaptation (leaf full-loop · plan review) + +A three-party-loop review (a full-loop leaf round, or the plan review over an orchestration task) +uses the **master-exit variant's shape minus the gate machinery**: drop the `gate evidence` header +row and the Judge-Evidence Note (a loop review attaches to no gate), set `decider` to the **loop +owner** (the leaf's owning seat, or the orchestrator for the plan review), scope to the round's +change set (or the orchestration-task draft), and keep everything else — recommendation, Criteria +Catalog Results (the loop's bound catalogs, e.g. `plan-review` + `report-verification` for a plan +review), ranked refute-tested findings, and fix decomposition. The verdict remains **evidence to +the loop owner, never a decision**; a delta-verify appends a dated delta section to this same +artifact rather than opening a new one. diff --git a/.hermes/skills/l-01-agent-lifecycles/templates/worker-brief.md b/.hermes/skills/l-01-agent-lifecycles/templates/worker-brief.md new file mode 100644 index 00000000..db8f44d0 --- /dev/null +++ b/.hermes/skills/l-01-agent-lifecycles/templates/worker-brief.md @@ -0,0 +1,72 @@ +# Template — Worker Brief + +The dispatch packet a spawning seat (manager / orchestrator) compiles for a worker. **The brief is +the worker's entire session start** — it replaces the front half the spawner already ran (trust +checkpoint, reframe, plan). Compile it fresh per leaf from this shape; the proven form below +absorbed a series of real dispatch frictions (route-index leaks, attestation format, provider-stack +keying, missing `python` shim), so deviate knowingly or not at all. + +Spawn with `env={"AR_SPAWN_ROLE": "worker"}` and the **qualified** leaf key +`//` so the session-start router and the dashboard leaf rail both engage. + +--- + +```md +ROLE BRIEF — worker + +# WORKER BRIEF — · + +You are a WORKER for leaf `` of master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/worker.md`; this brief is your session start. Execute the leaf +completely, write your turn report, then stop. + +## Worktrees (your ONLY writable areas) +- Code: `` (branch ``, base ``) +- Memory: `` +- Plus your turn report at the path below. Nothing else. NEVER `git commit` — the owning seat + closes out after reviewing your report. + +## Tool surface +- Native file tools inside the two worktrees; shell for the checks below. +- Read-only AR retrieval: `read_ar_files` (serves the OFFICIAL baseline, never your worktree — + final verification uses native reads), `grepai_search` / `cgc_*` (provider stack key: + ``), `context_packet`. +- No `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, or `route_index_refresh` — + generated route indexes are regenerated with a local `build_route_indexes(...)` from the memory + worktree. +- Interpreter: `` with `PYTHONPATH=/mcp/src` — there is no + `python` shim in this environment. + +## The task +Leaf spec: `` (read it first). + +## Checks (green before you report) +- Focused: . +- Full: — must exit 0. +- `git diff --check` in both worktrees. + +## Onboarding (same editing pass, per c-05) +- Changed source files: update the sidecar BODY now; new files: create the sidecar. +- Route overviews: genuine body update where routes changed; otherwise the newest history entry + uses the LITERAL form `- — No route impact: ` (timestamp first). +- Pin idiom for verification metadata: "Verification metadata pinned until closeout stamps the + commit." + +## Turn report (mandatory, last act) +Write `/-worker-report.md` following +`skills/l-01-agent-lifecycles/templates/turn-report.md` — including exact check commands + +outcomes, the retrieval-evidence tally, and the respawn state. If blocked: fill Escalations and +stop — escalate to , never to the developer. +``` + +--- + +**Compiler notes for the spawning seat.** + +- Fill every ``; a brief with an unresolved placeholder is not dispatchable. +- Verify the provider stack actually answers before naming it; write `NONE (native reads only)` + when it does not — a worker discovering dead providers mid-leaf wastes its turn. +- Deliver as an echo-confirmed paste; verify the harness's paste chip (`[Pasted Content N chars]`) + before submitting, and only count delivery on a post-boot echo. +- The report path lives under the series `notes/reports/` — the same folder the seam verdicts use. diff --git a/.hermes/skills/l-01-session-job-lifecycle/SKILL.md b/.hermes/skills/l-01-session-job-lifecycle/SKILL.md deleted file mode 100644 index 9b3cc6d6..00000000 --- a/.hermes/skills/l-01-session-job-lifecycle/SKILL.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -name: l-01-session-job-lifecycle -description: "The session job lifecycle the coordinator routes every session into: request -> context/trust checkpoint -> developer-agreed reframe -> deeper research -> decide build mode -> build -> close. Owns research-only exits, the build-mode decision (chat build vs durable w-02-light-task-workflow task), and the job lens (bug/feature/triage/research). Supersedes the retired chat workflow by migrating and modernizing its doctrine." ---- - -# l-01-session-job-lifecycle Session Job Lifecycle - -The `l-01-session-job-lifecycle` skill is the **canvas** the coordinator routes into at the start of every session. -It is not a task format. A task format is one outcome of a single step inside it. - -The lifecycle is one shared spine with thin per-job lenses. Its front half is a -developer/model collaboration loop: the developer states the request, the model -runs mandatory MCP grounding checks, the model presents an evidence-backed -reframe, and the developer agrees or revises that reframe before deeper research -or build-mode decisions proceed. - -## Companion Files - -1. `job-variants.md` — the four thin job lenses (bug / feature / triage / research). -2. `deep-research-report-template.md` — the reusable report and evidence-ledger shape for deeper research. - -``` -0 Request -> 1 Trust Checkpoint -> 2 Reframe + Research -> 3 Decide -> 4 Build -> 5 Close - | - +-- research-only (e.g. investigation, code questions...) -``` - -## Hand-off Protocol — Dry-run action => "Notify-and-stop" Action => "Report" Action - -Every developer hand-off / gate moment — reframe agreement, plan gate, worktree intent, commit -approval, push approval, integration, cleanup/finalization, regular turn-end — is **notify-and-continue**: -surface an attention item, present the result, and **end your turn**; the developer responds and your -**next** turn picks up automatically. It is **three actions, never one**: - -1. **Dry-run action.** Run applicable MCP tools in `dry-run` for the hand-off. If dry run succeeds, - proceed with the notify-and-stop action. If dry run fails, try to ammend the issue first before reporting failure. -2. **Notify-and-stop action.** Call `lifecycle_turn_end_notification(summary=…)`. It sets the new - **`awaiting-developer`** lifecycle state, surfaces a dashboard attention item, and **returns - immediately — no wait, no inbox.** This is the **last tool call of the turn** — the report prose - still follows it; do not STOP here. The developer responds on the - dashboard or in the leaf's attached chat, and the **first AR tool call of your next turn** - automatically resumes the lifecycle (`running`) and clears the attention item — you send **no** - explicit resume. -3. **Report action.** Deliver the complete hand-off report as plain assistant output - (the reframe, the plan, the intent packet, or the closeout relay with - preview facts, quality results, proposed commit messages, and - attestations), and make the decision you are handing to the developer the last - line of prose. **The report is the last thing in the turn — then STOP / end your turn.** - -Use the `dry-run` step to verify that the planned tool call (for example the closeout apply) will -succeed before you hand off, and self-fix any failure before reporting it. - -`lifecycle_turn_end_notification` returns immediately and does **not** render a prompt over your prose, -so the report you deliver after it is exactly what the developer sees — call the -notification, then deliver the report as your final prose, then stop. Keep the report turn free of any mutating or permission-triggering operation so -nothing obscures the report. - -Junction → Dry-run → notify (`lifecycle_turn_end_notification`) → Report. Every junction below now hands -off through that one notification; the named `kind` is the **parked** durable-gate label the fallback -would use (see "Parked fallback" below), kept so the dashboard can still classify each hand-off: - -| Junction | Parked durable gate `kind` | Skill that hands off | -| -------------------------------- | -------------------------- | ---------------------------------------------------------- | -| plan gate | `plan-approval` | `l-01-session-job-lifecycle` | -| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | -| commit / closeout | `closeout-approval` | `c-12-closeout` | -| push | `push-approval` | `l-01-session-job-lifecycle` / `c-09-git-worktree-manager` | -| integration | `integration-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| cleanup / lifecycle finalization | `cleanup-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| any other dev-wait | `agent-question` | `l-01-session-job-lifecycle` | - -`closeout-approval` **is** the commit hand-off — there is no separate -`commit-approval`. Closeout is the single commit-of-record for code, memory, and -ledger, so every commit (including a singular one) routes through the closeout -hand-off. `agent-question` is the non-exhaustive catch-all so any dev-wait that is -not a structured junction is still observable. - -### Parked fallback — block-and-wait `lifecycle_gate` - -The block-and-wait `lifecycle_gate(kind=…)` junction (which creates a durable gate and waits for a -developer decision), the operator inbox, and the dashboard GateResponder **still exist and still work** -when explicitly raised — but they are **no longer the active path**, and nothing routes toward them: -`next_step.py` repoints every gate moment to `lifecycle_turn_end_notification`. Reach for the -server-enforced `lifecycle_gate` (followed by `lifecycle_resume` after the developer decides) only when -you deliberately need a durable, developer-attributed, mutation-blocking approval record; its `kind` -values are the table above. If you ever do raise it, it renders an approval prompt **over** your prose, -so the report must land in an earlier turn — which is exactly why notify-and-stop is preferred. - -## Lifecycle Signals — Making The Session Observable - -Every session in a managed repo is a **lifecycle**: the six `lifecycle_*` signals -record where it is and what it is waiting on, so the work is observable and -resumable across chat deaths (design `docs/design/observable-lifecycle.md`). The -model **never handles a lifecycle id** — identity is server-side, anchored in the -worktree contract. - -| When (phase) | Signal | Why | -| ---------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Trust Checkpoint passes (managed repo) | `lifecycle_start` | Begin a **fleeting** lifecycle (guarded: one per session; takes no id). | -| Entering each phase | `lifecycle_phase` | Move the orthogonal phase axis (`request`/`trust-checkpoint`/`reframe-research`/`decide`/`build`/`close`). | -| At a hand-off (reframe, plan, commit, …) | `lifecycle_turn_end_notification(summary=…)` (last tool call), then the report prose, then **STOP** | Set `awaiting-developer`, surface the dashboard attention item, and return immediately (no wait, no inbox); the next turn's first AR tool call auto-resumes (`running`) and clears the item. Block-and-wait `lifecycle_gate(kind=, ask=…, packet=…)` + `lifecycle_resume` is the parked fallback. | -| `worktree_start` (Decide → Build) | _(promotion — automatic)_ | The fleeting lifecycle becomes **persistent**, anchored in the contract; no separate signal. | -| Resuming an existing task | `worktree_attach` | Re-adopts the contract's lifecycle (contract-resolved); the model passes no id. | -| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | The save gate: promote it or abandon it — never dropped silently. | -| Close | `lifecycle_end` (`completed`\|`abandoned`) | The terminal record. | - -Rules: `lifecycle_start` is guarded (one active lifecycle, no id). `paused` is -**system-owned** — there is no pause signal. `awaiting-developer` is set by -`lifecycle_turn_end_notification` and auto-cleared back to `running` by the next -turn's first AR tool call — you never resume it by hand. A tool call outside any -lifecycle is **dropped, never misattributed**. `worktree_start` **promotes** the current -lifecycle (fleeting → persistent); `worktree_attach` **resumes** the contract's -lifecycle; both keep identity server-side. - -## 0 — Request - -Receive the developer's raw request and identify the active repository. - -1. Treat the developer's statement as raw input, not yet as an implementation plan. -2. Infer the target code repository from the request and local context. Ask the - developer if the target is unclear. - -Request intake changes nothing. It only establishes which repository the next -checkpoint must inspect. - -The upcoming `Trust Checkpoint` reveals whether or not the request is related to repositories managed by Agents Remember. If not, then the lifecycle exits early and the agent can work as usual. - -However, if later work is to enter the boundary of repositories being managed by Agents Remember, -the lifecycle must be re-entered. - ---- - -## 1 — Trust Checkpoint - -Establish whether memory and providers are trustworthy enough to use. - -1. For the target repository, resolve coordination/memory context with - the MCP tool call: - - ```text - context_packet(repo_id="", include_providers=true, include_drift=true, include_freshness=true) - ``` - -2. Report the packet facts before relying on memory or providers: - - repository, branch, and dirty state - - memory root and onboarding root - - provider state - - drift status and actionable drift count - - branch freshness: whether the code and memory checkouts are current with - their upstreams (`behind`/`diverged` means the local official line is - stale — fast-forward it before trusting analysis or basing work on it) - and whether the ledger maps code HEAD (`ledgerMapsCodeHead=false` means - the memory checkout does not match the code state; run carryover or - check out the right memory branch first) -3. If onboarding for committed source is drifted, missing verification, or - orphaned, and the corresponding source file is not dirty in the code - worktree, stop and ask the developer whether or not to refresh it through - `c-05-create-or-update-onboarding-files`. Drift handling is approval-gated! -4. If drift is tied to dirty source, report it as active work-in-progress. Do - not adopt it as maintenance or silently trust it as current state unless the - developer explicitly says this job owns it. -5. If providers are stopped or degraded, use the matching MCP provider/runtime - operations, then re-run the provider check. If providers are ready, report - readiness and continue. If issues persist, report it to the developer and - wait for instructions. If the packet's providers summary lists `indexing` - targets, report them to the developer: those providers are healthy but - busy, and their results may be partial until the scan completes. -6. After the trust checkpoint passes, read committed-state onboarding for the - in-scope anchors as needed. A file dirty in another chat is still valid for - HEAD and worth comparing, but its dirty-source drift remains active work. - ---- - -## 2 — Reframe And Research - -Turn the developer's raw request into an agreed piece of work, then perform the -deeper research that the agreed frame requires. The `tasks/AGENTS.md` -collaboration doctrine applies here in plain chat, before any task file or task -format exists. - -**Read tool for this phase.** Until the build-mode decision (Phase 3), read managed-repo source -through the `read_ar_files` MCP tool, not the harness's native read — it returns paired -source+onboarding plus the repository/route overviews in one observable, lifecycle-attributed -call, and you keep a running count of those calls as evidence. Native read is the edit -precondition in Phase 4. - -1. **Gather evidence for the reframe** through reading the - `c-04-retrieval-strategy-router` skill. Pick the strategy by the question: - - _Semantics_ (grepai over onboarding) — "where does X live / what handles Y." - - _Relationship_ (cgc) — callers/callees/dependencies/impact. - - _Intent_ (onboarding + bounded source confirmation) — hidden contracts, invariants, - branch-valid truths, behavioral expectations. This is a workflow of paired - source+onboarding reads via the `read_ar_files` MCP tool: one call pairs each source - file with its verified onboarding and auto-attaches the repository overview + governing - route-overview chain (the bird's-eye view). -2. **Reframe** the request through `tasks/AGENTS.md`: distinguish the surface - request, deeper objective, highest-leverage framing, assumptions, boundaries, - invariants, and truth gaps. Do not rush a statement into a plan. -3. Present the reframe to the developer. If the developer disagrees, discuss and - revise the reframe. If the developer agrees, proceed to deeper research. -4. **Perform deeper research** for the agreed frame. This research still uses - `c-04-retrieval-strategy-router`, but it is now scoped by the developer-agreed - frame rather than by the model's first guess. Use - `deep-research-report-template.md` for the report shape; the lifecycle owns - the required proof categories, while the template owns evidence formatting. -5. The deeper research report must list its proof and tie evidence to the claim it supports: - - `read_ar_files` calls (paired source+onboarding reads — the running count) - - onboarding docs read - - semantic queries performed - - code graph queries performed - - source files inspected - - remaining truth gaps -6. Run the **job opening move** for the job lens (see `job-variants.md`) and use - the deeper research to name the truth gaps that remain. -7. Continue until the developer agrees the design is defined well enough to write - down, then produce the **plan**: the steps, and a **code example for every - distinct change** you intend to make. - -**Plan gate:** **hand off** before changing any code. No implementation begins -before the developer approves. Call -`lifecycle_turn_end_notification(summary={…the plan + the developer-facing approval ask…})` as the -**last tool call**, then present the plan as your final prose and **STOP**; -the developer approves on the dashboard or in chat and your next turn auto-resumes to begin -implementation. (Parked fallback: the server-enforced -`lifecycle_gate(kind="plan-approval", ask=…, packet=…)` + `lifecycle_resume` still exist if you -deliberately need a mutation-blocking approval record.) - ---- - -## 3 — Decide (build mode) - -One decision: does this job change code? - -- **No -> research-only exit.** Deliver the answer/assessment. No worktree, no task artifact, no closeout. - A research-only job may recommend or spawn a follow-up build job; it does not perform one itself. -- **Yes -> worktree intent hand-off, then always a worktree.** Read `c-09-git-worktree-manager` - and `system/git-workflow.md`, call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the worktree - intent packet as your final prose and **STOP**. The developer approves and your next turn - auto-resumes to `worktree_start`. Then open it with - `c-09-git-worktree-manager` and pick the build mode: - - **Chat build** — small enough to carry inline this session: worktree-backed, **no** `task.md`. - - **Durable task build** — hand off to `w-02-light-task-workflow`: `task.md`, checklist, decision - log, proposed code examples. Escalate to a master + light sub-task series when the work outgrows a - single-page plan. - -The worktree intent packet names the target repo, build mode, discovered branch policy, proposed -`source_branch`, proposed work branch/worktree name, memory mode, landing path, and material risks. -On PR-gated repos, the packet must prove that the recorded `source_branch` is pushable and that -protected targets are reached later through the repo's PR flow. - -Worktree granularity = the leaf task unit. A single task gets its own leaf enclosure/worktree. A -master multi-task owns a root `series-contract.md` and integration branch, while each active leaf -sub-task gets its own `enclosures//series-contract.md`, branch, and worktree. A chat build -gets its own leaf worktree without a task artifact. The git-landing decision (direct vs PR-gated) is -deferred to the repo's `system/git-workflow.md` — read it before landing on a gated branch. - ---- - -## 4 — Build - -Implement inside the worktree, keeping memory and tests in lockstep with the code. - -1. Apply the approved code changes. -2. **Refresh the matching onboarding in the same editing pass**, per completed plan-section — never - deferred to the end of the job. When a change affects durable current-state knowledge, the sidecar - is updated alongside it through `c-05-create-or-update-onboarding-files`. - - For **changed** (already-onboarded) source files, update the sidecar **body** now: the closeout - gate rejects a changed source file whose existing sidecar was not modified this job, because - refreshing `lastVerifiedCommitHash` over stale content silently defeats the drift check. - - For **new** source files, run `check_missing_onboarding` before the commit and create the - reported missing sidecars through the `c-05-create-or-update-onboarding-files` skill; the post-code-commit memory refresh stamps them with - the real code commit hash and date. -3. Run the checks from the `c-08-ar-coordination-context-resolver` resolved `system/tools.md` (lint, typecheck, complexity, tests) and - get them **green before each incremental commit**. Testing is never deferred to a final task; the - pre-commit/pre-push hooks enforce it. -4. **Watch the official line and sync early.** `worktree_status`'s `freshness` block reports when the - recorded base pair fell behind the local source branch tips (a parallel cycle landed). Pull the - moved official line in with `worktree_sync` — preferably **before memories are written**: with - parked memory the sync is a pure fast-forward, the other cycle's sidecars and ledger rows end up - beneath this task's future work, and end-of-series integration stays `ff-only` with no carryover - reconciliation. - -Incremental, pushable commits keep the work-loss window small. Each closeout below is one such commit. - ---- - -## 5 — Close - -Land the work. **Implementation approval is not commit approval.** - -1. Run the `c-09-git-worktree-manager` closeout **preview** for the worktree (`worktree_closeout_preview`). - Every build closes through its worktree — there is no direct-checkout closeout. - Relay the proposed code, memory, and ledger commit messages. -2. **Commit gate:** run the closeout **preview** (dry-run), then **hand off** before any real commit or closeout - apply. If required onboarding is missing, run the `c-05-create-or-update-onboarding-files` skill for the affected file and re-run the preview. - Call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the - **last tool call**, then deliver the preview facts as your final prose and **STOP**; - the developer approves on the dashboard or in chat and your next turn auto-resumes to - `worktree_closeout_apply`. The `c-12-closeout` skill owns this hand-off. Parked fallback: when you - deliberately raise the durable `closeout-approval` `lifecycle_gate`, it is enforced **server-side** — - `worktree_closeout_apply` refuses unless it is approved by the developer, and an agent self-approval - never satisfies it. -3. On approval, the `c-09-git-worktree-manager` skill owns the external-memory invariant in order: commit code → refresh affected - onboarding metadata to the new code commit → run memory quality control → commit memory content → - update and commit the ledger. -4. **Integrate + land** per `c-09-git-worktree-manager` and `system/git-workflow.md`: integrate the - worktree branch into the approved source/integration branch, then on a PR-gated repo push that - source branch, open the PR, wait for green checks, and merge per the repo convention. Never push a - protected branch directly. The agent does not push on its own authority — call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the push intent - as your final prose, and **STOP**; push only after the developer - approves and your next turn auto-resumes. The `c-09-git-worktree-manager` skill makes the matching - integration and cleanup/finalization hand-offs at its landing tail (parked durable kinds - `integration-approval` / `cleanup-approval`). -5. **Map the ledger to the landed commit.** A PR merge usually lands a **merge commit** on top of the - work — tree-identical to the verified tip but a new SHA the ledger does not yet map. Ensure the - ledger maps that merge commit so the next worktree can base off the merged branch without a manual - reconciliation. `system/git-workflow.md` owns this step. -6. **Finalize the lifecycle:** run `lifecycle_finalize_task(..., dry_run=true)` once the local parent - branch contains the landed commit and memory carryover is done. Call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then relay its landed-commit - proof, cleanup plan, and task-document updates as your final prose, and - **STOP**. The developer approves cleanup/finalization and your next turn auto-resumes to run the real - finalizer. The tool proves one parent-child branch edge, - reclaims the worktrees, and marks the leaf task plus immediate parent row `Completed` when those - task-doc paths are supplied. It does not recursively complete ancestors; repeat the edge at the next - parent level when that parent task lands. -7. **Keep squash out of the normal path.** A PR-gated edge is structurally the same as a direct edge - after the model finishes the PR merge and pulls the target branch locally. Do not use squash-merge - equivalence as a default finalization proof; squash is an emergency/manual recovery path because it - erases commit lineage and can make memory lookup history wrong. - -A research-only exit skips this phase entirely. - -## Relationship To Other Instructions - -This skill extends the coordinator `AGENTS.md` and the repository memory layer; it does not replace -them. Read `job-variants.md` for the per-job lenses, and `deep-research-report-template.md` for the -deeper research report shape. diff --git a/.hermes/skills/l-01-session-job-lifecycle/deep-research-report-template.md b/.hermes/skills/l-01-session-job-lifecycle/deep-research-report-template.md deleted file mode 100644 index 6e9d13d0..00000000 --- a/.hermes/skills/l-01-session-job-lifecycle/deep-research-report-template.md +++ /dev/null @@ -1,123 +0,0 @@ -# Deep Research Report Template - -Use this template after the developer-agreed reframe and before the lifecycle's -`decide` step. The lifecycle owns when deeper research happens and which proof -categories are required; this template owns the report shape, evidence IDs, and -optional sections. - -For small research-only answers, use the compact shape. For ambiguous, -architectural, taxonomy-heavy, bug-root-cause, triage-routing, or build-spawning -work, use the full shape. - -## Report Rules - -1. Keep the report claim-first: findings state what is now believed to be true. -2. Treat evidence rows as proof records, not activity logs. -3. Every finding cites evidence IDs, and every evidence row names the claim it proves. -4. Mark inference separately when the report reasons across multiple evidence rows. -5. Keep limits visible: every evidence row should say what it does not prove. -6. End with the lifecycle decision: research-only exit or recommended follow-up build. - -## Full Shape - -```md -# Deep Research Report: - -## Frame - -- Surface request: -- Deeper objective: -- Agreed scope: -- Non-goals: -- Invariants: -- Truth gaps before research: - -## Short Answer - - - -## Findings - -- F-01: [E-01, E-03] -- F-02: [E-02] - -## Evidence Ledger - -| ID | Kind | Source / Query | Claim Proven | Limits | -|----|------|----------------|--------------|--------| -| E-01 | Semantics | query: "" | F-01 | Does not prove runtime behavior. | -| E-02 | Intent | onboarding: ``; source: `` | F-02 | Covers committed HEAD only. | -| E-03 | Relationship | cgc callees/deps: `` | F-01 | Does not prove hidden business intent. | - -## Proof Inventory - -- Onboarding docs read: -- Semantic queries performed: -- Code graph queries performed: -- Source files inspected: -- External references checked: -- Executable validations run: - -## Remaining Truth Gaps - -| Gap | Why It Matters | Blocks Build? | -|-----|----------------|---------------| -| | | yes/no | - -## Decision - -- Research-only exit: -- Spawn build? -- Suggested build mode if spawned: -- Plan-gate status: -``` - -## Compact Shape - -```md -## Short Answer - - - -## Evidence - -- E-01 (): proves ; limits: . - -## Proof Inventory - -- Onboarding docs read: -- Semantic queries performed: -- Code graph queries performed: -- Source files inspected: - -## Remaining Truth Gaps - -- - -## Decision - - -``` - -## Evidence Kinds - -- `Semantics`: fuzzy routing through GrepAI or onboarding search. -- `Relationship`: CodeGraphContext callers, callees, dependencies, impact, or neighboring structure. -- `Intent`: paired onboarding plus bounded source confirmation for contracts, invariants, behavioral expectations, or branch-valid truths. -- `External`: domain documentation, standards, issues, PRs, release notes, or other non-repo references. -- `Executable`: reproduction steps, tests, scripts, command output, or generated validation artifacts. -- `Developer`: explicit clarification from the developer; verify against source before treating it as durable current-state knowledge. -- `Inference`: reasoning across evidence rows. Cite the input evidence IDs in `Source / Query` and state the remaining uncertainty. - -## Evidence Ledger Guidance - -The evidence ledger should be precise enough that another agent can tell why a -claim is supported without rerunning the entire investigation. Prefer concrete -paths, query strings, anchors, and command names over prose summaries. - -Use `Limits` to prevent overclaiming. Examples: - -- `Routes the feature area but does not prove current source behavior.` -- `Confirms the source contract at HEAD, not dirty work-in-progress.` -- `Shows the call path but not whether the path is user-facing.` -- `Explains the documented intent but needs executable validation before build.` diff --git a/.hermes/skills/l-01-session-job-lifecycle/job-variants.md b/.hermes/skills/l-01-session-job-lifecycle/job-variants.md deleted file mode 100644 index 48f032c6..00000000 --- a/.hermes/skills/l-01-session-job-lifecycle/job-variants.md +++ /dev/null @@ -1,43 +0,0 @@ -# l-01-session-job-lifecycle Job Variants — The Lenses - -The job type is a **lens**, picked during `reframe-research` and re-pickable at any time. It is not a gate and it -never changes the spine (`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three -things only: - -- **Opening move** — the first concrete thing `reframe-research` does for this kind of job. -- **Retrieval lean** — which `c-04-retrieval-strategy-router` strategy leads (others are still available). -- **Decide default** — where this job usually lands at `decide` (still a real decision, not automatic). - -| Job | Opening move (in `reframe-research`) | Retrieval lean (`c-04-retrieval-strategy-router`) | `decide` default | -| ---------- | ----------------------------------------------- | ---------------------------------- | --------------------------- | -| `bug` | reproduce the failure; prove the root cause | Relationship (cgc) + Intent | -> build | -| `feature` | clarify intent, scope, and explicit non-goals | design doctrine + Intent | -> build | -| `triage` | assess severity, blast radius, and ownership | breadth scan (Semantics first) | may exit (route or spawn) | -| `research` | state the question precisely | Semantics (grepai) + onboarding | research-only exit | - -## bug - -Lead with a reproduction and a proven root cause before proposing a fix — an unproven fix is a guess. -Lean on Relationship (callers/callees/impact via cgc) to bound the change, and Intent to confirm the -invariant the bug violates. Defaults to a build; the fix lands through `decide -> build -> close`. - -## feature - -Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the -design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the -contracts the feature must respect. Defaults to a build; size decides chat vs durable `w-02-light-task-workflow` task at -`decide`. - -## triage - -Lead by assessing severity, blast radius, and ownership — enough to route, not to fix. A breadth scan -(Semantics first) maps the surface fast. Triage frequently **exits research-only**: its product is a -recommendation, a routed owner, or a spawned build/bug job — not a code change. Only escalate to a -build when triage itself is the cheapest place to fix it. - -## research - -Lead by stating the question precisely. Semantics (grepai over onboarding) plus committed-state -onboarding usually answers it; reach for source only as bounded Intent confirmation. Research -**exits research-only** by design: it produces an answer, and may recommend a follow-up build job, but -performs none itself. diff --git a/.hermes/skills/w-02-light-task-workflow/SKILL.md b/.hermes/skills/w-02-light-task-workflow/SKILL.md index 248e6f3c..b34f3017 100644 --- a/.hermes/skills/w-02-light-task-workflow/SKILL.md +++ b/.hermes/skills/w-02-light-task-workflow/SKILL.md @@ -40,7 +40,7 @@ Light-task artifacts use minute-precision timestamps in `YYYY-MM-DDTHH:MM` forma The task document is **JSON-primary**: an `ar-task-document/v1` JSON file is the source of truth, and the `task.md` (or `.md` for a sub-task) is a deterministic **render** of it. Author and update it with the `task_doc` MCP tool — `create`, `set_status`, `set_step`, `append_decision`, `set_field` — which writes the JSON and re-renders the markdown on every write. Do not hand-edit a tool-managed `task.md`; edit through the tool and let it re-render. `template.md` and `master-template.md` document the **render spec** (the shape the renderer produces), not a separate hand-authored format. When a planning slice defers its code examples to the plan gate, record that with `codeExamplesNote` (a `set_field` value, e.g. "Drafted at the plan gate.") so the rendered "Proposed Code Examples" section reads as *deferred* rather than as if none are needed. A leaf doc may also carry a descriptive `statusNote` (a suffix beside the strict status enum), `headerNotes` (extra `**Key:** value` header lines such as Verified/Source), and freeform `sections` appended after References — the escape hatch for bespoke prose (e.g. a Status history) while the standard template sections stay the backbone. Pass `dry_run=true` to any op to **preview** — it builds + validates and returns the rendered markdown, a unified `diff` vs the on-disk `.md`, and a `wouldLose` flag, **without writing**; use it before adopting a hand-authored `.md` into JSON-primary (author the JSON → dry-run → confirm `wouldLose` is false → then write). -Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for a chat build (a thin doc: title plus a few steps, so even a no-`task.md` session is legible) and a *full* one for a durable task; the difference is content completeness, not a separate format. +Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for the smallest single-session build (a THIN doc: title plus a few steps — chat is never a build route, so even micro-work gets this thin doc and stays legible on the dashboard) and a *full* one for a durable task; the difference is content completeness, not a separate format. Scope and transition: the tool manages **`light` and `subTask`** documents, and the format also covers a series **master** (`kind:"master"`: a structured `subTasks` index + ordered `sections` that preserve a master's bespoke prose, so a re-render is lossless). Masters and existing markdown task files stay hand-authored markdown until the runtime ships `task_doc` and they are intentionally migrated — new tasks adopt the JSON-primary format going forward. diff --git a/.hermes/skills/w-02-light-task-workflow/master-template.md b/.hermes/skills/w-02-light-task-workflow/master-template.md index 7cb4e85a..42738c16 100644 --- a/.hermes/skills/w-02-light-task-workflow/master-template.md +++ b/.hermes/skills/w-02-light-task-workflow/master-template.md @@ -7,7 +7,7 @@ built to grow as the work unfolds. ## When to escalate to a series -The `l-01-session-job-lifecycle` skill's `decide` build-mode step escalates a single task to a series once its size is apparent — the +The `l-01-agent-lifecycles` orchestrator lifecycle's `decide` step escalates a single task to a series once its size is apparent — the implementation plan no longer fits on a single page, or the work splits into distinct slices that each deserve their own checklist and commit. You can also start single and escalate later: drop in the master `task.md` and move the existing plan into the first `NN_.md`. diff --git a/.openclaw/workspace/AGENTS.md b/.openclaw/workspace/AGENTS.md index 7ef0da32..c76ee270 100644 --- a/.openclaw/workspace/AGENTS.md +++ b/.openclaw/workspace/AGENTS.md @@ -1,23 +1,17 @@ # OpenClaw Workspace Instructions -MANDATORY FIRST ACTION for this workspace: +**Agents Remember — session start.** -You are not allowed to read, write, or execute code on any repository until you -read `/ar-coordination/AGENTS.md` and started its -`l-01` procedure. +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** -Read and follow `/ar-coordination/AGENTS.md` -before working in any sibling project. -Treat those rules as workspace instructions. - -Until the build/job decision is made, read managed-repo source with the -`read_ar_files` MCP tool — not the harness's native read tool. One call returns -each file paired with its onboarding plus the repository and governing route -overviews. Native read is reserved as the edit precondition once building begins. - -During the `l-01` deep research step, keep a tally of the retrieval strategies -used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent), and -keep a running count of your `read_ar_files` calls. Include the onboarding files -inspected and every CGC, GrepAI, and `read_ar_files` call made as evidence. +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`/ar-coordination/AGENTS.md` and treat those rules +as workspace instructions, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. @/ar-coordination/AGENTS.md diff --git a/.openclaw/workspace/skills/c-01-findings-capture/SKILL.md b/.openclaw/workspace/skills/c-01-findings-capture/SKILL.md index e145d7ee..d413e8fe 100644 --- a/.openclaw/workspace/skills/c-01-findings-capture/SKILL.md +++ b/.openclaw/workspace/skills/c-01-findings-capture/SKILL.md @@ -13,7 +13,7 @@ Companion file: ## Operating Modes -1. Inside a task workflow (an `l-01-session-job-lifecycle` build job or a `w-02-light-task-workflow` task, including a master + light sub-task series). +1. Inside a task workflow (an `l-01-agent-lifecycles` orchestrator build phase or a `w-02-light-task-workflow` task, including a master + light sub-task series). 2. Standalone during direct clarification. ## Durable Destinations diff --git a/.openclaw/workspace/skills/c-03-repo-bootstrap/SKILL.md b/.openclaw/workspace/skills/c-03-repo-bootstrap/SKILL.md index 40148918..44f14f78 100644 --- a/.openclaw/workspace/skills/c-03-repo-bootstrap/SKILL.md +++ b/.openclaw/workspace/skills/c-03-repo-bootstrap/SKILL.md @@ -1240,7 +1240,7 @@ The orchestrator remains thin throughout. | `c-05-create-or-update-onboarding-files` | Owns final file-level onboarding semantics and routes structural slice maintenance back to the `c-03-repo-bootstrap` skill. The `c-03-repo-bootstrap` skill creates cards/waves and delegates file output rules to the `c-05-create-or-update-onboarding-files` skill. | | `c-04-retrieval-strategy-router` | Consumes bootstrapped overviews and file maps as the Intent substrate and can route to semantic/relationship providers first. | | `c-02-memory-quality-control` | Becomes relevant after bootstrap; touched files can be promoted from deferred to covered. | -| `l-01-session-job-lifecycle` | May trigger targeted bootstrap when an active job enters an uncovered area. | +| `l-01-agent-lifecycles` | May trigger targeted bootstrap when an active job enters an uncovered area. | | `confluence-search` / documentation search skills | Feed the docs evidence pass through approved sources from the input ledger. | --- diff --git a/.openclaw/workspace/skills/c-04-retrieval-strategy-router/SKILL.md b/.openclaw/workspace/skills/c-04-retrieval-strategy-router/SKILL.md index 01434c77..e226f8c0 100644 --- a/.openclaw/workspace/skills/c-04-retrieval-strategy-router/SKILL.md +++ b/.openclaw/workspace/skills/c-04-retrieval-strategy-router/SKILL.md @@ -160,7 +160,7 @@ names an unresolved source question. ### Rules: -- During the research phase (the lifecycle up to the build/job decision), read managed-repo +- During the research phase (the lifecycle up to the build decision), read managed-repo source with `read_ar_files`, not the native read tool — one call returns each file paired with its onboarding plus the repository and governing route overviews (the recipe above, batched and observable). diff --git a/.openclaw/workspace/skills/c-09-git-worktree-manager/SKILL.md b/.openclaw/workspace/skills/c-09-git-worktree-manager/SKILL.md index e19c7902..692dec19 100644 --- a/.openclaw/workspace/skills/c-09-git-worktree-manager/SKILL.md +++ b/.openclaw/workspace/skills/c-09-git-worktree-manager/SKILL.md @@ -7,7 +7,7 @@ description: "Create, attach to, report on, integrate, finalize, and clean up Ag Use this skill when a task should run through an explicit code/memory worktree wrapper. -The `c-09-git-worktree-manager` skill wraps the existing chat-build, light-task, or external workflow. It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. +The `c-09-git-worktree-manager` skill wraps the existing light-task or external workflow (a build that fits one session still rides a THIN `w-02-light-task-workflow` doc — chat is never a build route, per the `l-01-agent-lifecycles` invariant). It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. For closeout, use the `c-12-closeout` skill. The `c-09-git-worktree-manager` skill only supplies the worktree-specific contract path and integration/finalization follow-up rules. @@ -67,7 +67,7 @@ The intended order is: 1. run the `c-08-ar-coordination-context-resolver` skill for the target repository 2. run the `c-02-memory-quality-control` skill's task-start drift check and follow the existing AGENTS Gate 3/4 choice point 3. when onboarding is refreshed, commit the memory content and ledger before starting any worktree -4. decide whether the work is a chat build, a `w-02-light-task-workflow` light task (or master + light sub-task series), or external workflow +4. decide whether the work is a `w-02-light-task-workflow` light task — possibly a THIN one for single-session work; chat never builds — a master + light sub-task series, or external workflow 5. read the repository's `system/git-workflow.md` and identify the parent branch edge. For a standalone task, the leaf worktree branches from the approved source branch. For a master series, the master owns a root `series-contract.md` @@ -198,7 +198,9 @@ moved since task start. ## Integration -Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. +Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. Orchestrated-run carve-out (ruled 2026-07-06): dependency-ordered leaf→master and master→super integrations ride the series' standing approval (the developer's portfolio-gate approval recorded in the planner master) — the developer hand-off concentrates at the super PR/carry-over gate per the `l-01-agent-lifecycles` loop/orchestrator doctrine; a raised durable `integration-approval` gate still awaits the developer. + +On an orchestrated master's exit (master → super integration) the integrate step additionally enforces the delegated `master-handover-approval` seam: an undecided or policy-invalid handover gate addressed to the master (by `enclosure` = master task name) returns `handover-gate-blocked` instead of landing — decide the gate per the `l-01-agent-lifecycles` seam doctrine, then rerun. When no gate addresses the integrating master but open `master-handover-approval` gates exist elsewhere, integrate still proceeds and its result carries a `handover_gate_warning` naming them — treat it as a spelling check on the raised gate's `enclosure`. Run `worktree_integrate(..., dry_run=true)` first, then **hand off**: call `lifecycle_turn_end_notification(summary={…the integration plan…})` as the **last tool call**, then diff --git a/.openclaw/workspace/skills/c-12-closeout/SKILL.md b/.openclaw/workspace/skills/c-12-closeout/SKILL.md index f83071d9..2c7fe3ff 100644 --- a/.openclaw/workspace/skills/c-12-closeout/SKILL.md +++ b/.openclaw/workspace/skills/c-12-closeout/SKILL.md @@ -40,7 +40,7 @@ records the developer's explicit commit approval. Agents must not treat implementation approval, a previous "looks good", or their own judgment as commit approval. -The relay follows the `l-01-session-job-lifecycle` skill hand-off protocol: run the +The relay follows the `l-01-agent-lifecycles` orchestrator hand-off protocol: run the preview/dry-run first, then call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the **last tool call**, then deliver the preview facts and proposed messages as plain diff --git a/.openclaw/workspace/skills/c-13-install-and-onboard/SKILL.md b/.openclaw/workspace/skills/c-13-install-and-onboard/SKILL.md index 6515ae46..d583fd13 100644 --- a/.openclaw/workspace/skills/c-13-install-and-onboard/SKILL.md +++ b/.openclaw/workspace/skills/c-13-install-and-onboard/SKILL.md @@ -52,10 +52,12 @@ Run this sequence in order: 0. Preflight: verify the copied package and MCP setup are usable enough to continue. 1. Runtime scaffold: run or verify `runtime_install()`. -2. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. -3. Bootstrap: when a new memory repo was scaffolded, hand off to +2. Agentic settings: walk the developer through the orchestration defaults in + the seeded global settings file. +3. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. +4. Bootstrap: when a new memory repo was scaffolded, hand off to `c-03-repo-bootstrap`. -4. Providers: when providers are enabled, start/refresh indexing and verify +5. Providers: when providers are enabled, start/refresh indexing and verify readiness. This skill orchestrates and delegates. It does not reimplement @@ -79,7 +81,9 @@ Check, in order: 3. **Settings sane.** Confirm `server_info` reports the expected `coordinationRoot`, `workspaceRoot`, allowed repositories, and providers. Surface the resolved absolute paths because wrong paths are the common cause - of resolver failures. + of resolver failures. Also report whether the global agentic settings file + (`/system/settings.json`) exists yet; Stage 1 seeds it + when missing and Stage 2 configures it. 4. **Runtime state.** Check whether the coordinator scaffold already exists under `coordinationRoot` (`AGENTS.md`, `skills/`, `tasks/`, `memory-repos/`, `system/` as applicable). If it is missing or stale, Stage 1 will run @@ -118,7 +122,61 @@ Do not run `skills_install()` as part of first-run setup. The harness starter package already carries the skills. `skills_install()` remains available for manual maintenance or non-package setups, but it is not the default path. -## Stage 2 - Memory Repo: Ask Scaffold Vs Existing +## Stage 2 - Agentic Settings: Interview The Developer + +`runtime_install()` seeds the GLOBAL agentic settings file at +`/system/settings.json` copy-if-missing, with every knob at +its documented default: all-human gate delegation, the standard three-party-loop +defaults, no concurrency caps, no spawn harness preference. This stage turns +those defaults into the developer's actual posture so the intended workflows +run on ANY harness. The schema reference is `docs/reference/settings-json.md` +(Agentic Settings); unknown `orchestration.*` keys fail loud, so write only +documented keys. + +Walk the developer through the four knob families and edit the global file with +their answers (leave a family at its seeded default when they have no +preference): + +1. **Gate delegation posture** (`orchestration.gateDelegation`; GLOBAL file only - the + loader refuses it repo-locally and the boot snapshot reads the coordinator file) - keep every + gate human (`all-human`, the default), or delegate leaf gates with the + `manager-decides-leaf-gates` policy, optional per-kind `kinds` overrides, + and `requireReviewerVerdictAtSeams`. Say explicitly that this one key is + boot-snapshot: a change needs an MCP/harness restart. +2. **Loop defaults** (`orchestration.loops`) - the review-round cap + (`defaults.maxRounds`), reviewer reuse (`defaults.reviewerReuse`), + complexity thresholds (`defaults.complexity`), and per-level loop postures + (`perLevel`). Read per-use; edits apply on the next use, no restart. +3. **Concurrency caps** (`orchestration.concurrency`) - `maxParallelMasters`, + `maxParallelLeaves`, `maxSubAgents`. Default: uncapped. +4. **Harness preference + role knobs** (`orchestration.spawn.harness`, + per-role `orchestration.roles.`, per-level + `orchestration.rolesPerLevel..`) - which installed harness + `spawn_agent_session` uses when the spawning seat passes none, per-role + harness/model/effort overrides, and per-LEVEL overrides + (leaf|master|portfolio) for tiered economics (e.g. a cheap leaf reviewer, + a smarter master-seam reviewer). Harness values must be known ids: the + builtin registry (`claude`, `codex`, `pi`) or an `orchestration.harnesses` + entry the developer defines (new TUIs, or a pre-customized launch argv for + a builtin). `effort` is validated per-harness at dispatch (claude: + `low|medium|high|xhigh|max` on the `--effort` flag plus the session-level + `ultracode`); mention the FREE-FORM escape hatch for anything outside the + vocabularies - `launchArgs` (verbatim argv), `sessionCommands` (pasted + before the brief), `promptKeywords` (prepended to the brief) - never + validated, recorded in spawn provenance. Default: detection-gated (the + first detected harness). The full spawn-surface manual is + `docs/reference/harnesses.md`. + +If the developer wants to skip the interview, confirm the seeded defaults +apply and continue; tell them the file can be edited any time (picked up +per-use, except the gateDelegation restart note above). + +Per-repo overrides: a code repo may carry its own `/system/settings.json` +with the same `orchestration.*` shape; repo-local leaf values override the +global file (arrays replace). Offer this only when the developer asks for +repo-specific behavior; do not create the file unprompted. + +## Stage 3 - Memory Repo: Ask Scaffold Vs Existing Do not assume the developer wants a fresh memory repo. Ask which case applies, unless a memory repo is already present and resolvable: @@ -126,10 +184,10 @@ unless a memory repo is already present and resolvable: 1. **Scaffold a new memory repo** - they have no existing memory for this code repo. Run `c-00-initialize-memory-repo` (internal by default; external only if the developer asks or the configured topology requires it). Continue to Stage - 3. + 4. 2. **Use an existing memory repo** - they already have one. Clone or checkout it to the resolved memory location, then adopt it as the ledgered baseline with - `c-10-adopt-memory-baseline`. Skip Stage 3 because its onboarding already + `c-10-adopt-memory-baseline`. Skip Stage 4 because its onboarding already exists. Internal-memory note: pre-existing internal memory lives inside the code repo @@ -137,9 +195,9 @@ Internal-memory note: pre-existing internal memory lives inside the code repo `c-08-ar-coordination-context-resolver` and skip the question when the memory layer is already there. -## Stage 3 - Bootstrap +## Stage 4 - Bootstrap -Run this stage only when Stage 2 scaffolded a new memory repo. +Run this stage only when Stage 3 scaffolded a new memory repo. Hand off to `c-03-repo-bootstrap` to generate initial onboarding. A thin `overview.md` is enough to start; deeper route-local overviews and file-level @@ -147,7 +205,7 @@ onboarding should grow as work touches new areas. Skip this stage when an existing memory repo was adopted. -## Stage 4 - Configure Providers To Index +## Stage 5 - Configure Providers To Index If providers are enabled, make them index the configured code and memory: @@ -177,10 +235,12 @@ Summarize: step the developer must perform; 2. runtime scaffold: `runtime_install()` run or already current, with the resolved coordination root; -3. memory repo: scaffolded, existing-adopted, or already present, with the +3. agentic settings: interviewed and written, or left at the seeded defaults, + with the global file path; +4. memory repo: scaffolded, existing-adopted, or already present, with the resolved memory root; -4. bootstrap: run via `c-03-repo-bootstrap` or skipped; -5. providers: indexing status and any deferred/degraded state. +5. bootstrap: run via `c-03-repo-bootstrap` or skipped; +6. providers: indexing status and any deferred/degraded state. End by telling the developer whether the project is ready for normal work. Do not tell them to restart for hooks installed by this skill, because this skill no diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/SKILL.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/SKILL.md new file mode 100644 index 00000000..1d390618 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/SKILL.md @@ -0,0 +1,259 @@ +--- +name: l-01-agent-lifecycles +description: "The agent lifecycles: one lifecycle per agent type, under one roof. Routes every session by exactly three conditions (spawn-role env -> role brief -> otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator, designer, strategist, manager, worker, adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. A developer-facing session IS the orchestrator; solo work is the degenerate portfolio. Supersedes and replaces both l-01-session-job-lifecycle and l-02-agent-orchestration." +--- + +# l-01-agent-lifecycles — The Agent Lifecycles + +Lifecycle and job are **one entity**: each agent type runs its own, self-contained lifecycle. This +skill is the single roof over all of them — a thin router, the minimal frame every session shares, +and the role lifecycles as the payload files. No role is defined by reference to another role's +lifecycle, and no role reads another role's file. + +## Which Lifecycle Am I? (the router — exactly three conditions, in order) + +1. **`AR_SPAWN_ROLE` is set** (spawn env, injected by `spawn_agent_session`) → run + `roles/.md`. Nothing else in this file's "developer session" material applies to you. + (`designer` here means the same design hat in a separate chair — see `roles/designer.md`.) +2. **Else: the first user message is a role brief** — a `templates/*-brief.md`-shaped dispatch or + a first line of the form `ROLE BRIEF — ` from an orchestrating agent → run that role's + lifecycle. The brief is your session start; a workspace session-start notice is not addressed + to you. +3. **Else** (a developer opened this session) → you are the **orchestrator**: run + `roles/orchestrator.md`. Solo work is the degenerate portfolio — the same three jobs with hats + collapsed (the orchestrator wears the manager hat in flat runs and builds hands-on at session + scale); the task doc still comes first. + +There is no fourth entry, and the edge cases are decided: an **unresolvable `AR_SPAWN_ROLE` +value** (no matching `roles/.md`) falls through to condition 2 (the brief); a role-env +session **whose brief never arrives** announces itself on the inbox and waits — it never +improvises a task; `AR_SPAWN_ROLE=orchestrator` is valid only as a takeover chair (the Profile +check (takeover) in `roles/orchestrator.md`, The Event Loop) — the developer still talks to **one** orchestrator. Orchestrated +fan-out (spawning managers/workers at scale) begins only on an explicit developer request (e.g. +*"orchestrate these masters"*) — no agent promotes itself into a spawning seat. + +One exception to the no-cross-reading rule above: **a seat that WEARS a hat runs that hat's file +as its own** — the orchestrator always for `roles/designer.md`, and in flat runs for +`roles/manager.md` (the hat-collapse rule). + +## The Role Registry + +| Role | Seat | Lifecycle file | +| --- | --- | --- | +| **orchestrator** | the developer-facing session; first coordination leaf of an orchestrated series | `roles/orchestrator.md` | +| **designer** | a HAT the orchestrator pulls inline (front of the pipeline or mid-flight; separate chair optional) | `roles/designer.md` | +| **strategist** | the sprint planner, SPAWN-FIRST; a strategist run is a **mandatory precondition for any orchestrated run** — its deliverable is the orchestration task (sprint plan + scope); spawn value `strategist` | `roles/strategist.md` | +| **manager** | one coordination leaf per master; drives that master's leaf loop | `roles/manager.md` | +| **worker** | one leaf worktree, short-lived, fresh session | `roles/worker.md` | +| **adversarial reviewer** | short-lived, spawned at the two seams (master-exit, super-exit) and as any three-party loop's reviewer seat (criteria catalogs bound per review type); spawn value `reviewer` | `roles/reviewer.md` | + +The **lenses** (bug · feature · triage · research — `lenses.md`) are how the scoping seats +(orchestrator, designer) read a piece of work; a dispatched role never picks a lens — its brief +already carries the flavor. + +## The Minimal Frame (the only machinery every session shares) + +Every session in a managed repo may be a **lifecycle**: six signals — `lifecycle_start` · +`lifecycle_phase` · `lifecycle_turn_end_notification` · `worktree_attach` · `switch_lifecycle` · +`lifecycle_end` (plus the automatic `worktree_start` promotion) — record where it +is and what it waits on, so work is observable and resumable across chat deaths. The model **never +handles a lifecycle id** — identity is server-side, anchored in the worktree contract. + +| When | Signal | Effect | +| --- | --- | --- | +| Trust checkpoint passes (managed repo) | `lifecycle_start` | begin a **fleeting** lifecycle (guarded: one per session; no id) | +| Entering a phase | `lifecycle_phase` | move the phase axis (`request` / `trust-checkpoint` / `reframe-research` / `decide` / `build` / `close`) | +| A developer hand-off | `lifecycle_turn_end_notification(summary=…)` | set `awaiting-developer`, surface the attention item, return immediately; the **next turn's first AR call auto-resumes** — never resume by hand | +| `worktree_start` | *(automatic promotion)* | the fleeting lifecycle becomes **persistent**, anchored in the contract | +| Resuming an existing task | `worktree_attach` | re-adopts the contract's lifecycle (contract-resolved) | +| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | the save gate — never dropped silently | +| Close | `lifecycle_end` (`completed`\|`abandoned`) | the terminal record | + +Rules: a tool call outside any lifecycle is **dropped, never misattributed**; `paused` is +system-owned. **A spawned role that never touches mutating AR tools simply never instantiates a +lifecycle — that is correct, not a violation.** A spawned role runs its **own** lifecycle when it +runs one; it never adopts its spawner's. The session↔leaf association is the catalog binding made +at spawn (the **qualified** leaf key `//`), not lifecycle adoption. + +## Shared Invariants (every role can count on these) + +- **Continuity lives in the `task_doc` + durable artifacts, never in transcripts** — which is why + short-lived workers and reviewers are safe, and why every seat writes its artifact of record. +- **Escalation ladder: worker → manager → orchestrator → developer.** No rung is skipped, ever. + Each role file states only its own rung. +- **Observability:** coordination seats are `task_doc` leaves with attached chats; the developer + can walk into any seat at any level. +- **Decision-needing questions land in the task doc's `openQuestions`** — the rendered decision + surface; `notes/` carries the analysis behind them. + +## The Three-Party Loop (one home — this section owns the loop doctrine) + +**OWNER → BUILDER → REVIEWER → owner, at every level that owns work.** The owner never +self-approves; the builder never lands; the reviewer never decides — verdicts are evidence. The +owner checks the verdict and either redispatches a builder or escalates. Role files reference this +section; they do not restate it. + +| Level | Owner (holds the deliverable, rules, lands) | Builder | Reviewer | +| --- | --- | --- | --- | +| Leaf | the leaf's owning seat (manager; orchestrator in tight/flat mode) | spawned worker (no-commit contract) | spawned reviewer, criteria catalog + liberty | +| Master | the manager | the leaf workers | the master-exit seam reviewer (verdict rides `master-handover-approval`) | +| Portfolio | the orchestrator | the STRATEGIST (spawn-first) | reviewer with the plan-review catalog | + +**Complexity-scored tiers (per leaf, at dispatch).** The owning seat scores three axes — blast +radius (doctrine/enforcement/public surface vs leaf-local) · novelty (new subsystem vs +pattern-following) · size (files × steps) — into three tiers: **direct** (no loop +machinery — the level's ordinary build channel implements: hands-on at session scale, the leaf's +worker under a manager; self-check + checks ladder only), **builder-verified** (builder +implements; owner verifies report-vs-artifact; no reviewer), **full loop** (builder + independent +reviewer rounds). The +strategist's blast-radius register is the scoring input when an orchestration task exists. A +leaf's loop mark (tier + scope: manager | orchestrator — the owning level runs the loop with ITS +agent set) is recorded on the leaf doc with a decision-log entry. **A master whose leaves all +score `direct` is a workflow-free manager** — no loop machinery; the knobs make every loop +optional per level, never mandatory ceremony. + +**Rounds and the HARD cap.** A round = implement → review. **Hard cap: 3 rounds per loop — and +ONLY full end-to-end rounds count against it.** Residuals of a passing round are landed and +**delta-verified by the SAME reviewer via a follow-up message** (it retains everything it already +verified, at a fraction of a fresh round's cost); **fix rounds resume the SAME builder**. A fresh +reviewer is spawned only for a full round or when new scope opens. Delta-verifies close rounds; +they do not open them. + +**The convergence rule (the real control; the cap is the backstop).** Every round must SHRINK the +open finding set. A round that does not shrink it escalates immediately, regardless of the count; +a monotonically converging loop may never hit the cap at all. At the cap, or on non-convergence, +the owner does not spin another round — it **escalates one seat up the ladder (worker → manager → +orchestrator → developer) with the full round history attached**; the escalation packet IS the +upper seat's visibility. + +**Quo-vadis (the written developer-escalation criterion).** A question is developer-worthy when it +is a **high-blast-radius truth** — answered wrong it means big rewrites later (architecture +direction, security posture, doctrine contradictions, irreversible data/branch operations, where +agent settings live). Quo-vadis questions escalate IMMEDIATELY, regardless of round count. +Presentation-grade choices (2px vs 3px) never do — the owner rules and logs. + +**Criteria catalogs (the reviewer as test bench).** Criteria are never made up on the spot: every +review runs its type's standing catalog from `criteria/` (code-seam · doctrine · +onboarding-memory · report-verification · plan-review) plus an exploratory mandate, under the +promotion ratchet (each catalog carries it). `roles/reviewer.md` binds them. + +**Per-level agent sets.** Each level runs its loop with its own harness/model/effort set — the +orchestrator-level set (the strongest models) and the manager-level set (cheaper, possibly +workflow-free) are configured per level in the `orchestration.loops` settings block (schema in +`docs/reference/settings-json.md`; stored in the global agentic settings file with repo-local +override, parsed by the kernel agentic-settings loader — L13, landed). The strategist's mandatory +pre-run is doctrine, not a knob — it is unconditional. + +## Knob Block & Capability Doctrine (no per-harness files) + +Role files are **model-interpreted markdown, never an executor**. Each carries a portable **knob +block** (harness / model / effort / tools) — the defaults the terminal host injects at spawn. +Resolution: **role-file defaults < settings.json orchestration block.** There are deliberately +**no per-harness role files** (developer decision 2026-07-05): harness-specific ABILITIES — +sub-agent fan-out and the like — are covered inside the portable files as capability-conditional +doctrine any coding agent can apply, and harness PREFERENCE is deployment configuration +(settings), not doctrine. Hard-coding a vendor would fork the doctrine per harness. For spawning +seats, `spawn_agent_session` is itself the harness-independent fan-out: a harness with no +sub-agent facility still dispatches seats through the framework (a chat, no leaf attachment +required) — the DBMS principle: one behavior, any engine. + +## settings.json Orchestration Block + +Machine/user overrides layer over the role-file defaults, in the **global agentic settings file** +(`/system/settings.json`), with `/system/settings.json` as the +repo-local override layer (leaf-key deep merge, arrays replace, unknown `orchestration.*` keys +fail loud — schema in `docs/reference/settings-json.md`, Agentic Settings). Precedence: role-file +defaults < global settings < repo-local settings. + +```jsonc +{ + "orchestration": { + "roles": { // role → knob override; validated: harness/model/effort · free-form: launchArgs/promptKeywords/sessionCommands + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { // per-LEVEL agent sets (leaf|master|portfolio), deep-merged over roles + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" }, // spawn_agent_session default when the seat passes none + "gateDelegation": { + "policy": "manager-decides-leaf-gates", + "requireReviewerVerdictAtSeams": true + } + } +} +``` + +**As-built (L13 + L16):** the whole block is parsed by the kernel agentic-settings loader +(`kernel/agentic_settings.py`) — typed models for `roles` / `rolesPerLevel` / `concurrency` / +`spawn` / `harnesses` / `loops`, +read PER-USE (an edit applies on the next use, no restart). `orchestration.gateDelegation` is +parsed and **enforced** (`controlplane/gate_policy.py` — all-human default, opt-in delegation, +human-pinned kinds `integration-approval` / `push-approval` / `cleanup-approval`, owner never +self-approves); it is the ONE boot-snapshot key — read from the global file at MCP boot, a change +needs a restart (an authority-file value is a one-cycle legacy fallback with a boot warning). +`requireReviewerVerdictAtSeams` **binds delegated seam decisions** (`master-handover-approval`) to +attached reviewer-verdict evidence; the named policy `manager-decides-leaf-gates` routes leaf gates +to the manager and the master-exit handover to the **orchestrator** (human review concentrates at +the super gate). `spawn_agent_session` resolves its knobs (260703-L16) as explicit args > +repo-local level override > global level override > repo-local role default > global role default +> detection-gated default — the dispatcher declares its `level` (leaf|master|portfolio, default +leaf) and the resolved level rides spawn provenance — and **applies** them at the harness +boundary: model/effort ride as `AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` env AND map onto the launch argv +per-harness via the effective registry (claude `--model`/`--effort`; a mapping-less harness stays +env-only; a session-vocabulary effort like claude's `ultracode` is delivered as a post-launch +`/effort` paste). Unknown effort values REFUSE at dispatch naming the harness's vocabulary — the +CLI would warn-and-silently-degrade. The free-form escape hatch (`launchArgs` verbatim argv, +`promptKeywords` riding the brief paste, `sessionCommands` pasted before the brief) is never +validated, only recorded in spawn provenance; `orchestration.harnesses` teaches the framework new +TUIs or pre-customizes builtin launches (manual: `docs/reference/harnesses.md`). +`orchestration.loops` (the three-party-loop knobs: per-level loop sets, round cap, reviewer +reuse, complexity thresholds) lives in the same block — meaning in +`docs/reference/settings-json.md`; no knob touches the master-exit seam gate. + +## Companion Files + +- `lenses.md` — the four job lenses for the scoping seats. +- `roles/…` — the six self-contained role lifecycles (the registry above). +- `templates/…` — turn-report · worker-brief · manager-brief (`ROLE BRIEF — manager`; the + orchestrator compiles a manager's session start from it) · master-handover-packet · + conversation-handover-packet · verdict · impact-analysis · onboarding-coherency · + deep-research-report · orchestration-task (the strategist's sprint plan). Spawning seats compile + briefs FROM these; sub-agents fan out and fill them, so analysis survives compaction. +- `criteria/…` — the reviewer criteria catalogs (code-seam · doctrine · onboarding-memory · + report-verification · plan-review), the review test bench the three-party loop binds; maintained + through the promotion ratchet, never made up on the spot. + +## The Super Integration Branch (orientation only — the doctrine lives with its owner) + +``` +main + └── super-integration (orchestrator-owned, off main) + ├── master-A branch (off super) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, C-11) + ├── master-B branch (off the moved super — sees A) + └── … final: super → main PR + memory carry-over + push +``` + +The full topology — dependency-ordered dispatch, the integration-duty procedure, the two +conflict-resolution modes, leaf moves — lives in **`roles/orchestrator.md`** and only there. + +## Credits + +This skill absorbs and supersedes `l-01-session-job-lifecycle` and `l-02-agent-orchestration` +(converged 2026-07-05: lifecycle and job are one entity — one lifecycle per agent type). The +orchestration vocabulary adopts the parked `260619_agentic-control-plane` spec — jobs as +model-interpreted markdown (D6), the knob block (D7), role + lens in one file (D10), the +ambient-singleton rule (D11), per-harness variants (D12), the judge rung, short-lived workers with +structured handoff, dev-talks-to-one-orchestrator (D15) — which in turn credits **Archon** and the +**agent-control-plane** project (D14); that credit carries forward. + +## Relationship To Other Instructions + +This skill extends — never replaces — the coordinator `AGENTS.md`, the `w-02-light-task-workflow` +task format, and the memory layer (`c-…` skills). Each `roles/.md` is self-contained for its +seat; read exactly the one the router selects. diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/code-seam.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/code-seam.md new file mode 100644 index 00000000..053feb1b --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/code-seam.md @@ -0,0 +1,85 @@ +# Criteria Catalog — Code-Seam Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review wires code seams: consumers, enforcement points, gates, addresses, tool contracts. +Binds at the master-exit and super-exit seams and in any loop review whose change set touches code +(see the binding table in `../roles/reviewer.md`). Criteria are never made up on the spot: the +standing list below is the regression floor, run every time; the exploratory mandate and the +promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### CS-1 — Production-wiring walk + +**Trace the real call path, never a hand-aligned harness.** A claim that a consumer or an +enforcement point exists must be walked through the PRODUCTION call path — the controller, the +tool registration, the store fold — not through a test that hand-assembles the pieces into +alignment. A test can pass while the production consumer is inert. + +- Catching evidence: 260703-L8 review 3 (AR3-1) — the integrate consumer was proven **inert**: the + policy was omitted at the controller and the gate was looked up on the wrong lifecycle, while a + hand-aligned test passed (L8 decision log, cycle-6 entry). + +### CS-2 — Fail-open hunt + +**What happens when the address/config is absent or mistyped?** For every identity, address, key, +or config the seam matches on: feed it nothing, feed it a near-miss, and confirm the seam fails +CLOSED (refuses) rather than open (silently proceeds unmatched). + +- Catching evidence: 260703-L8 review 4 (AR4-1) — the seam's `enclosure` address had to be pinned + as an exact-string contract and the enclosure-less raise made a refusal (L8 decision log, + cycle-7 entry). + +### CS-3 — Validate-then-mutate + +**Every raise/write validates before it mutates.** A call that records state (a gate raise, a +store append, a contract write) must perform its refusal checks before any durable effect; a +mutation that precedes validation leaves half-states behind on refusal. + +- Catching evidence: 260703-L8 cycle 6 — the `wait=false` raise was reworked to be + validate-then-mutate and seam-kind-restricted (L8 decision log, cycle-6 entry). + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### CS-4 — Reused-primitive affordance parity *(candidate — 1 catch)* + +**When a screen reuses a shared content primitive, verify every branch of the ORIGINAL's +affordances (banners, status chips, truncation notices, error states) still fires on the reuse +path.** A dropped affordance is a silent regression the reuse's own tests won't catch — they +assert the new screen's happy paths, not the primitive's full surface. + +- Catching evidence (single engagement): 260703-L17 review (L17R-2) — the notes reader's + `DualPane` reuse drops the "first 2 MiB" truncation banner on the markdown path (the banner + lives in `CodeSide`, which markdown never reaches); text and binary keep it. + +### CS-5 — Cross-repo side-effect safety *(candidate — seeded from a clean exemplar, 0 catches)* + +**Any step that writes to a repository OTHER than the one it operates in gets the full +validate-then-mutate treatment plus partial-failure and dirty-target analysis.** Check the order +of validation vs the foreign write, the state left behind when the write lands but the caller +fails afterward, behavior against a dirty target repo, and an exact format round-trip with the +foreign artifact's consumer. + +- Seeding evidence: 260703-L18 finding 7 (`_reconcile_missing_mapping` writing the official + memory repo's ledger mid-`worktree_start`) PASSED all four lenses under this analysis — the + clean exemplar that defined the class. A catch in a later engagement promotes. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS change set the catalog does not name yet. Every novel finding-class that survives +refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/doctrine.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/doctrine.md new file mode 100644 index 00000000..9b9ccae1 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/doctrine.md @@ -0,0 +1,58 @@ +# Criteria Catalog — Doctrine Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review is doctrine: skill files, role lifecycles, templates, instruction surfaces, docs +that agents obey. Binds whenever doctrine/skill files are in the change set (see the binding table +in `../roles/reviewer.md`). Criteria are never made up on the spot: the standing list below is the +regression floor, run every time; the exploratory mandate and the promotion ratchet keep the +catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### D-1 — Doctrine-vs-code anchoring + +**Every "X enforces Y" needs a code anchor.** A doctrine sentence claiming enforcement, refusal, +or automatic behavior must resolve to the code that does it (file + mechanism). Doctrine that +narrates enforcement which does not exist is a defect, not an aspiration. + +- Catching evidence: 260703-L8 review 1 (AR-5) — `requireReviewerVerdictAtSeams` was documented as + binding while the flag was **inert**; the finding forced the wiring (L8 decision log, AR-1 + entry: "closing AR-5's inert flag"). + +### D-2 — Cross-file contradiction sweep + +**Sweep sibling doctrine for statements the change set now contradicts.** A doctrine change is +reviewed against the whole doctrine surface (skills, role files, templates, docs, hooks, canvas +prose), not just the edited files — one file's new invariant is another file's stale sentence. + +- Catching evidence: 260703-L10 — the landed "chat is never a build route" invariant contradicted + surviving chat-build wording inside `c-09` / `w-02` (builder escalation 1, owner-sanctioned + sweep; L10 builder report). + +### D-3 — Stuck-state walk + +**Can an agent following the prose deadlock?** Walk the doctrine as the obeying agent: at every +wait, gate, and handover, ask who unblocks it and through which channel. Prose in which two seats +each wait on the other — or a seat waits on a channel nobody is told to serve — is a blocking +finding. + +- Catching evidence: 260703-L8 review 2 — the seam deadlock: the manager's blocking raise and the + orchestrator's decide path could not meet as written; the ruled `wait=false` + + packet-carried-gateId channel resolved it (L8 rounds 2/4b history). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS doctrine change the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md new file mode 100644 index 00000000..e47783e3 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md @@ -0,0 +1,67 @@ +# Criteria Catalog — Onboarding/Memory Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run over the +memory side of a change set: sidecars, route overviews, route indexes, update histories. Binds at +the master-exit and super-exit seams (the onboarding-vs-code lens) and in loop reviews whose change +set carries onboarding (see the binding table in `../roles/reviewer.md`). Criteria are never made +up on the spot: the standing list below is the regression floor, run every time; the exploratory +mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### OM-1 — Staleness diff vs as-landed code + +**Diff every body claim about current behavior against the as-landed code.** A sidecar or overview +body that describes the present tense is checked against what the branch actually ships — deleted +things still described, renamed things under old names, duplicated rows. + +- Catching evidence, two separate engagements: 260703-L8 cycle 6 (owner follow-up pass) — route + overview bodies still described **deleted canvas models** (the panels overview's build-job/frame + tail) and carried **duplicated table rows** (the tools and controlplane overviews' Layout + tables), durably recorded in those overviews' own 2026-07-05T19:25 Update History entries; + 260703-L10 — the flowModels sidecar body was still the pre-convergence 8-model census and its + references row still said "8 models" (the sidecar's 2026-07-06T12:05 history entry + L10R-3). + +### OM-2 — History-only-update detection + +**"Refreshed" must mean a genuine body edit.** An onboarding file whose only change is a new +Update History line has NOT been refreshed — the body still asserts the old truth. Check that +every claimed refresh touched body sentences, not just the history list. + +- Catching evidence: 260703-L8 cycle 6 — the builder reported route overviews as refreshed when + they were **history-only**; the closeout body gate caught it (L8 decision log, cycle-6 entry: + "report-vs-artifact verification belongs in the reviewer criteria catalog"). + +## Candidate Criteria (seeded exploratory — one catching engagement; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### OM-3 — Newest-first with the checker's own semantics *(candidate — 1 catch)* + +**Update History sorts newest-first under the CHECKER's datetime parse, not lexicographically.** +The quality checker compares naive timestamps as-is and folds tz-aware stamps to UTC; a merge or +mechanical insert that sorts by string can pass the eye and fail the gate (or worse, pass the gate +in the wrong order). Verify ordering with the checker's semantics. + +- Catching evidence (single engagement): 260703-L11 — four onboarding history collisions from the + parallel wave had to be re-sorted **with the checker's own datetime semantics** (naive compare + as-is, tz-aware folds to UTC); the quality gates caught the owner's wrong sort key (L11 decision + log). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS memory delta the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate is the working example, and it is THIS catalog's own OM-2 mechanized: the gate catches + history-only "refreshes" at commit time, where prose requests did not. diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/plan-review.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/plan-review.md new file mode 100644 index 00000000..ef4d2d90 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/plan-review.md @@ -0,0 +1,69 @@ +# Criteria Catalog — Plan Review (the strategist loop) + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run against an +**orchestration task** (`../templates/orchestration-task.md`) — the strategist's sprint plan — +before the developer's drawing board. This is the portfolio loop's review type: owner = +orchestrator, builder = strategist, reviewer = this catalog. The reviewer holds the same read-only +analysis tools the strategist used (`cgc_*`, `grepai_*`, `read_ar_files`), so the plan's mechanical +claims are re-derivable, not just readable. Criteria are never made up on the spot: the standing +list below is the regression floor, run every time; the exploratory mandate and the promotion +ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### PR-1 — Refute uncited edges + +**An uncited dependency edge is refutable by default.** Every edge in the dependency graph must +carry evidence — a cgc/grepai query, a file, a decision-log entry, a design-section citation, or +(for new surfaces) a declaration cross-reference naming both leaf declarations. An edge with no +evidence is challenged as a finding; so is evidence that does not actually support the edge's +direction or kind. + +### PR-2 — Missed-shared-surface hunt (class-completeness on intersections) + +**Re-intersect the surface lists independently.** Take the plan's per-leaf touch surfaces (both +existing and declared-new), recompute the pairwise intersections, and hunt pairs the edge list +omits — including CONFLICT-risk at a shared parent route where two leaves declare additions +(wiring points, shared registries). A plan that lists surfaces but misses one of their +intersections has a hole exactly where collisions happen. + +### PR-3 — Blast-radius re-derivation + +**Re-derive at least the HIGH-blast-radius entries with the cgc tools** (`cgc_dependencies` / +`cgc_callers` / `cgc_callees`, capped depth) — and spot-check a sample of the low/medium entries. +A register entry whose derivation cannot be reproduced, or whose classification drops the doctrine +propagation / migration / user-visible unions, is a finding; the register parameterizes every +downstream loop tier, so an understated radius under-reviews a leaf. + +### PR-4 — Order-respects-edges + +**Check the sprint order/waves against the edge list, mechanically.** No ORDER edge may run +backwards across the proposed sequence; every CONFLICT edge must be resolved by serialization or a +recorded leaf move (from→to + rationale); parallel waves may contain only INDEPENDENT pairs, and +the wave plan must acknowledge the landing-reconciliation cost. + +### PR-5 — Honesty of the findings section + +**Verify the plan's failure claims both ways.** Every "unplannable as scoped" finding must be +genuine (the leaf can name neither existing surfaces nor the parent anchoring of its additions — +a merely not-yet-existing surface is NOT unplannable); and thin leaf scopes the plan silently +guessed around instead of flagging are themselves findings. Quo-vadis contradictions must be +flagged at the top of the coherence findings, not buried. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS plan could be wrong that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example; PR-4 is this catalog's mechanization candidate (a topological check over + a structured edge list). diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/report-verification.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/report-verification.md new file mode 100644 index 00000000..fb3bdda8 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/criteria/report-verification.md @@ -0,0 +1,95 @@ +# Criteria Catalog — Report Verification + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) — and the loop OWNER +verifying a builder round — MUST run over every report, claim, and summary in the change set: +builder reports, owner claims, handover packets. **Standing from day one** in every review type: +report-vs-artifact caught real defects in three separate engagements before this catalog existed. +Criteria are never made up on the spot: the standing list below is the regression floor, run every +time; the exploratory mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### RV-1 — Report-vs-artifact on EVERY claim + +**Open the artifact behind every claim.** A report sentence asserting "X was done / is green / +was refreshed" is verified against the artifact itself, not trusted — claim by claim, no sampling +of the load-bearing ones. + +- Catching evidence, three separate engagements (260703-L8): review 3 caught a **hand-aligned + test** behind a wiring claim; cycle 6's closeout gate caught **"refreshed" overviews that were + history-only**; review 4 caught the **OWNER's own canvas overclaim** (L8 decision log, cycle-7 + entry) — builder reports and owner claims fail the same way. + +### RV-2 — CLASS-completeness *(promoted to standing at 260703-L18 — 2 catches)* + +**Hunt the siblings of every found instance.** A finding or a fix names an instance of a CLASS +(a directive surface, a census count, a vocabulary token). Enumerate the class — every sibling +surface, not just the instances the report names — and check each one. + +- Catching evidence: (1) 260703-L10 round 1 — the reviewer's completeness sweep found **six of + ten first-action surfaces** still shipping the retired directive when the report claimed the + flip done (L10 decision log). (2) 260703-L18 review (L18R-3) — the fix for + advertised-but-unimplemented recovery choices named the `cli.py` `custom` residual but missed + the SIBLING `_load_memory_ledger` block still advertising an inert `reconciliation`; the + sibling hunt found it. + +### RV-4 — Decision-log completeness for scope-expanding disclosures *(promoted to standing at 260703-L18 — 2 catches)* + +**A scope-expanding owner supplement or load-bearing builder disclosure must be verifiable in +the task-doc decision log, not only the builder report.** Continuity lives in the task_doc + +durable artifacts, never in transcripts; a ruling or environment finding that exists only in a +report is one lost file away from unrecoverable. Cross-check every supplement and disclosure the +builder report carries against the decision log. + +- Catching evidence: (1) 260703-L17 review (L17R-1) — supplement 2 (the wait-loop-era remnant + sweep with per-hit verdicts and two named follow-ups) was recorded only in the builder report. + (2) 260703-L18 review (L18R-4) — the load-bearing editable-install/PYTHONPATH environment + finding + named follow-ups lived only in the builder report; the leaf's `decisions[]` was + empty. Both folded by the owner at closeout. + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### RV-3 — Partial-fix-creates-falsehoods *(candidate — 1 catch)* + +**Verify claims ABOUT the changed artifacts, not only the artifacts.** A partial fix can turn +previously-true sentences elsewhere false (docs describing the artifact, install guides quoting +it, counts referencing it). Sweep for statements about what changed and re-verify their truth +after the change. + +- Catching evidence (single engagement): 260703-L10 round 1 — the partial hook flip made **two + install-doc claims false** ("injects the same startup directive" no longer held); round 2 + restored byte-identity so the claims became true again (L10 decision log + builder report). + +### RV-5 — Worktree-shadowed regression pins *(candidate — 1 catch)* + +**A regression test must bite under the invocation the owner actually runs.** An editable +install pointing at another checkout can shadow the worktree's sources, making a mutation-tested +pin pass vacuously under the canonical invocation while failing only under a hand-set +`PYTHONPATH`. Verify sensitivity by mutating the target and running the CANONICAL invocation; +a pin that only bites under a nonstandard environment is not yet a pin. + +- Catching evidence (single engagement): 260703-L18 review (L18R-1) — the inbox + delivered/unconfirmed pin failed its mutation check only under `PYTHONPATH=src`; under the + canonical `pytest mcp/tests` the main-repo editable install shadowed the worktree and the + mutated code still passed. Remedy: the `sys.path` pin idiom the sibling suites carry. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS report could mislead that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests (RV-1 is itself the precedent: promoted on three catches). Promotion is proposed in the + verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/lenses.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/lenses.md new file mode 100644 index 00000000..0f277b06 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/lenses.md @@ -0,0 +1,45 @@ +# Lenses — How the Scoping Seats Read a Job + +Read by the **scoping seats** (orchestrator, designer); a dispatched role never picks a lens — its +brief already carries the flavor. The job type is a **lens**, picked during `reframe-research` and +re-pickable at any time. It is not a gate and it never changes the orchestrator phase axis +(`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three +things only: + +- **Opening move** — the first concrete thing `reframe-research` does for this kind of job. +- **Retrieval lean** — which `c-04-retrieval-strategy-router` strategy leads (others are still available). +- **Decide default** — where this job usually lands at `decide` (still a real decision, not automatic). + +| Job | Opening move (in `reframe-research`) | Retrieval lean (`c-04-retrieval-strategy-router`) | `decide` default | +| ---------- | ----------------------------------------------- | ---------------------------------- | --------------------------- | +| `bug` | reproduce the failure; prove the root cause | Relationship (cgc) + Intent | -> build | +| `feature` | clarify intent, scope, and explicit non-goals | design doctrine + Intent | -> build | +| `triage` | assess severity, blast radius, and ownership | breadth scan (Semantics first) | may exit (route or spawn) | +| `research` | state the question precisely | Semantics (grepai) + onboarding | research-only exit | + +## bug + +Lead with a reproduction and a proven root cause before proposing a fix — an unproven fix is a guess. +Lean on Relationship (callers/callees/impact via cgc) to bound the change, and Intent to confirm the +invariant the bug violates. Defaults to a build; the fix lands through `decide -> build -> close`. + +## feature + +Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the +design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the +contracts the feature must respect. Defaults to a build; size decides the minimal `w-02-light-task-workflow` artifact vs a master + +sub-task series at `decide`. + +## triage + +Lead by assessing severity, blast radius, and ownership — enough to route, not to fix. A breadth scan +(Semantics first) maps the surface fast. Triage frequently **exits research-only**: its product is a +recommendation, a routed owner, or a spawned build/bug job — not a code change. Only escalate to a +build when triage itself is the cheapest place to fix it. + +## research + +Lead by stating the question precisely. Semantics (grepai over onboarding) plus committed-state +onboarding usually answers it; reach for source only as bounded Intent confirmation. Research +**exits research-only** by design: it produces an answer, and may recommend a follow-up build job, but +performs none itself. diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/designer.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/designer.md new file mode 100644 index 00000000..c67cec40 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/designer.md @@ -0,0 +1,91 @@ +# Lifecycle — Designer (the hat) + +> The design lifecycle the **orchestrator pulls inline** whenever design is needed — front of the +> pipeline or mid-flight. **A hat, not a seat**: it cannot sit in a coordination leaf because the +> task is what it exists to create — no leaf, no worktree, no branch, no spawn required. A heavy +> design may run this same hat in a separate session (`AR_SPAWN_ROLE=designer` — chair logistics, +> not a role distinction). +> +> Drawn as the **DESIGNER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Hat Is + +Task design is **its own job** (developer decision 2026-07-04). Before orchestration one implicit +do-it-all role did design, features, and fixes; the roles now diversify, and design routes +**through the orchestrator, which wears this hat** — at the front of the pipeline AND mid-flight +(most leaves of a live series are designed mid-flight). It is the `tasks/AGENTS.md` collaboration +doctrine (meta-questioning, reframe-before-execution, evidence-first) given a distinct, optimized +shape as a job. Nothing here assumes a master exists yet — producing one is the point. + +The designer shares the orchestrator's **bird's-eye toolkit** — route indexes, onboarding, the +`grepai_search` MCP tool, the code-graph (`cgc_*`) MCP tools, blast-radius analysis — but is **scoped +to one master**. Collisions with *other* — especially **future** — masters can slip past a +single-master view. That residual risk is **owned downstream, not here**: at portfolio streamlining the +**orchestrator doubles as the designer's adversarial reviewer** (planned-vs-planned and +planned-vs-past). The designer's duty is to *declare* the limit, not to close it. + +## Lens + +- **Opening move:** meta-question the ask. Surface the request, the deeper objective, and the + highest-leverage framing before any structure exists — do not jump from the developer's first + phrasing to a plan. +- **Retrieval lean:** evidence-first, within the master's scope. Route indexes and onboarding for the + map; `grepai_search` for semantics; `cgc_*` for relationships/impact; bounded `read_ar_files` for + intent confirmation. Sub-agents fan out and write durable reports. +- **Decide default:** a `w-02-light-task-workflow`-shaped master + leaf task_doc, handed into the + portfolio — **not** a build. The designer designs; it does not implement. + +## Duties + +1. **Reframe with `tasks/AGENTS.md`.** Distinguish surface request · deeper objective · highest-leverage + framing · assumptions · boundaries · invariants · truth gaps. Material scope/intent/sequencing + changes are **played back and wait for confirmation**; a pure clarification may be presented and + continued. +2. **Evidence-first, master-scoped.** Make the evidence model visible before or alongside the plan + (external · repo-internal · cross-repo · executable). Gather it through the + `c-04-retrieval-strategy-router` skill, not ad-hoc reads. +3. **Blast-radius WITHIN the master.** Routes touched · invariants at risk · regressions — bounded to + this master's scope. Cross-master and future-master reasoning is explicitly out of the designer's + reach. +4. **Author the task_doc.** Master + leaves (requirements · steps · code examples per distinct change, + the `w-02-light-task-workflow` shape), leaves scoped around routes/areas, via the `task_doc` MCP + tool. Include a **code example for every distinct change** when code is in scope. + Decision-needing questions land in the task doc's `openQuestions` — the rendered decision + surface; `notes/` carries the analysis behind them. +5. **Declare the designer limit.** Record on the doc that this is a **master-scoped bird's-eye**: + cross-master and future-master collisions can slip and are owned downstream at streamlining. Never + hide the limit. +6. **Ask, never fill silently.** Assumptions and truth gaps only the developer can resolve are asked as + a short, high-leverage list — never filled silently. + +## Artifact Obligations + +- The **task_doc** (master + leaves) is the durable artifact of the designer job. +- A **designer-limits note** on the doc — the declared master-scoped blind spot, for the orchestrator's + later adversarial pass. +- Evidence reports from fan-out sub-agents (durable), so the framing survives into streamlining. + +## Comms Protocol + +- **Primary channel:** the developer, directly, in the designer's attached chat — this seat is a + co-thinking loop, so the developer is the standing interlocutor here (unlike the deeper seats, which + relay through the ladder). +- **Handover:** the finished design **joins the portfolio**. At streamlining the orchestrator + adversarially reviews it; hand the task_doc + the designer-limits note over via the inbox + (`operator_inbox_post`) and, for a hosted orchestrator, stdin push. +- **Escalation:** the hat's "escalation" is simply the handover into the portfolio job — the + orchestrator that wears it is already the last resolver before the developer. + +## Knobs + +| Knob | Default | Notes | +| ------- | ------------------ | --------------------------------------------------------------------- | +| harness | (the wearer's) | the hat runs inside the orchestrator session, or a spawned design chair | +| model | high-reasoning | reframe + blast-radius reasoning wants a strong model | +| effort | high | design leverage justifies the thinking budget | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | bird's-eye toolkit | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · inbox | + +Settings.json `orchestration.roles.designer` overrides these, and `orchestration.rolesPerLevel..designer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/manager.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/manager.md new file mode 100644 index 00000000..0b42124a --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/manager.md @@ -0,0 +1,168 @@ +# Lifecycle — Manager + +> One master, one seat, self-contained. The manager lifecycle drives exactly one master series: +> spawn a fresh worker per leaf, review turn reports, decide the delegated leaf gates, close out and +> integrate each leaf, hand the completed master to the orchestrator through the master-exit seam. +> Your **brief is your session start**. +> +> Drawn as the **MANAGER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**One per master task.** Spawned by the orchestrator with the master's context packet. It owns its own +coordination leaf + chat (**no worktree**) and drives exactly one master series: spawns/respawns a fresh +worker per leaf, reviews turn-report artifacts, decides **delegated** leaf gates, integrates leaves into +the master integration branch via the `c-11-memory-carryover-from-branch` skill, and hands the completed +master to the orchestrator through the master-exit adversarial seam. + +The manager owns the leaf lifecycle machinery **end-to-end**: `worktree_start` → (the worker +builds) → closeout preview/apply (deciding the delegated gates per the gate policy) → +`worktree_integrate` → finalize — task-doc statuses via the finalizer, **steps checked by this +seat by hand** (the tool does not reconcile checkboxes). The worker's terminal +state is checks-green + turn report; everything after that is this seat's. + +**Flat-run note:** in a flat series (no managers spawned) the **orchestrator wears this hat** — +same duties, same artifacts, one chair. + +A manager has **no bird's-eye view** — it sees one master, not the portfolio. That boundary shapes +everything below. + +## Lens + +- **Opening move:** read the master `task_doc` + its leaf docs; order the leaves (parallel where safe — + the C-11 reconcile absorbs a moved base). +- **Retrieval lean:** intent-confirmation on the master's own routes (paired `read_ar_files`); the + breadth/blast-radius reasoning belongs to the orchestrator, not here. +- **Decide default:** dispatch the next ready leaf; the master exits through the master-exit seam. + +## The Default-Behavior Rule (read this before anything else) + +The **default agent behavior stands**: **fulfill the task, fill small blanks.** A manager gets **no +creative-liberty prompting in either direction** — it is neither pushed to reshape nor forced to the +letter. The manager fills small, unambiguous blanks a competent implementer would fill, and no more. + +> **The spirit test does NOT apply to this seat.** It is orchestrator-only. A manager's changes can +> collide with what it cannot see, so a **plan delta beyond blank-filling escalates to the +> orchestrator** — the manager does not reshape plans. This is not a licence to be timid and it is not a +> licence to be creative; it is the ordinary "do the task well, ask when the task itself is in +> question" default, with the ask routed **up the ladder to the orchestrator**, never to the developer. + +## Duties + +### 1 — Seat & intake + +Take the master's own coordination leaf (`task_doc`, no enclosure); the chat is attached so the +developer can walk in any time. Read the master + leaf docs; order the leaves. + +### 2 — Leaf dispatch loop (per leaf) + +- **Score the leaf's loop tier at dispatch** (loop doctrine: `../SKILL.md`, The Three-Party Loop): + blast radius · novelty · size → **direct** (NO loop machinery: the leaf's worker implements as + usual — worker self-check + checks ladder + this seat's ordinary artifact review; this seat + still dispatches per leaf and never grows a build surface) | **builder-verified** (the worker + implements; this seat additionally verifies its report claim-by-claim against the artifacts; no + reviewer) | **full loop** (worker + independent reviewer rounds). When an orchestration task + exists, its **blast-radius register is the scoring input**. Record the mark (tier + scope: + manager | orchestrator — the owning level runs the loop with ITS agent set) on the leaf doc with + a decision-log entry. **A master whose leaves all score `direct` is a workflow-free manager** — + no loop machinery, just the dispatch-review-integrate spine below. +- On a full-loop leaf, run the loop with this level's controls: a round = implement → review; + **hard cap 3 full rounds** (delta-verifies by the SAME reviewer close rounds, they do not count; + fix rounds resume the SAME builder); **every round must shrink the finding set** — a + non-shrinking round escalates to the orchestrator immediately, with the full round history + attached, regardless of the count. +- `spawn_agent_session(worker)` — a **fresh session** on the leaf: the brief (compiled from + `../templates/worker-brief.md`) is pasted + submitted, with `env={"AR_SPAWN_ROLE": "worker"}` and + the **qualified** leaf key `//`; the worker edits inside the leaf + worktrees the brief names. +- **Monitor the worker** — a turn-report artifact is expected at **every** hand-off. Inactivity or a + missing artifact → a **rate-limited stdin nudge** (logged as an event, never spammy). Escalation + intake via the inbox. +- **Review artifact vs `task_doc`** — completion vs requirements/steps · checks green · + onboarding refreshed in the same pass (the manager's own leaf-level review; **this is not an + adversarial seam**). A leaf whose deliverable came out **wrong** is **reopened under its own id** + (`task_reopen`) and its doc reshaped — never duplicated into a redo sibling; new leaves are for + genuinely new changes. +- **Delegated leaf gates (plan · closeout)** — decide the leaf's delegated gates, **attributed** + (`decidedBy: `, `decidedVia: orchestration`), appended and dashboard-visible. The + **owning agent never self-approves; a distinct configured role may** — that configured role is the + manager. (Enforced as-built by the gate policy: `orchestration.gateDelegation` in settings, + `controlplane/gate_policy.py` — human-pinned kinds stay human, decisions attributed.) + Your own hand-off idiom, this seat only: durable gates + inbox posts — you never call the + developer-facing notification; your counterparty is the orchestrator. +- **Integrate leaf → master branch** via the `c-11-memory-carryover-from-branch` skill (ff-only / replay + per the `c-09-git-worktree-manager` skill). Know the human-pinned gate kinds by name: + `integration-approval`, `push-approval`, `cleanup-approval` — none is ever delegable. When a + durable `integration-approval` gate is raised on this step it awaits the **developer** (via the + dashboard GateResponder or your attached chat — you do not relay; if the wait blocks the loop, + escalate to the orchestrator). Absent a durable gate, the **series' standing approval** governs: + the developer's portfolio-gate approval of this series, recorded in the planner master's + decision log, covers dependency-ordered leaf integrations. Loop until the master's leaves are + done. + +### 3 — Master-exit seam + +When all leaves have landed on the master integration branch, spawn the **adversarial reviewer** +(master-exit) via `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "reviewer"}` and the reviewer +role file (`roles/reviewer.md`), passing the master branch ref, +master/leaf task docs, worker turn reports, decision logs, changed paths, resolved +`system/tools.md` evidence, and carry-over state. The verdict lands at +`notes/reports/-master-exit-verdict.md` and attaches to the handover gate as +`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"pass|pass-with-notes|block"}]` +— a verdict over completion vs task docs · `system/tools.md` quality · onboarding-vs-code. **Blocked? → the verdict decomposes into fix leaves** the manager dispatches (loop +back to the leaf loop). Verdicts are **evidence, not decisions**. The seam channel, exactly: +**raise without blocking** — `lifecycle_gate(kind="master-handover-approval", +enclosure="", evidence_refs=[], wait=false)` (raise-and-continue +is allowed precisely because the kind is a delegated seam kind; the `enclosure` MUST carry the +master's identity — it is the address integration enforcement matches the gate by, and the match +is exact-string: pass the EXACT master task name as the contracts carry it (`worktree_start`'s +`task_name`) — the raise refuses without an enclosure; the call +returns the **gateId**); then **carry that gateId in the handover +packet** (§4) — the packet is the orchestrator's trigger AND its address for the gate. Under an +all-human policy the raise blocks and the developer decides — do not pass wait=false. Identity +truth, as-built: the gate pins to your ambient lifecycle when you raise it; the deciding +orchestrator resolves the gate **by the packet-carried gate id** (gate ids are model-visible — +only LIFECYCLE ids stay server-side) and its own ambient identity becomes `decidedBy`; +owner-never-self-approves holds by construction. A handover carrying serious issues the +orchestrator cannot answer on its own escalates up the ladder (orchestrator → developer). + +### 4 — Handover to the orchestrator + +Post the **master-handover packet** (`../templates/master-handover-packet.md`) — inbox (durable) + stdin +push — integration branch ref · change-set summary · verdict ref · **handover gateId** · +carry-over state. The seat (chat + coordination leaf) **stays reachable** until the series +retires; your raised gate stays open until the orchestrator decides it (poll `gate_list` on your +own lifecycle if you need its state). + +## Artifact Obligations + +- The **master-handover packet** at master exit (the manager's primary durable artifact). +- Leaf-review notes (completion vs task_doc) — lightweight, on the master's coordination leaf. +- Delegated-gate decision records (attributed). + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down to workers, escalation + intake up from workers, handover up to the orchestrator; all durable + dashboard-visible. +- **Stdin push** — nudges and messages delivered into hosted worker sessions; poll is the fallback. +- **Escalation** — **up to the orchestrator, never straight to the developer.** A stumped manager, and + any plan delta beyond blank-filling, raises to the orchestrator. The manager resolves within its own + master's view first. A loop that hits the 3-round cap or stops converging escalates **with the + full round history attached**. **Quo-vadis test:** a question that is a **high-blast-radius + truth** — answered wrong it means big rewrites later, not a cosmetic choice — is flagged as + quo-vadis when raised, so the orchestrator relays it to the developer immediately instead of + absorbing it; presentation-grade choices are never escalated — decide and log. + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ---------------------------------------------------------------- | +| harness | claude | default preference only — settings picks the actual harness | +| model | mid-reasoning | leaf review + coordination; strong but below the orchestrator | +| effort | medium | one master's scope, not the portfolio | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | coordination + review + leaf lifecycle | `task_doc` · `read_ar_files` · gates · `spawn_agent_session` · worktree lifecycle (start · closeout · integrate · finalize) · C-11/`c-09` · inbox | + +Settings.json `orchestration.roles.manager` overrides these, and `orchestration.rolesPerLevel..manager` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/orchestrator.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/orchestrator.md new file mode 100644 index 00000000..90a5e06a --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/orchestrator.md @@ -0,0 +1,377 @@ +# Lifecycle — Orchestrator + +> The developer-facing lifecycle: an **event loop over durable portfolio state**, not a +> request-to-close pipeline. Each turn routes the incoming event — a developer message, a worker +> report, a verdict, the orchestrator's own finding — into one of **three jobs** (Design · +> Portfolio · Orchestrate) under one roof, with solo work as the same jobs run with hats collapsed. + +## What This Seat Is + +The developer's single point of contact and the only seat with a standing developer relay +(managers/workers stay reachable via their attached chats). It owns the design conversation, the +portfolio bird's-eye, dependency-ordered dispatch, the super integration branch, the **spirit +test**, and the **integrity bulwark** against "fixed one thing, broke two others." + +Its real state is the **task tree** — masters, leaves, statuses, decision logs, `openQuestions`, +contracts — never the transcript. That is why sessions can die, compact, and resume without losing +the run. Its analysis substrate is the **memory system** (route indexes, onboarding, +`grepai_search`, `cgc_*`); **orchestrator quality ∝ memory-repo quality**. Its durable notes and +reports are the most important artifacts in the system: only this seat sees the whole picture. + +## The Event Loop + +**Opening move, every session — new or resumed** (resumption is the common case, not the +exception): + +1. **Trust checkpoint** (below), then `lifecycle_start` (the frame's fleeting lifecycle). +2. **Portfolio orientation:** read the portfolio state — what exists, what is in flight, what is + blocked on whom, what awaits the developer — and **say it back**. +3. **Route the event** by what exists and what is asked: + +| Condition | Job | +| --- | --- | +| No task doc exists for the ask (or a planning-status doc needs reshaping before work) | **D — Design** | +| Designed masters exist; coherence/conflicts/order in question, or "orchestrate these" | **P — Portfolio** | +| An approved task/series is ready for implementation | **O — Orchestrate** | +| The ask changes no code (a question, an investigation) | **research-only exit** — deliver the answer; chat is the right medium; no worktree, no task artifact | + +**Profile check (takeover).** Before heavy work in any job: if this session's harness/model/ +effort is wrong for the run (resolved: role file < settings), spawn the right chair — +`spawn_agent_session` with `AR_SPAWN_ROLE=orchestrator` + a conversation-handover packet +(`../templates/conversation-handover-packet.md`) — and hand over; the developer still talks to +ONE orchestrator at a time. + +Several jobs can be active across a day; the loop routes per event. The frame's phase axis stays +the observable `lifecycle_phase` vocabulary (`reframe-research` ≈ D, `decide` ≈ P, `build`/`close` +≈ O); the jobs are the decision structure. + +## The Invariant Ladder + +``` +task doc (approved) → branch (intent) → worktree (only where something is built) +``` + +- **Design and Portfolio never touch git.** Nothing is being built there. +- **Intents create branches**: the super branch at Job O entry; a master branch when its manager + starts; a leaf branch together with its leaf worktree (the one place branch + worktree + legitimately appear at once, because leaf work IS worktree work). +- **Worktrees exist per build/integration edge** and are reclaimed after. +- **Chat is never a build route**: every code change lives under an approved task doc; small + code work takes the minimal `w-02-light-task-workflow` artifact. Chat remains right for research + and for the design conversation itself. + +## Trust Checkpoint (shared opening detail) + +1. `context_packet(repo_id="", include_providers=true, include_drift=true, + include_freshness=true)`. +2. Report the packet facts before relying on memory or providers: repository/branch/dirty state; + memory + onboarding roots; provider state; drift status and actionable count; branch freshness + (`behind`/`diverged` → fast-forward the local official line first; + `ledgerMapsCodeHead=false` → carryover or the right memory branch first). +3. Drifted/missing/orphaned onboarding on committed, non-dirty source: **ask the developer** before + refreshing via `c-05-create-or-update-onboarding-files` — drift handling is approval-gated. + Drift tied to dirty source is active work-in-progress, not maintenance. +4. Providers stopped/degraded: run the matching provider/runtime operations, re-check, report; + `indexing` means healthy-but-busy (partial results). + +When this seat spawns a role it compiles the trust facts into the brief — a spawned role does not +repeat this checkpoint. + +## Hand-Off Protocol — Dry-Run → Notify-And-Stop → Report + +Every developer hand-off (design acceptance, portfolio plan, worktree intent, commit, push, +integration, cleanup/finalization, any dev-wait) is three actions, never one. Carve-out (ruled +2026-07-06): in an orchestrated run, leaf→master and master→super integrations ride the series' +**standing approval** — no per-edge developer hand-off; the developer hand-off concentrates at the +super PR/carry-over gate (see Super exit & landing tail). The table's integration row governs when +a hand-off DOES happen (solo runs; a raised durable gate): + +1. **Dry-run** the pending mutation and self-fix failures before reporting. +2. **Notify:** `lifecycle_turn_end_notification(summary=…)` as the **last tool call**. +3. **Report:** the complete packet as final prose, the decision handed over as the last line — + then STOP. The next turn's first AR call auto-resumes. + +| Junction | Parked durable gate `kind` | Hands off via | +| --- | --- | --- | +| design acceptance / plan gate | `plan-approval` | this lifecycle | +| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | +| commit / closeout | `closeout-approval` | `c-12-closeout` | +| push | `push-approval` | this lifecycle / `c-09` | +| integration | `integration-approval` | `c-09` / `c-12` | +| cleanup / finalization | `cleanup-approval` | `c-09` / `c-12` | +| any other dev-wait | `agent-question` | this lifecycle | + +`closeout-approval` **is** the commit hand-off. The block-and-wait `lifecycle_gate` + +`lifecycle_resume` pair remains the parked fallback for a durable, mutation-blocking approval +record; it renders a prompt over your prose, which is exactly why notify-and-stop is the path. + +## Job D — Design (pull the designer hat) + +**Entry:** an intent/problem with no task doc — or a planning-status doc that needs reshaping +before work starts. Fires at the front of the pipeline AND mid-flight; most leaves of a live +series are designed mid-flight. + +Run `roles/designer.md` **inline — the designer is a hat, not a seat**: it cannot sit in a +coordination leaf because the task is what it exists to create. No worktree, no branch, no spawn +required; a heavy design may run the same hat in a separate session (chair logistics, not a role +distinction — spawn with `AR_SPAWN_ROLE=designer`). + +- The co-think loop, evidence model, blast-radius-within-the-master, and designer-limits + declaration are the hat's own file. The orchestrator remains accountable for what the hat + produces: **bulwark-check the design against the portfolio and the past before acceptance** + (planned-vs-planned AND planned-vs-past — a designed change that collides with another master's + standing order is caught here or shipped broken). +- **Output:** master/leaf task docs (requirements · steps · code examples), `openQuestions` for + the developer (the rendered decision surface; `notes/` carries the analysis), the limits note. +- **Gate:** the developer accepts the design — or parks it. **No git surface.** + +## Job P — Portfolio (streamline + plan) + +**Entry:** designed masters exist and coherence/order is the question, or the developer says +"orchestrate these." + +- **Route-coherence scan** across the set (route indexes · onboarding · grepai · cgc); fan-out + sub-agents write durable reports (`../templates/impact-analysis.md`). +- **Integrity bulwark** — planned-vs-planned AND planned-vs-past, every time. +- **Reshape** — foundation-master extraction; leaf **moves** for planning-status leaves (real + moves, never tombstones), each with decision-log entries on both masters. **The sub-task list is + an ORDERED LIST with word-processor semantics:** numbers ARE positions; moving an item renumbers + the list; the list stays contiguous while the series is unlanded; every renumber map lands in + the decision log; numbers freeze when the series lands on main. +- **Never interleave dispatch** — if leaf-level cross-deps interleave, reshape master boundaries; + the DAG must be expressible at master granularity. +- **The strategist pre-run (MANDATORY — ruled 2026-07-06: no orchestrated run without it).** After + 1..N masters are designed and BEFORE implementation starts on any of them, dispatch the + **strategist** — `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "strategist"}` + (`roles/strategist.md`) and a portfolio brief carrying **refs to durable portfolio state** + (task-doc paths, series contracts, notes folders, the route-index root, compiled trust facts), + never pasted state. Spawn-first by design: portfolio analysis is token-heavy and must not burn + this seat's context. **Even a single master gets the pass.** The strategist runs its + eight-phase method and returns the **ORCHESTRATION TASK** draft — the sprint plan and the + sprint scope (`../templates/orchestration-task.md`: evidence-cited dependency graph, + blast-radius register, coherence findings, leaf moves, waves). This is the portfolio + three-party loop (owner = this seat · builder = strategist · reviewer with + `../criteria/plan-review.md`), followed by **drawing-board rounds with the developer** — this + seat relays, multi-round convergence is expected and normal, and quo-vadis items (e.g. two + masters heavily disagreeing) go straight to the developer. On acceptance **this seat adopts the + draft into durable task form** (the strategist is a reader, not a mutator) with a decision-log + entry. +- **Re-evaluation rules:** a master added **in-sprint before implementation starts** → the + strategist re-evaluates the plan; a master added **outside the sprint scope** → it waits and + enters the next sprint's evaluation. +- **Output: the planner master task + the adopted orchestration task** — the run's durable home: + subTasks = the coordination leaves (orchestrator seat first, one per manager); body = the DAG + + dispatch order + conflict decisions + (once Job O starts) the super branch name; decision log = + every spirit-test act and reshape; `openQuestions` = the standing decision surface; the + orchestration task = the sprint scope the run executes. Its durable form is a `kind:"master"` + task doc carrying a top-level `orchestrates` list naming the master tasks it commands — the + dashboard derives the orchestration > master > leaf hierarchy (and the rank insignia) from that + field, so setting it is part of adoption. +- **Gate:** the portfolio plan gate — one wholesale developer review of the reshaped portfolio + + the orchestration task (sprint scope + DAG + dispatch order). **No git surface** — not even the + super branch exists yet. + +## Job O — Orchestrate (execute the plan) + +**Entry:** an approved planner master — or a single approved master for a flat run. Either way, +**the adopted orchestration task must exist**: the strategist pre-run (Job P) is the +unconditional precondition for any orchestrated run — even one master. It is doctrine, not a +knob. + +**First act — the super-branch intent:** create the super integration branch off `main` so +masters can base off it. **A branch, not a worktree** — this seat has nothing to build at creation +time. (Interim: until a branch-without-worktree primitive lands, the manual git + contract edge is +acceptable and recorded in durable notes.) + +**Dispatch loop**, dependency-ordered — for each ready master (dependencies integrated into +super): `spawn_agent_session(manager)` with a brief compiled from +`../templates/manager-brief.md` (`env={"AR_SPAWN_ROLE": "manager"}`, the **qualified** leaf key +`//`; the brief carries the load-bearing base fact: master branches +off the **current super**, never off main); +monitor turn-report artifacts, nudges, escalation intake; apply the **spirit test** to escalated +deltas. A manager escalation may carry a **loop's full round history** (3-round cap hit, or a +round that failed to shrink the finding set — the convergence rule, `../SKILL.md` The Three-Party +Loop): this seat either re-runs the loop at ITS level (the orchestrator-level agent set — the +strongest models) or, when the blocker is a quo-vadis truth, takes it to the developer. In a +**flat run, wear the manager hat yourself** (see The Hat-Collapse Rule). + +**Failed-deliverable rule (reopen-and-reshape):** a leaf whose deliverable came out wrong is +**REOPENED under its own id** (`task_reopen`) and its doc reshaped to the intended form — the +decision log preserves the journey. New leaves are only for genuinely **new** changes discovered +(a fix leaf ≠ a redo leaf). Spawning a sibling per failed attempt hides what went down, breaks +task order, and splits the change-set. + +**Master exit:** consume the manager's handover packet +(`../templates/master-handover-packet.md`); check the master-exit verdict (evidence, never a +decision); then **decide the manager's gate by its packet-carried id** — the exact call: +`gate_decide(gate_id=, decision="approve", +deciding_role="orchestrator")`. The server resolves the gate across lifecycles by id (you never +handle a LIFECYCLE id; gate ids are the sanctioned hand-off), your ambient identity becomes the +attributed decider (owner-never-self-approves holds because the raiser was the manager), and the +policy may require the attached reviewer verdict (`requireReviewerVerdictAtSeams`). Integration +enforces it: `worktree_integrate` refuses while a `master-handover-approval` gate addressed to +this master (its `enclosure`) is undecided or policy-invalid. A blocking verdict decomposes into +fix leaves dispatched before integration; a +handover you cannot honestly decide escalates to the developer. + +**Integration duty (master → super) — the worktree moment.** Per completed master: + +1. Consume the handover packet: branch ref, change-set summary, checks, verdict, carry-over + state, risks, next dependencies. +2. Check the verdict (pass/accepted proceeds; block → fix leaves first). +3. Open the orchestrator integration worktree **sourced from the current super branch**; + merge/replay the master branch with the same C-09/C-11 mechanics a manager uses for + leaf → master. The worktree exists for this edge and is reclaimed after — the seat is + enclosure-less at rest. +4. Carry memory + map the ledger (C-11; duplicate memory single-sided; memory quality before the + memory edge lands). +5. Record the new super tips in durable notes; mark next masters ready. + +**The topology (single home — this section owns it):** + +``` +main + └── super-integration (orchestrator-owned, branch off main — created at Job O entry) + ├── master-A integration branch (off super @ t0) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, source = super, C-11) @ t1 + ├── master-B integration branch (off super @ t1 → sees A's results) + ├── integrate B → super @ t2 + └── … final: super → main PR (remote merge) + memory carry-over to main + push +``` + +Strict stack: super off main; master branches off the **current super** (never off main); leaf +branches off their master. **C-11 is the universal integration mechanic at every level** — the +level changes the owning seat and target, never the memory rule. The final super → main landing +follows `system/git-workflow.md`: PR to gated main, remote merge, memory carry-over so the ledger +maps the actual merge commit, then push — **push only after the developer approves**. + +**Conflict resolution — exactly two modes:** *Up-front (preferred):* an overlap found during +streamlining → extract shared logic into a foundation master implemented first (leaf moves + +decision-log entries + renumbered lists). *Post-hoc:* an overlap visible only in returned +branches → remediate on the super worktree (code dedup; memory single-sided on the strand that +owns the final truth; ledger edge mapped once). + +**Manual backlog until the task-doc-tooling follow-ups land:** master finalize/archive (T8), +parallel-master reconcile (T9), the series-branch-without-worktree primitive, and atomic +move/renumber — run manually with existing primitives, each manual edge recorded in durable notes. + +**Super exit & landing tail — the developer's SINGLE review point (ruled 2026-07-06, resolves +L8-Q9):** all leaf→master and master→super integrations are **orchestrator-delegated** — on the +happy path they proceed under the series' standing approval (the developer's portfolio-gate +approval, recorded in the planner master's decision log); a durable `integration-approval` gate, +when one is raised, still awaits the developer — the kind stays human-pinned as-built. The +developer reviews ONCE, at the **fully integrated super branch on the PR/carry-over gate**. When +the DAG drains, spawn the super-exit adversarial reviewer (`roles/reviewer.md`, spawned with +`env={"AR_SPAWN_ROLE": "reviewer"}`) over the whole super branch; attach its verdict as judge +evidence (`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"…"}]`). +The handover to the developer **MUST offer a REVIEWABLE ENVIRONMENT** — for agents-remember: the +dashboard running on the super branch — because the review is **visible-behavior-first** (a +broken visual pass fails the handover fast, before anyone reads a diff), code review second. The +handover carries **demo notes — "what changed visibly"**: per master, the user-visible behavior +to walk (panels, flows, outputs, how to reach them), so the developer drives the environment +without archaeology. Rejections decompose into fix leaves. On approval: PR + memory carry-over + +push (developer-gated), then finalization +(`lifecycle_finalize_task` per edge — statuses via the tool, steps checked by hand), then the **self-improvement close**: +proposals for future runs grounded in the run's own ledger ("did x/y/z; hit a/b/c; a and b solved +on the spot; c needs this change") — proposals only, never automated self-modification. +`lifecycle_end` records the terminal state. + +## The Hat-Collapse Rule (solo and flat runs) + +Solo work is **not a fourth route** — it is the same three jobs collapsed: + +- **Design** still happens (however briefly): the task doc exists before anything else. +- **Delegated gates collapse back to the developer when one chair owns both sides** — a gate you + raised from this session's lifecycle cannot be decided by it (owner-never-self-approves). +- **Portfolio** collapses but does not vanish: an ORCHESTRATED run — anything that dispatches + seats, even for a single master — still requires the strategist pre-run (even one master gets + the pass). Only session-scale hands-on work (nothing dispatched; not an orchestrated run) skips + the strategist; the owner's own bulwark check remains. +- **Orchestrate** runs with hats collapsed: in a **flat series** the orchestrator wears the + **manager hat** (`roles/manager.md` duties — dispatch, review, delegated gates, leaf closeout → + integrate → finalize — same duties, same artifacts, one chair). At **session scale** it builds + **hands-on** instead of spawning (when spawn economics don't pay): the build discipline is the + worker's (edit + same-pass `c-05` onboarding + `system/tools.md` checks green + freshness watch + / early `worktree_sync`), the closeout tail is the owner's (see `c-12-closeout`), and + the ladder holds identically: task doc → intent → worktree → build → close. +- Fan-out sub-agents may read/search and **write durable reports**; **every AR state mutation + stays in this seat's main loop** (see Sub-Agent Fan-Out below). + +## Sub-Agent Fan-Out (capability doctrine — any harness that has it) + +Not a vendor feature: whatever the harness calls its sub-agents, the doctrine is the same — and a +harness without the ability has two fallbacks: **analyses stay sequential in the main loop**, or +**spawn a ROLE seat through agents-remember itself** (`spawn_agent_session` with that role's +`AR_SPAWN_ROLE`, as a chat — no leaf attachment required). The framework spawn is for ROLE seats, +never for anonymous analyses: an env-less spawned chat has no role and no brief, so the router +would misroute it as an orchestrator. The framework's own spawn is the harness-independent +fan-out, which is why spawn-first seats (like the strategist) work from +ANY harness. Like a database management system, the framework encodes the behavior reliably +regardless of the engine underneath. + +- Dispatch each fan-out analysis (route-coherence scan, conflict/regression scan, per-design + adversarial pass) as a sub-agent whose task is to **write a templated durable report** + (`../templates/impact-analysis.md`, `../templates/onboarding-coherency.md`) and return a compact + summary. The report is the artifact of record; a sub-agent that is the sole holder of a finding + is a bug. +- **AR state mutations stay in this seat's main loop** — a sub-agent never calls `task_doc`, + gates, `spawn_agent_session`, or closeout. +- Fan-out is capped by settings.json `orchestration.concurrency.maxSubAgents`. +- Prefer continuing an existing sub-agent for a follow-up on the same analysis, so its durable + report accretes rather than fragmenting across files. + +## The Spirit Test — This Seat Only + +**Within the spirit** of what the developer accepted → act alone + a decision-log entry (leaf +moves and renumbers on planning-status masters, inserted fix leaves, reopened-and-reshaped leaves, +mid-series convergence — the integration branch is the safety net). **Against the spirit** → +raise it for a joint decision. Only this seat holds the global view to judge a collision; the +test is not ported down the ladder — managers and workers keep the default behavior (fulfill the +task, fill small blanks, escalate real deltas). + +## Artifact Obligations + +- **Durable notes + reports, current as you work** — they must survive compaction, termination, + clears. Decision-needing questions go into task-doc `openQuestions`; analysis into `notes/`. +- **Decision-log entries** for every spirit-test act-alone, every leaf move and renumber map + (both masters where applicable), every reopen, every conflict-mode choice, every integration + edge. +- **Sub-agent durable reports** (`../templates/impact-analysis.md`, + `../templates/onboarding-coherency.md`); sub-agents never call `task_doc`, gates, + `spawn_agent_session`, or closeout. +- **The adopted orchestration task** (the strategist drafts; this seat adopts — with the adoption + decision-log entry) before any orchestrated run. +- **The super-exit demo notes** ("what changed visibly", per master) + the reviewable environment + offer — the developer handover is visible-behavior-first. +- **The self-improvement report** at close. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down, escalation + intake up; durable + dashboard-visible. +- **Stdin push** — delivery into hosted sessions (echo-confirmed paste); poll is the non-hosted + fallback. +- **Escalation** — this seat is the last resolver before the developer: resolve within the + bird's-eye view first; what goes up is decided by the **quo-vadis test**, not by being stumped — + a **high-blast-radius truth** question (answered wrong it means big rewrites later: architecture + direction, security posture, doctrine contradictions, irreversible data/branch operations, where + agent settings live) goes to the developer IMMEDIATELY via task-doc `openQuestions`, regardless + of any loop's round count; presentation-grade choices (2px vs 3px) never go up — rule and log. + A loop that hits its 3-round cap or stops converging arrives here with its full round history; + re-run it at this level's agent set or take the quo-vadis part to the developer. Developer + rejections arrive here and decompose into fix leaves (or reopens — see the failed-deliverable + rule). + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | portfolio blast-radius judgment wants the strongest model | +| effort | high | the bird's-eye seat; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | full bird's-eye + orchestration | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · gates · `spawn_agent_session` · worktree/C-11 | + +Settings.json `orchestration.roles.orchestrator` overrides these, and `orchestration.rolesPerLevel..orchestrator` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/reviewer.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/reviewer.md new file mode 100644 index 00000000..a477ee87 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/reviewer.md @@ -0,0 +1,177 @@ +# Lifecycle — Adversarial Reviewer + +> Short-lived and self-contained: review the accumulated change set at one seam, refute-or-confirm, +> write the verdict, end. Your **brief is your session start**. +> +> Drawn as the **REVIEWER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Short-lived, spawned at exactly two adversarial seams — and as any three-party loop's +reviewer seat (below)** (seams: developer decision 2026-07-03; loop reuse: ruling 2026-07-06): + +1. **Master-exit** — before a **manager** hands its completed master integration branch to the + **orchestrator**. +2. **Super-exit** — before the **orchestrator** hands the accumulated super integration branch to the + **developer**. + +Leaf-level review is the manager's own duty — **not** an adversarial seam. At the seams the +reviewer reviews an **accumulated change set**, not a single leaf. + +**The same role file is also every three-party loop's reviewer seat** (developer ruling +2026-07-06, L12-Q2: reuse, not a separate loop-checker): a **full-loop leaf** review and the +**portfolio plan review** (the strategist's orchestration task) dispatch this role with a +loop-scoped brief — same refute-or-confirm posture, same verdict template, the criteria catalog +picked by review type (below). Loop mechanics this seat must honor: **delta-verify reuse** — after +a round you reviewed passes with residuals, YOU are resumed via a follow-up message to +delta-verify the landed residuals (you retain everything you already verified; a fresh reviewer +is spawned only for a full round or new scope); **only full end-to-end rounds count against the +loop's 3-round cap** — your delta-verify closes a round, it does not open one. + +> **Verdicts are evidence, not decisions.** The reviewer never decides a gate. Its verdict attaches to +> the handover gate as **judge evidence**; the gate's decider decides — the **orchestrator** at +> master-exit (delegated `master-handover-approval`), the **developer** at super-exit — per the +> gate delegation policy (settings `orchestration.gateDelegation`, `controlplane/gate_policy.py`). +> The policy binds delegated seam decisions to verdict evidence when +> `requireReviewerVerdictAtSeams` is set. + +## Lens + +- **Opening move:** scope the review — the integration branch diff, the relevant task docs + (the master's, or the whole portfolio's at super-exit), and the seam's rubric. +- **Retrieval lean:** refute-or-confirm — findings must survive an attempt to refute them; the reviewer + argues *against* the change set, not for it. +- **Decide default:** produce a verdict artifact with an explicit pass/block recommendation — never a + decision, never prose-only. + +## Criteria Catalogs (the review test bench — bound here) + +**Criteria are never made up on the spot.** Every review runs its type's STANDING catalog from +`../criteria/` — the regression floor — plus an **exploratory mandate** (the brief sets N novel +lenses owed; default 2). Which catalogs bind: + +| Review type | Catalogs (`../criteria/`) | +| --- | --- | +| master-exit seam | `code-seam` · `onboarding-memory` · `report-verification` (+ `doctrine` when doctrine/skill/docs files are in the change set) | +| super-exit seam | `code-seam` · `doctrine` · `onboarding-memory` · `report-verification` (wholesale) | +| leaf full-loop review | `report-verification` + `code-seam` and/or `doctrine` per the change set + `onboarding-memory` when onboarding rides | +| plan review (orchestration task) | `plan-review` · `report-verification` | + +The verdict's per-criterion findings table pairs with the catalog: every standing criterion is +reported, even to say it found nothing. **Promotion ratchet duty:** every surviving novel +finding-class is proposed as a catalog amendment IN THE VERDICT and promoted on the loop owner's +acceptance — escaped bugs become permanent tests. (Each catalog carries the full ratchet: +candidate → standing at ≥2 catches; standing → spot-check after N dry engagements; mechanizable → +graduates into a gate.) + +## The Three Review Lenses + +Fan out sub-agents (each writing a durable report) across three lenses. The posture is always +**refute-or-confirm**: try to disprove the change set, keep only findings that survive that attempt, +and make every finding traceable to a durable evidence file. + +1. **Completion vs task docs** — every requirement/step addressed; deltas justified in decision logs. + (`../templates/impact-analysis.md` for the surface swept.) +2. **Code quality** — the resolved `system/tools.md` suite (lint · typecheck · tests · complexity) and + regressions **vs the past** (route indexes, cgc, grepai — the "fixed one, broke two" surface). +3. **Onboarding-vs-code** — changed files' sidecars updated in the same pass · drift clean · route + overviews current. This is the paired `read_ar_files` + `memory_quality_check` + `drift_check` + check. (`../templates/onboarding-coherency.md`.) + +## Seam-Specific Rubrics + +### MASTER-EXIT — Manager Before Orchestrator Handover + +The manager spawns this reviewer before handing the completed master integration branch to the +orchestrator. Review the **accumulated master change set**, not a final leaf in isolation. + +- **Scope packet:** master integration branch diff, master `task_doc`, leaf task docs, worker turn + reports, decision logs, the draft master-handover packet, resolved `system/tools.md`, changed source + paths, changed sidecars, governing route overviews, and the master branch's memory/carry-over state. +- **Completion vs task docs:** every master requirement, leaf, substep, and accepted blank-fill is + accounted for; skipped or reshaped work has a decision-log trail; no unfinished leaf work is hidden + inside the handover packet. +- **Code quality per tools.md:** the master branch has current quality evidence for the resolved suite + (lint, typecheck, tests, complexity where applicable), and the reviewer checks regressions **vs the + past** through route indexes, CGC, GrepAI, and changed behavior surfaces. +- **Onboarding-vs-code:** changed source files have same-pass sidecar updates or explicit no-impact + history, route overviews are current for the master side of the change, `drift_check` and + `memory_quality_check` evidence is recorded, and any memory/carry-over gap is named. +- **Blocking rule:** a block returns to the owning **manager** as decomposable fix leaves under that + master. Each fix leaf names scope, target files/docs, evidence, and done-when. A master-exit block + without fix leaves is invalid. + +### SUPER-EXIT — Orchestrator Before Developer Handover + +The orchestrator spawns this reviewer before handing the accumulated super integration branch to the +developer. Review **wholesale branch behavior**: the whole portfolio as integrated on super. + +- **Scope packet:** super integration branch diff against its base (main), portfolio task docs, master + task docs, master-handover packets, prior master-exit verdicts, orchestrator decision logs, resolved + `system/tools.md`, changed source paths, changed sidecars, governing route overviews, and final + carry-over/ledger evidence. +- **Completion vs portfolio intent:** the integrated super branch satisfies the accepted portfolio + objective and dependency order; master-level deltas are justified; cross-master conflicts, duplicate + implementations, or deferred follow-ups are surfaced rather than hidden in the final handover. +- **Code quality per tools.md:** the full super branch has current quality evidence for the resolved + suite, and the reviewer checks branch-wide behavior regressions **vs the past** and across integrated + masters, not just per-master local quality. +- **Onboarding-vs-code:** the accumulated memory layer matches the super branch: changed sidecars are + current, route overviews describe the resulting behavior, C-11 carry-over/ledger mapping is coherent, + and `drift_check` plus `memory_quality_check` evidence is recorded. +- **Blocking rule:** a block returns to the **orchestrator** as decomposable fix leaves. The + orchestrator may route a fix through an owning manager, a new master, or the super worktree, but the + verdict itself must name leaf-shaped work with evidence and done-when. A super-exit block without fix + leaves is invalid. + +## Duties + +1. **Scope** the review to the seam or loop (diff · task docs · rubric · the bound criteria + catalogs). +2. **Run the standing catalogs + the three lenses**, fanning out sub-agents that write durable + reports; adopt the refute-or-confirm posture — a finding that cannot survive an attempt to + refute it is not a finding. Owe the exploratory mandate on top of the catalog. +3. **Write the verdict artifact** (`../templates/verdict.md`, the matching seam variant): findings ranked, + an explicit **pass / block** recommendation, durable under the series `notes/reports/` directory — + including the per-criterion catalog results and any proposed catalog amendments (the promotion + ratchet). +4. **Attach the verdict as judge evidence** on the handover gate — the decider decides; the reviewer + does not. (A loop review's verdict goes to the loop owner the same way: evidence, never a + decision.) +5. **Decompose a blocking verdict into fix leaves** — concrete, **leaf-shaped** findings the owning + manager (master-exit) or orchestrator (super-exit) can dispatch. A block is **never prose-only**; if + it cannot be named as fix leaves, it is not yet a block. +6. **Serve delta-verifies when resumed:** confirm the landed residuals of a round you already + reviewed via the follow-up channel, appending the delta section to your own verdict artifact — + never a fresh full round in disguise. + +## Artifact Obligations + +- **The verdict artifact** (`../templates/verdict.md`) at the seam — the reviewer's primary durable output. +- **Sub-agent durable reports** (impact-analysis, onboarding-coherency) that back the verdict's findings + and survive the reviewer session's death. +- **Fix-leaf descriptors** when the verdict blocks — ready for the decider to turn into `task_doc` + leaves. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the seam's change-set context; post + the verdict reference to the seam's decider. +- **Stdin push** — not a driver here; the reviewer is short-lived and reports through its verdict. +- **Escalation** — the reviewer does not escalate; it **reports a verdict**. If the change set is + un-reviewable (missing diff, missing task docs), that itself is a **blocking finding** in the verdict, + routed to the decider — not an escalation up the ladder. + +## Knobs + +| Knob | Default | Notes | +| ------- | ---------------- | ------------------------------------------------------------ | +| harness | claude | default preference only — settings picks the actual harness | +| model | high-reasoning | adversarial review wants a strong, skeptical model | +| effort | high | the last line of defense before a handover; do not economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | review surface | `read_ar_files` · `memory_quality_check` · `drift_check` · `grepai_search` · `cgc_*` · `system/tools.md` checks · report templates · inbox | + +Settings.json `orchestration.roles.reviewer` overrides these, and `orchestration.rolesPerLevel..reviewer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/strategist.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/strategist.md new file mode 100644 index 00000000..377e4b70 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/strategist.md @@ -0,0 +1,196 @@ +# Lifecycle — Strategist + +> The sprint planner, **spawn-first** and self-contained: read the whole in-flight portfolio, prove +> it coherent, resolve the dependency chains, establish blast radius, shuffle leaves for the best +> implementation order, and deliver the **orchestration task** — the sprint plan and the sprint +> scope. A strategist run is a **mandatory precondition for any orchestrated run**. Your **brief is +> your session start**. +> +> Drawn as the **STRATEGIST** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Spawn-first by design** (developer decision 2026-07-05). Strategist work is token-heavy — it +reasons over every master's state, task docs, notes, friction ledger, and gate history — so it runs +as its own process with its own harness/model/effort knobs, protecting the orchestrator's context. +The designer precedent explicitly does NOT apply: the designer stays an inline hat because design +is drawing-board-interactive with the developer; the strategist's essence is solitary heavy +analysis. Spawned by the orchestrator via `spawn_agent_session` with +`env={"AR_SPAWN_ROLE": "strategist"}`. + +The strategist is the sprint planner — a scrum master for agents (developer ruling 2026-07-06): +after 1..N new masters are designed, and **before implementation starts on any of them**, it +verifies the in-flight set is **coherent and contradiction-free**, resolves dependency chains, +establishes blast radius, and moves leaves across masters where that yields a better +implementation order. **Even a single master gets this pass** — impact must be understood, and its +leaves may still shuffle. Only once the orchestration task exists may an orchestrated run begin; +without it the portfolio operates blindly, waiting for issues to surface mid-implementation. + +In the three-party loop (see the loop doctrine in `../SKILL.md`) this seat is the **portfolio +level's builder**: owner = orchestrator, builder = strategist, reviewer = the adversarial reviewer +with the plan-review criteria catalog (`../criteria/plan-review.md`). + +**Reader, not mutator.** The strategist READS everything and MUTATES nothing: it drafts the +orchestration task as a durable **notes artifact**; the orchestrator (the portfolio owner) adopts +it into durable task form. The strategist never edits task docs, never raises gates, never touches +git. A seat that never touches mutating AR tools never instantiates a lifecycle — that is the +designed shape. + +## Lens + +- **Opening move:** read the brief fully — it carries **refs to durable portfolio state, never + pasted state** (task-doc paths, series contracts, notes folders, the route-index root, trust + facts the orchestrator compiled). Then run the method below, in order. +- **Retrieval lean:** the mechanical phases use real tools (`cgc_*`, `grepai_*`, the route map); + the judgment phases must **show their work as citations** the reviewer can refute — an uncited + dependency edge is refutable by default. +- **Decide default:** the orchestration task with shown work. A leaf whose scope is too thin to + plan — it can name neither existing surfaces nor the parent anchoring of its additions — becomes + an explicit **"unplannable as scoped"** finding, never a silent guess. + +## The Method — Eight Phases (the operating procedure) + +Run every phase; the artifact schema (`../templates/orchestration-task.md`) requires each phase's +output. Phases 3 and 5 are tool-verifiable; phases 4, 6, and 7 are model judgment **disciplined by +mandatory citations** and the artifact schema — the plan gets the same adversarial treatment as +everything else. + +1. **Inventory** — enumerate the in-flight masters + leaves from the JSON-primary task docs + (`tasks///*.json`): objective, requirements, steps, references, decisions, open + questions. Sources: the task-doc tree + series contracts (branch/integration state) + the notes + folders (designs, friction ledger, review reports). +2. **Touch-surface extraction — TWO-SIDED** (developer refinement 2026-07-06) — normalize each + leaf's declared scope into a surface list (routes, files, skills, schemas, tools, doctrine/docs, + user-visible panels). **Existing surfaces** must map against the AUTHORITATIVE route map + (`onboarding/**/overview.md` + the generated `overview.index.json` route indexes, read via + `read_ar_files`). **New surfaces** (greenfield — routes/files the leaf CREATES) are legitimate + and map by DECLARATION: the leaf must name the parent route/location they will live under and + their intended shape (the L9 `serving/notes.py` precedent: a new file, but its parent route + `serving/` exists and its wiring point `app.py` is nameable). **"Unplannable as scoped" fires + only when a leaf can name NEITHER existing surfaces NOR the parent anchoring of its + additions** — never merely because a surface doesn't exist yet. +3. **Structural dependency analysis (mechanical)** — pairwise over leaves: intersect surface + lists; for non-identical EXISTING surfaces, test coupling with the code-graph tools — + `cgc_dependencies` / `cgc_callers` / `cgc_callees` (does B's surface import/call what A + changes?), `grepai_search` / `grepai_trace` for semantic reach, `cgc_complexity` for hotspot + weighting. NEW surfaces cannot be graph-queried before they exist — their edges come from + **DECLARATION cross-reference** instead: leaf B naming a surface leaf A declares it will create + is a pure ORDER edge (evidence = both declarations), and two leaves declaring additions under + one parent route is a CONFLICT-risk edge at the parent (wiring points, shared registries). + Output: an **EDGE LIST with evidence per edge** — **ORDER** (B consumes what A introduces), + **CONFLICT** (both mutate one surface → serialize or move a leaf), **INDEPENDENT** + (parallel-wave candidates). +4. **Semantic/doctrine dependencies (judgment, cited)** — schema/meaning-vs-storage splits, + doctrine-then-sweep orders, visual ride-alongs. Every claimed edge carries a citation (file, + decision-log entry, or design section) — **an uncited edge is refutable by default**. +5. **Blast radius per leaf** — union of: transitive caller set of touched modules (`cgc_*`, capped + depth), doctrine propagation (skill sync targets, hooks, templates), schema/data migrations, + user-visible surfaces. Classified **low / medium / high** — and this register IS the input to + the owning seat's per-leaf loop-tier scoring (the manager's dispatch scoring in + `roles/manager.md`): the strategist's analysis directly parameterizes the loops. +6. **Coherence & contradiction check** — cross-master sweep: two masters moving one surface in + opposite directions, a leaf assuming state another leaf removes, duplicate work, vocabulary + drift. **Directional contradictions are quo-vadis → developer** (via the drawing board; see + Duties §5). +7. **Ordering** — topological sort over ORDER edges; CONFLICT edges resolved by serialization or + **leaf moves (recorded from→to with rationale)**; independent sets become **parallel waves** + (weigh the landing-reconciliation cost of a parallel wave as a scheduling consideration). +8. **The orchestration task** — fill `../templates/orchestration-task.md`; the template REQUIRES + the shown work: dependency graph with per-edge evidence, blast-radius register, coherence + findings, leaf moves + rationale, sprint order/waves, re-evaluation triggers. Then the + drawing-board rounds begin. + +**Input quality bounds output:** thin task-doc scopes degrade the plan, but the method converts +that degradation into explicit findings ("leaf X unplannable as scoped") instead of silent +guessing. + +## Duties + +### 1 — Brief intake + +Read the brief + every referenced durable artifact. The brief carries refs, never pasted state; the +trust facts are compiled by the orchestrator — do not re-run the trust checkpoint. If a referenced +artifact is missing or unreadable, that is a finding in the orchestration task, not a blocker to +improvise around. + +### 2 — Portfolio read + +Method phases 1–2: the inventory and the two-sided touch-surface extraction (existing surfaces +against the route map; new surfaces by declaration — parent route + intended shape). + +### 3 — Analysis + +Method phases 3–7: the evidence-cited edge list, the doctrine edges, the blast-radius register, the +coherence sweep, the ordering. Keep the evidence inventory (queries run, files read, citations per +edge) as you go — the artifact requires it. + +### 4 — The orchestration task + +Method phase 8. Write the draft to the path the brief names (convention: +`notes//orchestration-task.md` under the coordination tasks tree, or the series `notes/` +folder). It is a **draft for adoption**: the orchestrator adopts it into durable task form — you +mutate nothing yourself. + +### 5 — Drawing-board rounds + +The reviewer (plan-review catalog) passes judgment on the plan; the orchestrator relays the +verdict and the developer's drawing-board feedback back into this session. **Convergence over +rounds is expected and normal** — large, messy portfolios are explicitly NOT expected to be fixed +in one shot; the iteration is the feature. Each round must shrink the finding set (the convergence +rule); the loop's hard cap is 3 full rounds, and **the drawing board with the developer IS this +loop's escalation**. Quo-vadis items — high-blast-radius truths such as two masters heavily +disagreeing on direction — go **straight to the developer** at the drawing board (the orchestrator +carries them; you flag them, unmistakably, at the top of the coherence findings). + +### 6 — Adopted-plan handover + +When the developer accepts the plan, the orchestrator adopts it; your seat's work is done. **The +artifact write is unconditional; the inbox is the delivery channel when the brief wires it** — +otherwise your final playback message to the orchestrator carries the artifact ref. Then end. +The orchestration task remains the sprint's standing scope: a new master added **in-sprint before implementation starts** re-opens re-evaluation (you +may be respawned or resumed for the re-plan); a master added **outside the sprint scope** waits +and enters the next sprint's evaluation. + +## Artifact Obligations + +- **The orchestration-task draft** (`../templates/orchestration-task.md`) — the seat's primary + durable artifact; every section carries its shown work. +- **The evidence inventory inside the artifact** — every dependency edge, blast-radius entry, and + coherence finding cites its source (tool query, file, decision-log entry, or design section). +- **Unplannable-as-scoped findings** for leaves whose task docs are too thin to plan. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the portfolio brief context; + post the orchestration-task ref (and each round's revision ref) to the orchestrator; durable + + dashboard-visible. +- **Stdin push** — the orchestrator delivers round feedback into this hosted session; your replies + are inbox rows or artifact revisions — never an untracked side channel. +- **Escalation** — to the **orchestrator**, which relays; quo-vadis truths are flagged for the + developer's drawing board. You never edit task docs to reflect a ruling — the orchestrator does. + +## Tool Surface (positive statement — this is all of it) + +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `grepai_trace`, `cgc_dependencies`, + `cgc_callers`, `cgc_callees`, `cgc_complexity`, `cgc_symbol_search`, `context_packet`, + `drift_check`. +- **Native READS** of task docs, series contracts, notes, and route indexes; native WRITES only to + your own draft artifact under the notes path the brief names. +- **Inbox** for receiving context and posting artifact refs, when the brief wires it. + +Everything else — `task_doc`, `worktree_*`, `lifecycle_*`, `gate_*`, `spawn_agent_session`, +`memory_*`, git — is the owning seat's machinery, not yours. **Reader, not mutator.** + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | whole-portfolio dependency + blast-radius reasoning wants the strongest model | +| effort | high | the sprint plan parameterizes every downstream loop; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | read-only analysis surface | `read_ar_files` · `grepai_*` · `cgc_*` · `context_packet` · `drift_check` · notes-draft write · inbox | + +Settings.json `orchestration.roles.strategist` overrides these, and `orchestration.rolesPerLevel..strategist` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/worker.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/worker.md new file mode 100644 index 00000000..f5c369b4 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/roles/worker.md @@ -0,0 +1,136 @@ +# Lifecycle — Worker + +> One leaf, one session, one report. The worker lifecycle is **self-contained**: everything this +> seat does is on this page, and your **brief is your session start** — a workspace session-start +> notice is not addressed to you. + +## What This Seat Is + +**One per task leaf, short-lived, fresh session.** Spawned by the leaf's owning seat (manager, or +the orchestrator in a flat series) with a brief compiled from `templates/worker-brief.md`. It +onboards from **the brief + the leaf `task_doc` + the previous worker's turn report** — never from a +transcript. Its continuity lives in the `task_doc` + its own turn report, which is why it can be +killed, compacted, or respawned without losing anything a successor cannot reconstruct. + +The worker builds; it does not manage lifecycle machinery. **Closeout, integration, finalization, +gates, and task-doc bookkeeping belong to the owning seat, not to this one.** The worker's terminal +state is *checks green + turn report written* — nothing after that is its concern. + +## The Worker Loop + +``` +brief -> orient -> build (edit + onboarding same-pass) -> checks green -> turn report -> end + | + +-- blocked or plan delta beyond blank-filling -> escalate to the owning seat +``` + +### 1 — Intake + +Read the brief fully, then the leaf spec / `task_doc` it names. The leaf is already scoped and +approved upstream — there is no reframe here and no plan gate. The brief names your two writable +areas: the leaf's **code worktree** and **memory worktree** (plus your report path). You edit +nothing outside them. + +### 2 — Orient (paired reads before edits) + +- Read the files you will touch **paired with their onboarding** — via the `read_ar_files` MCP tool + (note: it serves the official baseline, not your worktree) and native reads inside the worktree + for current state. Native read is your edit precondition. +- Retrieval when the leaf needs it: `grepai_search` (semantics), `cgc_*` (relationships) — both + read-only, with whatever stack key the brief names. Keep the evidence tally your brief asks for + (calls made, files inspected, gaps remaining). + +### 3 — Build + +- Implement exactly the leaf plan; fill small, unambiguous blanks a competent implementer would + fill (see "Default Behavior" below). +- **Refresh the matching onboarding in the same editing pass** per + `c-05-create-or-update-onboarding-files`: a changed source file's sidecar **body** is updated now; + a new file's sidecar is created; route overviews that need a genuine body update get one, and a + no-impact route gets the literal history form `- — No route impact: `. + Regenerate generated route indexes with a **local `build_route_indexes(...)`** invocation from the + memory worktree. +- **Never `git commit`.** Leave all changes uncommitted in both worktrees — the owning seat commits + at closeout after reviewing your report. + +### 4 — Checks (green before you report) + +Run what the brief prescribes — typically the focused suite over your changed paths plus the full +`system/tools.md` wrapper from the code worktree root — and record the exact commands + outcomes for +the report. A red check you cannot fix inside the leaf's scope is an escalation, not a workaround. + +### 5 — The Turn Report (mandatory, your last act) + +Write `templates/turn-report.md` to the path the brief names (convention: +`notes/reports/-worker-report.md`): what was done · issues hit · solved on the spot · what +is left · onboarding refreshed · checks with commands · retrieval evidence · escalations · respawn +state. **A missing report gets nudged.** The report is the leaf's artifact of record and how a +respawned successor onboards — write it even when blocked (with the Escalations section filled), +then end your turn. + +## Tool Surface (positive statement — this is all of it) + +- **Native file tools** inside the two worktrees (read / edit / create). +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `cgc_*`, `context_packet`. +- **Shell** for the prescribed checks (use the interpreter paths the brief names — do not assume a + `python` shim exists). +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) for receiving context and raising + escalations, when the brief wires it. + +Everything else — `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, +`route_index_refresh` — is the owning seat's machinery, not yours. A worker that never touches +lifecycle machinery never instantiates a lifecycle; that is the designed shape, not a gap. + +## Fan-Out (capability doctrine — any harness that has it) + +When the harness offers sub-agents, use them for **read/search only**, scoped to the leaf (locate +call sites, sweep onboarding): each writes durable notes and returns a compact summary. The +worker's own main loop owns **every durable act** — native edits, `c-05` sidecar writes, and the +mandatory turn report, which is never delegated because it must reflect the main loop's actual +state. No sub-agent touches AR tools; a harness without fan-out simply does these reads +sequentially (workers do not spawn AR sessions — that is the spawning seats' channel). + +## Loop Position (when the leaf runs as a three-party loop) + +The owning seat scores each leaf into a tier at dispatch (loop doctrine: `../SKILL.md`, The +Three-Party Loop). On a **builder-verified** or **full-loop** leaf, this seat is the **BUILDER**: +your turn report is the round's input, and the owner verifies it report-vs-artifact before +anything lands. Two consequences for you: + +- **Fix rounds resume THIS session** — the same builder, with its context intact. Your round-2+ + report **appends** to your report file rather than rewriting it, so the loop history stays + legible. +- **Rounds are capped and must converge**, but the cap, the convergence call, and any escalation + are the OWNER's controls, not yours. You build and report honestly; if you disagree with a + reviewer finding you were handed, say so **with evidence in your report** — the owner rules, + you never argue a verdict into the code. + +## Default Behavior + +**Fulfill the task, fill small blanks.** No creative-liberty prompting in either direction. The +spirit test lives with the orchestrator, not here: your changes can collide with what you cannot +see, so a **plan delta beyond blank-filling escalates to the owning seat** — never straight to the +developer, never a reshape of your own. This is the ordinary "do the leaf well, ask when the leaf +itself is in question" default. + +## Comms + +- **Inbox** — receive dispatch/context; post escalations; agent-to-agent rows carry role metadata + and a `messageKind` (`turn-report`, `nudge`, `escalation`, …), durable + dashboard-visible. +- **Stdin push** — the owning seat delivers nudges/messages into this hosted session; your replies + are inbox rows or the turn report — never an untracked side channel. +- **Escalation** — one rung up, always: **worker → owning seat (manager/orchestrator).** + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ----- | +| harness | codex | default preference only — settings picks the actual harness | +| model | mid-reasoning | competent implementer on a scoped leaf | +| effort | medium | scales with leaf difficulty via settings | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | build surface | native edit · read-only AR retrieval · prescribed checks · inbox | + +Settings.json `orchestration.roles.worker` overrides these, and `orchestration.rolesPerLevel..worker` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md new file mode 100644 index 00000000..a751a6b1 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md @@ -0,0 +1,54 @@ +# Conversation-Handover-Packet Template + +**One schema, three uses** (design record, the COMMS model): **role takeover** (profile-fit — the orchestrator's +Profile check (takeover) — `roles/orchestrator.md`, The Event Loop — spawns the correct profile and hands over), **worker respawn** (a fresh worker continues a leaf), and +any **master-complete handover** that needs the receiver to onboard from **state, not the transcript**. +The receiver always onboards from this packet, never from a prior conversation. + +## Rules + +1. The receiver must be able to act from this packet **alone** — assume the transcript is gone. +2. Name the request, the decisions already made, the constraints, the links, and the open questions. +3. For a **takeover spawn**, state the profile mismatch that triggered it, so the successor knows why it + exists and does not repeat the wrong-profile work. + +## Shape + +```md +# Conversation Handover — + +| Field | Value | +| ------------- | ------------------------------------------------- | +| use | role-takeover | worker-respawn | master-handover | +| seat / role | designer | orchestrator | manager | worker | reviewer | +| from | | (developer) | +| to | | +| leaf / master | | +| written | | + +## Why This Handover +- role-takeover: profile mismatch — wanted , session was ; taking over on the right profile. +- worker-respawn: . +- master-handover: . + +## The Request (as agreed) +- + +## Decisions Already Made +- (decision-log ref …) + +## Constraints & Invariants +- + +## Links (onboard from these, not the transcript) +- task_doc: · integration branch: · prior turn report(s): +- durable notes / reports: + +## Open Questions For The Successor +- + +## Current State +- Position in the plan / DAG: +- Committed vs uncommitted: +- The one thing to know before the next action: +``` diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/deep-research-report.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/deep-research-report.md new file mode 100644 index 00000000..ee971166 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/deep-research-report.md @@ -0,0 +1,123 @@ +# Deep Research Report Template + +Use this template after the developer-agreed reframe and before the lifecycle's +`decide` step. The lifecycle owns when deeper research happens and which proof +categories are required; this template owns the report shape, evidence IDs, and +optional sections. + +For small research-only answers, use the compact shape. For ambiguous, +architectural, taxonomy-heavy, bug-root-cause, triage-routing, or build-spawning +work, use the full shape. + +## Report Rules + +1. Keep the report claim-first: findings state what is now believed to be true. +2. Treat evidence rows as proof records, not activity logs. +3. Every finding cites evidence IDs, and every evidence row names the claim it proves. +4. Mark inference separately when the report reasons across multiple evidence rows. +5. Keep limits visible: every evidence row should say what it does not prove. +6. End with the lifecycle decision: research-only exit or recommended follow-up build. + +## Full Shape + +```md +# Deep Research Report: + +## Frame + +- Surface request: +- Deeper objective: +- Agreed scope: +- Non-goals: +- Invariants: +- Truth gaps before research: + +## Short Answer + + + +## Findings + +- F-01: [E-01, E-03] +- F-02: [E-02] + +## Evidence Ledger + +| ID | Kind | Source / Query | Claim Proven | Limits | +|----|------|----------------|--------------|--------| +| E-01 | Semantics | query: "" | F-01 | Does not prove runtime behavior. | +| E-02 | Intent | onboarding: ``; source: `` | F-02 | Covers committed HEAD only. | +| E-03 | Relationship | cgc callees/deps: `` | F-01 | Does not prove hidden business intent. | + +## Proof Inventory + +- Onboarding docs read: +- Semantic queries performed: +- Code graph queries performed: +- Source files inspected: +- External references checked: +- Executable validations run: + +## Remaining Truth Gaps + +| Gap | Why It Matters | Blocks Build? | +|-----|----------------|---------------| +| | | yes/no | + +## Decision + +- Research-only exit: +- Spawn build? +- Suggested artifact shape if spawned (minimal `w-02` task vs master + series): +- Plan-gate status: +``` + +## Compact Shape + +```md +## Short Answer + + + +## Evidence + +- E-01 (): proves ; limits: . + +## Proof Inventory + +- Onboarding docs read: +- Semantic queries performed: +- Code graph queries performed: +- Source files inspected: + +## Remaining Truth Gaps + +- + +## Decision + + +``` + +## Evidence Kinds + +- `Semantics`: fuzzy routing through GrepAI or onboarding search. +- `Relationship`: CodeGraphContext callers, callees, dependencies, impact, or neighboring structure. +- `Intent`: paired onboarding plus bounded source confirmation for contracts, invariants, behavioral expectations, or branch-valid truths. +- `External`: domain documentation, standards, issues, PRs, release notes, or other non-repo references. +- `Executable`: reproduction steps, tests, scripts, command output, or generated validation artifacts. +- `Developer`: explicit clarification from the developer; verify against source before treating it as durable current-state knowledge. +- `Inference`: reasoning across evidence rows. Cite the input evidence IDs in `Source / Query` and state the remaining uncertainty. + +## Evidence Ledger Guidance + +The evidence ledger should be precise enough that another agent can tell why a +claim is supported without rerunning the entire investigation. Prefer concrete +paths, query strings, anchors, and command names over prose summaries. + +Use `Limits` to prevent overclaiming. Examples: + +- `Routes the feature area but does not prove current source behavior.` +- `Confirms the source contract at HEAD, not dirty work-in-progress.` +- `Shows the call path but not whether the path is user-facing.` +- `Explains the documented intent but needs executable validation before build.` diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/impact-analysis.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/impact-analysis.md new file mode 100644 index 00000000..a9c97ff4 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/impact-analysis.md @@ -0,0 +1,52 @@ +# Impact-Analysis Template + +A durable report a fan-out sub-agent writes for the **orchestrator** (portfolio phase) or the +**adversarial reviewer** (completion + code-quality lenses). It is the **integrity-bulwark** artifact: +planned-vs-planned **and** planned-vs-past blast radius. Sub-agents WRITE it; AR state mutations stay in +the spawning agent's main loop. + +## Rules + +1. Cover **two axes**: planned-vs-planned (does this change collide with another master/leaf, present or + future?) and planned-vs-past (does it regress something already landed — the "fixed one, broke two" + surface?). +2. Evidence-first: cite the route indexes, `cgc_*` queries, `grepai_search` queries, and + `read_ar_files` reads that back each finding. +3. State limits per finding — what the evidence does **not** prove. +4. This is a report, not a decision: it feeds the orchestrator's spirit test / reshape proposals or the + reviewer's verdict; it never decides. + +## Shape + +```md +# Impact Analysis — + +| Field | Value | +| --------- | -------------------------------------------- | +| for | orchestrator (portfolio) | reviewer () | +| author | | +| subject | | +| written | | + +## Surface Swept +- Routes / areas touched: +- Anchors: + +## Planned-vs-Planned (collisions with other masters/leaves — incl. FUTURE) +| Collision | With (master/leaf) | Kind (code | memory | sequencing) | Evidence | Limits | +| --------- | ------------------ | --------------------------------- | -------- | ------ | +- Recommended resolution: up-front foundation-master extraction | leaf move | sequential ordering | none needed + +## Planned-vs-Past (regression surface) +| Risk | Landed thing at risk | Evidence (cgc/grepai/route index) | Limits | +| ---- | -------------------- | --------------------------------- | ------ | + +## Evidence Inventory +- Route indexes read: +- cgc queries (callers/callees/deps/impact): +- grepai queries: +- read_ar_files reads (paired source+onboarding): + +## Bottom Line (for the spawning agent's main loop) +- — no mutation performed here. +``` diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/manager-brief.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/manager-brief.md new file mode 100644 index 00000000..10c37922 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/manager-brief.md @@ -0,0 +1,62 @@ +# Template — Manager Brief + +The dispatch packet the orchestrator compiles for a manager taking one master. Like the worker +brief, **this brief is the manager's entire session start** — it replaces the front half the +orchestrator already ran. Spawn with `env={"AR_SPAWN_ROLE": "manager"}` and the **qualified** leaf +key of the master's coordination leaf (`//`). + +--- + +```md +ROLE BRIEF — manager + +# MANAGER BRIEF — · + +You are the MANAGER for master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/manager.md`; this brief is your session start. Drive this +master's leaf loop to the master-exit seam, then hand over. + +## The master +- Task doc: `` (read it + every leaf doc first). +- Planner master: +- Leaves, in order: . +- Trust facts (compiled by the orchestrator — do not re-run the checkpoint): providers , drift , freshness . + +## The branch base (load-bearing) +- Your master integration branch: ``, based off the CURRENT super branch + `` @ `` — master branches base off super, never off main. +- Leaf worktrees base off your master branch (normal `worktree_start` per leaf). + +## Dispatch defaults +- Worker spawns: `templates/worker-brief.md`, `env={"AR_SPAWN_ROLE": "worker"}`, qualified leaf + keys; knob overrides: . +- Concurrency: . + +## The exit +- When all leaves have landed on your branch: spawn the master-exit reviewer + (`env={"AR_SPAWN_ROLE": "reviewer"}`, `roles/reviewer.md`) with the scope packet your role file + enumerates; then RAISE the gate without blocking — + `lifecycle_gate(kind="master-handover-approval", enclosure="", + evidence_refs=[], wait=false)` — the `enclosure` MUST carry the master's identity: + the EXACT master task name as the contracts carry it (the raise refuses without one) — + and post the master-handover packet **carrying the returned gateId**: the ORCHESTRATOR decides + the gate by that id. Under an all-human policy the raise blocks and the developer decides — do + not pass wait=false. +- Escalation: to the orchestrator, never the developer. Human-pinned kinds you may meet: + `integration-approval`, `push-approval`, `cleanup-approval`. + +## Reports +- Your handover packet: `../templates/master-handover-packet.md`. +- Leaf-review notes on your coordination leaf; decision-log entries for every delegated gate you + decide and every reopen. +``` + +--- + +**Compiler notes for the orchestrator.** + +- Fill every ``; an unresolved placeholder is not dispatchable. +- The super-tip commit you write here is the reconciliation anchor if a sibling master lands + first — state it explicitly. +- Deliver as an echo-confirmed paste; only count delivery on a post-boot echo. diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/master-handover-packet.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/master-handover-packet.md new file mode 100644 index 00000000..c8f5cb5c --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/master-handover-packet.md @@ -0,0 +1,49 @@ +# Master-Handover-Packet Template + +The artifact a **manager** posts to the **orchestrator** at master exit (`roles/manager.md`), after the +master-exit adversarial seam. Delivered via the inbox (durable) + stdin push. It is what the +orchestrator integrates a completed master into the super branch from. + +## Rules + +1. Post it only **after** the master-exit verdict exists — the verdict reference is a required slot. +2. Name the integration branch precisely; the orchestrator bases its C-11 integration on it. +3. The carry-over state must let the orchestrator's `c-11-memory-carryover-from-branch` integration run + without re-deriving what landed. +4. Post the packet as an `operator_inbox_post` row with `messageKind="master-handover"` and push + delivery enabled so the durable inbox row and stdin notification agree. + +## Shape + +```md +# Master Handover — · + +| Field | Value | +| ------------------ | -------------------------------------------- | +| master | | +| manager seat | | +| integration branch | | +| handover gateId | | +| base | | +| verdict | | +| verdict outcome | pass | pass-with-notes | +| written | | + +## Change-Set Summary +- +- Leaves landed: , … + +## Requirements / Steps Completion +- All master requirements addressed: yes | with justified deltas (decision-log refs: …) + +## Carry-Over State (for the orchestrator's master → super C-11) +- Memory rows parked / carried: +- Ledger maps every leaf commit: yes | +- Single-siding notes (if this master overlaps another strand): + +## Known Follow-Ups +- | none + +## Reachability +- Manager seat (chat + coordination leaf) stays reachable until the series retires. +``` diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md new file mode 100644 index 00000000..81c2466b --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md @@ -0,0 +1,48 @@ +# Onboarding-Coherency Template + +A durable report a fan-out sub-agent writes for the **adversarial reviewer's** third lens +(onboarding-vs-code) and for the **orchestrator's** memory-quality checks. It is the paired +`read_ar_files` + `memory_quality_check` + `drift_check` review made durable — the check that the +memory repo stayed in lockstep with the code, since **orchestrator quality ∝ memory-repo quality**. + +## Rules + +1. Every **changed** source file must have its sidecar body updated **in the same pass** — a refreshed + `lastVerifiedCommitHash` over stale content silently defeats the drift check and is a finding. +2. Every **new** source file must have a created sidecar (`check_missing_onboarding` clean). +3. Route/repository overviews must reflect the change set; a moved/added/deleted slice must be + reflected in the governing overview. +4. This is a report; the reviewer's verdict or the orchestrator's main loop acts on it. + +## Shape + +```md +# Onboarding Coherency — + +| Field | Value | +| --------- | --------------------------------------- | +| for | reviewer () | orchestrator | +| author | | +| scope | | +| written | | + +## Changed Files — Sidecar Refresh +| Source file | Sidecar updated same pass? | Body reflects change? | Finding | +| ----------- | -------------------------- | --------------------- | ------- | + +## New Files — Missing Onboarding +| New source file | Sidecar created? | check_missing_onboarding clean? | Finding | +| --------------- | ---------------- | ------------------------------- | ------- | + +## Drift & Quality +- drift_check: clean | actionable (list) +- memory_quality_check: pass | +- Ledger maps code HEAD: yes | + +## Overviews +- Route/repository overviews current for touched routes: yes | +- Moved/added/deleted slices reflected in governing overviews: yes | + +## Bottom Line +- Onboarding-vs-code coherent: yes | NO — +``` diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/orchestration-task.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/orchestration-task.md new file mode 100644 index 00000000..c3d4bb08 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/orchestration-task.md @@ -0,0 +1,89 @@ +# Orchestration-Task Template + +The artifact a **strategist** drafts for the **orchestrator** (`roles/strategist.md`) — the sprint +plan and the sprint scope. A strategist run producing this artifact is a **mandatory precondition +for any orchestrated run**; the orchestrator adopts the accepted draft into durable task form (the +strategist is a reader, not a mutator). It is written under the series/coordination `notes/` path +the brief names and revised across drawing-board rounds. + +## Rules + +1. **Shown work is required per section.** Every dependency edge carries evidence (a tool query, a + file, a decision-log entry, a design-section citation, or — for new surfaces — a **declaration + cross-reference**: the two leaf declarations that couple) — an uncited edge is refutable by + default. Every blast-radius entry names its derivation (caller-set / doctrine-propagation / + migration / user-visible). Every leaf move carries from→to + rationale. +2. **Surfaces are two-sided:** the surface lists distinguish **existing** surfaces (mapped against + the route map) from **new** surfaces (greenfield, mapped by declaration: parent route/location + + intended shape). New-surface edges come from declaration cross-reference — leaf B naming a + surface leaf A creates is a pure ORDER edge; two leaves declaring additions under one parent + route is a CONFLICT-risk edge at the parent. +3. **Coherence findings include the honest failures:** a leaf that can name neither existing + surfaces nor the parent anchoring of its additions is recorded as **"unplannable as scoped"** — + never silently guessed around (a merely not-yet-existing surface is NOT unplannable). Directional + cross-master contradictions are flagged quo-vadis at the top of that section. +4. This is a **draft for adoption**, not a mutation: the strategist never edits task docs; the + orchestrator (the portfolio owner) adopts the plan and records the adoption in the decision log. +5. The plan is reviewed adversarially (the plan-review criteria catalog, + `../criteria/plan-review.md`) before the developer's drawing board; revisions append round + sections rather than rewriting history. +6. Once adopted, this artifact is the sprint's standing scope: in-sprint additions before + implementation starts trigger re-evaluation; out-of-sprint additions wait for the next sprint. + +## Shape + +```md +# Orchestration Task — · + +| Field | Value | +| ---------------- | ------------------------------------------------ | +| strategist | | +| masters in scope | | +| status | draft | in-review | round- | adopted | +| round | (3-round cap; the drawing board is the escalation) | +| written | | + +## Sprint Scope +- IN: +- OUT: + +## Touch Surfaces (per leaf — two-sided) +| Leaf | Existing surfaces (route-map-mapped) | New surfaces (declared: parent route/location + intended shape) | +| ---- | ------------------------------------ | ---------------------------------------------------------------- | + +## Dependency Graph (every edge cited — an uncited edge is refutable by default) +| From (leaf/master) | To | Kind (ORDER | CONFLICT | INDEPENDENT) | Evidence (cgc/grepai query · file · decision-log · design § · declaration cross-reference) | +| ------------------ | -- | ------------------------------------ | ------------------------------------------------------------------------------------------ | + +## Blast-Radius Register (feeds the owning seat's loop-tier scoring) +| Leaf | Radius (low | medium | high) | Derivation (caller-set | doctrine-propagation | migration | user-visible) | Evidence | +| ---- | ---------------------------- | ------------------------------------------------------------------------- | -------- | + +## Leaf Moves +| Leaf | From (master) | To (master) | Rationale | +| ---- | ------------- | ----------- | --------- | + +## Coherence Findings +- ⟁ QUO-VADIS (developer decision required): | none +- +- Unplannable as scoped: | none + +## Sprint Order / Waves +1. (note the + landing-reconciliation cost of parallel waves as a scheduling consideration) +2. + +## Open Risks +- + +## Re-Evaluation Triggers +- In-sprint master added before implementation starts → re-plan (strategist re-evaluates). +- Master added outside the sprint scope → next sprint's evaluation. +- + +## Evidence Inventory +- cgc queries (dependencies/callers/callees/complexity): +- grepai queries (search/trace): +- read_ar_files reads (paired source+onboarding) / route indexes read: +- task docs, decision logs, and design sections cited: +``` diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/turn-report.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/turn-report.md new file mode 100644 index 00000000..b771ada4 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/turn-report.md @@ -0,0 +1,57 @@ +# Turn-Report Template + +The **mandatory** artifact a worker writes at **every** hand-off (`roles/worker.md`). It is how the +leaf's work survives the session's death and how a respawned successor onboards from **state, not the +transcript**. A missing turn report is nudged by the manager. + +## Rules + +1. Write it in the **main loop**, from your own work plus any sub-agent summaries — never delegate it to + a sub-agent (it is the leaf's single artifact of record). +2. State facts, not a narrative: what changed, what broke, what is proven green, what remains. +3. The **Respawn State** section must let a fresh successor continue **without reading any transcript**. +4. Keep it durable and in the series notes; reference it from the leaf `task_doc`. +5. Default path: `notes/reports/-worker-report.md`. The control-plane helper exposes this + convention so manager nudges and respawn onboarding can point at the same artifact. + +## Shape + +```md +# Turn Report — · + +| Field | Value | +| ------------ | --------------------------------------- | +| leaf | | +| master | | +| worker | | +| worktree | | +| status | in-progress | leaf-complete | blocked | +| checks | green | failing: | not-yet-run | +| written | | +| inbox | | + +## What Was Done +- (files: ``, …) + +## Issues Hit +- → resolved: | still open: + +## Solved On The Spot +- (a plan delta beyond blank-filling is NOT here — it was + escalated to the manager; see Escalations) + +## What Is Left +- [ ] + +## Onboarding Refreshed +- in this pass (c-05) + +## Escalations +- | none + +## Respawn State (onboard a successor from this — no transcript needed) +- Current position in the leaf plan: +- Files touched so far: +- The one thing a successor must know before editing: +- Uncommitted vs committed state: +``` diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/verdict.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/verdict.md new file mode 100644 index 00000000..3f292443 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/verdict.md @@ -0,0 +1,142 @@ +# Verdict Template (adversarial reviewer) + +The artifact an **adversarial reviewer** writes at a seam (`roles/reviewer.md`). It lands +under the series `notes/reports/` directory and attaches to the handover gate as **judge evidence**. +There are two variants: **master-exit** (before a manager hands over to the orchestrator) and +**super-exit** (before the orchestrator hands over to the developer) — plus a loop-review +adaptation of the master-exit shape (see Loop-Review Adaptation below). + +## Rules + +1. **A verdict is evidence, not a decision.** State an explicit pass/block **recommendation**; the gate's + decider decides. Never write the verdict as if it were the gate outcome. +2. **A block must decompose into fix leaves** — concrete, leaf-shaped findings the owning + manager/orchestrator can dispatch. A block that cannot be named as fix leaves is not yet a block. +3. **Refute-or-confirm:** every finding must survive an attempt to refute it. Rank findings and cite + the backing evidence file. +4. Cover all three lenses (completion · code quality · onboarding-vs-code) explicitly, even to say a + lens is clean. +5. Record the gate evidence reference exactly: `kind=reviewer-verdict`, `ref=`, and + `verdict=`. +6. **Report every bound catalog criterion** in the Criteria Catalog Results table (the catalogs the + binding table in `roles/reviewer.md` assigns this review type, `../criteria/`) — one row per + standing criterion even when it found nothing, candidate rows when run — and carry any proposed + catalog amendments (the promotion ratchet) in that section. + +## Master-Exit Variant + +```md +# Adversarial Verdict — master-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | master-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | orchestrator (delegated `master-handover-approval`; serious issues escalate → developer) | +| artifact path | notes/reports/-master-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Task Docs +- Master requirement/substep coverage: addressed | delta justified | MISSING +- Leaf task docs and worker reports reconcile with the master task_doc: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite: green | failing: +- regressions vs the past (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- master-side route overviews current: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Manager Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the master-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Super-Exit Variant + +```md +# Adversarial Verdict — super-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | super-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | developer (human review concentrates at the super gate) | +| artifact path | notes/reports/-super-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Portfolio Task Docs +- Portfolio objective and dependency order satisfied: yes | +- Master handover packets and prior master-exit verdicts reconciled: yes | +- Cross-master conflicts, duplicate implementations, and deferred follow-ups surfaced: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite for the accumulated super branch: green | failing: +- branch-wide regressions vs the past and across masters (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- route overviews describe the accumulated behavior: yes | +- C-11 carry-over and ledger mapping coherent for the final super branch: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Orchestrator Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the super-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Loop-Review Adaptation (leaf full-loop · plan review) + +A three-party-loop review (a full-loop leaf round, or the plan review over an orchestration task) +uses the **master-exit variant's shape minus the gate machinery**: drop the `gate evidence` header +row and the Judge-Evidence Note (a loop review attaches to no gate), set `decider` to the **loop +owner** (the leaf's owning seat, or the orchestrator for the plan review), scope to the round's +change set (or the orchestration-task draft), and keep everything else — recommendation, Criteria +Catalog Results (the loop's bound catalogs, e.g. `plan-review` + `report-verification` for a plan +review), ranked refute-tested findings, and fix decomposition. The verdict remains **evidence to +the loop owner, never a decision**; a delta-verify appends a dated delta section to this same +artifact rather than opening a new one. diff --git a/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/worker-brief.md b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/worker-brief.md new file mode 100644 index 00000000..db8f44d0 --- /dev/null +++ b/.openclaw/workspace/skills/l-01-agent-lifecycles/templates/worker-brief.md @@ -0,0 +1,72 @@ +# Template — Worker Brief + +The dispatch packet a spawning seat (manager / orchestrator) compiles for a worker. **The brief is +the worker's entire session start** — it replaces the front half the spawner already ran (trust +checkpoint, reframe, plan). Compile it fresh per leaf from this shape; the proven form below +absorbed a series of real dispatch frictions (route-index leaks, attestation format, provider-stack +keying, missing `python` shim), so deviate knowingly or not at all. + +Spawn with `env={"AR_SPAWN_ROLE": "worker"}` and the **qualified** leaf key +`//` so the session-start router and the dashboard leaf rail both engage. + +--- + +```md +ROLE BRIEF — worker + +# WORKER BRIEF — · + +You are a WORKER for leaf `` of master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/worker.md`; this brief is your session start. Execute the leaf +completely, write your turn report, then stop. + +## Worktrees (your ONLY writable areas) +- Code: `` (branch ``, base ``) +- Memory: `` +- Plus your turn report at the path below. Nothing else. NEVER `git commit` — the owning seat + closes out after reviewing your report. + +## Tool surface +- Native file tools inside the two worktrees; shell for the checks below. +- Read-only AR retrieval: `read_ar_files` (serves the OFFICIAL baseline, never your worktree — + final verification uses native reads), `grepai_search` / `cgc_*` (provider stack key: + ``), `context_packet`. +- No `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, or `route_index_refresh` — + generated route indexes are regenerated with a local `build_route_indexes(...)` from the memory + worktree. +- Interpreter: `` with `PYTHONPATH=/mcp/src` — there is no + `python` shim in this environment. + +## The task +Leaf spec: `` (read it first). + +## Checks (green before you report) +- Focused: . +- Full: — must exit 0. +- `git diff --check` in both worktrees. + +## Onboarding (same editing pass, per c-05) +- Changed source files: update the sidecar BODY now; new files: create the sidecar. +- Route overviews: genuine body update where routes changed; otherwise the newest history entry + uses the LITERAL form `- — No route impact: ` (timestamp first). +- Pin idiom for verification metadata: "Verification metadata pinned until closeout stamps the + commit." + +## Turn report (mandatory, last act) +Write `/-worker-report.md` following +`skills/l-01-agent-lifecycles/templates/turn-report.md` — including exact check commands + +outcomes, the retrieval-evidence tally, and the respawn state. If blocked: fill Escalations and +stop — escalate to , never to the developer. +``` + +--- + +**Compiler notes for the spawning seat.** + +- Fill every ``; a brief with an unresolved placeholder is not dispatchable. +- Verify the provider stack actually answers before naming it; write `NONE (native reads only)` + when it does not — a worker discovering dead providers mid-leaf wastes its turn. +- Deliver as an echo-confirmed paste; verify the harness's paste chip (`[Pasted Content N chars]`) + before submitting, and only count delivery on a post-boot echo. +- The report path lives under the series `notes/reports/` — the same folder the seam verdicts use. diff --git a/.openclaw/workspace/skills/l-01-session-job-lifecycle/SKILL.md b/.openclaw/workspace/skills/l-01-session-job-lifecycle/SKILL.md deleted file mode 100644 index 9b3cc6d6..00000000 --- a/.openclaw/workspace/skills/l-01-session-job-lifecycle/SKILL.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -name: l-01-session-job-lifecycle -description: "The session job lifecycle the coordinator routes every session into: request -> context/trust checkpoint -> developer-agreed reframe -> deeper research -> decide build mode -> build -> close. Owns research-only exits, the build-mode decision (chat build vs durable w-02-light-task-workflow task), and the job lens (bug/feature/triage/research). Supersedes the retired chat workflow by migrating and modernizing its doctrine." ---- - -# l-01-session-job-lifecycle Session Job Lifecycle - -The `l-01-session-job-lifecycle` skill is the **canvas** the coordinator routes into at the start of every session. -It is not a task format. A task format is one outcome of a single step inside it. - -The lifecycle is one shared spine with thin per-job lenses. Its front half is a -developer/model collaboration loop: the developer states the request, the model -runs mandatory MCP grounding checks, the model presents an evidence-backed -reframe, and the developer agrees or revises that reframe before deeper research -or build-mode decisions proceed. - -## Companion Files - -1. `job-variants.md` — the four thin job lenses (bug / feature / triage / research). -2. `deep-research-report-template.md` — the reusable report and evidence-ledger shape for deeper research. - -``` -0 Request -> 1 Trust Checkpoint -> 2 Reframe + Research -> 3 Decide -> 4 Build -> 5 Close - | - +-- research-only (e.g. investigation, code questions...) -``` - -## Hand-off Protocol — Dry-run action => "Notify-and-stop" Action => "Report" Action - -Every developer hand-off / gate moment — reframe agreement, plan gate, worktree intent, commit -approval, push approval, integration, cleanup/finalization, regular turn-end — is **notify-and-continue**: -surface an attention item, present the result, and **end your turn**; the developer responds and your -**next** turn picks up automatically. It is **three actions, never one**: - -1. **Dry-run action.** Run applicable MCP tools in `dry-run` for the hand-off. If dry run succeeds, - proceed with the notify-and-stop action. If dry run fails, try to ammend the issue first before reporting failure. -2. **Notify-and-stop action.** Call `lifecycle_turn_end_notification(summary=…)`. It sets the new - **`awaiting-developer`** lifecycle state, surfaces a dashboard attention item, and **returns - immediately — no wait, no inbox.** This is the **last tool call of the turn** — the report prose - still follows it; do not STOP here. The developer responds on the - dashboard or in the leaf's attached chat, and the **first AR tool call of your next turn** - automatically resumes the lifecycle (`running`) and clears the attention item — you send **no** - explicit resume. -3. **Report action.** Deliver the complete hand-off report as plain assistant output - (the reframe, the plan, the intent packet, or the closeout relay with - preview facts, quality results, proposed commit messages, and - attestations), and make the decision you are handing to the developer the last - line of prose. **The report is the last thing in the turn — then STOP / end your turn.** - -Use the `dry-run` step to verify that the planned tool call (for example the closeout apply) will -succeed before you hand off, and self-fix any failure before reporting it. - -`lifecycle_turn_end_notification` returns immediately and does **not** render a prompt over your prose, -so the report you deliver after it is exactly what the developer sees — call the -notification, then deliver the report as your final prose, then stop. Keep the report turn free of any mutating or permission-triggering operation so -nothing obscures the report. - -Junction → Dry-run → notify (`lifecycle_turn_end_notification`) → Report. Every junction below now hands -off through that one notification; the named `kind` is the **parked** durable-gate label the fallback -would use (see "Parked fallback" below), kept so the dashboard can still classify each hand-off: - -| Junction | Parked durable gate `kind` | Skill that hands off | -| -------------------------------- | -------------------------- | ---------------------------------------------------------- | -| plan gate | `plan-approval` | `l-01-session-job-lifecycle` | -| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | -| commit / closeout | `closeout-approval` | `c-12-closeout` | -| push | `push-approval` | `l-01-session-job-lifecycle` / `c-09-git-worktree-manager` | -| integration | `integration-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| cleanup / lifecycle finalization | `cleanup-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| any other dev-wait | `agent-question` | `l-01-session-job-lifecycle` | - -`closeout-approval` **is** the commit hand-off — there is no separate -`commit-approval`. Closeout is the single commit-of-record for code, memory, and -ledger, so every commit (including a singular one) routes through the closeout -hand-off. `agent-question` is the non-exhaustive catch-all so any dev-wait that is -not a structured junction is still observable. - -### Parked fallback — block-and-wait `lifecycle_gate` - -The block-and-wait `lifecycle_gate(kind=…)` junction (which creates a durable gate and waits for a -developer decision), the operator inbox, and the dashboard GateResponder **still exist and still work** -when explicitly raised — but they are **no longer the active path**, and nothing routes toward them: -`next_step.py` repoints every gate moment to `lifecycle_turn_end_notification`. Reach for the -server-enforced `lifecycle_gate` (followed by `lifecycle_resume` after the developer decides) only when -you deliberately need a durable, developer-attributed, mutation-blocking approval record; its `kind` -values are the table above. If you ever do raise it, it renders an approval prompt **over** your prose, -so the report must land in an earlier turn — which is exactly why notify-and-stop is preferred. - -## Lifecycle Signals — Making The Session Observable - -Every session in a managed repo is a **lifecycle**: the six `lifecycle_*` signals -record where it is and what it is waiting on, so the work is observable and -resumable across chat deaths (design `docs/design/observable-lifecycle.md`). The -model **never handles a lifecycle id** — identity is server-side, anchored in the -worktree contract. - -| When (phase) | Signal | Why | -| ---------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Trust Checkpoint passes (managed repo) | `lifecycle_start` | Begin a **fleeting** lifecycle (guarded: one per session; takes no id). | -| Entering each phase | `lifecycle_phase` | Move the orthogonal phase axis (`request`/`trust-checkpoint`/`reframe-research`/`decide`/`build`/`close`). | -| At a hand-off (reframe, plan, commit, …) | `lifecycle_turn_end_notification(summary=…)` (last tool call), then the report prose, then **STOP** | Set `awaiting-developer`, surface the dashboard attention item, and return immediately (no wait, no inbox); the next turn's first AR tool call auto-resumes (`running`) and clears the item. Block-and-wait `lifecycle_gate(kind=, ask=…, packet=…)` + `lifecycle_resume` is the parked fallback. | -| `worktree_start` (Decide → Build) | _(promotion — automatic)_ | The fleeting lifecycle becomes **persistent**, anchored in the contract; no separate signal. | -| Resuming an existing task | `worktree_attach` | Re-adopts the contract's lifecycle (contract-resolved); the model passes no id. | -| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | The save gate: promote it or abandon it — never dropped silently. | -| Close | `lifecycle_end` (`completed`\|`abandoned`) | The terminal record. | - -Rules: `lifecycle_start` is guarded (one active lifecycle, no id). `paused` is -**system-owned** — there is no pause signal. `awaiting-developer` is set by -`lifecycle_turn_end_notification` and auto-cleared back to `running` by the next -turn's first AR tool call — you never resume it by hand. A tool call outside any -lifecycle is **dropped, never misattributed**. `worktree_start` **promotes** the current -lifecycle (fleeting → persistent); `worktree_attach` **resumes** the contract's -lifecycle; both keep identity server-side. - -## 0 — Request - -Receive the developer's raw request and identify the active repository. - -1. Treat the developer's statement as raw input, not yet as an implementation plan. -2. Infer the target code repository from the request and local context. Ask the - developer if the target is unclear. - -Request intake changes nothing. It only establishes which repository the next -checkpoint must inspect. - -The upcoming `Trust Checkpoint` reveals whether or not the request is related to repositories managed by Agents Remember. If not, then the lifecycle exits early and the agent can work as usual. - -However, if later work is to enter the boundary of repositories being managed by Agents Remember, -the lifecycle must be re-entered. - ---- - -## 1 — Trust Checkpoint - -Establish whether memory and providers are trustworthy enough to use. - -1. For the target repository, resolve coordination/memory context with - the MCP tool call: - - ```text - context_packet(repo_id="", include_providers=true, include_drift=true, include_freshness=true) - ``` - -2. Report the packet facts before relying on memory or providers: - - repository, branch, and dirty state - - memory root and onboarding root - - provider state - - drift status and actionable drift count - - branch freshness: whether the code and memory checkouts are current with - their upstreams (`behind`/`diverged` means the local official line is - stale — fast-forward it before trusting analysis or basing work on it) - and whether the ledger maps code HEAD (`ledgerMapsCodeHead=false` means - the memory checkout does not match the code state; run carryover or - check out the right memory branch first) -3. If onboarding for committed source is drifted, missing verification, or - orphaned, and the corresponding source file is not dirty in the code - worktree, stop and ask the developer whether or not to refresh it through - `c-05-create-or-update-onboarding-files`. Drift handling is approval-gated! -4. If drift is tied to dirty source, report it as active work-in-progress. Do - not adopt it as maintenance or silently trust it as current state unless the - developer explicitly says this job owns it. -5. If providers are stopped or degraded, use the matching MCP provider/runtime - operations, then re-run the provider check. If providers are ready, report - readiness and continue. If issues persist, report it to the developer and - wait for instructions. If the packet's providers summary lists `indexing` - targets, report them to the developer: those providers are healthy but - busy, and their results may be partial until the scan completes. -6. After the trust checkpoint passes, read committed-state onboarding for the - in-scope anchors as needed. A file dirty in another chat is still valid for - HEAD and worth comparing, but its dirty-source drift remains active work. - ---- - -## 2 — Reframe And Research - -Turn the developer's raw request into an agreed piece of work, then perform the -deeper research that the agreed frame requires. The `tasks/AGENTS.md` -collaboration doctrine applies here in plain chat, before any task file or task -format exists. - -**Read tool for this phase.** Until the build-mode decision (Phase 3), read managed-repo source -through the `read_ar_files` MCP tool, not the harness's native read — it returns paired -source+onboarding plus the repository/route overviews in one observable, lifecycle-attributed -call, and you keep a running count of those calls as evidence. Native read is the edit -precondition in Phase 4. - -1. **Gather evidence for the reframe** through reading the - `c-04-retrieval-strategy-router` skill. Pick the strategy by the question: - - _Semantics_ (grepai over onboarding) — "where does X live / what handles Y." - - _Relationship_ (cgc) — callers/callees/dependencies/impact. - - _Intent_ (onboarding + bounded source confirmation) — hidden contracts, invariants, - branch-valid truths, behavioral expectations. This is a workflow of paired - source+onboarding reads via the `read_ar_files` MCP tool: one call pairs each source - file with its verified onboarding and auto-attaches the repository overview + governing - route-overview chain (the bird's-eye view). -2. **Reframe** the request through `tasks/AGENTS.md`: distinguish the surface - request, deeper objective, highest-leverage framing, assumptions, boundaries, - invariants, and truth gaps. Do not rush a statement into a plan. -3. Present the reframe to the developer. If the developer disagrees, discuss and - revise the reframe. If the developer agrees, proceed to deeper research. -4. **Perform deeper research** for the agreed frame. This research still uses - `c-04-retrieval-strategy-router`, but it is now scoped by the developer-agreed - frame rather than by the model's first guess. Use - `deep-research-report-template.md` for the report shape; the lifecycle owns - the required proof categories, while the template owns evidence formatting. -5. The deeper research report must list its proof and tie evidence to the claim it supports: - - `read_ar_files` calls (paired source+onboarding reads — the running count) - - onboarding docs read - - semantic queries performed - - code graph queries performed - - source files inspected - - remaining truth gaps -6. Run the **job opening move** for the job lens (see `job-variants.md`) and use - the deeper research to name the truth gaps that remain. -7. Continue until the developer agrees the design is defined well enough to write - down, then produce the **plan**: the steps, and a **code example for every - distinct change** you intend to make. - -**Plan gate:** **hand off** before changing any code. No implementation begins -before the developer approves. Call -`lifecycle_turn_end_notification(summary={…the plan + the developer-facing approval ask…})` as the -**last tool call**, then present the plan as your final prose and **STOP**; -the developer approves on the dashboard or in chat and your next turn auto-resumes to begin -implementation. (Parked fallback: the server-enforced -`lifecycle_gate(kind="plan-approval", ask=…, packet=…)` + `lifecycle_resume` still exist if you -deliberately need a mutation-blocking approval record.) - ---- - -## 3 — Decide (build mode) - -One decision: does this job change code? - -- **No -> research-only exit.** Deliver the answer/assessment. No worktree, no task artifact, no closeout. - A research-only job may recommend or spawn a follow-up build job; it does not perform one itself. -- **Yes -> worktree intent hand-off, then always a worktree.** Read `c-09-git-worktree-manager` - and `system/git-workflow.md`, call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the worktree - intent packet as your final prose and **STOP**. The developer approves and your next turn - auto-resumes to `worktree_start`. Then open it with - `c-09-git-worktree-manager` and pick the build mode: - - **Chat build** — small enough to carry inline this session: worktree-backed, **no** `task.md`. - - **Durable task build** — hand off to `w-02-light-task-workflow`: `task.md`, checklist, decision - log, proposed code examples. Escalate to a master + light sub-task series when the work outgrows a - single-page plan. - -The worktree intent packet names the target repo, build mode, discovered branch policy, proposed -`source_branch`, proposed work branch/worktree name, memory mode, landing path, and material risks. -On PR-gated repos, the packet must prove that the recorded `source_branch` is pushable and that -protected targets are reached later through the repo's PR flow. - -Worktree granularity = the leaf task unit. A single task gets its own leaf enclosure/worktree. A -master multi-task owns a root `series-contract.md` and integration branch, while each active leaf -sub-task gets its own `enclosures//series-contract.md`, branch, and worktree. A chat build -gets its own leaf worktree without a task artifact. The git-landing decision (direct vs PR-gated) is -deferred to the repo's `system/git-workflow.md` — read it before landing on a gated branch. - ---- - -## 4 — Build - -Implement inside the worktree, keeping memory and tests in lockstep with the code. - -1. Apply the approved code changes. -2. **Refresh the matching onboarding in the same editing pass**, per completed plan-section — never - deferred to the end of the job. When a change affects durable current-state knowledge, the sidecar - is updated alongside it through `c-05-create-or-update-onboarding-files`. - - For **changed** (already-onboarded) source files, update the sidecar **body** now: the closeout - gate rejects a changed source file whose existing sidecar was not modified this job, because - refreshing `lastVerifiedCommitHash` over stale content silently defeats the drift check. - - For **new** source files, run `check_missing_onboarding` before the commit and create the - reported missing sidecars through the `c-05-create-or-update-onboarding-files` skill; the post-code-commit memory refresh stamps them with - the real code commit hash and date. -3. Run the checks from the `c-08-ar-coordination-context-resolver` resolved `system/tools.md` (lint, typecheck, complexity, tests) and - get them **green before each incremental commit**. Testing is never deferred to a final task; the - pre-commit/pre-push hooks enforce it. -4. **Watch the official line and sync early.** `worktree_status`'s `freshness` block reports when the - recorded base pair fell behind the local source branch tips (a parallel cycle landed). Pull the - moved official line in with `worktree_sync` — preferably **before memories are written**: with - parked memory the sync is a pure fast-forward, the other cycle's sidecars and ledger rows end up - beneath this task's future work, and end-of-series integration stays `ff-only` with no carryover - reconciliation. - -Incremental, pushable commits keep the work-loss window small. Each closeout below is one such commit. - ---- - -## 5 — Close - -Land the work. **Implementation approval is not commit approval.** - -1. Run the `c-09-git-worktree-manager` closeout **preview** for the worktree (`worktree_closeout_preview`). - Every build closes through its worktree — there is no direct-checkout closeout. - Relay the proposed code, memory, and ledger commit messages. -2. **Commit gate:** run the closeout **preview** (dry-run), then **hand off** before any real commit or closeout - apply. If required onboarding is missing, run the `c-05-create-or-update-onboarding-files` skill for the affected file and re-run the preview. - Call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the - **last tool call**, then deliver the preview facts as your final prose and **STOP**; - the developer approves on the dashboard or in chat and your next turn auto-resumes to - `worktree_closeout_apply`. The `c-12-closeout` skill owns this hand-off. Parked fallback: when you - deliberately raise the durable `closeout-approval` `lifecycle_gate`, it is enforced **server-side** — - `worktree_closeout_apply` refuses unless it is approved by the developer, and an agent self-approval - never satisfies it. -3. On approval, the `c-09-git-worktree-manager` skill owns the external-memory invariant in order: commit code → refresh affected - onboarding metadata to the new code commit → run memory quality control → commit memory content → - update and commit the ledger. -4. **Integrate + land** per `c-09-git-worktree-manager` and `system/git-workflow.md`: integrate the - worktree branch into the approved source/integration branch, then on a PR-gated repo push that - source branch, open the PR, wait for green checks, and merge per the repo convention. Never push a - protected branch directly. The agent does not push on its own authority — call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the push intent - as your final prose, and **STOP**; push only after the developer - approves and your next turn auto-resumes. The `c-09-git-worktree-manager` skill makes the matching - integration and cleanup/finalization hand-offs at its landing tail (parked durable kinds - `integration-approval` / `cleanup-approval`). -5. **Map the ledger to the landed commit.** A PR merge usually lands a **merge commit** on top of the - work — tree-identical to the verified tip but a new SHA the ledger does not yet map. Ensure the - ledger maps that merge commit so the next worktree can base off the merged branch without a manual - reconciliation. `system/git-workflow.md` owns this step. -6. **Finalize the lifecycle:** run `lifecycle_finalize_task(..., dry_run=true)` once the local parent - branch contains the landed commit and memory carryover is done. Call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then relay its landed-commit - proof, cleanup plan, and task-document updates as your final prose, and - **STOP**. The developer approves cleanup/finalization and your next turn auto-resumes to run the real - finalizer. The tool proves one parent-child branch edge, - reclaims the worktrees, and marks the leaf task plus immediate parent row `Completed` when those - task-doc paths are supplied. It does not recursively complete ancestors; repeat the edge at the next - parent level when that parent task lands. -7. **Keep squash out of the normal path.** A PR-gated edge is structurally the same as a direct edge - after the model finishes the PR merge and pulls the target branch locally. Do not use squash-merge - equivalence as a default finalization proof; squash is an emergency/manual recovery path because it - erases commit lineage and can make memory lookup history wrong. - -A research-only exit skips this phase entirely. - -## Relationship To Other Instructions - -This skill extends the coordinator `AGENTS.md` and the repository memory layer; it does not replace -them. Read `job-variants.md` for the per-job lenses, and `deep-research-report-template.md` for the -deeper research report shape. diff --git a/.openclaw/workspace/skills/l-01-session-job-lifecycle/deep-research-report-template.md b/.openclaw/workspace/skills/l-01-session-job-lifecycle/deep-research-report-template.md deleted file mode 100644 index 6e9d13d0..00000000 --- a/.openclaw/workspace/skills/l-01-session-job-lifecycle/deep-research-report-template.md +++ /dev/null @@ -1,123 +0,0 @@ -# Deep Research Report Template - -Use this template after the developer-agreed reframe and before the lifecycle's -`decide` step. The lifecycle owns when deeper research happens and which proof -categories are required; this template owns the report shape, evidence IDs, and -optional sections. - -For small research-only answers, use the compact shape. For ambiguous, -architectural, taxonomy-heavy, bug-root-cause, triage-routing, or build-spawning -work, use the full shape. - -## Report Rules - -1. Keep the report claim-first: findings state what is now believed to be true. -2. Treat evidence rows as proof records, not activity logs. -3. Every finding cites evidence IDs, and every evidence row names the claim it proves. -4. Mark inference separately when the report reasons across multiple evidence rows. -5. Keep limits visible: every evidence row should say what it does not prove. -6. End with the lifecycle decision: research-only exit or recommended follow-up build. - -## Full Shape - -```md -# Deep Research Report: - -## Frame - -- Surface request: -- Deeper objective: -- Agreed scope: -- Non-goals: -- Invariants: -- Truth gaps before research: - -## Short Answer - - - -## Findings - -- F-01: [E-01, E-03] -- F-02: [E-02] - -## Evidence Ledger - -| ID | Kind | Source / Query | Claim Proven | Limits | -|----|------|----------------|--------------|--------| -| E-01 | Semantics | query: "" | F-01 | Does not prove runtime behavior. | -| E-02 | Intent | onboarding: ``; source: `` | F-02 | Covers committed HEAD only. | -| E-03 | Relationship | cgc callees/deps: `` | F-01 | Does not prove hidden business intent. | - -## Proof Inventory - -- Onboarding docs read: -- Semantic queries performed: -- Code graph queries performed: -- Source files inspected: -- External references checked: -- Executable validations run: - -## Remaining Truth Gaps - -| Gap | Why It Matters | Blocks Build? | -|-----|----------------|---------------| -| | | yes/no | - -## Decision - -- Research-only exit: -- Spawn build? -- Suggested build mode if spawned: -- Plan-gate status: -``` - -## Compact Shape - -```md -## Short Answer - - - -## Evidence - -- E-01 (): proves ; limits: . - -## Proof Inventory - -- Onboarding docs read: -- Semantic queries performed: -- Code graph queries performed: -- Source files inspected: - -## Remaining Truth Gaps - -- - -## Decision - - -``` - -## Evidence Kinds - -- `Semantics`: fuzzy routing through GrepAI or onboarding search. -- `Relationship`: CodeGraphContext callers, callees, dependencies, impact, or neighboring structure. -- `Intent`: paired onboarding plus bounded source confirmation for contracts, invariants, behavioral expectations, or branch-valid truths. -- `External`: domain documentation, standards, issues, PRs, release notes, or other non-repo references. -- `Executable`: reproduction steps, tests, scripts, command output, or generated validation artifacts. -- `Developer`: explicit clarification from the developer; verify against source before treating it as durable current-state knowledge. -- `Inference`: reasoning across evidence rows. Cite the input evidence IDs in `Source / Query` and state the remaining uncertainty. - -## Evidence Ledger Guidance - -The evidence ledger should be precise enough that another agent can tell why a -claim is supported without rerunning the entire investigation. Prefer concrete -paths, query strings, anchors, and command names over prose summaries. - -Use `Limits` to prevent overclaiming. Examples: - -- `Routes the feature area but does not prove current source behavior.` -- `Confirms the source contract at HEAD, not dirty work-in-progress.` -- `Shows the call path but not whether the path is user-facing.` -- `Explains the documented intent but needs executable validation before build.` diff --git a/.openclaw/workspace/skills/l-01-session-job-lifecycle/job-variants.md b/.openclaw/workspace/skills/l-01-session-job-lifecycle/job-variants.md deleted file mode 100644 index 48f032c6..00000000 --- a/.openclaw/workspace/skills/l-01-session-job-lifecycle/job-variants.md +++ /dev/null @@ -1,43 +0,0 @@ -# l-01-session-job-lifecycle Job Variants — The Lenses - -The job type is a **lens**, picked during `reframe-research` and re-pickable at any time. It is not a gate and it -never changes the spine (`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three -things only: - -- **Opening move** — the first concrete thing `reframe-research` does for this kind of job. -- **Retrieval lean** — which `c-04-retrieval-strategy-router` strategy leads (others are still available). -- **Decide default** — where this job usually lands at `decide` (still a real decision, not automatic). - -| Job | Opening move (in `reframe-research`) | Retrieval lean (`c-04-retrieval-strategy-router`) | `decide` default | -| ---------- | ----------------------------------------------- | ---------------------------------- | --------------------------- | -| `bug` | reproduce the failure; prove the root cause | Relationship (cgc) + Intent | -> build | -| `feature` | clarify intent, scope, and explicit non-goals | design doctrine + Intent | -> build | -| `triage` | assess severity, blast radius, and ownership | breadth scan (Semantics first) | may exit (route or spawn) | -| `research` | state the question precisely | Semantics (grepai) + onboarding | research-only exit | - -## bug - -Lead with a reproduction and a proven root cause before proposing a fix — an unproven fix is a guess. -Lean on Relationship (callers/callees/impact via cgc) to bound the change, and Intent to confirm the -invariant the bug violates. Defaults to a build; the fix lands through `decide -> build -> close`. - -## feature - -Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the -design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the -contracts the feature must respect. Defaults to a build; size decides chat vs durable `w-02-light-task-workflow` task at -`decide`. - -## triage - -Lead by assessing severity, blast radius, and ownership — enough to route, not to fix. A breadth scan -(Semantics first) maps the surface fast. Triage frequently **exits research-only**: its product is a -recommendation, a routed owner, or a spawned build/bug job — not a code change. Only escalate to a -build when triage itself is the cheapest place to fix it. - -## research - -Lead by stating the question precisely. Semantics (grepai over onboarding) plus committed-state -onboarding usually answers it; reach for source only as bounded Intent confirmation. Research -**exits research-only** by design: it produces an answer, and may recommend a follow-up build job, but -performs none itself. diff --git a/.openclaw/workspace/skills/w-02-light-task-workflow/SKILL.md b/.openclaw/workspace/skills/w-02-light-task-workflow/SKILL.md index 248e6f3c..b34f3017 100644 --- a/.openclaw/workspace/skills/w-02-light-task-workflow/SKILL.md +++ b/.openclaw/workspace/skills/w-02-light-task-workflow/SKILL.md @@ -40,7 +40,7 @@ Light-task artifacts use minute-precision timestamps in `YYYY-MM-DDTHH:MM` forma The task document is **JSON-primary**: an `ar-task-document/v1` JSON file is the source of truth, and the `task.md` (or `.md` for a sub-task) is a deterministic **render** of it. Author and update it with the `task_doc` MCP tool — `create`, `set_status`, `set_step`, `append_decision`, `set_field` — which writes the JSON and re-renders the markdown on every write. Do not hand-edit a tool-managed `task.md`; edit through the tool and let it re-render. `template.md` and `master-template.md` document the **render spec** (the shape the renderer produces), not a separate hand-authored format. When a planning slice defers its code examples to the plan gate, record that with `codeExamplesNote` (a `set_field` value, e.g. "Drafted at the plan gate.") so the rendered "Proposed Code Examples" section reads as *deferred* rather than as if none are needed. A leaf doc may also carry a descriptive `statusNote` (a suffix beside the strict status enum), `headerNotes` (extra `**Key:** value` header lines such as Verified/Source), and freeform `sections` appended after References — the escape hatch for bespoke prose (e.g. a Status history) while the standard template sections stay the backbone. Pass `dry_run=true` to any op to **preview** — it builds + validates and returns the rendered markdown, a unified `diff` vs the on-disk `.md`, and a `wouldLose` flag, **without writing**; use it before adopting a hand-authored `.md` into JSON-primary (author the JSON → dry-run → confirm `wouldLose` is false → then write). -Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for a chat build (a thin doc: title plus a few steps, so even a no-`task.md` session is legible) and a *full* one for a durable task; the difference is content completeness, not a separate format. +Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for the smallest single-session build (a THIN doc: title plus a few steps — chat is never a build route, so even micro-work gets this thin doc and stays legible on the dashboard) and a *full* one for a durable task; the difference is content completeness, not a separate format. Scope and transition: the tool manages **`light` and `subTask`** documents, and the format also covers a series **master** (`kind:"master"`: a structured `subTasks` index + ordered `sections` that preserve a master's bespoke prose, so a re-render is lossless). Masters and existing markdown task files stay hand-authored markdown until the runtime ships `task_doc` and they are intentionally migrated — new tasks adopt the JSON-primary format going forward. diff --git a/.openclaw/workspace/skills/w-02-light-task-workflow/master-template.md b/.openclaw/workspace/skills/w-02-light-task-workflow/master-template.md index 7cb4e85a..42738c16 100644 --- a/.openclaw/workspace/skills/w-02-light-task-workflow/master-template.md +++ b/.openclaw/workspace/skills/w-02-light-task-workflow/master-template.md @@ -7,7 +7,7 @@ built to grow as the work unfolds. ## When to escalate to a series -The `l-01-session-job-lifecycle` skill's `decide` build-mode step escalates a single task to a series once its size is apparent — the +The `l-01-agent-lifecycles` orchestrator lifecycle's `decide` step escalates a single task to a series once its size is apparent — the implementation plan no longer fits on a single page, or the work splits into distinct slices that each deserve their own checklist and commit. You can also start single and escalate later: drop in the master `task.md` and move the existing plan into the first `NN_.md`. diff --git a/.pi/extensions/agents-remember-start.ts b/.pi/extensions/agents-remember-start.ts index cd664d44..3cc745dc 100644 --- a/.pi/extensions/agents-remember-start.ts +++ b/.pi/extensions/agents-remember-start.ts @@ -23,23 +23,19 @@ export default function (pi) { } const directive = [ - "MANDATORY FIRST ACTION for this workspace", + "**Agents Remember — session start.**", "", - "You are not allowed to read, write, or execute code on any repository", - "until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure.", + "If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an", + "orchestrating agent: **ignore this notice entirely — your brief is your session", + "start.**", "", - `Read and follow \`${WORKSPACE_ROOT}/ar-coordination/AGENTS.md\` before working in any sibling project.`, - "Treat those rules as workspace instructions.", - "", - "Until the build/job decision is made, read managed-repo source with the", - "`read_ar_files` MCP tool — not the harness's native read tool. One call returns", - "each file paired with its onboarding plus the repository and governing route", - "overviews. Native read is reserved as the edit precondition once building begins.", - "", - "During the `l-01` deep research step, keep a tally of the retrieval strategies", - "used from `c-04-retrieval-strategy-router` (Semantics, Relationship, Intent), and", - "keep a running count of your `read_ar_files` calls. Include the onboarding files", - "inspected and every CGC, GrepAI, and `read_ar_files` call made as evidence." + "Otherwise you are the developer-facing session, i.e. the **orchestrator**: read", + `\`${WORKSPACE_ROOT}/ar-coordination/AGENTS.md\` and treat those rules as workspace`, + "instructions, then run your lifecycle at", + "`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before", + "relying on memory, `read_ar_files` (paired source+onboarding) until the build", + "decision, retrieval-strategy tally as evidence, notify-and-stop at every", + "developer hand-off." ].join("\n"); return { diff --git a/.pi/skills/c-01-findings-capture/SKILL.md b/.pi/skills/c-01-findings-capture/SKILL.md index e145d7ee..d413e8fe 100644 --- a/.pi/skills/c-01-findings-capture/SKILL.md +++ b/.pi/skills/c-01-findings-capture/SKILL.md @@ -13,7 +13,7 @@ Companion file: ## Operating Modes -1. Inside a task workflow (an `l-01-session-job-lifecycle` build job or a `w-02-light-task-workflow` task, including a master + light sub-task series). +1. Inside a task workflow (an `l-01-agent-lifecycles` orchestrator build phase or a `w-02-light-task-workflow` task, including a master + light sub-task series). 2. Standalone during direct clarification. ## Durable Destinations diff --git a/.pi/skills/c-03-repo-bootstrap/SKILL.md b/.pi/skills/c-03-repo-bootstrap/SKILL.md index 40148918..44f14f78 100644 --- a/.pi/skills/c-03-repo-bootstrap/SKILL.md +++ b/.pi/skills/c-03-repo-bootstrap/SKILL.md @@ -1240,7 +1240,7 @@ The orchestrator remains thin throughout. | `c-05-create-or-update-onboarding-files` | Owns final file-level onboarding semantics and routes structural slice maintenance back to the `c-03-repo-bootstrap` skill. The `c-03-repo-bootstrap` skill creates cards/waves and delegates file output rules to the `c-05-create-or-update-onboarding-files` skill. | | `c-04-retrieval-strategy-router` | Consumes bootstrapped overviews and file maps as the Intent substrate and can route to semantic/relationship providers first. | | `c-02-memory-quality-control` | Becomes relevant after bootstrap; touched files can be promoted from deferred to covered. | -| `l-01-session-job-lifecycle` | May trigger targeted bootstrap when an active job enters an uncovered area. | +| `l-01-agent-lifecycles` | May trigger targeted bootstrap when an active job enters an uncovered area. | | `confluence-search` / documentation search skills | Feed the docs evidence pass through approved sources from the input ledger. | --- diff --git a/.pi/skills/c-04-retrieval-strategy-router/SKILL.md b/.pi/skills/c-04-retrieval-strategy-router/SKILL.md index 01434c77..e226f8c0 100644 --- a/.pi/skills/c-04-retrieval-strategy-router/SKILL.md +++ b/.pi/skills/c-04-retrieval-strategy-router/SKILL.md @@ -160,7 +160,7 @@ names an unresolved source question. ### Rules: -- During the research phase (the lifecycle up to the build/job decision), read managed-repo +- During the research phase (the lifecycle up to the build decision), read managed-repo source with `read_ar_files`, not the native read tool — one call returns each file paired with its onboarding plus the repository and governing route overviews (the recipe above, batched and observable). diff --git a/.pi/skills/c-09-git-worktree-manager/SKILL.md b/.pi/skills/c-09-git-worktree-manager/SKILL.md index e19c7902..692dec19 100644 --- a/.pi/skills/c-09-git-worktree-manager/SKILL.md +++ b/.pi/skills/c-09-git-worktree-manager/SKILL.md @@ -7,7 +7,7 @@ description: "Create, attach to, report on, integrate, finalize, and clean up Ag Use this skill when a task should run through an explicit code/memory worktree wrapper. -The `c-09-git-worktree-manager` skill wraps the existing chat-build, light-task, or external workflow. It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. +The `c-09-git-worktree-manager` skill wraps the existing light-task or external workflow (a build that fits one session still rides a THIN `w-02-light-task-workflow` doc — chat is never a build route, per the `l-01-agent-lifecycles` invariant). It owns Git worktree state, series contracts, leaf enclosures, external-memory compatibility checks, integration, lifecycle finalization, and cleanup. It does not replace the workflow that performs the actual implementation. For closeout, use the `c-12-closeout` skill. The `c-09-git-worktree-manager` skill only supplies the worktree-specific contract path and integration/finalization follow-up rules. @@ -67,7 +67,7 @@ The intended order is: 1. run the `c-08-ar-coordination-context-resolver` skill for the target repository 2. run the `c-02-memory-quality-control` skill's task-start drift check and follow the existing AGENTS Gate 3/4 choice point 3. when onboarding is refreshed, commit the memory content and ledger before starting any worktree -4. decide whether the work is a chat build, a `w-02-light-task-workflow` light task (or master + light sub-task series), or external workflow +4. decide whether the work is a `w-02-light-task-workflow` light task — possibly a THIN one for single-session work; chat never builds — a master + light sub-task series, or external workflow 5. read the repository's `system/git-workflow.md` and identify the parent branch edge. For a standalone task, the leaf worktree branches from the approved source branch. For a master series, the master owns a root `series-contract.md` @@ -198,7 +198,9 @@ moved since task start. ## Integration -Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. +Integration is explicitly human-gated and runs only after closeout completed. It lands the closed task branches back onto the recorded source branches and records the landed commits separately from the closeout commits. Orchestrated-run carve-out (ruled 2026-07-06): dependency-ordered leaf→master and master→super integrations ride the series' standing approval (the developer's portfolio-gate approval recorded in the planner master) — the developer hand-off concentrates at the super PR/carry-over gate per the `l-01-agent-lifecycles` loop/orchestrator doctrine; a raised durable `integration-approval` gate still awaits the developer. + +On an orchestrated master's exit (master → super integration) the integrate step additionally enforces the delegated `master-handover-approval` seam: an undecided or policy-invalid handover gate addressed to the master (by `enclosure` = master task name) returns `handover-gate-blocked` instead of landing — decide the gate per the `l-01-agent-lifecycles` seam doctrine, then rerun. When no gate addresses the integrating master but open `master-handover-approval` gates exist elsewhere, integrate still proceeds and its result carries a `handover_gate_warning` naming them — treat it as a spelling check on the raised gate's `enclosure`. Run `worktree_integrate(..., dry_run=true)` first, then **hand off**: call `lifecycle_turn_end_notification(summary={…the integration plan…})` as the **last tool call**, then diff --git a/.pi/skills/c-12-closeout/SKILL.md b/.pi/skills/c-12-closeout/SKILL.md index f83071d9..2c7fe3ff 100644 --- a/.pi/skills/c-12-closeout/SKILL.md +++ b/.pi/skills/c-12-closeout/SKILL.md @@ -40,7 +40,7 @@ records the developer's explicit commit approval. Agents must not treat implementation approval, a previous "looks good", or their own judgment as commit approval. -The relay follows the `l-01-session-job-lifecycle` skill hand-off protocol: run the +The relay follows the `l-01-agent-lifecycles` orchestrator hand-off protocol: run the preview/dry-run first, then call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the **last tool call**, then deliver the preview facts and proposed messages as plain diff --git a/.pi/skills/c-13-install-and-onboard/SKILL.md b/.pi/skills/c-13-install-and-onboard/SKILL.md index 6515ae46..d583fd13 100644 --- a/.pi/skills/c-13-install-and-onboard/SKILL.md +++ b/.pi/skills/c-13-install-and-onboard/SKILL.md @@ -52,10 +52,12 @@ Run this sequence in order: 0. Preflight: verify the copied package and MCP setup are usable enough to continue. 1. Runtime scaffold: run or verify `runtime_install()`. -2. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. -3. Bootstrap: when a new memory repo was scaffolded, hand off to +2. Agentic settings: walk the developer through the orchestration defaults in + the seeded global settings file. +3. Memory repo: ask scaffold-new vs use-existing, unless memory already exists. +4. Bootstrap: when a new memory repo was scaffolded, hand off to `c-03-repo-bootstrap`. -4. Providers: when providers are enabled, start/refresh indexing and verify +5. Providers: when providers are enabled, start/refresh indexing and verify readiness. This skill orchestrates and delegates. It does not reimplement @@ -79,7 +81,9 @@ Check, in order: 3. **Settings sane.** Confirm `server_info` reports the expected `coordinationRoot`, `workspaceRoot`, allowed repositories, and providers. Surface the resolved absolute paths because wrong paths are the common cause - of resolver failures. + of resolver failures. Also report whether the global agentic settings file + (`/system/settings.json`) exists yet; Stage 1 seeds it + when missing and Stage 2 configures it. 4. **Runtime state.** Check whether the coordinator scaffold already exists under `coordinationRoot` (`AGENTS.md`, `skills/`, `tasks/`, `memory-repos/`, `system/` as applicable). If it is missing or stale, Stage 1 will run @@ -118,7 +122,61 @@ Do not run `skills_install()` as part of first-run setup. The harness starter package already carries the skills. `skills_install()` remains available for manual maintenance or non-package setups, but it is not the default path. -## Stage 2 - Memory Repo: Ask Scaffold Vs Existing +## Stage 2 - Agentic Settings: Interview The Developer + +`runtime_install()` seeds the GLOBAL agentic settings file at +`/system/settings.json` copy-if-missing, with every knob at +its documented default: all-human gate delegation, the standard three-party-loop +defaults, no concurrency caps, no spawn harness preference. This stage turns +those defaults into the developer's actual posture so the intended workflows +run on ANY harness. The schema reference is `docs/reference/settings-json.md` +(Agentic Settings); unknown `orchestration.*` keys fail loud, so write only +documented keys. + +Walk the developer through the four knob families and edit the global file with +their answers (leave a family at its seeded default when they have no +preference): + +1. **Gate delegation posture** (`orchestration.gateDelegation`; GLOBAL file only - the + loader refuses it repo-locally and the boot snapshot reads the coordinator file) - keep every + gate human (`all-human`, the default), or delegate leaf gates with the + `manager-decides-leaf-gates` policy, optional per-kind `kinds` overrides, + and `requireReviewerVerdictAtSeams`. Say explicitly that this one key is + boot-snapshot: a change needs an MCP/harness restart. +2. **Loop defaults** (`orchestration.loops`) - the review-round cap + (`defaults.maxRounds`), reviewer reuse (`defaults.reviewerReuse`), + complexity thresholds (`defaults.complexity`), and per-level loop postures + (`perLevel`). Read per-use; edits apply on the next use, no restart. +3. **Concurrency caps** (`orchestration.concurrency`) - `maxParallelMasters`, + `maxParallelLeaves`, `maxSubAgents`. Default: uncapped. +4. **Harness preference + role knobs** (`orchestration.spawn.harness`, + per-role `orchestration.roles.`, per-level + `orchestration.rolesPerLevel..`) - which installed harness + `spawn_agent_session` uses when the spawning seat passes none, per-role + harness/model/effort overrides, and per-LEVEL overrides + (leaf|master|portfolio) for tiered economics (e.g. a cheap leaf reviewer, + a smarter master-seam reviewer). Harness values must be known ids: the + builtin registry (`claude`, `codex`, `pi`) or an `orchestration.harnesses` + entry the developer defines (new TUIs, or a pre-customized launch argv for + a builtin). `effort` is validated per-harness at dispatch (claude: + `low|medium|high|xhigh|max` on the `--effort` flag plus the session-level + `ultracode`); mention the FREE-FORM escape hatch for anything outside the + vocabularies - `launchArgs` (verbatim argv), `sessionCommands` (pasted + before the brief), `promptKeywords` (prepended to the brief) - never + validated, recorded in spawn provenance. Default: detection-gated (the + first detected harness). The full spawn-surface manual is + `docs/reference/harnesses.md`. + +If the developer wants to skip the interview, confirm the seeded defaults +apply and continue; tell them the file can be edited any time (picked up +per-use, except the gateDelegation restart note above). + +Per-repo overrides: a code repo may carry its own `/system/settings.json` +with the same `orchestration.*` shape; repo-local leaf values override the +global file (arrays replace). Offer this only when the developer asks for +repo-specific behavior; do not create the file unprompted. + +## Stage 3 - Memory Repo: Ask Scaffold Vs Existing Do not assume the developer wants a fresh memory repo. Ask which case applies, unless a memory repo is already present and resolvable: @@ -126,10 +184,10 @@ unless a memory repo is already present and resolvable: 1. **Scaffold a new memory repo** - they have no existing memory for this code repo. Run `c-00-initialize-memory-repo` (internal by default; external only if the developer asks or the configured topology requires it). Continue to Stage - 3. + 4. 2. **Use an existing memory repo** - they already have one. Clone or checkout it to the resolved memory location, then adopt it as the ledgered baseline with - `c-10-adopt-memory-baseline`. Skip Stage 3 because its onboarding already + `c-10-adopt-memory-baseline`. Skip Stage 4 because its onboarding already exists. Internal-memory note: pre-existing internal memory lives inside the code repo @@ -137,9 +195,9 @@ Internal-memory note: pre-existing internal memory lives inside the code repo `c-08-ar-coordination-context-resolver` and skip the question when the memory layer is already there. -## Stage 3 - Bootstrap +## Stage 4 - Bootstrap -Run this stage only when Stage 2 scaffolded a new memory repo. +Run this stage only when Stage 3 scaffolded a new memory repo. Hand off to `c-03-repo-bootstrap` to generate initial onboarding. A thin `overview.md` is enough to start; deeper route-local overviews and file-level @@ -147,7 +205,7 @@ onboarding should grow as work touches new areas. Skip this stage when an existing memory repo was adopted. -## Stage 4 - Configure Providers To Index +## Stage 5 - Configure Providers To Index If providers are enabled, make them index the configured code and memory: @@ -177,10 +235,12 @@ Summarize: step the developer must perform; 2. runtime scaffold: `runtime_install()` run or already current, with the resolved coordination root; -3. memory repo: scaffolded, existing-adopted, or already present, with the +3. agentic settings: interviewed and written, or left at the seeded defaults, + with the global file path; +4. memory repo: scaffolded, existing-adopted, or already present, with the resolved memory root; -4. bootstrap: run via `c-03-repo-bootstrap` or skipped; -5. providers: indexing status and any deferred/degraded state. +5. bootstrap: run via `c-03-repo-bootstrap` or skipped; +6. providers: indexing status and any deferred/degraded state. End by telling the developer whether the project is ready for normal work. Do not tell them to restart for hooks installed by this skill, because this skill no diff --git a/.pi/skills/l-01-agent-lifecycles/SKILL.md b/.pi/skills/l-01-agent-lifecycles/SKILL.md new file mode 100644 index 00000000..1d390618 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/SKILL.md @@ -0,0 +1,259 @@ +--- +name: l-01-agent-lifecycles +description: "The agent lifecycles: one lifecycle per agent type, under one roof. Routes every session by exactly three conditions (spawn-role env -> role brief -> otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator, designer, strategist, manager, worker, adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. A developer-facing session IS the orchestrator; solo work is the degenerate portfolio. Supersedes and replaces both l-01-session-job-lifecycle and l-02-agent-orchestration." +--- + +# l-01-agent-lifecycles — The Agent Lifecycles + +Lifecycle and job are **one entity**: each agent type runs its own, self-contained lifecycle. This +skill is the single roof over all of them — a thin router, the minimal frame every session shares, +and the role lifecycles as the payload files. No role is defined by reference to another role's +lifecycle, and no role reads another role's file. + +## Which Lifecycle Am I? (the router — exactly three conditions, in order) + +1. **`AR_SPAWN_ROLE` is set** (spawn env, injected by `spawn_agent_session`) → run + `roles/.md`. Nothing else in this file's "developer session" material applies to you. + (`designer` here means the same design hat in a separate chair — see `roles/designer.md`.) +2. **Else: the first user message is a role brief** — a `templates/*-brief.md`-shaped dispatch or + a first line of the form `ROLE BRIEF — ` from an orchestrating agent → run that role's + lifecycle. The brief is your session start; a workspace session-start notice is not addressed + to you. +3. **Else** (a developer opened this session) → you are the **orchestrator**: run + `roles/orchestrator.md`. Solo work is the degenerate portfolio — the same three jobs with hats + collapsed (the orchestrator wears the manager hat in flat runs and builds hands-on at session + scale); the task doc still comes first. + +There is no fourth entry, and the edge cases are decided: an **unresolvable `AR_SPAWN_ROLE` +value** (no matching `roles/.md`) falls through to condition 2 (the brief); a role-env +session **whose brief never arrives** announces itself on the inbox and waits — it never +improvises a task; `AR_SPAWN_ROLE=orchestrator` is valid only as a takeover chair (the Profile +check (takeover) in `roles/orchestrator.md`, The Event Loop) — the developer still talks to **one** orchestrator. Orchestrated +fan-out (spawning managers/workers at scale) begins only on an explicit developer request (e.g. +*"orchestrate these masters"*) — no agent promotes itself into a spawning seat. + +One exception to the no-cross-reading rule above: **a seat that WEARS a hat runs that hat's file +as its own** — the orchestrator always for `roles/designer.md`, and in flat runs for +`roles/manager.md` (the hat-collapse rule). + +## The Role Registry + +| Role | Seat | Lifecycle file | +| --- | --- | --- | +| **orchestrator** | the developer-facing session; first coordination leaf of an orchestrated series | `roles/orchestrator.md` | +| **designer** | a HAT the orchestrator pulls inline (front of the pipeline or mid-flight; separate chair optional) | `roles/designer.md` | +| **strategist** | the sprint planner, SPAWN-FIRST; a strategist run is a **mandatory precondition for any orchestrated run** — its deliverable is the orchestration task (sprint plan + scope); spawn value `strategist` | `roles/strategist.md` | +| **manager** | one coordination leaf per master; drives that master's leaf loop | `roles/manager.md` | +| **worker** | one leaf worktree, short-lived, fresh session | `roles/worker.md` | +| **adversarial reviewer** | short-lived, spawned at the two seams (master-exit, super-exit) and as any three-party loop's reviewer seat (criteria catalogs bound per review type); spawn value `reviewer` | `roles/reviewer.md` | + +The **lenses** (bug · feature · triage · research — `lenses.md`) are how the scoping seats +(orchestrator, designer) read a piece of work; a dispatched role never picks a lens — its brief +already carries the flavor. + +## The Minimal Frame (the only machinery every session shares) + +Every session in a managed repo may be a **lifecycle**: six signals — `lifecycle_start` · +`lifecycle_phase` · `lifecycle_turn_end_notification` · `worktree_attach` · `switch_lifecycle` · +`lifecycle_end` (plus the automatic `worktree_start` promotion) — record where it +is and what it waits on, so work is observable and resumable across chat deaths. The model **never +handles a lifecycle id** — identity is server-side, anchored in the worktree contract. + +| When | Signal | Effect | +| --- | --- | --- | +| Trust checkpoint passes (managed repo) | `lifecycle_start` | begin a **fleeting** lifecycle (guarded: one per session; no id) | +| Entering a phase | `lifecycle_phase` | move the phase axis (`request` / `trust-checkpoint` / `reframe-research` / `decide` / `build` / `close`) | +| A developer hand-off | `lifecycle_turn_end_notification(summary=…)` | set `awaiting-developer`, surface the attention item, return immediately; the **next turn's first AR call auto-resumes** — never resume by hand | +| `worktree_start` | *(automatic promotion)* | the fleeting lifecycle becomes **persistent**, anchored in the contract | +| Resuming an existing task | `worktree_attach` | re-adopts the contract's lifecycle (contract-resolved) | +| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | the save gate — never dropped silently | +| Close | `lifecycle_end` (`completed`\|`abandoned`) | the terminal record | + +Rules: a tool call outside any lifecycle is **dropped, never misattributed**; `paused` is +system-owned. **A spawned role that never touches mutating AR tools simply never instantiates a +lifecycle — that is correct, not a violation.** A spawned role runs its **own** lifecycle when it +runs one; it never adopts its spawner's. The session↔leaf association is the catalog binding made +at spawn (the **qualified** leaf key `//`), not lifecycle adoption. + +## Shared Invariants (every role can count on these) + +- **Continuity lives in the `task_doc` + durable artifacts, never in transcripts** — which is why + short-lived workers and reviewers are safe, and why every seat writes its artifact of record. +- **Escalation ladder: worker → manager → orchestrator → developer.** No rung is skipped, ever. + Each role file states only its own rung. +- **Observability:** coordination seats are `task_doc` leaves with attached chats; the developer + can walk into any seat at any level. +- **Decision-needing questions land in the task doc's `openQuestions`** — the rendered decision + surface; `notes/` carries the analysis behind them. + +## The Three-Party Loop (one home — this section owns the loop doctrine) + +**OWNER → BUILDER → REVIEWER → owner, at every level that owns work.** The owner never +self-approves; the builder never lands; the reviewer never decides — verdicts are evidence. The +owner checks the verdict and either redispatches a builder or escalates. Role files reference this +section; they do not restate it. + +| Level | Owner (holds the deliverable, rules, lands) | Builder | Reviewer | +| --- | --- | --- | --- | +| Leaf | the leaf's owning seat (manager; orchestrator in tight/flat mode) | spawned worker (no-commit contract) | spawned reviewer, criteria catalog + liberty | +| Master | the manager | the leaf workers | the master-exit seam reviewer (verdict rides `master-handover-approval`) | +| Portfolio | the orchestrator | the STRATEGIST (spawn-first) | reviewer with the plan-review catalog | + +**Complexity-scored tiers (per leaf, at dispatch).** The owning seat scores three axes — blast +radius (doctrine/enforcement/public surface vs leaf-local) · novelty (new subsystem vs +pattern-following) · size (files × steps) — into three tiers: **direct** (no loop +machinery — the level's ordinary build channel implements: hands-on at session scale, the leaf's +worker under a manager; self-check + checks ladder only), **builder-verified** (builder +implements; owner verifies report-vs-artifact; no reviewer), **full loop** (builder + independent +reviewer rounds). The +strategist's blast-radius register is the scoring input when an orchestration task exists. A +leaf's loop mark (tier + scope: manager | orchestrator — the owning level runs the loop with ITS +agent set) is recorded on the leaf doc with a decision-log entry. **A master whose leaves all +score `direct` is a workflow-free manager** — no loop machinery; the knobs make every loop +optional per level, never mandatory ceremony. + +**Rounds and the HARD cap.** A round = implement → review. **Hard cap: 3 rounds per loop — and +ONLY full end-to-end rounds count against it.** Residuals of a passing round are landed and +**delta-verified by the SAME reviewer via a follow-up message** (it retains everything it already +verified, at a fraction of a fresh round's cost); **fix rounds resume the SAME builder**. A fresh +reviewer is spawned only for a full round or when new scope opens. Delta-verifies close rounds; +they do not open them. + +**The convergence rule (the real control; the cap is the backstop).** Every round must SHRINK the +open finding set. A round that does not shrink it escalates immediately, regardless of the count; +a monotonically converging loop may never hit the cap at all. At the cap, or on non-convergence, +the owner does not spin another round — it **escalates one seat up the ladder (worker → manager → +orchestrator → developer) with the full round history attached**; the escalation packet IS the +upper seat's visibility. + +**Quo-vadis (the written developer-escalation criterion).** A question is developer-worthy when it +is a **high-blast-radius truth** — answered wrong it means big rewrites later (architecture +direction, security posture, doctrine contradictions, irreversible data/branch operations, where +agent settings live). Quo-vadis questions escalate IMMEDIATELY, regardless of round count. +Presentation-grade choices (2px vs 3px) never do — the owner rules and logs. + +**Criteria catalogs (the reviewer as test bench).** Criteria are never made up on the spot: every +review runs its type's standing catalog from `criteria/` (code-seam · doctrine · +onboarding-memory · report-verification · plan-review) plus an exploratory mandate, under the +promotion ratchet (each catalog carries it). `roles/reviewer.md` binds them. + +**Per-level agent sets.** Each level runs its loop with its own harness/model/effort set — the +orchestrator-level set (the strongest models) and the manager-level set (cheaper, possibly +workflow-free) are configured per level in the `orchestration.loops` settings block (schema in +`docs/reference/settings-json.md`; stored in the global agentic settings file with repo-local +override, parsed by the kernel agentic-settings loader — L13, landed). The strategist's mandatory +pre-run is doctrine, not a knob — it is unconditional. + +## Knob Block & Capability Doctrine (no per-harness files) + +Role files are **model-interpreted markdown, never an executor**. Each carries a portable **knob +block** (harness / model / effort / tools) — the defaults the terminal host injects at spawn. +Resolution: **role-file defaults < settings.json orchestration block.** There are deliberately +**no per-harness role files** (developer decision 2026-07-05): harness-specific ABILITIES — +sub-agent fan-out and the like — are covered inside the portable files as capability-conditional +doctrine any coding agent can apply, and harness PREFERENCE is deployment configuration +(settings), not doctrine. Hard-coding a vendor would fork the doctrine per harness. For spawning +seats, `spawn_agent_session` is itself the harness-independent fan-out: a harness with no +sub-agent facility still dispatches seats through the framework (a chat, no leaf attachment +required) — the DBMS principle: one behavior, any engine. + +## settings.json Orchestration Block + +Machine/user overrides layer over the role-file defaults, in the **global agentic settings file** +(`/system/settings.json`), with `/system/settings.json` as the +repo-local override layer (leaf-key deep merge, arrays replace, unknown `orchestration.*` keys +fail loud — schema in `docs/reference/settings-json.md`, Agentic Settings). Precedence: role-file +defaults < global settings < repo-local settings. + +```jsonc +{ + "orchestration": { + "roles": { // role → knob override; validated: harness/model/effort · free-form: launchArgs/promptKeywords/sessionCommands + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { // per-LEVEL agent sets (leaf|master|portfolio), deep-merged over roles + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" }, // spawn_agent_session default when the seat passes none + "gateDelegation": { + "policy": "manager-decides-leaf-gates", + "requireReviewerVerdictAtSeams": true + } + } +} +``` + +**As-built (L13 + L16):** the whole block is parsed by the kernel agentic-settings loader +(`kernel/agentic_settings.py`) — typed models for `roles` / `rolesPerLevel` / `concurrency` / +`spawn` / `harnesses` / `loops`, +read PER-USE (an edit applies on the next use, no restart). `orchestration.gateDelegation` is +parsed and **enforced** (`controlplane/gate_policy.py` — all-human default, opt-in delegation, +human-pinned kinds `integration-approval` / `push-approval` / `cleanup-approval`, owner never +self-approves); it is the ONE boot-snapshot key — read from the global file at MCP boot, a change +needs a restart (an authority-file value is a one-cycle legacy fallback with a boot warning). +`requireReviewerVerdictAtSeams` **binds delegated seam decisions** (`master-handover-approval`) to +attached reviewer-verdict evidence; the named policy `manager-decides-leaf-gates` routes leaf gates +to the manager and the master-exit handover to the **orchestrator** (human review concentrates at +the super gate). `spawn_agent_session` resolves its knobs (260703-L16) as explicit args > +repo-local level override > global level override > repo-local role default > global role default +> detection-gated default — the dispatcher declares its `level` (leaf|master|portfolio, default +leaf) and the resolved level rides spawn provenance — and **applies** them at the harness +boundary: model/effort ride as `AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` env AND map onto the launch argv +per-harness via the effective registry (claude `--model`/`--effort`; a mapping-less harness stays +env-only; a session-vocabulary effort like claude's `ultracode` is delivered as a post-launch +`/effort` paste). Unknown effort values REFUSE at dispatch naming the harness's vocabulary — the +CLI would warn-and-silently-degrade. The free-form escape hatch (`launchArgs` verbatim argv, +`promptKeywords` riding the brief paste, `sessionCommands` pasted before the brief) is never +validated, only recorded in spawn provenance; `orchestration.harnesses` teaches the framework new +TUIs or pre-customizes builtin launches (manual: `docs/reference/harnesses.md`). +`orchestration.loops` (the three-party-loop knobs: per-level loop sets, round cap, reviewer +reuse, complexity thresholds) lives in the same block — meaning in +`docs/reference/settings-json.md`; no knob touches the master-exit seam gate. + +## Companion Files + +- `lenses.md` — the four job lenses for the scoping seats. +- `roles/…` — the six self-contained role lifecycles (the registry above). +- `templates/…` — turn-report · worker-brief · manager-brief (`ROLE BRIEF — manager`; the + orchestrator compiles a manager's session start from it) · master-handover-packet · + conversation-handover-packet · verdict · impact-analysis · onboarding-coherency · + deep-research-report · orchestration-task (the strategist's sprint plan). Spawning seats compile + briefs FROM these; sub-agents fan out and fill them, so analysis survives compaction. +- `criteria/…` — the reviewer criteria catalogs (code-seam · doctrine · onboarding-memory · + report-verification · plan-review), the review test bench the three-party loop binds; maintained + through the promotion ratchet, never made up on the spot. + +## The Super Integration Branch (orientation only — the doctrine lives with its owner) + +``` +main + └── super-integration (orchestrator-owned, off main) + ├── master-A branch (off super) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, C-11) + ├── master-B branch (off the moved super — sees A) + └── … final: super → main PR + memory carry-over + push +``` + +The full topology — dependency-ordered dispatch, the integration-duty procedure, the two +conflict-resolution modes, leaf moves — lives in **`roles/orchestrator.md`** and only there. + +## Credits + +This skill absorbs and supersedes `l-01-session-job-lifecycle` and `l-02-agent-orchestration` +(converged 2026-07-05: lifecycle and job are one entity — one lifecycle per agent type). The +orchestration vocabulary adopts the parked `260619_agentic-control-plane` spec — jobs as +model-interpreted markdown (D6), the knob block (D7), role + lens in one file (D10), the +ambient-singleton rule (D11), per-harness variants (D12), the judge rung, short-lived workers with +structured handoff, dev-talks-to-one-orchestrator (D15) — which in turn credits **Archon** and the +**agent-control-plane** project (D14); that credit carries forward. + +## Relationship To Other Instructions + +This skill extends — never replaces — the coordinator `AGENTS.md`, the `w-02-light-task-workflow` +task format, and the memory layer (`c-…` skills). Each `roles/.md` is self-contained for its +seat; read exactly the one the router selects. diff --git a/.pi/skills/l-01-agent-lifecycles/criteria/code-seam.md b/.pi/skills/l-01-agent-lifecycles/criteria/code-seam.md new file mode 100644 index 00000000..053feb1b --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/criteria/code-seam.md @@ -0,0 +1,85 @@ +# Criteria Catalog — Code-Seam Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review wires code seams: consumers, enforcement points, gates, addresses, tool contracts. +Binds at the master-exit and super-exit seams and in any loop review whose change set touches code +(see the binding table in `../roles/reviewer.md`). Criteria are never made up on the spot: the +standing list below is the regression floor, run every time; the exploratory mandate and the +promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### CS-1 — Production-wiring walk + +**Trace the real call path, never a hand-aligned harness.** A claim that a consumer or an +enforcement point exists must be walked through the PRODUCTION call path — the controller, the +tool registration, the store fold — not through a test that hand-assembles the pieces into +alignment. A test can pass while the production consumer is inert. + +- Catching evidence: 260703-L8 review 3 (AR3-1) — the integrate consumer was proven **inert**: the + policy was omitted at the controller and the gate was looked up on the wrong lifecycle, while a + hand-aligned test passed (L8 decision log, cycle-6 entry). + +### CS-2 — Fail-open hunt + +**What happens when the address/config is absent or mistyped?** For every identity, address, key, +or config the seam matches on: feed it nothing, feed it a near-miss, and confirm the seam fails +CLOSED (refuses) rather than open (silently proceeds unmatched). + +- Catching evidence: 260703-L8 review 4 (AR4-1) — the seam's `enclosure` address had to be pinned + as an exact-string contract and the enclosure-less raise made a refusal (L8 decision log, + cycle-7 entry). + +### CS-3 — Validate-then-mutate + +**Every raise/write validates before it mutates.** A call that records state (a gate raise, a +store append, a contract write) must perform its refusal checks before any durable effect; a +mutation that precedes validation leaves half-states behind on refusal. + +- Catching evidence: 260703-L8 cycle 6 — the `wait=false` raise was reworked to be + validate-then-mutate and seam-kind-restricted (L8 decision log, cycle-6 entry). + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### CS-4 — Reused-primitive affordance parity *(candidate — 1 catch)* + +**When a screen reuses a shared content primitive, verify every branch of the ORIGINAL's +affordances (banners, status chips, truncation notices, error states) still fires on the reuse +path.** A dropped affordance is a silent regression the reuse's own tests won't catch — they +assert the new screen's happy paths, not the primitive's full surface. + +- Catching evidence (single engagement): 260703-L17 review (L17R-2) — the notes reader's + `DualPane` reuse drops the "first 2 MiB" truncation banner on the markdown path (the banner + lives in `CodeSide`, which markdown never reaches); text and binary keep it. + +### CS-5 — Cross-repo side-effect safety *(candidate — seeded from a clean exemplar, 0 catches)* + +**Any step that writes to a repository OTHER than the one it operates in gets the full +validate-then-mutate treatment plus partial-failure and dirty-target analysis.** Check the order +of validation vs the foreign write, the state left behind when the write lands but the caller +fails afterward, behavior against a dirty target repo, and an exact format round-trip with the +foreign artifact's consumer. + +- Seeding evidence: 260703-L18 finding 7 (`_reconcile_missing_mapping` writing the official + memory repo's ledger mid-`worktree_start`) PASSED all four lenses under this analysis — the + clean exemplar that defined the class. A catch in a later engagement promotes. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS change set the catalog does not name yet. Every novel finding-class that survives +refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.pi/skills/l-01-agent-lifecycles/criteria/doctrine.md b/.pi/skills/l-01-agent-lifecycles/criteria/doctrine.md new file mode 100644 index 00000000..9b9ccae1 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/criteria/doctrine.md @@ -0,0 +1,58 @@ +# Criteria Catalog — Doctrine Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run when the change +set under review is doctrine: skill files, role lifecycles, templates, instruction surfaces, docs +that agents obey. Binds whenever doctrine/skill files are in the change set (see the binding table +in `../roles/reviewer.md`). Criteria are never made up on the spot: the standing list below is the +regression floor, run every time; the exploratory mandate and the promotion ratchet keep the +catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### D-1 — Doctrine-vs-code anchoring + +**Every "X enforces Y" needs a code anchor.** A doctrine sentence claiming enforcement, refusal, +or automatic behavior must resolve to the code that does it (file + mechanism). Doctrine that +narrates enforcement which does not exist is a defect, not an aspiration. + +- Catching evidence: 260703-L8 review 1 (AR-5) — `requireReviewerVerdictAtSeams` was documented as + binding while the flag was **inert**; the finding forced the wiring (L8 decision log, AR-1 + entry: "closing AR-5's inert flag"). + +### D-2 — Cross-file contradiction sweep + +**Sweep sibling doctrine for statements the change set now contradicts.** A doctrine change is +reviewed against the whole doctrine surface (skills, role files, templates, docs, hooks, canvas +prose), not just the edited files — one file's new invariant is another file's stale sentence. + +- Catching evidence: 260703-L10 — the landed "chat is never a build route" invariant contradicted + surviving chat-build wording inside `c-09` / `w-02` (builder escalation 1, owner-sanctioned + sweep; L10 builder report). + +### D-3 — Stuck-state walk + +**Can an agent following the prose deadlock?** Walk the doctrine as the obeying agent: at every +wait, gate, and handover, ask who unblocks it and through which channel. Prose in which two seats +each wait on the other — or a seat waits on a channel nobody is told to serve — is a blocking +finding. + +- Catching evidence: 260703-L8 review 2 — the seam deadlock: the manager's blocking raise and the + orchestrator's decide path could not meet as written; the ruled `wait=false` + + packet-carried-gateId channel resolved it (L8 rounds 2/4b history). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS doctrine change the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.pi/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md b/.pi/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md new file mode 100644 index 00000000..e47783e3 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/criteria/onboarding-memory.md @@ -0,0 +1,67 @@ +# Criteria Catalog — Onboarding/Memory Review + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run over the +memory side of a change set: sidecars, route overviews, route indexes, update histories. Binds at +the master-exit and super-exit seams (the onboarding-vs-code lens) and in loop reviews whose change +set carries onboarding (see the binding table in `../roles/reviewer.md`). Criteria are never made +up on the spot: the standing list below is the regression floor, run every time; the exploratory +mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### OM-1 — Staleness diff vs as-landed code + +**Diff every body claim about current behavior against the as-landed code.** A sidecar or overview +body that describes the present tense is checked against what the branch actually ships — deleted +things still described, renamed things under old names, duplicated rows. + +- Catching evidence, two separate engagements: 260703-L8 cycle 6 (owner follow-up pass) — route + overview bodies still described **deleted canvas models** (the panels overview's build-job/frame + tail) and carried **duplicated table rows** (the tools and controlplane overviews' Layout + tables), durably recorded in those overviews' own 2026-07-05T19:25 Update History entries; + 260703-L10 — the flowModels sidecar body was still the pre-convergence 8-model census and its + references row still said "8 models" (the sidecar's 2026-07-06T12:05 history entry + L10R-3). + +### OM-2 — History-only-update detection + +**"Refreshed" must mean a genuine body edit.** An onboarding file whose only change is a new +Update History line has NOT been refreshed — the body still asserts the old truth. Check that +every claimed refresh touched body sentences, not just the history list. + +- Catching evidence: 260703-L8 cycle 6 — the builder reported route overviews as refreshed when + they were **history-only**; the closeout body gate caught it (L8 decision log, cycle-6 entry: + "report-vs-artifact verification belongs in the reviewer criteria catalog"). + +## Candidate Criteria (seeded exploratory — one catching engagement; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### OM-3 — Newest-first with the checker's own semantics *(candidate — 1 catch)* + +**Update History sorts newest-first under the CHECKER's datetime parse, not lexicographically.** +The quality checker compares naive timestamps as-is and folds tz-aware stamps to UTC; a merge or +mechanical insert that sorts by string can pass the eye and fail the gate (or worse, pass the gate +in the wrong order). Verify ordering with the checker's semantics. + +- Catching evidence (single engagement): 260703-L11 — four onboarding history collisions from the + parallel wave had to be re-sorted **with the checker's own datetime semantics** (naive compare + as-is, tz-aware folds to UTC); the quality gates caught the owner's wrong sort key (L11 decision + log). + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): attack +surfaces of THIS memory delta the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate is the working example, and it is THIS catalog's own OM-2 mechanized: the gate catches + history-only "refreshes" at commit time, where prose requests did not. diff --git a/.pi/skills/l-01-agent-lifecycles/criteria/plan-review.md b/.pi/skills/l-01-agent-lifecycles/criteria/plan-review.md new file mode 100644 index 00000000..ef4d2d90 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/criteria/plan-review.md @@ -0,0 +1,69 @@ +# Criteria Catalog — Plan Review (the strategist loop) + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) MUST run against an +**orchestration task** (`../templates/orchestration-task.md`) — the strategist's sprint plan — +before the developer's drawing board. This is the portfolio loop's review type: owner = +orchestrator, builder = strategist, reviewer = this catalog. The reviewer holds the same read-only +analysis tools the strategist used (`cgc_*`, `grepai_*`, `read_ar_files`), so the plan's mechanical +claims are re-derivable, not just readable. Criteria are never made up on the spot: the standing +list below is the regression floor, run every time; the exploratory mandate and the promotion +ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### PR-1 — Refute uncited edges + +**An uncited dependency edge is refutable by default.** Every edge in the dependency graph must +carry evidence — a cgc/grepai query, a file, a decision-log entry, a design-section citation, or +(for new surfaces) a declaration cross-reference naming both leaf declarations. An edge with no +evidence is challenged as a finding; so is evidence that does not actually support the edge's +direction or kind. + +### PR-2 — Missed-shared-surface hunt (class-completeness on intersections) + +**Re-intersect the surface lists independently.** Take the plan's per-leaf touch surfaces (both +existing and declared-new), recompute the pairwise intersections, and hunt pairs the edge list +omits — including CONFLICT-risk at a shared parent route where two leaves declare additions +(wiring points, shared registries). A plan that lists surfaces but misses one of their +intersections has a hole exactly where collisions happen. + +### PR-3 — Blast-radius re-derivation + +**Re-derive at least the HIGH-blast-radius entries with the cgc tools** (`cgc_dependencies` / +`cgc_callers` / `cgc_callees`, capped depth) — and spot-check a sample of the low/medium entries. +A register entry whose derivation cannot be reproduced, or whose classification drops the doctrine +propagation / migration / user-visible unions, is a finding; the register parameterizes every +downstream loop tier, so an understated radius under-reviews a leaf. + +### PR-4 — Order-respects-edges + +**Check the sprint order/waves against the edge list, mechanically.** No ORDER edge may run +backwards across the proposed sequence; every CONFLICT edge must be resolved by serialization or a +recorded leaf move (from→to + rationale); parallel waves may contain only INDEPENDENT pairs, and +the wave plan must acknowledge the landing-reconciliation cost. + +### PR-5 — Honesty of the findings section + +**Verify the plan's failure claims both ways.** Every "unplannable as scoped" finding must be +genuine (the leaf can name neither existing surfaces nor the parent anchoring of its additions — +a merely not-yet-existing surface is NOT unplannable); and thin leaf scopes the plan silently +guessed around instead of flagging are themselves findings. Quo-vadis contradictions must be +flagged at the top of the coherence findings, not buried. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS plan could be wrong that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests. Promotion is proposed in the verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example; PR-4 is this catalog's mechanization candidate (a topological check over + a structured edge list). diff --git a/.pi/skills/l-01-agent-lifecycles/criteria/report-verification.md b/.pi/skills/l-01-agent-lifecycles/criteria/report-verification.md new file mode 100644 index 00000000..fb3bdda8 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/criteria/report-verification.md @@ -0,0 +1,95 @@ +# Criteria Catalog — Report Verification + +The standing criteria an **adversarial reviewer** (`../roles/reviewer.md`) — and the loop OWNER +verifying a builder round — MUST run over every report, claim, and summary in the change set: +builder reports, owner claims, handover packets. **Standing from day one** in every review type: +report-vs-artifact caught real defects in three separate engagements before this catalog existed. +Criteria are never made up on the spot: the standing list below is the regression floor, run every +time; the exploratory mandate and the promotion ratchet keep the catalog alive. + +## Standing Criteria (MUST RUN — the regression floor) + +### RV-1 — Report-vs-artifact on EVERY claim + +**Open the artifact behind every claim.** A report sentence asserting "X was done / is green / +was refreshed" is verified against the artifact itself, not trusted — claim by claim, no sampling +of the load-bearing ones. + +- Catching evidence, three separate engagements (260703-L8): review 3 caught a **hand-aligned + test** behind a wiring claim; cycle 6's closeout gate caught **"refreshed" overviews that were + history-only**; review 4 caught the **OWNER's own canvas overclaim** (L8 decision log, cycle-7 + entry) — builder reports and owner claims fail the same way. + +### RV-2 — CLASS-completeness *(promoted to standing at 260703-L18 — 2 catches)* + +**Hunt the siblings of every found instance.** A finding or a fix names an instance of a CLASS +(a directive surface, a census count, a vocabulary token). Enumerate the class — every sibling +surface, not just the instances the report names — and check each one. + +- Catching evidence: (1) 260703-L10 round 1 — the reviewer's completeness sweep found **six of + ten first-action surfaces** still shipping the retired directive when the report claimed the + flip done (L10 decision log). (2) 260703-L18 review (L18R-3) — the fix for + advertised-but-unimplemented recovery choices named the `cli.py` `custom` residual but missed + the SIBLING `_load_memory_ledger` block still advertising an inert `reconciliation`; the + sibling hunt found it. + +### RV-4 — Decision-log completeness for scope-expanding disclosures *(promoted to standing at 260703-L18 — 2 catches)* + +**A scope-expanding owner supplement or load-bearing builder disclosure must be verifiable in +the task-doc decision log, not only the builder report.** Continuity lives in the task_doc + +durable artifacts, never in transcripts; a ruling or environment finding that exists only in a +report is one lost file away from unrecoverable. Cross-check every supplement and disclosure the +builder report carries against the decision log. + +- Catching evidence: (1) 260703-L17 review (L17R-1) — supplement 2 (the wait-loop-era remnant + sweep with per-hit verdicts and two named follow-ups) was recorded only in the builder report. + (2) 260703-L18 review (L18R-4) — the load-bearing editable-install/PYTHONPATH environment + finding + named follow-ups lived only in the builder report; the leaf's `decisions[]` was + empty. Both folded by the owner at closeout. + +## Candidate Criteria (seeded exploratory — one catching engagement each; promote at ≥2) + +Run under the exploratory mandate; a candidate is proposed for promotion into the standing list +when it catches in a second engagement (the ratchet below). + +### RV-3 — Partial-fix-creates-falsehoods *(candidate — 1 catch)* + +**Verify claims ABOUT the changed artifacts, not only the artifacts.** A partial fix can turn +previously-true sentences elsewhere false (docs describing the artifact, install guides quoting +it, counts referencing it). Sweep for statements about what changed and re-verify their truth +after the change. + +- Catching evidence (single engagement): 260703-L10 round 1 — the partial hook flip made **two + install-doc claims false** ("injects the same startup directive" no longer held); round 2 + restored byte-identity so the claims became true again (L10 decision log + builder report). + +### RV-5 — Worktree-shadowed regression pins *(candidate — 1 catch)* + +**A regression test must bite under the invocation the owner actually runs.** An editable +install pointing at another checkout can shadow the worktree's sources, making a mutation-tested +pin pass vacuously under the canonical invocation while failing only under a hand-set +`PYTHONPATH`. Verify sensitivity by mutating the target and running the CANONICAL invocation; +a pin that only bites under a nonstandard environment is not yet a pin. + +- Catching evidence (single engagement): 260703-L18 review (L18R-1) — the inbox + delivered/unconfirmed pin failed its mutation check only under `PYTHONPATH=src`; under the + canonical `pytest mcp/tests` the main-repo editable install shadowed the worktree and the + mutated code still passed. Remedy: the `sys.path` pin idiom the sibling suites carry. + +## Exploratory Mandate + +Beyond the standing list, the reviewer owes **novel lenses** (the brief sets N; default 2): ways +THIS report could mislead that the catalog does not name yet. Every novel finding-class that +survives refutation is proposed as a catalog amendment in the verdict. + +## Promotion Ratchet + +- A **candidate** criterion that catches a real defect in **≥2 separate engagements** is promoted + into the standing list above, with its catching evidence cited — escaped bugs become permanent + tests (RV-1 is itself the precedent: promoted on three catches). Promotion is proposed in the + verdict and lands on the loop owner's acceptance. +- A **standing** criterion that fires nothing for **N consecutive engagements** (default 5) + demotes to spot-check. +- A criterion that can be **mechanized graduates out of the catalog into a gate** — the closeout + body gate (which catches history-only "refreshes" at commit time, where prose requests did not) + is the working example. diff --git a/.pi/skills/l-01-agent-lifecycles/lenses.md b/.pi/skills/l-01-agent-lifecycles/lenses.md new file mode 100644 index 00000000..0f277b06 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/lenses.md @@ -0,0 +1,45 @@ +# Lenses — How the Scoping Seats Read a Job + +Read by the **scoping seats** (orchestrator, designer); a dispatched role never picks a lens — its +brief already carries the flavor. The job type is a **lens**, picked during `reframe-research` and +re-pickable at any time. It is not a gate and it never changes the orchestrator phase axis +(`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three +things only: + +- **Opening move** — the first concrete thing `reframe-research` does for this kind of job. +- **Retrieval lean** — which `c-04-retrieval-strategy-router` strategy leads (others are still available). +- **Decide default** — where this job usually lands at `decide` (still a real decision, not automatic). + +| Job | Opening move (in `reframe-research`) | Retrieval lean (`c-04-retrieval-strategy-router`) | `decide` default | +| ---------- | ----------------------------------------------- | ---------------------------------- | --------------------------- | +| `bug` | reproduce the failure; prove the root cause | Relationship (cgc) + Intent | -> build | +| `feature` | clarify intent, scope, and explicit non-goals | design doctrine + Intent | -> build | +| `triage` | assess severity, blast radius, and ownership | breadth scan (Semantics first) | may exit (route or spawn) | +| `research` | state the question precisely | Semantics (grepai) + onboarding | research-only exit | + +## bug + +Lead with a reproduction and a proven root cause before proposing a fix — an unproven fix is a guess. +Lean on Relationship (callers/callees/impact via cgc) to bound the change, and Intent to confirm the +invariant the bug violates. Defaults to a build; the fix lands through `decide -> build -> close`. + +## feature + +Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the +design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the +contracts the feature must respect. Defaults to a build; size decides the minimal `w-02-light-task-workflow` artifact vs a master + +sub-task series at `decide`. + +## triage + +Lead by assessing severity, blast radius, and ownership — enough to route, not to fix. A breadth scan +(Semantics first) maps the surface fast. Triage frequently **exits research-only**: its product is a +recommendation, a routed owner, or a spawned build/bug job — not a code change. Only escalate to a +build when triage itself is the cheapest place to fix it. + +## research + +Lead by stating the question precisely. Semantics (grepai over onboarding) plus committed-state +onboarding usually answers it; reach for source only as bounded Intent confirmation. Research +**exits research-only** by design: it produces an answer, and may recommend a follow-up build job, but +performs none itself. diff --git a/.pi/skills/l-01-agent-lifecycles/roles/designer.md b/.pi/skills/l-01-agent-lifecycles/roles/designer.md new file mode 100644 index 00000000..c67cec40 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/roles/designer.md @@ -0,0 +1,91 @@ +# Lifecycle — Designer (the hat) + +> The design lifecycle the **orchestrator pulls inline** whenever design is needed — front of the +> pipeline or mid-flight. **A hat, not a seat**: it cannot sit in a coordination leaf because the +> task is what it exists to create — no leaf, no worktree, no branch, no spawn required. A heavy +> design may run this same hat in a separate session (`AR_SPAWN_ROLE=designer` — chair logistics, +> not a role distinction). +> +> Drawn as the **DESIGNER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Hat Is + +Task design is **its own job** (developer decision 2026-07-04). Before orchestration one implicit +do-it-all role did design, features, and fixes; the roles now diversify, and design routes +**through the orchestrator, which wears this hat** — at the front of the pipeline AND mid-flight +(most leaves of a live series are designed mid-flight). It is the `tasks/AGENTS.md` collaboration +doctrine (meta-questioning, reframe-before-execution, evidence-first) given a distinct, optimized +shape as a job. Nothing here assumes a master exists yet — producing one is the point. + +The designer shares the orchestrator's **bird's-eye toolkit** — route indexes, onboarding, the +`grepai_search` MCP tool, the code-graph (`cgc_*`) MCP tools, blast-radius analysis — but is **scoped +to one master**. Collisions with *other* — especially **future** — masters can slip past a +single-master view. That residual risk is **owned downstream, not here**: at portfolio streamlining the +**orchestrator doubles as the designer's adversarial reviewer** (planned-vs-planned and +planned-vs-past). The designer's duty is to *declare* the limit, not to close it. + +## Lens + +- **Opening move:** meta-question the ask. Surface the request, the deeper objective, and the + highest-leverage framing before any structure exists — do not jump from the developer's first + phrasing to a plan. +- **Retrieval lean:** evidence-first, within the master's scope. Route indexes and onboarding for the + map; `grepai_search` for semantics; `cgc_*` for relationships/impact; bounded `read_ar_files` for + intent confirmation. Sub-agents fan out and write durable reports. +- **Decide default:** a `w-02-light-task-workflow`-shaped master + leaf task_doc, handed into the + portfolio — **not** a build. The designer designs; it does not implement. + +## Duties + +1. **Reframe with `tasks/AGENTS.md`.** Distinguish surface request · deeper objective · highest-leverage + framing · assumptions · boundaries · invariants · truth gaps. Material scope/intent/sequencing + changes are **played back and wait for confirmation**; a pure clarification may be presented and + continued. +2. **Evidence-first, master-scoped.** Make the evidence model visible before or alongside the plan + (external · repo-internal · cross-repo · executable). Gather it through the + `c-04-retrieval-strategy-router` skill, not ad-hoc reads. +3. **Blast-radius WITHIN the master.** Routes touched · invariants at risk · regressions — bounded to + this master's scope. Cross-master and future-master reasoning is explicitly out of the designer's + reach. +4. **Author the task_doc.** Master + leaves (requirements · steps · code examples per distinct change, + the `w-02-light-task-workflow` shape), leaves scoped around routes/areas, via the `task_doc` MCP + tool. Include a **code example for every distinct change** when code is in scope. + Decision-needing questions land in the task doc's `openQuestions` — the rendered decision + surface; `notes/` carries the analysis behind them. +5. **Declare the designer limit.** Record on the doc that this is a **master-scoped bird's-eye**: + cross-master and future-master collisions can slip and are owned downstream at streamlining. Never + hide the limit. +6. **Ask, never fill silently.** Assumptions and truth gaps only the developer can resolve are asked as + a short, high-leverage list — never filled silently. + +## Artifact Obligations + +- The **task_doc** (master + leaves) is the durable artifact of the designer job. +- A **designer-limits note** on the doc — the declared master-scoped blind spot, for the orchestrator's + later adversarial pass. +- Evidence reports from fan-out sub-agents (durable), so the framing survives into streamlining. + +## Comms Protocol + +- **Primary channel:** the developer, directly, in the designer's attached chat — this seat is a + co-thinking loop, so the developer is the standing interlocutor here (unlike the deeper seats, which + relay through the ladder). +- **Handover:** the finished design **joins the portfolio**. At streamlining the orchestrator + adversarially reviews it; hand the task_doc + the designer-limits note over via the inbox + (`operator_inbox_post`) and, for a hosted orchestrator, stdin push. +- **Escalation:** the hat's "escalation" is simply the handover into the portfolio job — the + orchestrator that wears it is already the last resolver before the developer. + +## Knobs + +| Knob | Default | Notes | +| ------- | ------------------ | --------------------------------------------------------------------- | +| harness | (the wearer's) | the hat runs inside the orchestrator session, or a spawned design chair | +| model | high-reasoning | reframe + blast-radius reasoning wants a strong model | +| effort | high | design leverage justifies the thinking budget | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | bird's-eye toolkit | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · inbox | + +Settings.json `orchestration.roles.designer` overrides these, and `orchestration.rolesPerLevel..designer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.pi/skills/l-01-agent-lifecycles/roles/manager.md b/.pi/skills/l-01-agent-lifecycles/roles/manager.md new file mode 100644 index 00000000..0b42124a --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/roles/manager.md @@ -0,0 +1,168 @@ +# Lifecycle — Manager + +> One master, one seat, self-contained. The manager lifecycle drives exactly one master series: +> spawn a fresh worker per leaf, review turn reports, decide the delegated leaf gates, close out and +> integrate each leaf, hand the completed master to the orchestrator through the master-exit seam. +> Your **brief is your session start**. +> +> Drawn as the **MANAGER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**One per master task.** Spawned by the orchestrator with the master's context packet. It owns its own +coordination leaf + chat (**no worktree**) and drives exactly one master series: spawns/respawns a fresh +worker per leaf, reviews turn-report artifacts, decides **delegated** leaf gates, integrates leaves into +the master integration branch via the `c-11-memory-carryover-from-branch` skill, and hands the completed +master to the orchestrator through the master-exit adversarial seam. + +The manager owns the leaf lifecycle machinery **end-to-end**: `worktree_start` → (the worker +builds) → closeout preview/apply (deciding the delegated gates per the gate policy) → +`worktree_integrate` → finalize — task-doc statuses via the finalizer, **steps checked by this +seat by hand** (the tool does not reconcile checkboxes). The worker's terminal +state is checks-green + turn report; everything after that is this seat's. + +**Flat-run note:** in a flat series (no managers spawned) the **orchestrator wears this hat** — +same duties, same artifacts, one chair. + +A manager has **no bird's-eye view** — it sees one master, not the portfolio. That boundary shapes +everything below. + +## Lens + +- **Opening move:** read the master `task_doc` + its leaf docs; order the leaves (parallel where safe — + the C-11 reconcile absorbs a moved base). +- **Retrieval lean:** intent-confirmation on the master's own routes (paired `read_ar_files`); the + breadth/blast-radius reasoning belongs to the orchestrator, not here. +- **Decide default:** dispatch the next ready leaf; the master exits through the master-exit seam. + +## The Default-Behavior Rule (read this before anything else) + +The **default agent behavior stands**: **fulfill the task, fill small blanks.** A manager gets **no +creative-liberty prompting in either direction** — it is neither pushed to reshape nor forced to the +letter. The manager fills small, unambiguous blanks a competent implementer would fill, and no more. + +> **The spirit test does NOT apply to this seat.** It is orchestrator-only. A manager's changes can +> collide with what it cannot see, so a **plan delta beyond blank-filling escalates to the +> orchestrator** — the manager does not reshape plans. This is not a licence to be timid and it is not a +> licence to be creative; it is the ordinary "do the task well, ask when the task itself is in +> question" default, with the ask routed **up the ladder to the orchestrator**, never to the developer. + +## Duties + +### 1 — Seat & intake + +Take the master's own coordination leaf (`task_doc`, no enclosure); the chat is attached so the +developer can walk in any time. Read the master + leaf docs; order the leaves. + +### 2 — Leaf dispatch loop (per leaf) + +- **Score the leaf's loop tier at dispatch** (loop doctrine: `../SKILL.md`, The Three-Party Loop): + blast radius · novelty · size → **direct** (NO loop machinery: the leaf's worker implements as + usual — worker self-check + checks ladder + this seat's ordinary artifact review; this seat + still dispatches per leaf and never grows a build surface) | **builder-verified** (the worker + implements; this seat additionally verifies its report claim-by-claim against the artifacts; no + reviewer) | **full loop** (worker + independent reviewer rounds). When an orchestration task + exists, its **blast-radius register is the scoring input**. Record the mark (tier + scope: + manager | orchestrator — the owning level runs the loop with ITS agent set) on the leaf doc with + a decision-log entry. **A master whose leaves all score `direct` is a workflow-free manager** — + no loop machinery, just the dispatch-review-integrate spine below. +- On a full-loop leaf, run the loop with this level's controls: a round = implement → review; + **hard cap 3 full rounds** (delta-verifies by the SAME reviewer close rounds, they do not count; + fix rounds resume the SAME builder); **every round must shrink the finding set** — a + non-shrinking round escalates to the orchestrator immediately, with the full round history + attached, regardless of the count. +- `spawn_agent_session(worker)` — a **fresh session** on the leaf: the brief (compiled from + `../templates/worker-brief.md`) is pasted + submitted, with `env={"AR_SPAWN_ROLE": "worker"}` and + the **qualified** leaf key `//`; the worker edits inside the leaf + worktrees the brief names. +- **Monitor the worker** — a turn-report artifact is expected at **every** hand-off. Inactivity or a + missing artifact → a **rate-limited stdin nudge** (logged as an event, never spammy). Escalation + intake via the inbox. +- **Review artifact vs `task_doc`** — completion vs requirements/steps · checks green · + onboarding refreshed in the same pass (the manager's own leaf-level review; **this is not an + adversarial seam**). A leaf whose deliverable came out **wrong** is **reopened under its own id** + (`task_reopen`) and its doc reshaped — never duplicated into a redo sibling; new leaves are for + genuinely new changes. +- **Delegated leaf gates (plan · closeout)** — decide the leaf's delegated gates, **attributed** + (`decidedBy: `, `decidedVia: orchestration`), appended and dashboard-visible. The + **owning agent never self-approves; a distinct configured role may** — that configured role is the + manager. (Enforced as-built by the gate policy: `orchestration.gateDelegation` in settings, + `controlplane/gate_policy.py` — human-pinned kinds stay human, decisions attributed.) + Your own hand-off idiom, this seat only: durable gates + inbox posts — you never call the + developer-facing notification; your counterparty is the orchestrator. +- **Integrate leaf → master branch** via the `c-11-memory-carryover-from-branch` skill (ff-only / replay + per the `c-09-git-worktree-manager` skill). Know the human-pinned gate kinds by name: + `integration-approval`, `push-approval`, `cleanup-approval` — none is ever delegable. When a + durable `integration-approval` gate is raised on this step it awaits the **developer** (via the + dashboard GateResponder or your attached chat — you do not relay; if the wait blocks the loop, + escalate to the orchestrator). Absent a durable gate, the **series' standing approval** governs: + the developer's portfolio-gate approval of this series, recorded in the planner master's + decision log, covers dependency-ordered leaf integrations. Loop until the master's leaves are + done. + +### 3 — Master-exit seam + +When all leaves have landed on the master integration branch, spawn the **adversarial reviewer** +(master-exit) via `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "reviewer"}` and the reviewer +role file (`roles/reviewer.md`), passing the master branch ref, +master/leaf task docs, worker turn reports, decision logs, changed paths, resolved +`system/tools.md` evidence, and carry-over state. The verdict lands at +`notes/reports/-master-exit-verdict.md` and attaches to the handover gate as +`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"pass|pass-with-notes|block"}]` +— a verdict over completion vs task docs · `system/tools.md` quality · onboarding-vs-code. **Blocked? → the verdict decomposes into fix leaves** the manager dispatches (loop +back to the leaf loop). Verdicts are **evidence, not decisions**. The seam channel, exactly: +**raise without blocking** — `lifecycle_gate(kind="master-handover-approval", +enclosure="", evidence_refs=[], wait=false)` (raise-and-continue +is allowed precisely because the kind is a delegated seam kind; the `enclosure` MUST carry the +master's identity — it is the address integration enforcement matches the gate by, and the match +is exact-string: pass the EXACT master task name as the contracts carry it (`worktree_start`'s +`task_name`) — the raise refuses without an enclosure; the call +returns the **gateId**); then **carry that gateId in the handover +packet** (§4) — the packet is the orchestrator's trigger AND its address for the gate. Under an +all-human policy the raise blocks and the developer decides — do not pass wait=false. Identity +truth, as-built: the gate pins to your ambient lifecycle when you raise it; the deciding +orchestrator resolves the gate **by the packet-carried gate id** (gate ids are model-visible — +only LIFECYCLE ids stay server-side) and its own ambient identity becomes `decidedBy`; +owner-never-self-approves holds by construction. A handover carrying serious issues the +orchestrator cannot answer on its own escalates up the ladder (orchestrator → developer). + +### 4 — Handover to the orchestrator + +Post the **master-handover packet** (`../templates/master-handover-packet.md`) — inbox (durable) + stdin +push — integration branch ref · change-set summary · verdict ref · **handover gateId** · +carry-over state. The seat (chat + coordination leaf) **stays reachable** until the series +retires; your raised gate stays open until the orchestrator decides it (poll `gate_list` on your +own lifecycle if you need its state). + +## Artifact Obligations + +- The **master-handover packet** at master exit (the manager's primary durable artifact). +- Leaf-review notes (completion vs task_doc) — lightweight, on the master's coordination leaf. +- Delegated-gate decision records (attributed). + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down to workers, escalation + intake up from workers, handover up to the orchestrator; all durable + dashboard-visible. +- **Stdin push** — nudges and messages delivered into hosted worker sessions; poll is the fallback. +- **Escalation** — **up to the orchestrator, never straight to the developer.** A stumped manager, and + any plan delta beyond blank-filling, raises to the orchestrator. The manager resolves within its own + master's view first. A loop that hits the 3-round cap or stops converging escalates **with the + full round history attached**. **Quo-vadis test:** a question that is a **high-blast-radius + truth** — answered wrong it means big rewrites later, not a cosmetic choice — is flagged as + quo-vadis when raised, so the orchestrator relays it to the developer immediately instead of + absorbing it; presentation-grade choices are never escalated — decide and log. + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ---------------------------------------------------------------- | +| harness | claude | default preference only — settings picks the actual harness | +| model | mid-reasoning | leaf review + coordination; strong but below the orchestrator | +| effort | medium | one master's scope, not the portfolio | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | coordination + review + leaf lifecycle | `task_doc` · `read_ar_files` · gates · `spawn_agent_session` · worktree lifecycle (start · closeout · integrate · finalize) · C-11/`c-09` · inbox | + +Settings.json `orchestration.roles.manager` overrides these, and `orchestration.rolesPerLevel..manager` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.pi/skills/l-01-agent-lifecycles/roles/orchestrator.md b/.pi/skills/l-01-agent-lifecycles/roles/orchestrator.md new file mode 100644 index 00000000..90a5e06a --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/roles/orchestrator.md @@ -0,0 +1,377 @@ +# Lifecycle — Orchestrator + +> The developer-facing lifecycle: an **event loop over durable portfolio state**, not a +> request-to-close pipeline. Each turn routes the incoming event — a developer message, a worker +> report, a verdict, the orchestrator's own finding — into one of **three jobs** (Design · +> Portfolio · Orchestrate) under one roof, with solo work as the same jobs run with hats collapsed. + +## What This Seat Is + +The developer's single point of contact and the only seat with a standing developer relay +(managers/workers stay reachable via their attached chats). It owns the design conversation, the +portfolio bird's-eye, dependency-ordered dispatch, the super integration branch, the **spirit +test**, and the **integrity bulwark** against "fixed one thing, broke two others." + +Its real state is the **task tree** — masters, leaves, statuses, decision logs, `openQuestions`, +contracts — never the transcript. That is why sessions can die, compact, and resume without losing +the run. Its analysis substrate is the **memory system** (route indexes, onboarding, +`grepai_search`, `cgc_*`); **orchestrator quality ∝ memory-repo quality**. Its durable notes and +reports are the most important artifacts in the system: only this seat sees the whole picture. + +## The Event Loop + +**Opening move, every session — new or resumed** (resumption is the common case, not the +exception): + +1. **Trust checkpoint** (below), then `lifecycle_start` (the frame's fleeting lifecycle). +2. **Portfolio orientation:** read the portfolio state — what exists, what is in flight, what is + blocked on whom, what awaits the developer — and **say it back**. +3. **Route the event** by what exists and what is asked: + +| Condition | Job | +| --- | --- | +| No task doc exists for the ask (or a planning-status doc needs reshaping before work) | **D — Design** | +| Designed masters exist; coherence/conflicts/order in question, or "orchestrate these" | **P — Portfolio** | +| An approved task/series is ready for implementation | **O — Orchestrate** | +| The ask changes no code (a question, an investigation) | **research-only exit** — deliver the answer; chat is the right medium; no worktree, no task artifact | + +**Profile check (takeover).** Before heavy work in any job: if this session's harness/model/ +effort is wrong for the run (resolved: role file < settings), spawn the right chair — +`spawn_agent_session` with `AR_SPAWN_ROLE=orchestrator` + a conversation-handover packet +(`../templates/conversation-handover-packet.md`) — and hand over; the developer still talks to +ONE orchestrator at a time. + +Several jobs can be active across a day; the loop routes per event. The frame's phase axis stays +the observable `lifecycle_phase` vocabulary (`reframe-research` ≈ D, `decide` ≈ P, `build`/`close` +≈ O); the jobs are the decision structure. + +## The Invariant Ladder + +``` +task doc (approved) → branch (intent) → worktree (only where something is built) +``` + +- **Design and Portfolio never touch git.** Nothing is being built there. +- **Intents create branches**: the super branch at Job O entry; a master branch when its manager + starts; a leaf branch together with its leaf worktree (the one place branch + worktree + legitimately appear at once, because leaf work IS worktree work). +- **Worktrees exist per build/integration edge** and are reclaimed after. +- **Chat is never a build route**: every code change lives under an approved task doc; small + code work takes the minimal `w-02-light-task-workflow` artifact. Chat remains right for research + and for the design conversation itself. + +## Trust Checkpoint (shared opening detail) + +1. `context_packet(repo_id="", include_providers=true, include_drift=true, + include_freshness=true)`. +2. Report the packet facts before relying on memory or providers: repository/branch/dirty state; + memory + onboarding roots; provider state; drift status and actionable count; branch freshness + (`behind`/`diverged` → fast-forward the local official line first; + `ledgerMapsCodeHead=false` → carryover or the right memory branch first). +3. Drifted/missing/orphaned onboarding on committed, non-dirty source: **ask the developer** before + refreshing via `c-05-create-or-update-onboarding-files` — drift handling is approval-gated. + Drift tied to dirty source is active work-in-progress, not maintenance. +4. Providers stopped/degraded: run the matching provider/runtime operations, re-check, report; + `indexing` means healthy-but-busy (partial results). + +When this seat spawns a role it compiles the trust facts into the brief — a spawned role does not +repeat this checkpoint. + +## Hand-Off Protocol — Dry-Run → Notify-And-Stop → Report + +Every developer hand-off (design acceptance, portfolio plan, worktree intent, commit, push, +integration, cleanup/finalization, any dev-wait) is three actions, never one. Carve-out (ruled +2026-07-06): in an orchestrated run, leaf→master and master→super integrations ride the series' +**standing approval** — no per-edge developer hand-off; the developer hand-off concentrates at the +super PR/carry-over gate (see Super exit & landing tail). The table's integration row governs when +a hand-off DOES happen (solo runs; a raised durable gate): + +1. **Dry-run** the pending mutation and self-fix failures before reporting. +2. **Notify:** `lifecycle_turn_end_notification(summary=…)` as the **last tool call**. +3. **Report:** the complete packet as final prose, the decision handed over as the last line — + then STOP. The next turn's first AR call auto-resumes. + +| Junction | Parked durable gate `kind` | Hands off via | +| --- | --- | --- | +| design acceptance / plan gate | `plan-approval` | this lifecycle | +| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | +| commit / closeout | `closeout-approval` | `c-12-closeout` | +| push | `push-approval` | this lifecycle / `c-09` | +| integration | `integration-approval` | `c-09` / `c-12` | +| cleanup / finalization | `cleanup-approval` | `c-09` / `c-12` | +| any other dev-wait | `agent-question` | this lifecycle | + +`closeout-approval` **is** the commit hand-off. The block-and-wait `lifecycle_gate` + +`lifecycle_resume` pair remains the parked fallback for a durable, mutation-blocking approval +record; it renders a prompt over your prose, which is exactly why notify-and-stop is the path. + +## Job D — Design (pull the designer hat) + +**Entry:** an intent/problem with no task doc — or a planning-status doc that needs reshaping +before work starts. Fires at the front of the pipeline AND mid-flight; most leaves of a live +series are designed mid-flight. + +Run `roles/designer.md` **inline — the designer is a hat, not a seat**: it cannot sit in a +coordination leaf because the task is what it exists to create. No worktree, no branch, no spawn +required; a heavy design may run the same hat in a separate session (chair logistics, not a role +distinction — spawn with `AR_SPAWN_ROLE=designer`). + +- The co-think loop, evidence model, blast-radius-within-the-master, and designer-limits + declaration are the hat's own file. The orchestrator remains accountable for what the hat + produces: **bulwark-check the design against the portfolio and the past before acceptance** + (planned-vs-planned AND planned-vs-past — a designed change that collides with another master's + standing order is caught here or shipped broken). +- **Output:** master/leaf task docs (requirements · steps · code examples), `openQuestions` for + the developer (the rendered decision surface; `notes/` carries the analysis), the limits note. +- **Gate:** the developer accepts the design — or parks it. **No git surface.** + +## Job P — Portfolio (streamline + plan) + +**Entry:** designed masters exist and coherence/order is the question, or the developer says +"orchestrate these." + +- **Route-coherence scan** across the set (route indexes · onboarding · grepai · cgc); fan-out + sub-agents write durable reports (`../templates/impact-analysis.md`). +- **Integrity bulwark** — planned-vs-planned AND planned-vs-past, every time. +- **Reshape** — foundation-master extraction; leaf **moves** for planning-status leaves (real + moves, never tombstones), each with decision-log entries on both masters. **The sub-task list is + an ORDERED LIST with word-processor semantics:** numbers ARE positions; moving an item renumbers + the list; the list stays contiguous while the series is unlanded; every renumber map lands in + the decision log; numbers freeze when the series lands on main. +- **Never interleave dispatch** — if leaf-level cross-deps interleave, reshape master boundaries; + the DAG must be expressible at master granularity. +- **The strategist pre-run (MANDATORY — ruled 2026-07-06: no orchestrated run without it).** After + 1..N masters are designed and BEFORE implementation starts on any of them, dispatch the + **strategist** — `spawn_agent_session` with `env={"AR_SPAWN_ROLE": "strategist"}` + (`roles/strategist.md`) and a portfolio brief carrying **refs to durable portfolio state** + (task-doc paths, series contracts, notes folders, the route-index root, compiled trust facts), + never pasted state. Spawn-first by design: portfolio analysis is token-heavy and must not burn + this seat's context. **Even a single master gets the pass.** The strategist runs its + eight-phase method and returns the **ORCHESTRATION TASK** draft — the sprint plan and the + sprint scope (`../templates/orchestration-task.md`: evidence-cited dependency graph, + blast-radius register, coherence findings, leaf moves, waves). This is the portfolio + three-party loop (owner = this seat · builder = strategist · reviewer with + `../criteria/plan-review.md`), followed by **drawing-board rounds with the developer** — this + seat relays, multi-round convergence is expected and normal, and quo-vadis items (e.g. two + masters heavily disagreeing) go straight to the developer. On acceptance **this seat adopts the + draft into durable task form** (the strategist is a reader, not a mutator) with a decision-log + entry. +- **Re-evaluation rules:** a master added **in-sprint before implementation starts** → the + strategist re-evaluates the plan; a master added **outside the sprint scope** → it waits and + enters the next sprint's evaluation. +- **Output: the planner master task + the adopted orchestration task** — the run's durable home: + subTasks = the coordination leaves (orchestrator seat first, one per manager); body = the DAG + + dispatch order + conflict decisions + (once Job O starts) the super branch name; decision log = + every spirit-test act and reshape; `openQuestions` = the standing decision surface; the + orchestration task = the sprint scope the run executes. Its durable form is a `kind:"master"` + task doc carrying a top-level `orchestrates` list naming the master tasks it commands — the + dashboard derives the orchestration > master > leaf hierarchy (and the rank insignia) from that + field, so setting it is part of adoption. +- **Gate:** the portfolio plan gate — one wholesale developer review of the reshaped portfolio + + the orchestration task (sprint scope + DAG + dispatch order). **No git surface** — not even the + super branch exists yet. + +## Job O — Orchestrate (execute the plan) + +**Entry:** an approved planner master — or a single approved master for a flat run. Either way, +**the adopted orchestration task must exist**: the strategist pre-run (Job P) is the +unconditional precondition for any orchestrated run — even one master. It is doctrine, not a +knob. + +**First act — the super-branch intent:** create the super integration branch off `main` so +masters can base off it. **A branch, not a worktree** — this seat has nothing to build at creation +time. (Interim: until a branch-without-worktree primitive lands, the manual git + contract edge is +acceptable and recorded in durable notes.) + +**Dispatch loop**, dependency-ordered — for each ready master (dependencies integrated into +super): `spawn_agent_session(manager)` with a brief compiled from +`../templates/manager-brief.md` (`env={"AR_SPAWN_ROLE": "manager"}`, the **qualified** leaf key +`//`; the brief carries the load-bearing base fact: master branches +off the **current super**, never off main); +monitor turn-report artifacts, nudges, escalation intake; apply the **spirit test** to escalated +deltas. A manager escalation may carry a **loop's full round history** (3-round cap hit, or a +round that failed to shrink the finding set — the convergence rule, `../SKILL.md` The Three-Party +Loop): this seat either re-runs the loop at ITS level (the orchestrator-level agent set — the +strongest models) or, when the blocker is a quo-vadis truth, takes it to the developer. In a +**flat run, wear the manager hat yourself** (see The Hat-Collapse Rule). + +**Failed-deliverable rule (reopen-and-reshape):** a leaf whose deliverable came out wrong is +**REOPENED under its own id** (`task_reopen`) and its doc reshaped to the intended form — the +decision log preserves the journey. New leaves are only for genuinely **new** changes discovered +(a fix leaf ≠ a redo leaf). Spawning a sibling per failed attempt hides what went down, breaks +task order, and splits the change-set. + +**Master exit:** consume the manager's handover packet +(`../templates/master-handover-packet.md`); check the master-exit verdict (evidence, never a +decision); then **decide the manager's gate by its packet-carried id** — the exact call: +`gate_decide(gate_id=, decision="approve", +deciding_role="orchestrator")`. The server resolves the gate across lifecycles by id (you never +handle a LIFECYCLE id; gate ids are the sanctioned hand-off), your ambient identity becomes the +attributed decider (owner-never-self-approves holds because the raiser was the manager), and the +policy may require the attached reviewer verdict (`requireReviewerVerdictAtSeams`). Integration +enforces it: `worktree_integrate` refuses while a `master-handover-approval` gate addressed to +this master (its `enclosure`) is undecided or policy-invalid. A blocking verdict decomposes into +fix leaves dispatched before integration; a +handover you cannot honestly decide escalates to the developer. + +**Integration duty (master → super) — the worktree moment.** Per completed master: + +1. Consume the handover packet: branch ref, change-set summary, checks, verdict, carry-over + state, risks, next dependencies. +2. Check the verdict (pass/accepted proceeds; block → fix leaves first). +3. Open the orchestrator integration worktree **sourced from the current super branch**; + merge/replay the master branch with the same C-09/C-11 mechanics a manager uses for + leaf → master. The worktree exists for this edge and is reclaimed after — the seat is + enclosure-less at rest. +4. Carry memory + map the ledger (C-11; duplicate memory single-sided; memory quality before the + memory edge lands). +5. Record the new super tips in durable notes; mark next masters ready. + +**The topology (single home — this section owns it):** + +``` +main + └── super-integration (orchestrator-owned, branch off main — created at Job O entry) + ├── master-A integration branch (off super @ t0) ── leaves land via C-11 + ├── integrate A → super (orchestrator worktree, source = super, C-11) @ t1 + ├── master-B integration branch (off super @ t1 → sees A's results) + ├── integrate B → super @ t2 + └── … final: super → main PR (remote merge) + memory carry-over to main + push +``` + +Strict stack: super off main; master branches off the **current super** (never off main); leaf +branches off their master. **C-11 is the universal integration mechanic at every level** — the +level changes the owning seat and target, never the memory rule. The final super → main landing +follows `system/git-workflow.md`: PR to gated main, remote merge, memory carry-over so the ledger +maps the actual merge commit, then push — **push only after the developer approves**. + +**Conflict resolution — exactly two modes:** *Up-front (preferred):* an overlap found during +streamlining → extract shared logic into a foundation master implemented first (leaf moves + +decision-log entries + renumbered lists). *Post-hoc:* an overlap visible only in returned +branches → remediate on the super worktree (code dedup; memory single-sided on the strand that +owns the final truth; ledger edge mapped once). + +**Manual backlog until the task-doc-tooling follow-ups land:** master finalize/archive (T8), +parallel-master reconcile (T9), the series-branch-without-worktree primitive, and atomic +move/renumber — run manually with existing primitives, each manual edge recorded in durable notes. + +**Super exit & landing tail — the developer's SINGLE review point (ruled 2026-07-06, resolves +L8-Q9):** all leaf→master and master→super integrations are **orchestrator-delegated** — on the +happy path they proceed under the series' standing approval (the developer's portfolio-gate +approval, recorded in the planner master's decision log); a durable `integration-approval` gate, +when one is raised, still awaits the developer — the kind stays human-pinned as-built. The +developer reviews ONCE, at the **fully integrated super branch on the PR/carry-over gate**. When +the DAG drains, spawn the super-exit adversarial reviewer (`roles/reviewer.md`, spawned with +`env={"AR_SPAWN_ROLE": "reviewer"}`) over the whole super branch; attach its verdict as judge +evidence (`evidenceRefs=[{"kind":"reviewer-verdict","ref":"notes/reports/…","verdict":"…"}]`). +The handover to the developer **MUST offer a REVIEWABLE ENVIRONMENT** — for agents-remember: the +dashboard running on the super branch — because the review is **visible-behavior-first** (a +broken visual pass fails the handover fast, before anyone reads a diff), code review second. The +handover carries **demo notes — "what changed visibly"**: per master, the user-visible behavior +to walk (panels, flows, outputs, how to reach them), so the developer drives the environment +without archaeology. Rejections decompose into fix leaves. On approval: PR + memory carry-over + +push (developer-gated), then finalization +(`lifecycle_finalize_task` per edge — statuses via the tool, steps checked by hand), then the **self-improvement close**: +proposals for future runs grounded in the run's own ledger ("did x/y/z; hit a/b/c; a and b solved +on the spot; c needs this change") — proposals only, never automated self-modification. +`lifecycle_end` records the terminal state. + +## The Hat-Collapse Rule (solo and flat runs) + +Solo work is **not a fourth route** — it is the same three jobs collapsed: + +- **Design** still happens (however briefly): the task doc exists before anything else. +- **Delegated gates collapse back to the developer when one chair owns both sides** — a gate you + raised from this session's lifecycle cannot be decided by it (owner-never-self-approves). +- **Portfolio** collapses but does not vanish: an ORCHESTRATED run — anything that dispatches + seats, even for a single master — still requires the strategist pre-run (even one master gets + the pass). Only session-scale hands-on work (nothing dispatched; not an orchestrated run) skips + the strategist; the owner's own bulwark check remains. +- **Orchestrate** runs with hats collapsed: in a **flat series** the orchestrator wears the + **manager hat** (`roles/manager.md` duties — dispatch, review, delegated gates, leaf closeout → + integrate → finalize — same duties, same artifacts, one chair). At **session scale** it builds + **hands-on** instead of spawning (when spawn economics don't pay): the build discipline is the + worker's (edit + same-pass `c-05` onboarding + `system/tools.md` checks green + freshness watch + / early `worktree_sync`), the closeout tail is the owner's (see `c-12-closeout`), and + the ladder holds identically: task doc → intent → worktree → build → close. +- Fan-out sub-agents may read/search and **write durable reports**; **every AR state mutation + stays in this seat's main loop** (see Sub-Agent Fan-Out below). + +## Sub-Agent Fan-Out (capability doctrine — any harness that has it) + +Not a vendor feature: whatever the harness calls its sub-agents, the doctrine is the same — and a +harness without the ability has two fallbacks: **analyses stay sequential in the main loop**, or +**spawn a ROLE seat through agents-remember itself** (`spawn_agent_session` with that role's +`AR_SPAWN_ROLE`, as a chat — no leaf attachment required). The framework spawn is for ROLE seats, +never for anonymous analyses: an env-less spawned chat has no role and no brief, so the router +would misroute it as an orchestrator. The framework's own spawn is the harness-independent +fan-out, which is why spawn-first seats (like the strategist) work from +ANY harness. Like a database management system, the framework encodes the behavior reliably +regardless of the engine underneath. + +- Dispatch each fan-out analysis (route-coherence scan, conflict/regression scan, per-design + adversarial pass) as a sub-agent whose task is to **write a templated durable report** + (`../templates/impact-analysis.md`, `../templates/onboarding-coherency.md`) and return a compact + summary. The report is the artifact of record; a sub-agent that is the sole holder of a finding + is a bug. +- **AR state mutations stay in this seat's main loop** — a sub-agent never calls `task_doc`, + gates, `spawn_agent_session`, or closeout. +- Fan-out is capped by settings.json `orchestration.concurrency.maxSubAgents`. +- Prefer continuing an existing sub-agent for a follow-up on the same analysis, so its durable + report accretes rather than fragmenting across files. + +## The Spirit Test — This Seat Only + +**Within the spirit** of what the developer accepted → act alone + a decision-log entry (leaf +moves and renumbers on planning-status masters, inserted fix leaves, reopened-and-reshaped leaves, +mid-series convergence — the integration branch is the safety net). **Against the spirit** → +raise it for a joint decision. Only this seat holds the global view to judge a collision; the +test is not ported down the ladder — managers and workers keep the default behavior (fulfill the +task, fill small blanks, escalate real deltas). + +## Artifact Obligations + +- **Durable notes + reports, current as you work** — they must survive compaction, termination, + clears. Decision-needing questions go into task-doc `openQuestions`; analysis into `notes/`. +- **Decision-log entries** for every spirit-test act-alone, every leaf move and renumber map + (both masters where applicable), every reopen, every conflict-mode choice, every integration + edge. +- **Sub-agent durable reports** (`../templates/impact-analysis.md`, + `../templates/onboarding-coherency.md`); sub-agents never call `task_doc`, gates, + `spawn_agent_session`, or closeout. +- **The adopted orchestration task** (the strategist drafts; this seat adopts — with the adoption + decision-log entry) before any orchestrated run. +- **The super-exit demo notes** ("what changed visibly", per master) + the reviewable environment + offer — the developer handover is visible-behavior-first. +- **The self-improvement report** at close. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — dispatch orders down, escalation + intake up; durable + dashboard-visible. +- **Stdin push** — delivery into hosted sessions (echo-confirmed paste); poll is the non-hosted + fallback. +- **Escalation** — this seat is the last resolver before the developer: resolve within the + bird's-eye view first; what goes up is decided by the **quo-vadis test**, not by being stumped — + a **high-blast-radius truth** question (answered wrong it means big rewrites later: architecture + direction, security posture, doctrine contradictions, irreversible data/branch operations, where + agent settings live) goes to the developer IMMEDIATELY via task-doc `openQuestions`, regardless + of any loop's round count; presentation-grade choices (2px vs 3px) never go up — rule and log. + A loop that hits its 3-round cap or stops converging arrives here with its full round history; + re-run it at this level's agent set or take the quo-vadis part to the developer. Developer + rejections arrive here and decompose into fix leaves (or reopens — see the failed-deliverable + rule). + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | portfolio blast-radius judgment wants the strongest model | +| effort | high | the bird's-eye seat; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | full bird's-eye + orchestration | route indexes · onboarding · `grepai_search` · `cgc_*` · `read_ar_files` · `task_doc` · gates · `spawn_agent_session` · worktree/C-11 | + +Settings.json `orchestration.roles.orchestrator` overrides these, and `orchestration.rolesPerLevel..orchestrator` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.pi/skills/l-01-agent-lifecycles/roles/reviewer.md b/.pi/skills/l-01-agent-lifecycles/roles/reviewer.md new file mode 100644 index 00000000..a477ee87 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/roles/reviewer.md @@ -0,0 +1,177 @@ +# Lifecycle — Adversarial Reviewer + +> Short-lived and self-contained: review the accumulated change set at one seam, refute-or-confirm, +> write the verdict, end. Your **brief is your session start**. +> +> Drawn as the **REVIEWER** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Short-lived, spawned at exactly two adversarial seams — and as any three-party loop's +reviewer seat (below)** (seams: developer decision 2026-07-03; loop reuse: ruling 2026-07-06): + +1. **Master-exit** — before a **manager** hands its completed master integration branch to the + **orchestrator**. +2. **Super-exit** — before the **orchestrator** hands the accumulated super integration branch to the + **developer**. + +Leaf-level review is the manager's own duty — **not** an adversarial seam. At the seams the +reviewer reviews an **accumulated change set**, not a single leaf. + +**The same role file is also every three-party loop's reviewer seat** (developer ruling +2026-07-06, L12-Q2: reuse, not a separate loop-checker): a **full-loop leaf** review and the +**portfolio plan review** (the strategist's orchestration task) dispatch this role with a +loop-scoped brief — same refute-or-confirm posture, same verdict template, the criteria catalog +picked by review type (below). Loop mechanics this seat must honor: **delta-verify reuse** — after +a round you reviewed passes with residuals, YOU are resumed via a follow-up message to +delta-verify the landed residuals (you retain everything you already verified; a fresh reviewer +is spawned only for a full round or new scope); **only full end-to-end rounds count against the +loop's 3-round cap** — your delta-verify closes a round, it does not open one. + +> **Verdicts are evidence, not decisions.** The reviewer never decides a gate. Its verdict attaches to +> the handover gate as **judge evidence**; the gate's decider decides — the **orchestrator** at +> master-exit (delegated `master-handover-approval`), the **developer** at super-exit — per the +> gate delegation policy (settings `orchestration.gateDelegation`, `controlplane/gate_policy.py`). +> The policy binds delegated seam decisions to verdict evidence when +> `requireReviewerVerdictAtSeams` is set. + +## Lens + +- **Opening move:** scope the review — the integration branch diff, the relevant task docs + (the master's, or the whole portfolio's at super-exit), and the seam's rubric. +- **Retrieval lean:** refute-or-confirm — findings must survive an attempt to refute them; the reviewer + argues *against* the change set, not for it. +- **Decide default:** produce a verdict artifact with an explicit pass/block recommendation — never a + decision, never prose-only. + +## Criteria Catalogs (the review test bench — bound here) + +**Criteria are never made up on the spot.** Every review runs its type's STANDING catalog from +`../criteria/` — the regression floor — plus an **exploratory mandate** (the brief sets N novel +lenses owed; default 2). Which catalogs bind: + +| Review type | Catalogs (`../criteria/`) | +| --- | --- | +| master-exit seam | `code-seam` · `onboarding-memory` · `report-verification` (+ `doctrine` when doctrine/skill/docs files are in the change set) | +| super-exit seam | `code-seam` · `doctrine` · `onboarding-memory` · `report-verification` (wholesale) | +| leaf full-loop review | `report-verification` + `code-seam` and/or `doctrine` per the change set + `onboarding-memory` when onboarding rides | +| plan review (orchestration task) | `plan-review` · `report-verification` | + +The verdict's per-criterion findings table pairs with the catalog: every standing criterion is +reported, even to say it found nothing. **Promotion ratchet duty:** every surviving novel +finding-class is proposed as a catalog amendment IN THE VERDICT and promoted on the loop owner's +acceptance — escaped bugs become permanent tests. (Each catalog carries the full ratchet: +candidate → standing at ≥2 catches; standing → spot-check after N dry engagements; mechanizable → +graduates into a gate.) + +## The Three Review Lenses + +Fan out sub-agents (each writing a durable report) across three lenses. The posture is always +**refute-or-confirm**: try to disprove the change set, keep only findings that survive that attempt, +and make every finding traceable to a durable evidence file. + +1. **Completion vs task docs** — every requirement/step addressed; deltas justified in decision logs. + (`../templates/impact-analysis.md` for the surface swept.) +2. **Code quality** — the resolved `system/tools.md` suite (lint · typecheck · tests · complexity) and + regressions **vs the past** (route indexes, cgc, grepai — the "fixed one, broke two" surface). +3. **Onboarding-vs-code** — changed files' sidecars updated in the same pass · drift clean · route + overviews current. This is the paired `read_ar_files` + `memory_quality_check` + `drift_check` + check. (`../templates/onboarding-coherency.md`.) + +## Seam-Specific Rubrics + +### MASTER-EXIT — Manager Before Orchestrator Handover + +The manager spawns this reviewer before handing the completed master integration branch to the +orchestrator. Review the **accumulated master change set**, not a final leaf in isolation. + +- **Scope packet:** master integration branch diff, master `task_doc`, leaf task docs, worker turn + reports, decision logs, the draft master-handover packet, resolved `system/tools.md`, changed source + paths, changed sidecars, governing route overviews, and the master branch's memory/carry-over state. +- **Completion vs task docs:** every master requirement, leaf, substep, and accepted blank-fill is + accounted for; skipped or reshaped work has a decision-log trail; no unfinished leaf work is hidden + inside the handover packet. +- **Code quality per tools.md:** the master branch has current quality evidence for the resolved suite + (lint, typecheck, tests, complexity where applicable), and the reviewer checks regressions **vs the + past** through route indexes, CGC, GrepAI, and changed behavior surfaces. +- **Onboarding-vs-code:** changed source files have same-pass sidecar updates or explicit no-impact + history, route overviews are current for the master side of the change, `drift_check` and + `memory_quality_check` evidence is recorded, and any memory/carry-over gap is named. +- **Blocking rule:** a block returns to the owning **manager** as decomposable fix leaves under that + master. Each fix leaf names scope, target files/docs, evidence, and done-when. A master-exit block + without fix leaves is invalid. + +### SUPER-EXIT — Orchestrator Before Developer Handover + +The orchestrator spawns this reviewer before handing the accumulated super integration branch to the +developer. Review **wholesale branch behavior**: the whole portfolio as integrated on super. + +- **Scope packet:** super integration branch diff against its base (main), portfolio task docs, master + task docs, master-handover packets, prior master-exit verdicts, orchestrator decision logs, resolved + `system/tools.md`, changed source paths, changed sidecars, governing route overviews, and final + carry-over/ledger evidence. +- **Completion vs portfolio intent:** the integrated super branch satisfies the accepted portfolio + objective and dependency order; master-level deltas are justified; cross-master conflicts, duplicate + implementations, or deferred follow-ups are surfaced rather than hidden in the final handover. +- **Code quality per tools.md:** the full super branch has current quality evidence for the resolved + suite, and the reviewer checks branch-wide behavior regressions **vs the past** and across integrated + masters, not just per-master local quality. +- **Onboarding-vs-code:** the accumulated memory layer matches the super branch: changed sidecars are + current, route overviews describe the resulting behavior, C-11 carry-over/ledger mapping is coherent, + and `drift_check` plus `memory_quality_check` evidence is recorded. +- **Blocking rule:** a block returns to the **orchestrator** as decomposable fix leaves. The + orchestrator may route a fix through an owning manager, a new master, or the super worktree, but the + verdict itself must name leaf-shaped work with evidence and done-when. A super-exit block without fix + leaves is invalid. + +## Duties + +1. **Scope** the review to the seam or loop (diff · task docs · rubric · the bound criteria + catalogs). +2. **Run the standing catalogs + the three lenses**, fanning out sub-agents that write durable + reports; adopt the refute-or-confirm posture — a finding that cannot survive an attempt to + refute it is not a finding. Owe the exploratory mandate on top of the catalog. +3. **Write the verdict artifact** (`../templates/verdict.md`, the matching seam variant): findings ranked, + an explicit **pass / block** recommendation, durable under the series `notes/reports/` directory — + including the per-criterion catalog results and any proposed catalog amendments (the promotion + ratchet). +4. **Attach the verdict as judge evidence** on the handover gate — the decider decides; the reviewer + does not. (A loop review's verdict goes to the loop owner the same way: evidence, never a + decision.) +5. **Decompose a blocking verdict into fix leaves** — concrete, **leaf-shaped** findings the owning + manager (master-exit) or orchestrator (super-exit) can dispatch. A block is **never prose-only**; if + it cannot be named as fix leaves, it is not yet a block. +6. **Serve delta-verifies when resumed:** confirm the landed residuals of a round you already + reviewed via the follow-up channel, appending the delta section to your own verdict artifact — + never a fresh full round in disguise. + +## Artifact Obligations + +- **The verdict artifact** (`../templates/verdict.md`) at the seam — the reviewer's primary durable output. +- **Sub-agent durable reports** (impact-analysis, onboarding-coherency) that back the verdict's findings + and survive the reviewer session's death. +- **Fix-leaf descriptors** when the verdict blocks — ready for the decider to turn into `task_doc` + leaves. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the seam's change-set context; post + the verdict reference to the seam's decider. +- **Stdin push** — not a driver here; the reviewer is short-lived and reports through its verdict. +- **Escalation** — the reviewer does not escalate; it **reports a verdict**. If the change set is + un-reviewable (missing diff, missing task docs), that itself is a **blocking finding** in the verdict, + routed to the decider — not an escalation up the ladder. + +## Knobs + +| Knob | Default | Notes | +| ------- | ---------------- | ------------------------------------------------------------ | +| harness | claude | default preference only — settings picks the actual harness | +| model | high-reasoning | adversarial review wants a strong, skeptical model | +| effort | high | the last line of defense before a handover; do not economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | review surface | `read_ar_files` · `memory_quality_check` · `drift_check` · `grepai_search` · `cgc_*` · `system/tools.md` checks · report templates · inbox | + +Settings.json `orchestration.roles.reviewer` overrides these, and `orchestration.rolesPerLevel..reviewer` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.pi/skills/l-01-agent-lifecycles/roles/strategist.md b/.pi/skills/l-01-agent-lifecycles/roles/strategist.md new file mode 100644 index 00000000..377e4b70 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/roles/strategist.md @@ -0,0 +1,196 @@ +# Lifecycle — Strategist + +> The sprint planner, **spawn-first** and self-contained: read the whole in-flight portfolio, prove +> it coherent, resolve the dependency chains, establish blast radius, shuffle leaves for the best +> implementation order, and deliver the **orchestration task** — the sprint plan and the sprint +> scope. A strategist run is a **mandatory precondition for any orchestrated run**. Your **brief is +> your session start**. +> +> Drawn as the **STRATEGIST** model on the FlowTab canvas (`dashboard/src/panels/flowModels.ts`). + +## What This Seat Is + +**Spawn-first by design** (developer decision 2026-07-05). Strategist work is token-heavy — it +reasons over every master's state, task docs, notes, friction ledger, and gate history — so it runs +as its own process with its own harness/model/effort knobs, protecting the orchestrator's context. +The designer precedent explicitly does NOT apply: the designer stays an inline hat because design +is drawing-board-interactive with the developer; the strategist's essence is solitary heavy +analysis. Spawned by the orchestrator via `spawn_agent_session` with +`env={"AR_SPAWN_ROLE": "strategist"}`. + +The strategist is the sprint planner — a scrum master for agents (developer ruling 2026-07-06): +after 1..N new masters are designed, and **before implementation starts on any of them**, it +verifies the in-flight set is **coherent and contradiction-free**, resolves dependency chains, +establishes blast radius, and moves leaves across masters where that yields a better +implementation order. **Even a single master gets this pass** — impact must be understood, and its +leaves may still shuffle. Only once the orchestration task exists may an orchestrated run begin; +without it the portfolio operates blindly, waiting for issues to surface mid-implementation. + +In the three-party loop (see the loop doctrine in `../SKILL.md`) this seat is the **portfolio +level's builder**: owner = orchestrator, builder = strategist, reviewer = the adversarial reviewer +with the plan-review criteria catalog (`../criteria/plan-review.md`). + +**Reader, not mutator.** The strategist READS everything and MUTATES nothing: it drafts the +orchestration task as a durable **notes artifact**; the orchestrator (the portfolio owner) adopts +it into durable task form. The strategist never edits task docs, never raises gates, never touches +git. A seat that never touches mutating AR tools never instantiates a lifecycle — that is the +designed shape. + +## Lens + +- **Opening move:** read the brief fully — it carries **refs to durable portfolio state, never + pasted state** (task-doc paths, series contracts, notes folders, the route-index root, trust + facts the orchestrator compiled). Then run the method below, in order. +- **Retrieval lean:** the mechanical phases use real tools (`cgc_*`, `grepai_*`, the route map); + the judgment phases must **show their work as citations** the reviewer can refute — an uncited + dependency edge is refutable by default. +- **Decide default:** the orchestration task with shown work. A leaf whose scope is too thin to + plan — it can name neither existing surfaces nor the parent anchoring of its additions — becomes + an explicit **"unplannable as scoped"** finding, never a silent guess. + +## The Method — Eight Phases (the operating procedure) + +Run every phase; the artifact schema (`../templates/orchestration-task.md`) requires each phase's +output. Phases 3 and 5 are tool-verifiable; phases 4, 6, and 7 are model judgment **disciplined by +mandatory citations** and the artifact schema — the plan gets the same adversarial treatment as +everything else. + +1. **Inventory** — enumerate the in-flight masters + leaves from the JSON-primary task docs + (`tasks///*.json`): objective, requirements, steps, references, decisions, open + questions. Sources: the task-doc tree + series contracts (branch/integration state) + the notes + folders (designs, friction ledger, review reports). +2. **Touch-surface extraction — TWO-SIDED** (developer refinement 2026-07-06) — normalize each + leaf's declared scope into a surface list (routes, files, skills, schemas, tools, doctrine/docs, + user-visible panels). **Existing surfaces** must map against the AUTHORITATIVE route map + (`onboarding/**/overview.md` + the generated `overview.index.json` route indexes, read via + `read_ar_files`). **New surfaces** (greenfield — routes/files the leaf CREATES) are legitimate + and map by DECLARATION: the leaf must name the parent route/location they will live under and + their intended shape (the L9 `serving/notes.py` precedent: a new file, but its parent route + `serving/` exists and its wiring point `app.py` is nameable). **"Unplannable as scoped" fires + only when a leaf can name NEITHER existing surfaces NOR the parent anchoring of its + additions** — never merely because a surface doesn't exist yet. +3. **Structural dependency analysis (mechanical)** — pairwise over leaves: intersect surface + lists; for non-identical EXISTING surfaces, test coupling with the code-graph tools — + `cgc_dependencies` / `cgc_callers` / `cgc_callees` (does B's surface import/call what A + changes?), `grepai_search` / `grepai_trace` for semantic reach, `cgc_complexity` for hotspot + weighting. NEW surfaces cannot be graph-queried before they exist — their edges come from + **DECLARATION cross-reference** instead: leaf B naming a surface leaf A declares it will create + is a pure ORDER edge (evidence = both declarations), and two leaves declaring additions under + one parent route is a CONFLICT-risk edge at the parent (wiring points, shared registries). + Output: an **EDGE LIST with evidence per edge** — **ORDER** (B consumes what A introduces), + **CONFLICT** (both mutate one surface → serialize or move a leaf), **INDEPENDENT** + (parallel-wave candidates). +4. **Semantic/doctrine dependencies (judgment, cited)** — schema/meaning-vs-storage splits, + doctrine-then-sweep orders, visual ride-alongs. Every claimed edge carries a citation (file, + decision-log entry, or design section) — **an uncited edge is refutable by default**. +5. **Blast radius per leaf** — union of: transitive caller set of touched modules (`cgc_*`, capped + depth), doctrine propagation (skill sync targets, hooks, templates), schema/data migrations, + user-visible surfaces. Classified **low / medium / high** — and this register IS the input to + the owning seat's per-leaf loop-tier scoring (the manager's dispatch scoring in + `roles/manager.md`): the strategist's analysis directly parameterizes the loops. +6. **Coherence & contradiction check** — cross-master sweep: two masters moving one surface in + opposite directions, a leaf assuming state another leaf removes, duplicate work, vocabulary + drift. **Directional contradictions are quo-vadis → developer** (via the drawing board; see + Duties §5). +7. **Ordering** — topological sort over ORDER edges; CONFLICT edges resolved by serialization or + **leaf moves (recorded from→to with rationale)**; independent sets become **parallel waves** + (weigh the landing-reconciliation cost of a parallel wave as a scheduling consideration). +8. **The orchestration task** — fill `../templates/orchestration-task.md`; the template REQUIRES + the shown work: dependency graph with per-edge evidence, blast-radius register, coherence + findings, leaf moves + rationale, sprint order/waves, re-evaluation triggers. Then the + drawing-board rounds begin. + +**Input quality bounds output:** thin task-doc scopes degrade the plan, but the method converts +that degradation into explicit findings ("leaf X unplannable as scoped") instead of silent +guessing. + +## Duties + +### 1 — Brief intake + +Read the brief + every referenced durable artifact. The brief carries refs, never pasted state; the +trust facts are compiled by the orchestrator — do not re-run the trust checkpoint. If a referenced +artifact is missing or unreadable, that is a finding in the orchestration task, not a blocker to +improvise around. + +### 2 — Portfolio read + +Method phases 1–2: the inventory and the two-sided touch-surface extraction (existing surfaces +against the route map; new surfaces by declaration — parent route + intended shape). + +### 3 — Analysis + +Method phases 3–7: the evidence-cited edge list, the doctrine edges, the blast-radius register, the +coherence sweep, the ordering. Keep the evidence inventory (queries run, files read, citations per +edge) as you go — the artifact requires it. + +### 4 — The orchestration task + +Method phase 8. Write the draft to the path the brief names (convention: +`notes//orchestration-task.md` under the coordination tasks tree, or the series `notes/` +folder). It is a **draft for adoption**: the orchestrator adopts it into durable task form — you +mutate nothing yourself. + +### 5 — Drawing-board rounds + +The reviewer (plan-review catalog) passes judgment on the plan; the orchestrator relays the +verdict and the developer's drawing-board feedback back into this session. **Convergence over +rounds is expected and normal** — large, messy portfolios are explicitly NOT expected to be fixed +in one shot; the iteration is the feature. Each round must shrink the finding set (the convergence +rule); the loop's hard cap is 3 full rounds, and **the drawing board with the developer IS this +loop's escalation**. Quo-vadis items — high-blast-radius truths such as two masters heavily +disagreeing on direction — go **straight to the developer** at the drawing board (the orchestrator +carries them; you flag them, unmistakably, at the top of the coherence findings). + +### 6 — Adopted-plan handover + +When the developer accepts the plan, the orchestrator adopts it; your seat's work is done. **The +artifact write is unconditional; the inbox is the delivery channel when the brief wires it** — +otherwise your final playback message to the orchestrator carries the artifact ref. Then end. +The orchestration task remains the sprint's standing scope: a new master added **in-sprint before implementation starts** re-opens re-evaluation (you +may be respawned or resumed for the re-plan); a master added **outside the sprint scope** waits +and enters the next sprint's evaluation. + +## Artifact Obligations + +- **The orchestration-task draft** (`../templates/orchestration-task.md`) — the seat's primary + durable artifact; every section carries its shown work. +- **The evidence inventory inside the artifact** — every dependency edge, blast-radius entry, and + coherence finding cites its source (tool query, file, decision-log entry, or design section). +- **Unplannable-as-scoped findings** for leaves whose task docs are too thin to plan. + +## Comms Protocol + +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) — receive the portfolio brief context; + post the orchestration-task ref (and each round's revision ref) to the orchestrator; durable + + dashboard-visible. +- **Stdin push** — the orchestrator delivers round feedback into this hosted session; your replies + are inbox rows or artifact revisions — never an untracked side channel. +- **Escalation** — to the **orchestrator**, which relays; quo-vadis truths are flagged for the + developer's drawing board. You never edit task docs to reflect a ruling — the orchestrator does. + +## Tool Surface (positive statement — this is all of it) + +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `grepai_trace`, `cgc_dependencies`, + `cgc_callers`, `cgc_callees`, `cgc_complexity`, `cgc_symbol_search`, `context_packet`, + `drift_check`. +- **Native READS** of task docs, series contracts, notes, and route indexes; native WRITES only to + your own draft artifact under the notes path the brief names. +- **Inbox** for receiving context and posting artifact refs, when the brief wires it. + +Everything else — `task_doc`, `worktree_*`, `lifecycle_*`, `gate_*`, `spawn_agent_session`, +`memory_*`, git — is the owning seat's machinery, not yours. **Reader, not mutator.** + +## Knobs + +| Knob | Default | Notes | +| ------- | ----------------- | ----- | +| harness | claude | default preference only — settings picks the actual harness | +| model | highest-reasoning | whole-portfolio dependency + blast-radius reasoning wants the strongest model | +| effort | high | the sprint plan parameterizes every downstream loop; not the place to economize | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | read-only analysis surface | `read_ar_files` · `grepai_*` · `cgc_*` · `context_packet` · `drift_check` · notes-draft write · inbox | + +Settings.json `orchestration.roles.strategist` overrides these, and `orchestration.rolesPerLevel..strategist` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.pi/skills/l-01-agent-lifecycles/roles/worker.md b/.pi/skills/l-01-agent-lifecycles/roles/worker.md new file mode 100644 index 00000000..f5c369b4 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/roles/worker.md @@ -0,0 +1,136 @@ +# Lifecycle — Worker + +> One leaf, one session, one report. The worker lifecycle is **self-contained**: everything this +> seat does is on this page, and your **brief is your session start** — a workspace session-start +> notice is not addressed to you. + +## What This Seat Is + +**One per task leaf, short-lived, fresh session.** Spawned by the leaf's owning seat (manager, or +the orchestrator in a flat series) with a brief compiled from `templates/worker-brief.md`. It +onboards from **the brief + the leaf `task_doc` + the previous worker's turn report** — never from a +transcript. Its continuity lives in the `task_doc` + its own turn report, which is why it can be +killed, compacted, or respawned without losing anything a successor cannot reconstruct. + +The worker builds; it does not manage lifecycle machinery. **Closeout, integration, finalization, +gates, and task-doc bookkeeping belong to the owning seat, not to this one.** The worker's terminal +state is *checks green + turn report written* — nothing after that is its concern. + +## The Worker Loop + +``` +brief -> orient -> build (edit + onboarding same-pass) -> checks green -> turn report -> end + | + +-- blocked or plan delta beyond blank-filling -> escalate to the owning seat +``` + +### 1 — Intake + +Read the brief fully, then the leaf spec / `task_doc` it names. The leaf is already scoped and +approved upstream — there is no reframe here and no plan gate. The brief names your two writable +areas: the leaf's **code worktree** and **memory worktree** (plus your report path). You edit +nothing outside them. + +### 2 — Orient (paired reads before edits) + +- Read the files you will touch **paired with their onboarding** — via the `read_ar_files` MCP tool + (note: it serves the official baseline, not your worktree) and native reads inside the worktree + for current state. Native read is your edit precondition. +- Retrieval when the leaf needs it: `grepai_search` (semantics), `cgc_*` (relationships) — both + read-only, with whatever stack key the brief names. Keep the evidence tally your brief asks for + (calls made, files inspected, gaps remaining). + +### 3 — Build + +- Implement exactly the leaf plan; fill small, unambiguous blanks a competent implementer would + fill (see "Default Behavior" below). +- **Refresh the matching onboarding in the same editing pass** per + `c-05-create-or-update-onboarding-files`: a changed source file's sidecar **body** is updated now; + a new file's sidecar is created; route overviews that need a genuine body update get one, and a + no-impact route gets the literal history form `- — No route impact: `. + Regenerate generated route indexes with a **local `build_route_indexes(...)`** invocation from the + memory worktree. +- **Never `git commit`.** Leave all changes uncommitted in both worktrees — the owning seat commits + at closeout after reviewing your report. + +### 4 — Checks (green before you report) + +Run what the brief prescribes — typically the focused suite over your changed paths plus the full +`system/tools.md` wrapper from the code worktree root — and record the exact commands + outcomes for +the report. A red check you cannot fix inside the leaf's scope is an escalation, not a workaround. + +### 5 — The Turn Report (mandatory, your last act) + +Write `templates/turn-report.md` to the path the brief names (convention: +`notes/reports/-worker-report.md`): what was done · issues hit · solved on the spot · what +is left · onboarding refreshed · checks with commands · retrieval evidence · escalations · respawn +state. **A missing report gets nudged.** The report is the leaf's artifact of record and how a +respawned successor onboards — write it even when blocked (with the Escalations section filled), +then end your turn. + +## Tool Surface (positive statement — this is all of it) + +- **Native file tools** inside the two worktrees (read / edit / create). +- **Read-only AR retrieval:** `read_ar_files`, `grepai_search`, `cgc_*`, `context_packet`. +- **Shell** for the prescribed checks (use the interpreter paths the brief names — do not assume a + `python` shim exists). +- **Inbox** (`operator_inbox_post` / `_poll` / `_consume`) for receiving context and raising + escalations, when the brief wires it. + +Everything else — `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, +`route_index_refresh` — is the owning seat's machinery, not yours. A worker that never touches +lifecycle machinery never instantiates a lifecycle; that is the designed shape, not a gap. + +## Fan-Out (capability doctrine — any harness that has it) + +When the harness offers sub-agents, use them for **read/search only**, scoped to the leaf (locate +call sites, sweep onboarding): each writes durable notes and returns a compact summary. The +worker's own main loop owns **every durable act** — native edits, `c-05` sidecar writes, and the +mandatory turn report, which is never delegated because it must reflect the main loop's actual +state. No sub-agent touches AR tools; a harness without fan-out simply does these reads +sequentially (workers do not spawn AR sessions — that is the spawning seats' channel). + +## Loop Position (when the leaf runs as a three-party loop) + +The owning seat scores each leaf into a tier at dispatch (loop doctrine: `../SKILL.md`, The +Three-Party Loop). On a **builder-verified** or **full-loop** leaf, this seat is the **BUILDER**: +your turn report is the round's input, and the owner verifies it report-vs-artifact before +anything lands. Two consequences for you: + +- **Fix rounds resume THIS session** — the same builder, with its context intact. Your round-2+ + report **appends** to your report file rather than rewriting it, so the loop history stays + legible. +- **Rounds are capped and must converge**, but the cap, the convergence call, and any escalation + are the OWNER's controls, not yours. You build and report honestly; if you disagree with a + reviewer finding you were handed, say so **with evidence in your report** — the owner rules, + you never argue a verdict into the code. + +## Default Behavior + +**Fulfill the task, fill small blanks.** No creative-liberty prompting in either direction. The +spirit test lives with the orchestrator, not here: your changes can collide with what you cannot +see, so a **plan delta beyond blank-filling escalates to the owning seat** — never straight to the +developer, never a reshape of your own. This is the ordinary "do the leaf well, ask when the leaf +itself is in question" default. + +## Comms + +- **Inbox** — receive dispatch/context; post escalations; agent-to-agent rows carry role metadata + and a `messageKind` (`turn-report`, `nudge`, `escalation`, …), durable + dashboard-visible. +- **Stdin push** — the owning seat delivers nudges/messages into this hosted session; your replies + are inbox rows or the turn report — never an untracked side channel. +- **Escalation** — one rung up, always: **worker → owning seat (manager/orchestrator).** + +## Knobs + +| Knob | Default | Notes | +| ------- | -------------- | ----- | +| harness | codex | default preference only — settings picks the actual harness | +| model | mid-reasoning | competent implementer on a scoped leaf | +| effort | medium | scales with leaf difficulty via settings | +| launchArgs | — | free-form escape: verbatim harness argv (settings-only; never validated, recorded in spawn provenance) | +| sessionCommands | — | free-form escape: lines pasted + submitted into the fresh session before the brief (settings-only; never validated) | +| promptKeywords | — | free-form escape: prepended as the first line of the dispatch brief paste (settings-only; never validated) | +| tools | build surface | native edit · read-only AR retrieval · prescribed checks · inbox | + +Settings.json `orchestration.roles.worker` overrides these, and `orchestration.rolesPerLevel..worker` overrides per dispatch level (role-file defaults < settings < level override; spawn knobs manual: `docs/reference/harnesses.md`). diff --git a/.pi/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md b/.pi/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md new file mode 100644 index 00000000..a751a6b1 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/conversation-handover-packet.md @@ -0,0 +1,54 @@ +# Conversation-Handover-Packet Template + +**One schema, three uses** (design record, the COMMS model): **role takeover** (profile-fit — the orchestrator's +Profile check (takeover) — `roles/orchestrator.md`, The Event Loop — spawns the correct profile and hands over), **worker respawn** (a fresh worker continues a leaf), and +any **master-complete handover** that needs the receiver to onboard from **state, not the transcript**. +The receiver always onboards from this packet, never from a prior conversation. + +## Rules + +1. The receiver must be able to act from this packet **alone** — assume the transcript is gone. +2. Name the request, the decisions already made, the constraints, the links, and the open questions. +3. For a **takeover spawn**, state the profile mismatch that triggered it, so the successor knows why it + exists and does not repeat the wrong-profile work. + +## Shape + +```md +# Conversation Handover — + +| Field | Value | +| ------------- | ------------------------------------------------- | +| use | role-takeover | worker-respawn | master-handover | +| seat / role | designer | orchestrator | manager | worker | reviewer | +| from | | (developer) | +| to | | +| leaf / master | | +| written | | + +## Why This Handover +- role-takeover: profile mismatch — wanted , session was ; taking over on the right profile. +- worker-respawn: . +- master-handover: . + +## The Request (as agreed) +- + +## Decisions Already Made +- (decision-log ref …) + +## Constraints & Invariants +- + +## Links (onboard from these, not the transcript) +- task_doc: · integration branch: · prior turn report(s): +- durable notes / reports: + +## Open Questions For The Successor +- + +## Current State +- Position in the plan / DAG: +- Committed vs uncommitted: +- The one thing to know before the next action: +``` diff --git a/.pi/skills/l-01-agent-lifecycles/templates/deep-research-report.md b/.pi/skills/l-01-agent-lifecycles/templates/deep-research-report.md new file mode 100644 index 00000000..ee971166 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/deep-research-report.md @@ -0,0 +1,123 @@ +# Deep Research Report Template + +Use this template after the developer-agreed reframe and before the lifecycle's +`decide` step. The lifecycle owns when deeper research happens and which proof +categories are required; this template owns the report shape, evidence IDs, and +optional sections. + +For small research-only answers, use the compact shape. For ambiguous, +architectural, taxonomy-heavy, bug-root-cause, triage-routing, or build-spawning +work, use the full shape. + +## Report Rules + +1. Keep the report claim-first: findings state what is now believed to be true. +2. Treat evidence rows as proof records, not activity logs. +3. Every finding cites evidence IDs, and every evidence row names the claim it proves. +4. Mark inference separately when the report reasons across multiple evidence rows. +5. Keep limits visible: every evidence row should say what it does not prove. +6. End with the lifecycle decision: research-only exit or recommended follow-up build. + +## Full Shape + +```md +# Deep Research Report: + +## Frame + +- Surface request: +- Deeper objective: +- Agreed scope: +- Non-goals: +- Invariants: +- Truth gaps before research: + +## Short Answer + + + +## Findings + +- F-01: [E-01, E-03] +- F-02: [E-02] + +## Evidence Ledger + +| ID | Kind | Source / Query | Claim Proven | Limits | +|----|------|----------------|--------------|--------| +| E-01 | Semantics | query: "" | F-01 | Does not prove runtime behavior. | +| E-02 | Intent | onboarding: ``; source: `` | F-02 | Covers committed HEAD only. | +| E-03 | Relationship | cgc callees/deps: `` | F-01 | Does not prove hidden business intent. | + +## Proof Inventory + +- Onboarding docs read: +- Semantic queries performed: +- Code graph queries performed: +- Source files inspected: +- External references checked: +- Executable validations run: + +## Remaining Truth Gaps + +| Gap | Why It Matters | Blocks Build? | +|-----|----------------|---------------| +| | | yes/no | + +## Decision + +- Research-only exit: +- Spawn build? +- Suggested artifact shape if spawned (minimal `w-02` task vs master + series): +- Plan-gate status: +``` + +## Compact Shape + +```md +## Short Answer + + + +## Evidence + +- E-01 (): proves ; limits: . + +## Proof Inventory + +- Onboarding docs read: +- Semantic queries performed: +- Code graph queries performed: +- Source files inspected: + +## Remaining Truth Gaps + +- + +## Decision + + +``` + +## Evidence Kinds + +- `Semantics`: fuzzy routing through GrepAI or onboarding search. +- `Relationship`: CodeGraphContext callers, callees, dependencies, impact, or neighboring structure. +- `Intent`: paired onboarding plus bounded source confirmation for contracts, invariants, behavioral expectations, or branch-valid truths. +- `External`: domain documentation, standards, issues, PRs, release notes, or other non-repo references. +- `Executable`: reproduction steps, tests, scripts, command output, or generated validation artifacts. +- `Developer`: explicit clarification from the developer; verify against source before treating it as durable current-state knowledge. +- `Inference`: reasoning across evidence rows. Cite the input evidence IDs in `Source / Query` and state the remaining uncertainty. + +## Evidence Ledger Guidance + +The evidence ledger should be precise enough that another agent can tell why a +claim is supported without rerunning the entire investigation. Prefer concrete +paths, query strings, anchors, and command names over prose summaries. + +Use `Limits` to prevent overclaiming. Examples: + +- `Routes the feature area but does not prove current source behavior.` +- `Confirms the source contract at HEAD, not dirty work-in-progress.` +- `Shows the call path but not whether the path is user-facing.` +- `Explains the documented intent but needs executable validation before build.` diff --git a/.pi/skills/l-01-agent-lifecycles/templates/impact-analysis.md b/.pi/skills/l-01-agent-lifecycles/templates/impact-analysis.md new file mode 100644 index 00000000..a9c97ff4 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/impact-analysis.md @@ -0,0 +1,52 @@ +# Impact-Analysis Template + +A durable report a fan-out sub-agent writes for the **orchestrator** (portfolio phase) or the +**adversarial reviewer** (completion + code-quality lenses). It is the **integrity-bulwark** artifact: +planned-vs-planned **and** planned-vs-past blast radius. Sub-agents WRITE it; AR state mutations stay in +the spawning agent's main loop. + +## Rules + +1. Cover **two axes**: planned-vs-planned (does this change collide with another master/leaf, present or + future?) and planned-vs-past (does it regress something already landed — the "fixed one, broke two" + surface?). +2. Evidence-first: cite the route indexes, `cgc_*` queries, `grepai_search` queries, and + `read_ar_files` reads that back each finding. +3. State limits per finding — what the evidence does **not** prove. +4. This is a report, not a decision: it feeds the orchestrator's spirit test / reshape proposals or the + reviewer's verdict; it never decides. + +## Shape + +```md +# Impact Analysis — + +| Field | Value | +| --------- | -------------------------------------------- | +| for | orchestrator (portfolio) | reviewer () | +| author | | +| subject | | +| written | | + +## Surface Swept +- Routes / areas touched: +- Anchors: + +## Planned-vs-Planned (collisions with other masters/leaves — incl. FUTURE) +| Collision | With (master/leaf) | Kind (code | memory | sequencing) | Evidence | Limits | +| --------- | ------------------ | --------------------------------- | -------- | ------ | +- Recommended resolution: up-front foundation-master extraction | leaf move | sequential ordering | none needed + +## Planned-vs-Past (regression surface) +| Risk | Landed thing at risk | Evidence (cgc/grepai/route index) | Limits | +| ---- | -------------------- | --------------------------------- | ------ | + +## Evidence Inventory +- Route indexes read: +- cgc queries (callers/callees/deps/impact): +- grepai queries: +- read_ar_files reads (paired source+onboarding): + +## Bottom Line (for the spawning agent's main loop) +- — no mutation performed here. +``` diff --git a/.pi/skills/l-01-agent-lifecycles/templates/manager-brief.md b/.pi/skills/l-01-agent-lifecycles/templates/manager-brief.md new file mode 100644 index 00000000..10c37922 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/manager-brief.md @@ -0,0 +1,62 @@ +# Template — Manager Brief + +The dispatch packet the orchestrator compiles for a manager taking one master. Like the worker +brief, **this brief is the manager's entire session start** — it replaces the front half the +orchestrator already ran. Spawn with `env={"AR_SPAWN_ROLE": "manager"}` and the **qualified** leaf +key of the master's coordination leaf (`//`). + +--- + +```md +ROLE BRIEF — manager + +# MANAGER BRIEF — · + +You are the MANAGER for master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/manager.md`; this brief is your session start. Drive this +master's leaf loop to the master-exit seam, then hand over. + +## The master +- Task doc: `` (read it + every leaf doc first). +- Planner master: +- Leaves, in order: . +- Trust facts (compiled by the orchestrator — do not re-run the checkpoint): providers , drift , freshness . + +## The branch base (load-bearing) +- Your master integration branch: ``, based off the CURRENT super branch + `` @ `` — master branches base off super, never off main. +- Leaf worktrees base off your master branch (normal `worktree_start` per leaf). + +## Dispatch defaults +- Worker spawns: `templates/worker-brief.md`, `env={"AR_SPAWN_ROLE": "worker"}`, qualified leaf + keys; knob overrides: . +- Concurrency: . + +## The exit +- When all leaves have landed on your branch: spawn the master-exit reviewer + (`env={"AR_SPAWN_ROLE": "reviewer"}`, `roles/reviewer.md`) with the scope packet your role file + enumerates; then RAISE the gate without blocking — + `lifecycle_gate(kind="master-handover-approval", enclosure="", + evidence_refs=[], wait=false)` — the `enclosure` MUST carry the master's identity: + the EXACT master task name as the contracts carry it (the raise refuses without one) — + and post the master-handover packet **carrying the returned gateId**: the ORCHESTRATOR decides + the gate by that id. Under an all-human policy the raise blocks and the developer decides — do + not pass wait=false. +- Escalation: to the orchestrator, never the developer. Human-pinned kinds you may meet: + `integration-approval`, `push-approval`, `cleanup-approval`. + +## Reports +- Your handover packet: `../templates/master-handover-packet.md`. +- Leaf-review notes on your coordination leaf; decision-log entries for every delegated gate you + decide and every reopen. +``` + +--- + +**Compiler notes for the orchestrator.** + +- Fill every ``; an unresolved placeholder is not dispatchable. +- The super-tip commit you write here is the reconciliation anchor if a sibling master lands + first — state it explicitly. +- Deliver as an echo-confirmed paste; only count delivery on a post-boot echo. diff --git a/.pi/skills/l-01-agent-lifecycles/templates/master-handover-packet.md b/.pi/skills/l-01-agent-lifecycles/templates/master-handover-packet.md new file mode 100644 index 00000000..c8f5cb5c --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/master-handover-packet.md @@ -0,0 +1,49 @@ +# Master-Handover-Packet Template + +The artifact a **manager** posts to the **orchestrator** at master exit (`roles/manager.md`), after the +master-exit adversarial seam. Delivered via the inbox (durable) + stdin push. It is what the +orchestrator integrates a completed master into the super branch from. + +## Rules + +1. Post it only **after** the master-exit verdict exists — the verdict reference is a required slot. +2. Name the integration branch precisely; the orchestrator bases its C-11 integration on it. +3. The carry-over state must let the orchestrator's `c-11-memory-carryover-from-branch` integration run + without re-deriving what landed. +4. Post the packet as an `operator_inbox_post` row with `messageKind="master-handover"` and push + delivery enabled so the durable inbox row and stdin notification agree. + +## Shape + +```md +# Master Handover — · + +| Field | Value | +| ------------------ | -------------------------------------------- | +| master | | +| manager seat | | +| integration branch | | +| handover gateId | | +| base | | +| verdict | | +| verdict outcome | pass | pass-with-notes | +| written | | + +## Change-Set Summary +- +- Leaves landed: , … + +## Requirements / Steps Completion +- All master requirements addressed: yes | with justified deltas (decision-log refs: …) + +## Carry-Over State (for the orchestrator's master → super C-11) +- Memory rows parked / carried: +- Ledger maps every leaf commit: yes | +- Single-siding notes (if this master overlaps another strand): + +## Known Follow-Ups +- | none + +## Reachability +- Manager seat (chat + coordination leaf) stays reachable until the series retires. +``` diff --git a/.pi/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md b/.pi/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md new file mode 100644 index 00000000..81c2466b --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/onboarding-coherency.md @@ -0,0 +1,48 @@ +# Onboarding-Coherency Template + +A durable report a fan-out sub-agent writes for the **adversarial reviewer's** third lens +(onboarding-vs-code) and for the **orchestrator's** memory-quality checks. It is the paired +`read_ar_files` + `memory_quality_check` + `drift_check` review made durable — the check that the +memory repo stayed in lockstep with the code, since **orchestrator quality ∝ memory-repo quality**. + +## Rules + +1. Every **changed** source file must have its sidecar body updated **in the same pass** — a refreshed + `lastVerifiedCommitHash` over stale content silently defeats the drift check and is a finding. +2. Every **new** source file must have a created sidecar (`check_missing_onboarding` clean). +3. Route/repository overviews must reflect the change set; a moved/added/deleted slice must be + reflected in the governing overview. +4. This is a report; the reviewer's verdict or the orchestrator's main loop acts on it. + +## Shape + +```md +# Onboarding Coherency — + +| Field | Value | +| --------- | --------------------------------------- | +| for | reviewer () | orchestrator | +| author | | +| scope | | +| written | | + +## Changed Files — Sidecar Refresh +| Source file | Sidecar updated same pass? | Body reflects change? | Finding | +| ----------- | -------------------------- | --------------------- | ------- | + +## New Files — Missing Onboarding +| New source file | Sidecar created? | check_missing_onboarding clean? | Finding | +| --------------- | ---------------- | ------------------------------- | ------- | + +## Drift & Quality +- drift_check: clean | actionable (list) +- memory_quality_check: pass | +- Ledger maps code HEAD: yes | + +## Overviews +- Route/repository overviews current for touched routes: yes | +- Moved/added/deleted slices reflected in governing overviews: yes | + +## Bottom Line +- Onboarding-vs-code coherent: yes | NO — +``` diff --git a/.pi/skills/l-01-agent-lifecycles/templates/orchestration-task.md b/.pi/skills/l-01-agent-lifecycles/templates/orchestration-task.md new file mode 100644 index 00000000..c3d4bb08 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/orchestration-task.md @@ -0,0 +1,89 @@ +# Orchestration-Task Template + +The artifact a **strategist** drafts for the **orchestrator** (`roles/strategist.md`) — the sprint +plan and the sprint scope. A strategist run producing this artifact is a **mandatory precondition +for any orchestrated run**; the orchestrator adopts the accepted draft into durable task form (the +strategist is a reader, not a mutator). It is written under the series/coordination `notes/` path +the brief names and revised across drawing-board rounds. + +## Rules + +1. **Shown work is required per section.** Every dependency edge carries evidence (a tool query, a + file, a decision-log entry, a design-section citation, or — for new surfaces — a **declaration + cross-reference**: the two leaf declarations that couple) — an uncited edge is refutable by + default. Every blast-radius entry names its derivation (caller-set / doctrine-propagation / + migration / user-visible). Every leaf move carries from→to + rationale. +2. **Surfaces are two-sided:** the surface lists distinguish **existing** surfaces (mapped against + the route map) from **new** surfaces (greenfield, mapped by declaration: parent route/location + + intended shape). New-surface edges come from declaration cross-reference — leaf B naming a + surface leaf A creates is a pure ORDER edge; two leaves declaring additions under one parent + route is a CONFLICT-risk edge at the parent. +3. **Coherence findings include the honest failures:** a leaf that can name neither existing + surfaces nor the parent anchoring of its additions is recorded as **"unplannable as scoped"** — + never silently guessed around (a merely not-yet-existing surface is NOT unplannable). Directional + cross-master contradictions are flagged quo-vadis at the top of that section. +4. This is a **draft for adoption**, not a mutation: the strategist never edits task docs; the + orchestrator (the portfolio owner) adopts the plan and records the adoption in the decision log. +5. The plan is reviewed adversarially (the plan-review criteria catalog, + `../criteria/plan-review.md`) before the developer's drawing board; revisions append round + sections rather than rewriting history. +6. Once adopted, this artifact is the sprint's standing scope: in-sprint additions before + implementation starts trigger re-evaluation; out-of-sprint additions wait for the next sprint. + +## Shape + +```md +# Orchestration Task — · + +| Field | Value | +| ---------------- | ------------------------------------------------ | +| strategist | | +| masters in scope | | +| status | draft | in-review | round- | adopted | +| round | (3-round cap; the drawing board is the escalation) | +| written | | + +## Sprint Scope +- IN: +- OUT: + +## Touch Surfaces (per leaf — two-sided) +| Leaf | Existing surfaces (route-map-mapped) | New surfaces (declared: parent route/location + intended shape) | +| ---- | ------------------------------------ | ---------------------------------------------------------------- | + +## Dependency Graph (every edge cited — an uncited edge is refutable by default) +| From (leaf/master) | To | Kind (ORDER | CONFLICT | INDEPENDENT) | Evidence (cgc/grepai query · file · decision-log · design § · declaration cross-reference) | +| ------------------ | -- | ------------------------------------ | ------------------------------------------------------------------------------------------ | + +## Blast-Radius Register (feeds the owning seat's loop-tier scoring) +| Leaf | Radius (low | medium | high) | Derivation (caller-set | doctrine-propagation | migration | user-visible) | Evidence | +| ---- | ---------------------------- | ------------------------------------------------------------------------- | -------- | + +## Leaf Moves +| Leaf | From (master) | To (master) | Rationale | +| ---- | ------------- | ----------- | --------- | + +## Coherence Findings +- ⟁ QUO-VADIS (developer decision required): | none +- +- Unplannable as scoped: | none + +## Sprint Order / Waves +1. (note the + landing-reconciliation cost of parallel waves as a scheduling consideration) +2. + +## Open Risks +- + +## Re-Evaluation Triggers +- In-sprint master added before implementation starts → re-plan (strategist re-evaluates). +- Master added outside the sprint scope → next sprint's evaluation. +- + +## Evidence Inventory +- cgc queries (dependencies/callers/callees/complexity): +- grepai queries (search/trace): +- read_ar_files reads (paired source+onboarding) / route indexes read: +- task docs, decision logs, and design sections cited: +``` diff --git a/.pi/skills/l-01-agent-lifecycles/templates/turn-report.md b/.pi/skills/l-01-agent-lifecycles/templates/turn-report.md new file mode 100644 index 00000000..b771ada4 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/turn-report.md @@ -0,0 +1,57 @@ +# Turn-Report Template + +The **mandatory** artifact a worker writes at **every** hand-off (`roles/worker.md`). It is how the +leaf's work survives the session's death and how a respawned successor onboards from **state, not the +transcript**. A missing turn report is nudged by the manager. + +## Rules + +1. Write it in the **main loop**, from your own work plus any sub-agent summaries — never delegate it to + a sub-agent (it is the leaf's single artifact of record). +2. State facts, not a narrative: what changed, what broke, what is proven green, what remains. +3. The **Respawn State** section must let a fresh successor continue **without reading any transcript**. +4. Keep it durable and in the series notes; reference it from the leaf `task_doc`. +5. Default path: `notes/reports/-worker-report.md`. The control-plane helper exposes this + convention so manager nudges and respawn onboarding can point at the same artifact. + +## Shape + +```md +# Turn Report — · + +| Field | Value | +| ------------ | --------------------------------------- | +| leaf | | +| master | | +| worker | | +| worktree | | +| status | in-progress | leaf-complete | blocked | +| checks | green | failing: | not-yet-run | +| written | | +| inbox | | + +## What Was Done +- (files: ``, …) + +## Issues Hit +- → resolved: | still open: + +## Solved On The Spot +- (a plan delta beyond blank-filling is NOT here — it was + escalated to the manager; see Escalations) + +## What Is Left +- [ ] + +## Onboarding Refreshed +- in this pass (c-05) + +## Escalations +- | none + +## Respawn State (onboard a successor from this — no transcript needed) +- Current position in the leaf plan: +- Files touched so far: +- The one thing a successor must know before editing: +- Uncommitted vs committed state: +``` diff --git a/.pi/skills/l-01-agent-lifecycles/templates/verdict.md b/.pi/skills/l-01-agent-lifecycles/templates/verdict.md new file mode 100644 index 00000000..3f292443 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/verdict.md @@ -0,0 +1,142 @@ +# Verdict Template (adversarial reviewer) + +The artifact an **adversarial reviewer** writes at a seam (`roles/reviewer.md`). It lands +under the series `notes/reports/` directory and attaches to the handover gate as **judge evidence**. +There are two variants: **master-exit** (before a manager hands over to the orchestrator) and +**super-exit** (before the orchestrator hands over to the developer) — plus a loop-review +adaptation of the master-exit shape (see Loop-Review Adaptation below). + +## Rules + +1. **A verdict is evidence, not a decision.** State an explicit pass/block **recommendation**; the gate's + decider decides. Never write the verdict as if it were the gate outcome. +2. **A block must decompose into fix leaves** — concrete, leaf-shaped findings the owning + manager/orchestrator can dispatch. A block that cannot be named as fix leaves is not yet a block. +3. **Refute-or-confirm:** every finding must survive an attempt to refute it. Rank findings and cite + the backing evidence file. +4. Cover all three lenses (completion · code quality · onboarding-vs-code) explicitly, even to say a + lens is clean. +5. Record the gate evidence reference exactly: `kind=reviewer-verdict`, `ref=`, and + `verdict=`. +6. **Report every bound catalog criterion** in the Criteria Catalog Results table (the catalogs the + binding table in `roles/reviewer.md` assigns this review type, `../criteria/`) — one row per + standing criterion even when it found nothing, candidate rows when run — and carry any proposed + catalog amendments (the promotion ratchet) in that section. + +## Master-Exit Variant + +```md +# Adversarial Verdict — master-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | master-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | orchestrator (delegated `master-handover-approval`; serious issues escalate → developer) | +| artifact path | notes/reports/-master-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Task Docs +- Master requirement/substep coverage: addressed | delta justified | MISSING +- Leaf task docs and worker reports reconcile with the master task_doc: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite: green | failing: +- regressions vs the past (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- master-side route overviews current: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Manager Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the master-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Super-Exit Variant + +```md +# Adversarial Verdict — super-exit · + +| Field | Value | +| --------------- | -------------------------------------------------- | +| seam | super-exit | +| scope | | +| reviewer | | +| task docs | | +| recommendation | PASS | PASS-WITH-NOTES | BLOCK | +| decider | developer (human review concentrates at the super gate) | +| artifact path | notes/reports/-super-exit-verdict.md | +| gate evidence | kind=reviewer-verdict; ref=; verdict= | +| written | | + +## Lens 1 — Completion vs Portfolio Task Docs +- Portfolio objective and dependency order satisfied: yes | +- Master handover packets and prior master-exit verdicts reconciled: yes | +- Cross-master conflicts, duplicate implementations, and deferred follow-ups surfaced: yes | +- backing evidence file: + +## Lens 2 — Code Quality +- resolved system/tools.md suite for the accumulated super branch: green | failing: +- branch-wide regressions vs the past and across masters (route indexes · CGC · GrepAI): none | +- backing evidence file: + +## Lens 3 — Onboarding vs Code +- changed files' sidecars refreshed same pass: yes | +- drift_check clean and memory_quality_check clean: yes | +- route overviews describe the accumulated behavior: yes | +- C-11 carry-over and ledger mapping coherent for the final super branch: yes | +- backing evidence file: + +## Criteria Catalog Results (every bound criterion reported — see roles/reviewer.md binding table) +| Criterion (id · catalog) | Ran | Finding | Evidence | +| ------------------------ | --- | ------------- | -------- | +| | yes | none | | +- Proposed catalog amendments (promotion ratchet): | none + +## Findings (ranked; each refute-tested) +| # | Severity | Finding | Evidence file/ref | Refutation attempted | Survives? | +| - | -------- | ------- | ----------------- | -------------------- | --------- | + +## If BLOCK — Orchestrator Fix Leaves +1. + (A BLOCK with no fix leaves here is invalid — resolve to PASS-WITH-NOTES or name the leaves.) + +## Judge-Evidence Note +This verdict attaches to the super-exit handover gate as judge evidence. The decider decides; this +reviewer does not. +``` + +## Loop-Review Adaptation (leaf full-loop · plan review) + +A three-party-loop review (a full-loop leaf round, or the plan review over an orchestration task) +uses the **master-exit variant's shape minus the gate machinery**: drop the `gate evidence` header +row and the Judge-Evidence Note (a loop review attaches to no gate), set `decider` to the **loop +owner** (the leaf's owning seat, or the orchestrator for the plan review), scope to the round's +change set (or the orchestration-task draft), and keep everything else — recommendation, Criteria +Catalog Results (the loop's bound catalogs, e.g. `plan-review` + `report-verification` for a plan +review), ranked refute-tested findings, and fix decomposition. The verdict remains **evidence to +the loop owner, never a decision**; a delta-verify appends a dated delta section to this same +artifact rather than opening a new one. diff --git a/.pi/skills/l-01-agent-lifecycles/templates/worker-brief.md b/.pi/skills/l-01-agent-lifecycles/templates/worker-brief.md new file mode 100644 index 00000000..db8f44d0 --- /dev/null +++ b/.pi/skills/l-01-agent-lifecycles/templates/worker-brief.md @@ -0,0 +1,72 @@ +# Template — Worker Brief + +The dispatch packet a spawning seat (manager / orchestrator) compiles for a worker. **The brief is +the worker's entire session start** — it replaces the front half the spawner already ran (trust +checkpoint, reframe, plan). Compile it fresh per leaf from this shape; the proven form below +absorbed a series of real dispatch frictions (route-index leaks, attestation format, provider-stack +keying, missing `python` shim), so deviate knowingly or not at all. + +Spawn with `env={"AR_SPAWN_ROLE": "worker"}` and the **qualified** leaf key +`//` so the session-start router and the dashboard leaf rail both engage. + +--- + +```md +ROLE BRIEF — worker + +# WORKER BRIEF — · + +You are a WORKER for leaf `` of master `` (repo: ). Your lifecycle is +`skills/l-01-agent-lifecycles/roles/worker.md`; this brief is your session start. Execute the leaf +completely, write your turn report, then stop. + +## Worktrees (your ONLY writable areas) +- Code: `` (branch ``, base ``) +- Memory: `` +- Plus your turn report at the path below. Nothing else. NEVER `git commit` — the owning seat + closes out after reviewing your report. + +## Tool surface +- Native file tools inside the two worktrees; shell for the checks below. +- Read-only AR retrieval: `read_ar_files` (serves the OFFICIAL baseline, never your worktree — + final verification uses native reads), `grepai_search` / `cgc_*` (provider stack key: + ``), `context_packet`. +- No `worktree_*`, `lifecycle_*`, `task_doc`, `gate_*`, `memory_*`, or `route_index_refresh` — + generated route indexes are regenerated with a local `build_route_indexes(...)` from the memory + worktree. +- Interpreter: `` with `PYTHONPATH=/mcp/src` — there is no + `python` shim in this environment. + +## The task +Leaf spec: `` (read it first). + +## Checks (green before you report) +- Focused: . +- Full: — must exit 0. +- `git diff --check` in both worktrees. + +## Onboarding (same editing pass, per c-05) +- Changed source files: update the sidecar BODY now; new files: create the sidecar. +- Route overviews: genuine body update where routes changed; otherwise the newest history entry + uses the LITERAL form `- — No route impact: ` (timestamp first). +- Pin idiom for verification metadata: "Verification metadata pinned until closeout stamps the + commit." + +## Turn report (mandatory, last act) +Write `/-worker-report.md` following +`skills/l-01-agent-lifecycles/templates/turn-report.md` — including exact check commands + +outcomes, the retrieval-evidence tally, and the respawn state. If blocked: fill Escalations and +stop — escalate to , never to the developer. +``` + +--- + +**Compiler notes for the spawning seat.** + +- Fill every ``; a brief with an unresolved placeholder is not dispatchable. +- Verify the provider stack actually answers before naming it; write `NONE (native reads only)` + when it does not — a worker discovering dead providers mid-leaf wastes its turn. +- Deliver as an echo-confirmed paste; verify the harness's paste chip (`[Pasted Content N chars]`) + before submitting, and only count delivery on a post-boot echo. +- The report path lives under the series `notes/reports/` — the same folder the seam verdicts use. diff --git a/.pi/skills/l-01-session-job-lifecycle/SKILL.md b/.pi/skills/l-01-session-job-lifecycle/SKILL.md deleted file mode 100644 index 9b3cc6d6..00000000 --- a/.pi/skills/l-01-session-job-lifecycle/SKILL.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -name: l-01-session-job-lifecycle -description: "The session job lifecycle the coordinator routes every session into: request -> context/trust checkpoint -> developer-agreed reframe -> deeper research -> decide build mode -> build -> close. Owns research-only exits, the build-mode decision (chat build vs durable w-02-light-task-workflow task), and the job lens (bug/feature/triage/research). Supersedes the retired chat workflow by migrating and modernizing its doctrine." ---- - -# l-01-session-job-lifecycle Session Job Lifecycle - -The `l-01-session-job-lifecycle` skill is the **canvas** the coordinator routes into at the start of every session. -It is not a task format. A task format is one outcome of a single step inside it. - -The lifecycle is one shared spine with thin per-job lenses. Its front half is a -developer/model collaboration loop: the developer states the request, the model -runs mandatory MCP grounding checks, the model presents an evidence-backed -reframe, and the developer agrees or revises that reframe before deeper research -or build-mode decisions proceed. - -## Companion Files - -1. `job-variants.md` — the four thin job lenses (bug / feature / triage / research). -2. `deep-research-report-template.md` — the reusable report and evidence-ledger shape for deeper research. - -``` -0 Request -> 1 Trust Checkpoint -> 2 Reframe + Research -> 3 Decide -> 4 Build -> 5 Close - | - +-- research-only (e.g. investigation, code questions...) -``` - -## Hand-off Protocol — Dry-run action => "Notify-and-stop" Action => "Report" Action - -Every developer hand-off / gate moment — reframe agreement, plan gate, worktree intent, commit -approval, push approval, integration, cleanup/finalization, regular turn-end — is **notify-and-continue**: -surface an attention item, present the result, and **end your turn**; the developer responds and your -**next** turn picks up automatically. It is **three actions, never one**: - -1. **Dry-run action.** Run applicable MCP tools in `dry-run` for the hand-off. If dry run succeeds, - proceed with the notify-and-stop action. If dry run fails, try to ammend the issue first before reporting failure. -2. **Notify-and-stop action.** Call `lifecycle_turn_end_notification(summary=…)`. It sets the new - **`awaiting-developer`** lifecycle state, surfaces a dashboard attention item, and **returns - immediately — no wait, no inbox.** This is the **last tool call of the turn** — the report prose - still follows it; do not STOP here. The developer responds on the - dashboard or in the leaf's attached chat, and the **first AR tool call of your next turn** - automatically resumes the lifecycle (`running`) and clears the attention item — you send **no** - explicit resume. -3. **Report action.** Deliver the complete hand-off report as plain assistant output - (the reframe, the plan, the intent packet, or the closeout relay with - preview facts, quality results, proposed commit messages, and - attestations), and make the decision you are handing to the developer the last - line of prose. **The report is the last thing in the turn — then STOP / end your turn.** - -Use the `dry-run` step to verify that the planned tool call (for example the closeout apply) will -succeed before you hand off, and self-fix any failure before reporting it. - -`lifecycle_turn_end_notification` returns immediately and does **not** render a prompt over your prose, -so the report you deliver after it is exactly what the developer sees — call the -notification, then deliver the report as your final prose, then stop. Keep the report turn free of any mutating or permission-triggering operation so -nothing obscures the report. - -Junction → Dry-run → notify (`lifecycle_turn_end_notification`) → Report. Every junction below now hands -off through that one notification; the named `kind` is the **parked** durable-gate label the fallback -would use (see "Parked fallback" below), kept so the dashboard can still classify each hand-off: - -| Junction | Parked durable gate `kind` | Skill that hands off | -| -------------------------------- | -------------------------- | ---------------------------------------------------------- | -| plan gate | `plan-approval` | `l-01-session-job-lifecycle` | -| worktree intent | `worktree-intent` | `c-09-git-worktree-manager` | -| commit / closeout | `closeout-approval` | `c-12-closeout` | -| push | `push-approval` | `l-01-session-job-lifecycle` / `c-09-git-worktree-manager` | -| integration | `integration-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| cleanup / lifecycle finalization | `cleanup-approval` | `c-09-git-worktree-manager` / `c-12-closeout` | -| any other dev-wait | `agent-question` | `l-01-session-job-lifecycle` | - -`closeout-approval` **is** the commit hand-off — there is no separate -`commit-approval`. Closeout is the single commit-of-record for code, memory, and -ledger, so every commit (including a singular one) routes through the closeout -hand-off. `agent-question` is the non-exhaustive catch-all so any dev-wait that is -not a structured junction is still observable. - -### Parked fallback — block-and-wait `lifecycle_gate` - -The block-and-wait `lifecycle_gate(kind=…)` junction (which creates a durable gate and waits for a -developer decision), the operator inbox, and the dashboard GateResponder **still exist and still work** -when explicitly raised — but they are **no longer the active path**, and nothing routes toward them: -`next_step.py` repoints every gate moment to `lifecycle_turn_end_notification`. Reach for the -server-enforced `lifecycle_gate` (followed by `lifecycle_resume` after the developer decides) only when -you deliberately need a durable, developer-attributed, mutation-blocking approval record; its `kind` -values are the table above. If you ever do raise it, it renders an approval prompt **over** your prose, -so the report must land in an earlier turn — which is exactly why notify-and-stop is preferred. - -## Lifecycle Signals — Making The Session Observable - -Every session in a managed repo is a **lifecycle**: the six `lifecycle_*` signals -record where it is and what it is waiting on, so the work is observable and -resumable across chat deaths (design `docs/design/observable-lifecycle.md`). The -model **never handles a lifecycle id** — identity is server-side, anchored in the -worktree contract. - -| When (phase) | Signal | Why | -| ---------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Trust Checkpoint passes (managed repo) | `lifecycle_start` | Begin a **fleeting** lifecycle (guarded: one per session; takes no id). | -| Entering each phase | `lifecycle_phase` | Move the orthogonal phase axis (`request`/`trust-checkpoint`/`reframe-research`/`decide`/`build`/`close`). | -| At a hand-off (reframe, plan, commit, …) | `lifecycle_turn_end_notification(summary=…)` (last tool call), then the report prose, then **STOP** | Set `awaiting-developer`, surface the dashboard attention item, and return immediately (no wait, no inbox); the next turn's first AR tool call auto-resumes (`running`) and clears the item. Block-and-wait `lifecycle_gate(kind=, ask=…, packet=…)` + `lifecycle_resume` is the parked fallback. | -| `worktree_start` (Decide → Build) | _(promotion — automatic)_ | The fleeting lifecycle becomes **persistent**, anchored in the contract; no separate signal. | -| Resuming an existing task | `worktree_attach` | Re-adopts the contract's lifecycle (contract-resolved); the model passes no id. | -| Leaving unsaved fleeting work | `switch_lifecycle` (`on_unsaved=save`\|`discard`) | The save gate: promote it or abandon it — never dropped silently. | -| Close | `lifecycle_end` (`completed`\|`abandoned`) | The terminal record. | - -Rules: `lifecycle_start` is guarded (one active lifecycle, no id). `paused` is -**system-owned** — there is no pause signal. `awaiting-developer` is set by -`lifecycle_turn_end_notification` and auto-cleared back to `running` by the next -turn's first AR tool call — you never resume it by hand. A tool call outside any -lifecycle is **dropped, never misattributed**. `worktree_start` **promotes** the current -lifecycle (fleeting → persistent); `worktree_attach` **resumes** the contract's -lifecycle; both keep identity server-side. - -## 0 — Request - -Receive the developer's raw request and identify the active repository. - -1. Treat the developer's statement as raw input, not yet as an implementation plan. -2. Infer the target code repository from the request and local context. Ask the - developer if the target is unclear. - -Request intake changes nothing. It only establishes which repository the next -checkpoint must inspect. - -The upcoming `Trust Checkpoint` reveals whether or not the request is related to repositories managed by Agents Remember. If not, then the lifecycle exits early and the agent can work as usual. - -However, if later work is to enter the boundary of repositories being managed by Agents Remember, -the lifecycle must be re-entered. - ---- - -## 1 — Trust Checkpoint - -Establish whether memory and providers are trustworthy enough to use. - -1. For the target repository, resolve coordination/memory context with - the MCP tool call: - - ```text - context_packet(repo_id="", include_providers=true, include_drift=true, include_freshness=true) - ``` - -2. Report the packet facts before relying on memory or providers: - - repository, branch, and dirty state - - memory root and onboarding root - - provider state - - drift status and actionable drift count - - branch freshness: whether the code and memory checkouts are current with - their upstreams (`behind`/`diverged` means the local official line is - stale — fast-forward it before trusting analysis or basing work on it) - and whether the ledger maps code HEAD (`ledgerMapsCodeHead=false` means - the memory checkout does not match the code state; run carryover or - check out the right memory branch first) -3. If onboarding for committed source is drifted, missing verification, or - orphaned, and the corresponding source file is not dirty in the code - worktree, stop and ask the developer whether or not to refresh it through - `c-05-create-or-update-onboarding-files`. Drift handling is approval-gated! -4. If drift is tied to dirty source, report it as active work-in-progress. Do - not adopt it as maintenance or silently trust it as current state unless the - developer explicitly says this job owns it. -5. If providers are stopped or degraded, use the matching MCP provider/runtime - operations, then re-run the provider check. If providers are ready, report - readiness and continue. If issues persist, report it to the developer and - wait for instructions. If the packet's providers summary lists `indexing` - targets, report them to the developer: those providers are healthy but - busy, and their results may be partial until the scan completes. -6. After the trust checkpoint passes, read committed-state onboarding for the - in-scope anchors as needed. A file dirty in another chat is still valid for - HEAD and worth comparing, but its dirty-source drift remains active work. - ---- - -## 2 — Reframe And Research - -Turn the developer's raw request into an agreed piece of work, then perform the -deeper research that the agreed frame requires. The `tasks/AGENTS.md` -collaboration doctrine applies here in plain chat, before any task file or task -format exists. - -**Read tool for this phase.** Until the build-mode decision (Phase 3), read managed-repo source -through the `read_ar_files` MCP tool, not the harness's native read — it returns paired -source+onboarding plus the repository/route overviews in one observable, lifecycle-attributed -call, and you keep a running count of those calls as evidence. Native read is the edit -precondition in Phase 4. - -1. **Gather evidence for the reframe** through reading the - `c-04-retrieval-strategy-router` skill. Pick the strategy by the question: - - _Semantics_ (grepai over onboarding) — "where does X live / what handles Y." - - _Relationship_ (cgc) — callers/callees/dependencies/impact. - - _Intent_ (onboarding + bounded source confirmation) — hidden contracts, invariants, - branch-valid truths, behavioral expectations. This is a workflow of paired - source+onboarding reads via the `read_ar_files` MCP tool: one call pairs each source - file with its verified onboarding and auto-attaches the repository overview + governing - route-overview chain (the bird's-eye view). -2. **Reframe** the request through `tasks/AGENTS.md`: distinguish the surface - request, deeper objective, highest-leverage framing, assumptions, boundaries, - invariants, and truth gaps. Do not rush a statement into a plan. -3. Present the reframe to the developer. If the developer disagrees, discuss and - revise the reframe. If the developer agrees, proceed to deeper research. -4. **Perform deeper research** for the agreed frame. This research still uses - `c-04-retrieval-strategy-router`, but it is now scoped by the developer-agreed - frame rather than by the model's first guess. Use - `deep-research-report-template.md` for the report shape; the lifecycle owns - the required proof categories, while the template owns evidence formatting. -5. The deeper research report must list its proof and tie evidence to the claim it supports: - - `read_ar_files` calls (paired source+onboarding reads — the running count) - - onboarding docs read - - semantic queries performed - - code graph queries performed - - source files inspected - - remaining truth gaps -6. Run the **job opening move** for the job lens (see `job-variants.md`) and use - the deeper research to name the truth gaps that remain. -7. Continue until the developer agrees the design is defined well enough to write - down, then produce the **plan**: the steps, and a **code example for every - distinct change** you intend to make. - -**Plan gate:** **hand off** before changing any code. No implementation begins -before the developer approves. Call -`lifecycle_turn_end_notification(summary={…the plan + the developer-facing approval ask…})` as the -**last tool call**, then present the plan as your final prose and **STOP**; -the developer approves on the dashboard or in chat and your next turn auto-resumes to begin -implementation. (Parked fallback: the server-enforced -`lifecycle_gate(kind="plan-approval", ask=…, packet=…)` + `lifecycle_resume` still exist if you -deliberately need a mutation-blocking approval record.) - ---- - -## 3 — Decide (build mode) - -One decision: does this job change code? - -- **No -> research-only exit.** Deliver the answer/assessment. No worktree, no task artifact, no closeout. - A research-only job may recommend or spawn a follow-up build job; it does not perform one itself. -- **Yes -> worktree intent hand-off, then always a worktree.** Read `c-09-git-worktree-manager` - and `system/git-workflow.md`, call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the worktree - intent packet as your final prose and **STOP**. The developer approves and your next turn - auto-resumes to `worktree_start`. Then open it with - `c-09-git-worktree-manager` and pick the build mode: - - **Chat build** — small enough to carry inline this session: worktree-backed, **no** `task.md`. - - **Durable task build** — hand off to `w-02-light-task-workflow`: `task.md`, checklist, decision - log, proposed code examples. Escalate to a master + light sub-task series when the work outgrows a - single-page plan. - -The worktree intent packet names the target repo, build mode, discovered branch policy, proposed -`source_branch`, proposed work branch/worktree name, memory mode, landing path, and material risks. -On PR-gated repos, the packet must prove that the recorded `source_branch` is pushable and that -protected targets are reached later through the repo's PR flow. - -Worktree granularity = the leaf task unit. A single task gets its own leaf enclosure/worktree. A -master multi-task owns a root `series-contract.md` and integration branch, while each active leaf -sub-task gets its own `enclosures//series-contract.md`, branch, and worktree. A chat build -gets its own leaf worktree without a task artifact. The git-landing decision (direct vs PR-gated) is -deferred to the repo's `system/git-workflow.md` — read it before landing on a gated branch. - ---- - -## 4 — Build - -Implement inside the worktree, keeping memory and tests in lockstep with the code. - -1. Apply the approved code changes. -2. **Refresh the matching onboarding in the same editing pass**, per completed plan-section — never - deferred to the end of the job. When a change affects durable current-state knowledge, the sidecar - is updated alongside it through `c-05-create-or-update-onboarding-files`. - - For **changed** (already-onboarded) source files, update the sidecar **body** now: the closeout - gate rejects a changed source file whose existing sidecar was not modified this job, because - refreshing `lastVerifiedCommitHash` over stale content silently defeats the drift check. - - For **new** source files, run `check_missing_onboarding` before the commit and create the - reported missing sidecars through the `c-05-create-or-update-onboarding-files` skill; the post-code-commit memory refresh stamps them with - the real code commit hash and date. -3. Run the checks from the `c-08-ar-coordination-context-resolver` resolved `system/tools.md` (lint, typecheck, complexity, tests) and - get them **green before each incremental commit**. Testing is never deferred to a final task; the - pre-commit/pre-push hooks enforce it. -4. **Watch the official line and sync early.** `worktree_status`'s `freshness` block reports when the - recorded base pair fell behind the local source branch tips (a parallel cycle landed). Pull the - moved official line in with `worktree_sync` — preferably **before memories are written**: with - parked memory the sync is a pure fast-forward, the other cycle's sidecars and ledger rows end up - beneath this task's future work, and end-of-series integration stays `ff-only` with no carryover - reconciliation. - -Incremental, pushable commits keep the work-loss window small. Each closeout below is one such commit. - ---- - -## 5 — Close - -Land the work. **Implementation approval is not commit approval.** - -1. Run the `c-09-git-worktree-manager` closeout **preview** for the worktree (`worktree_closeout_preview`). - Every build closes through its worktree — there is no direct-checkout closeout. - Relay the proposed code, memory, and ledger commit messages. -2. **Commit gate:** run the closeout **preview** (dry-run), then **hand off** before any real commit or closeout - apply. If required onboarding is missing, run the `c-05-create-or-update-onboarding-files` skill for the affected file and re-run the preview. - Call `lifecycle_turn_end_notification(summary={…the preview facts + the commit ask…})` as the - **last tool call**, then deliver the preview facts as your final prose and **STOP**; - the developer approves on the dashboard or in chat and your next turn auto-resumes to - `worktree_closeout_apply`. The `c-12-closeout` skill owns this hand-off. Parked fallback: when you - deliberately raise the durable `closeout-approval` `lifecycle_gate`, it is enforced **server-side** — - `worktree_closeout_apply` refuses unless it is approved by the developer, and an agent self-approval - never satisfies it. -3. On approval, the `c-09-git-worktree-manager` skill owns the external-memory invariant in order: commit code → refresh affected - onboarding metadata to the new code commit → run memory quality control → commit memory content → - update and commit the ledger. -4. **Integrate + land** per `c-09-git-worktree-manager` and `system/git-workflow.md`: integrate the - worktree branch into the approved source/integration branch, then on a PR-gated repo push that - source branch, open the PR, wait for green checks, and merge per the repo convention. Never push a - protected branch directly. The agent does not push on its own authority — call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then present the push intent - as your final prose, and **STOP**; push only after the developer - approves and your next turn auto-resumes. The `c-09-git-worktree-manager` skill makes the matching - integration and cleanup/finalization hand-offs at its landing tail (parked durable kinds - `integration-approval` / `cleanup-approval`). -5. **Map the ledger to the landed commit.** A PR merge usually lands a **merge commit** on top of the - work — tree-identical to the verified tip but a new SHA the ledger does not yet map. Ensure the - ledger maps that merge commit so the next worktree can base off the merged branch without a manual - reconciliation. `system/git-workflow.md` owns this step. -6. **Finalize the lifecycle:** run `lifecycle_finalize_task(..., dry_run=true)` once the local parent - branch contains the landed commit and memory carryover is done. Call - `lifecycle_turn_end_notification(summary=…)` as the **last tool call**, then relay its landed-commit - proof, cleanup plan, and task-document updates as your final prose, and - **STOP**. The developer approves cleanup/finalization and your next turn auto-resumes to run the real - finalizer. The tool proves one parent-child branch edge, - reclaims the worktrees, and marks the leaf task plus immediate parent row `Completed` when those - task-doc paths are supplied. It does not recursively complete ancestors; repeat the edge at the next - parent level when that parent task lands. -7. **Keep squash out of the normal path.** A PR-gated edge is structurally the same as a direct edge - after the model finishes the PR merge and pulls the target branch locally. Do not use squash-merge - equivalence as a default finalization proof; squash is an emergency/manual recovery path because it - erases commit lineage and can make memory lookup history wrong. - -A research-only exit skips this phase entirely. - -## Relationship To Other Instructions - -This skill extends the coordinator `AGENTS.md` and the repository memory layer; it does not replace -them. Read `job-variants.md` for the per-job lenses, and `deep-research-report-template.md` for the -deeper research report shape. diff --git a/.pi/skills/l-01-session-job-lifecycle/deep-research-report-template.md b/.pi/skills/l-01-session-job-lifecycle/deep-research-report-template.md deleted file mode 100644 index 6e9d13d0..00000000 --- a/.pi/skills/l-01-session-job-lifecycle/deep-research-report-template.md +++ /dev/null @@ -1,123 +0,0 @@ -# Deep Research Report Template - -Use this template after the developer-agreed reframe and before the lifecycle's -`decide` step. The lifecycle owns when deeper research happens and which proof -categories are required; this template owns the report shape, evidence IDs, and -optional sections. - -For small research-only answers, use the compact shape. For ambiguous, -architectural, taxonomy-heavy, bug-root-cause, triage-routing, or build-spawning -work, use the full shape. - -## Report Rules - -1. Keep the report claim-first: findings state what is now believed to be true. -2. Treat evidence rows as proof records, not activity logs. -3. Every finding cites evidence IDs, and every evidence row names the claim it proves. -4. Mark inference separately when the report reasons across multiple evidence rows. -5. Keep limits visible: every evidence row should say what it does not prove. -6. End with the lifecycle decision: research-only exit or recommended follow-up build. - -## Full Shape - -```md -# Deep Research Report: - -## Frame - -- Surface request: -- Deeper objective: -- Agreed scope: -- Non-goals: -- Invariants: -- Truth gaps before research: - -## Short Answer - - - -## Findings - -- F-01: [E-01, E-03] -- F-02: [E-02] - -## Evidence Ledger - -| ID | Kind | Source / Query | Claim Proven | Limits | -|----|------|----------------|--------------|--------| -| E-01 | Semantics | query: "" | F-01 | Does not prove runtime behavior. | -| E-02 | Intent | onboarding: ``; source: `` | F-02 | Covers committed HEAD only. | -| E-03 | Relationship | cgc callees/deps: `` | F-01 | Does not prove hidden business intent. | - -## Proof Inventory - -- Onboarding docs read: -- Semantic queries performed: -- Code graph queries performed: -- Source files inspected: -- External references checked: -- Executable validations run: - -## Remaining Truth Gaps - -| Gap | Why It Matters | Blocks Build? | -|-----|----------------|---------------| -| | | yes/no | - -## Decision - -- Research-only exit: -- Spawn build? -- Suggested build mode if spawned: -- Plan-gate status: -``` - -## Compact Shape - -```md -## Short Answer - - - -## Evidence - -- E-01 (): proves ; limits: . - -## Proof Inventory - -- Onboarding docs read: -- Semantic queries performed: -- Code graph queries performed: -- Source files inspected: - -## Remaining Truth Gaps - -- - -## Decision - - -``` - -## Evidence Kinds - -- `Semantics`: fuzzy routing through GrepAI or onboarding search. -- `Relationship`: CodeGraphContext callers, callees, dependencies, impact, or neighboring structure. -- `Intent`: paired onboarding plus bounded source confirmation for contracts, invariants, behavioral expectations, or branch-valid truths. -- `External`: domain documentation, standards, issues, PRs, release notes, or other non-repo references. -- `Executable`: reproduction steps, tests, scripts, command output, or generated validation artifacts. -- `Developer`: explicit clarification from the developer; verify against source before treating it as durable current-state knowledge. -- `Inference`: reasoning across evidence rows. Cite the input evidence IDs in `Source / Query` and state the remaining uncertainty. - -## Evidence Ledger Guidance - -The evidence ledger should be precise enough that another agent can tell why a -claim is supported without rerunning the entire investigation. Prefer concrete -paths, query strings, anchors, and command names over prose summaries. - -Use `Limits` to prevent overclaiming. Examples: - -- `Routes the feature area but does not prove current source behavior.` -- `Confirms the source contract at HEAD, not dirty work-in-progress.` -- `Shows the call path but not whether the path is user-facing.` -- `Explains the documented intent but needs executable validation before build.` diff --git a/.pi/skills/l-01-session-job-lifecycle/job-variants.md b/.pi/skills/l-01-session-job-lifecycle/job-variants.md deleted file mode 100644 index 48f032c6..00000000 --- a/.pi/skills/l-01-session-job-lifecycle/job-variants.md +++ /dev/null @@ -1,43 +0,0 @@ -# l-01-session-job-lifecycle Job Variants — The Lenses - -The job type is a **lens**, picked during `reframe-research` and re-pickable at any time. It is not a gate and it -never changes the spine (`request -> trust-checkpoint -> reframe-research -> decide -> build -> close`). A lens tunes three -things only: - -- **Opening move** — the first concrete thing `reframe-research` does for this kind of job. -- **Retrieval lean** — which `c-04-retrieval-strategy-router` strategy leads (others are still available). -- **Decide default** — where this job usually lands at `decide` (still a real decision, not automatic). - -| Job | Opening move (in `reframe-research`) | Retrieval lean (`c-04-retrieval-strategy-router`) | `decide` default | -| ---------- | ----------------------------------------------- | ---------------------------------- | --------------------------- | -| `bug` | reproduce the failure; prove the root cause | Relationship (cgc) + Intent | -> build | -| `feature` | clarify intent, scope, and explicit non-goals | design doctrine + Intent | -> build | -| `triage` | assess severity, blast radius, and ownership | breadth scan (Semantics first) | may exit (route or spawn) | -| `research` | state the question precisely | Semantics (grepai) + onboarding | research-only exit | - -## bug - -Lead with a reproduction and a proven root cause before proposing a fix — an unproven fix is a guess. -Lean on Relationship (callers/callees/impact via cgc) to bound the change, and Intent to confirm the -invariant the bug violates. Defaults to a build; the fix lands through `decide -> build -> close`. - -## feature - -Lead by pinning down intent, scope, and the non-goals — what this feature is explicitly *not*. Use the -design doctrine in `tasks/AGENTS.md` to pressure-test the shape, and Intent retrieval to find the -contracts the feature must respect. Defaults to a build; size decides chat vs durable `w-02-light-task-workflow` task at -`decide`. - -## triage - -Lead by assessing severity, blast radius, and ownership — enough to route, not to fix. A breadth scan -(Semantics first) maps the surface fast. Triage frequently **exits research-only**: its product is a -recommendation, a routed owner, or a spawned build/bug job — not a code change. Only escalate to a -build when triage itself is the cheapest place to fix it. - -## research - -Lead by stating the question precisely. Semantics (grepai over onboarding) plus committed-state -onboarding usually answers it; reach for source only as bounded Intent confirmation. Research -**exits research-only** by design: it produces an answer, and may recommend a follow-up build job, but -performs none itself. diff --git a/.pi/skills/w-02-light-task-workflow/SKILL.md b/.pi/skills/w-02-light-task-workflow/SKILL.md index 248e6f3c..b34f3017 100644 --- a/.pi/skills/w-02-light-task-workflow/SKILL.md +++ b/.pi/skills/w-02-light-task-workflow/SKILL.md @@ -40,7 +40,7 @@ Light-task artifacts use minute-precision timestamps in `YYYY-MM-DDTHH:MM` forma The task document is **JSON-primary**: an `ar-task-document/v1` JSON file is the source of truth, and the `task.md` (or `.md` for a sub-task) is a deterministic **render** of it. Author and update it with the `task_doc` MCP tool — `create`, `set_status`, `set_step`, `append_decision`, `set_field` — which writes the JSON and re-renders the markdown on every write. Do not hand-edit a tool-managed `task.md`; edit through the tool and let it re-render. `template.md` and `master-template.md` document the **render spec** (the shape the renderer produces), not a separate hand-authored format. When a planning slice defers its code examples to the plan gate, record that with `codeExamplesNote` (a `set_field` value, e.g. "Drafted at the plan gate.") so the rendered "Proposed Code Examples" section reads as *deferred* rather than as if none are needed. A leaf doc may also carry a descriptive `statusNote` (a suffix beside the strict status enum), `headerNotes` (extra `**Key:** value` header lines such as Verified/Source), and freeform `sections` appended after References — the escape hatch for bespoke prose (e.g. a Status history) while the standard template sections stay the backbone. Pass `dry_run=true` to any op to **preview** — it builds + validates and returns the rendered markdown, a unified `diff` vs the on-disk `.md`, and a `wouldLose` flag, **without writing**; use it before adopting a hand-authored `.md` into JSON-primary (author the JSON → dry-run → confirm `wouldLose` is false → then write). -Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for a chat build (a thin doc: title plus a few steps, so even a no-`task.md` session is legible) and a *full* one for a durable task; the difference is content completeness, not a separate format. +Because the JSON encodes step/substep status explicitly, a tool-managed document is legible on the dashboard — the observer projects leaf documents through their enclosure entry in `enclosures[].enclosurePath`, at step granularity. The same schema/tool serves a *lightweight* document for the smallest single-session build (a THIN doc: title plus a few steps — chat is never a build route, so even micro-work gets this thin doc and stays legible on the dashboard) and a *full* one for a durable task; the difference is content completeness, not a separate format. Scope and transition: the tool manages **`light` and `subTask`** documents, and the format also covers a series **master** (`kind:"master"`: a structured `subTasks` index + ordered `sections` that preserve a master's bespoke prose, so a re-render is lossless). Masters and existing markdown task files stay hand-authored markdown until the runtime ships `task_doc` and they are intentionally migrated — new tasks adopt the JSON-primary format going forward. diff --git a/.pi/skills/w-02-light-task-workflow/master-template.md b/.pi/skills/w-02-light-task-workflow/master-template.md index 7cb4e85a..42738c16 100644 --- a/.pi/skills/w-02-light-task-workflow/master-template.md +++ b/.pi/skills/w-02-light-task-workflow/master-template.md @@ -7,7 +7,7 @@ built to grow as the work unfolds. ## When to escalate to a series -The `l-01-session-job-lifecycle` skill's `decide` build-mode step escalates a single task to a series once its size is apparent — the +The `l-01-agent-lifecycles` orchestrator lifecycle's `decide` step escalates a single task to a series once its size is apparent — the implementation plan no longer fits on a single page, or the work splits into distinct slices that each deserve their own checklist and commit. You can also start single and escalate later: drop in the master `task.md` and move the existing plan into the first `NN_.md`. diff --git a/AGENTS.md b/AGENTS.md index 63ba654d..62e05208 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,30 +13,36 @@ on a sibling repository, use the installed runtime instructions instead: When working on this repository itself, use `agents-remember` as the target code repository for resolver, onboarding, workflow, and closeout commands. -## Start Here — Enter the Job Lifecycle - -Every session enters `l-01-session-job-lifecycle` — the lifecycle this checkout -routes into. The `l-01-session-job-lifecycle` skill owns the whole arc: orient → ground → frame → decide → build → -close. Classify the job (bug / feature / triage / research) as a *lens* during -framing — a hint, re-pickable, never a gate. - -The only task-format decision is the `l-01-session-job-lifecycle` skill's **build-mode** step, taken at `decide`: - -1. **Read-only exit** — answers or assessments that change no code: no worktree, - no task file. -2. **Chat build** — a code change carried inline this session: worktree-backed, - no durable task file. -3. **Durable task** — `w-02-light-task-workflow`: a `task.md` with checklist, - decision log, and proposed code examples; escalates to a master + light - sub-task series when the work outgrows a single-page plan. - -The task-collaboration doctrine in `tasks/AGENTS.md` applies inside the `l-01-session-job-lifecycle` skill's -`frame` phase, in plain chat, before any task file or format is chosen. +## Start Here — Route By Role + +Sessions route by role through the `l-01-agent-lifecycles` skill — the lifecycle +roof this checkout routes into. A **spawned agent** (the `AR_SPAWN_ROLE` env var +is set, or the first message is a role brief) follows its brief — the brief is +its session start, and the rest of this section is not addressed to it. A +**developer-facing session** is the **orchestrator**: it runs +`skills/l-01-agent-lifecycles/roles/orchestrator.md`, whose phase axis is +request → trust-checkpoint → reframe-research → decide → build → close. +Classify the job (bug / feature / triage / research) as a *lens* during +reframe-research — a hint, re-pickable, never a gate. + +The build decision is taken at `decide`. Chat is never a build route — every +code change lives under an approved task doc: + +1. **Research-only exit** — answers or assessments that change no code: no + worktree, no task file; chat is the right medium. +2. **Durable task** — `w-02-light-task-workflow`: a task document with + checklist, decision log, and proposed code examples; small code work takes + the minimal `w-02-light-task-workflow` artifact, and the work escalates to a + master + light sub-task series when it outgrows a single-page plan. + +The task-collaboration doctrine in `tasks/AGENTS.md` applies inside the +orchestrator lifecycle's reframe-research phase, in plain chat, before any task +file or format is chosen. --- **IMPORTANT:** -Do not change code or documentation without entering the lifecycle and clearing its `frame` plan gate. +Do not change code or documentation without entering the orchestrator lifecycle and clearing its plan gate. Do not change task plan items without approval. Think before acting. Do not randomly commit. Use the `c-12-closeout` skill instead! diff --git a/README.md b/README.md index 23d3055f..3718dd54 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ That is the normal first-run path. `skills_install()` remains available as a maintenance/manual MCP tool, but the starter packages already provide the initial skills and harness files. -After that, normal work runs through the `l-01-session-job-lifecycle` skill. The agent resolves the active context with `c-08-ar-coordination-context-resolver`, checks memory quality with `c-02-memory-quality-control`, reads relevant onboarding beside code, and updates onboarding after approved changes. +After that, normal work runs through the `l-01-agent-lifecycles` skill: a developer-facing session is the orchestrator; spawned agents follow their role briefs. The agent resolves the active context with `c-08-ar-coordination-context-resolver`, checks memory quality with `c-02-memory-quality-control`, reads relevant onboarding beside code, and updates onboarding after approved changes. ## Run The Dashboard @@ -162,8 +162,8 @@ upgrade is picked up by the next session ([Settings Reference](docs/reference/settings-json.md)). Pinning a version is the debugging/repro path, not the default: `uv tool -install 'agents-remember-mcp==3.0.0rc2'`, or one-shot without installing, -`uvx --from 'agents-remember-mcp==3.0.0rc2' agents-remember dashboard`. +install 'agents-remember-mcp==3.0.0rc3'`, or one-shot without installing, +`uvx --from 'agents-remember-mcp==3.0.0rc3' agents-remember dashboard`. > **Pre-release note (until 3.0.0 final):** the dashboard currently ships in > `3.0.0rcN` pre-releases, which default version resolution skips. Install with @@ -177,7 +177,7 @@ install 'agents-remember-mcp==3.0.0rc2'`, or one-shot without installing, - [Getting Started](docs/getting-started.md) - a fuller first-run setup. - [Concepts](docs/concepts.md) - onboarding units, memory roots, drift, and approval gates. - [Architecture](docs/architecture.md) - runtime, coordination, internal memory, and external memory. -- [Workflows](docs/workflows.md) - the `l-01-session-job-lifecycle` skill and its build modes (read-only / chat build / `w-02-light-task-workflow` skill), and when to use each. +- [Workflows](docs/workflows.md) - the `l-01-agent-lifecycles` skill and its build modes (research-only exit / `w-02-light-task-workflow` skill task / master + light sub-task series), and when to use each. - [Benchmark Methodology](docs/benchmarks-methodology.md) - how paired `codex exec --json` runs are captured and compared. - [FAQ](docs/FAQ.md) - design principles, objections, and comparisons. - [External Memory Guide](docs/guides/use-external-memory.md) - separate memory repos for selected code repos. @@ -239,9 +239,9 @@ ar-coordination/ ## Status -Agents Remember is at `3.0.0rc2` and actively developed. The core path — by-path onboarding, drift checks, and approval-gated updates — is in real use and stable enough to rely on. The public contracts listed under [Stability](#stability) are held stable across minor releases and change only on a major bump; the internals beneath them and the optional semantic/relationship providers may still evolve, so pin a version and read the notes for your target version in [GitHub Releases](https://github.com/Foxfire1st/agents-remember/releases) — the repository's canonical changelog — before upgrading. The Claude Code path is the most exercised; other harnesses are supported but less battle-tested. +Agents Remember is at `3.0.0rc3` and actively developed. The core path — by-path onboarding, drift checks, and approval-gated updates — is in real use and stable enough to rely on. The public contracts listed under [Stability](#stability) are held stable across minor releases and change only on a major bump; the internals beneath them and the optional semantic/relationship providers may still evolve, so pin a version and read the notes for your target version in [GitHub Releases](https://github.com/Foxfire1st/agents-remember/releases) — the repository's canonical changelog — before upgrading. The Claude Code path is the most exercised; other harnesses are supported but less battle-tested. -The 3.0 arc: the working session itself is now observable and steerable — a system-managed session job lifecycle with durable approval gates and an event/projection layer, served as the mission-control browser cockpit directly from the MCP package (`agents-remember dashboard`; [#2](https://github.com/Foxfire1st/agents-remember/issues/2), [#43](https://github.com/Foxfire1st/agents-remember/issues/43)). The `rc` tag means the cockpit surface is still settling toward the final 3.0.0 contract; the architecture beneath it is the one described above. +The 3.0 arc: the working session itself is now observable and steerable — a system-managed agent lifecycle with durable approval gates and an event/projection layer, served as the mission-control browser cockpit directly from the MCP package (`agents-remember dashboard`; [#2](https://github.com/Foxfire1st/agents-remember/issues/2), [#43](https://github.com/Foxfire1st/agents-remember/issues/43)). The `rc` tag means the cockpit surface is still settling toward the final 3.0.0 contract; the architecture beneath it is the one described above. ## Stability diff --git a/agents-md-files/coordinator/AGENTS.md b/agents-md-files/coordinator/AGENTS.md index e545e7e0..f0f280ca 100644 --- a/agents-md-files/coordinator/AGENTS.md +++ b/agents-md-files/coordinator/AGENTS.md @@ -1,18 +1,22 @@ # AGENTS.md -## Start Here — Enter the Job Lifecycle +## Start Here — Route By Role -Every session enters `l-01-session-job-lifecycle` — the canvas this coordinator -routes into. +Sessions route by role through the `l-01-agent-lifecycles` skill. A **spawned +agent** (the `AR_SPAWN_ROLE` env var is set, or the first message is a role +brief) follows its brief — the brief is its session start, and the rest of this +section is not addressed to it. A **developer-facing session** is the +**orchestrator**: it enters `skills/l-01-agent-lifecycles/roles/orchestrator.md` +before working in any managed repository. During an already-running session, the agent must stay aware of managed-repo boundaries. If a new turn or tool target may cross from outside Agents Remember -scope into a managed repository, enter the lifecycle at `l-01-session-job-lifecycle`. +scope into a managed repository, enter the orchestrator lifecycle first. --- **IMPORTANT:** -Do not change code without entering the lifecycle and clearing its `frame` plan gate. +Do not change code without entering the orchestrator lifecycle and clearing its plan gate. Do not change task plan items without approval. Do not randomly commit. Use the `c-12-closeout` skill instead! @@ -27,8 +31,8 @@ This workspace uses a layered memory system. Make sure to read the below rules b This coordinator file is the workspace entrypoint. Read these installed `AGENTS.md` files when their scope becomes relevant: -- `tasks/AGENTS.md` — task collaboration doctrine (applied up front in the `l-01-session-job-lifecycle` skill's - `frame` phase; see _Start Here — Enter the Job Lifecycle_ above). +- `tasks/AGENTS.md` — task collaboration doctrine (applied up front in the `l-01-agent-lifecycles` orchestrator lifecycle's + reframe-research phase; see _Start Here — Route By Role_ above). ### Onboarding Documentation @@ -38,7 +42,7 @@ inspected. Route retrieval through `c-04-retrieval-strategy-router` (see _Memory Retrieval Strategies_ below) before relying on onboarding, providers, or repository source. -Until the build/job decision, read managed-repo source through the `read_ar_files` MCP tool +Until the build decision, read managed-repo source through the `read_ar_files` MCP tool rather than the native read tool — it pairs each file with its onboarding by construction and keeps the read trail observable. Native read is the edit precondition once building begins. Count your `read_ar_files` calls as retrieval evidence alongside CGC and GrepAI. diff --git a/agents-md-files/skills/AGENTS.md b/agents-md-files/skills/AGENTS.md index 4cbafda5..4c9c3c74 100644 --- a/agents-md-files/skills/AGENTS.md +++ b/agents-md-files/skills/AGENTS.md @@ -40,7 +40,7 @@ explicitly and in full — never abbreviate, so a reader can always tell a skill invocation from an MCP tool call: - **Skills** — the full lowercase skill id followed by the word "skill": - e.g. *the `c-12-closeout` skill*, *the `l-01-session-job-lifecycle` skill*. + e.g. *the `c-12-closeout` skill*, *the `l-01-agent-lifecycles` skill*. Never use an abbreviation (`C-12`, `L-01`, `W-02`) and never the bare id without the word "skill". Skill directory names match the installed lowercase ids (e.g. `runtime/skills/c-12-closeout/`). diff --git a/dashboard/panda.config.ts b/dashboard/panda.config.ts index b65aba7f..a2bff027 100644 --- a/dashboard/panda.config.ts +++ b/dashboard/panda.config.ts @@ -38,6 +38,13 @@ export default defineConfig({ alarm: { value: "oklch(0.63 0.24 25)" }, // whole-silhouette alarm mint: { value: "oklch(0.88 0.16 165)" }, // fresh-online / live dormant: { value: "oklch(0.45 0.06 25)" }, // skeletal dark-red dormant + // Rank-insignia tiers (L14, V4 spec): gold = orchestration seat, purple = management. + gold: { value: "oklch(0.87 0.15 95)" }, // orchestration tier (chevrons, corner) + goldDim: { value: "oklch(0.55 0.09 95)" }, // orchestration hairline + goldGhost: { value: "oklch(0.32 0.05 95)" }, // orchestration row wash + purple: { value: "oklch(0.76 0.14 305)" }, // management tier (chevrons) + purpleDim: { value: "oklch(0.5 0.09 305)" }, // management corner + purpleGhost: { value: "oklch(0.3 0.05 305)" }, // management row wash }, fonts: { mono: { value: 'ui-monospace, "JetBrains Mono", "SFMono-Regular", Menlo, monospace' }, diff --git a/dashboard/src/cockpit/Cockpit.test.tsx b/dashboard/src/cockpit/Cockpit.test.tsx index 976c9b6d..846ebe78 100644 --- a/dashboard/src/cockpit/Cockpit.test.tsx +++ b/dashboard/src/cockpit/Cockpit.test.tsx @@ -118,6 +118,37 @@ afterEach(() => { window.localStorage.clear(); // the rail toggle now persists its choice; isolate it between tests }); +describe("serving-build stamp (260703-L15 — the July-4 ghost-process lesson)", () => { + it("renders the muted stamp from the snapshot's servingBuild (commit-first)", () => { + const fixture = GALLERY.find((entry) => entry.name === "engine-fleet"); + if (!fixture) throw new Error("fixture not found: engine-fleet"); + dashboardStore.getState().applySnapshot({ + ...fixture.projection, + servingBuild: { version: "9.9.9", commit: "abc1234", bootedAt: "2026-07-07T05:00:00Z" }, + }); + const { getByTestId } = render(); + expect(getByTestId("serving-build").textContent).toContain("abc1234"); + expect(getByTestId("serving-build").textContent).toContain("up "); + }); + + it("falls back to the package version off-checkout; renders nothing without a stamp", () => { + const fixture = GALLERY.find((entry) => entry.name === "engine-fleet"); + if (!fixture) throw new Error("fixture not found: engine-fleet"); + dashboardStore.getState().applySnapshot({ + ...fixture.projection, + servingBuild: { version: "9.9.9", bootedAt: "2026-07-07T05:00:00Z" }, + }); + const first = render(); + expect(first.getByTestId("serving-build").textContent).toContain("v9.9.9"); + first.unmount(); + + dashboardStore.getState().reset(); + seed("engine-fleet"); // no servingBuild on the wire (a pre-L15 server) + const second = render(); + expect(second.queryByTestId("serving-build")).toBeNull(); // absent stamp: nothing, never faked + }); +}); + describe("CockpitShell full-bleed machine-map views (5f S1)", () => { it("rails the Operations view but goes full-bleed (no rails) for the Engine Room", () => { seed("engine-fleet"); diff --git a/dashboard/src/cockpit/Cockpit.tsx b/dashboard/src/cockpit/Cockpit.tsx index 8bd6bf47..f8142007 100644 --- a/dashboard/src/cockpit/Cockpit.tsx +++ b/dashboard/src/cockpit/Cockpit.tsx @@ -20,6 +20,7 @@ import { ModeBar } from "../grammar/ModeBar"; import { AttentionQueue } from "../panels/AttentionQueue"; import { Chats } from "../panels/Chats"; import { ChangeSetViewer, type ChangeSetTarget } from "../panels/changeset/ChangeSetViewer"; +import { NotesReaderViewer, type NotesReaderTarget } from "../panels/notes-reader/NotesReaderViewer"; import { DetailPanel } from "../panels/DetailPanel"; import { EngineRoom } from "../panels/EngineRoom"; import { useShouldAnimate } from "../panels/engine-room/useShouldAnimate"; @@ -330,6 +331,12 @@ export function CockpitShell() { // full-bleed; the screen's back link clears it, restoring the rails + Operations. A mode-bar // switch or an open() also clears it (the takeover is transient, not a standing tab). const [changeSet, setChangeSet] = useState(null); + // The Notes Reader (L17) is a task-scoped TAKEOVER like the Change-Set Viewer, but it PERSISTS its + // selection like the File Viewer: `notes` (the open note) is retained once opened so the reader stays + // mounted (hidden) — selection survives back/forward — and `notesOpen` toggles the takeover's visibility. + // Back + mode-bar/node switches hide it (retaining `notes`); a fresh entry point re-shows it on the note. + const [notes, setNotes] = useState(null); + const [notesOpen, setNotesOpen] = useState(false); // The right rail toggles between the Event River (default) and the single-instance leaf chat (L5). // Persisted to localStorage (same pattern as the effects toggle) so the choice survives a window refresh. const [chatRail, setChatRail] = usePersistedFlag("cockpit.rail-chat", false); @@ -358,11 +365,14 @@ export function CockpitShell() { // The machine-map views + the Chats terminal span full width: the rails hide and the view's own // layout breathes. const fullBleed = view === "files" || view === "engine" || view === "topology" || view === "chats"; + // A takeover (Change-Set Viewer or the L17 Notes Reader) replaces the railed body full-bleed. + const takeover = Boolean(changeSet) || notesOpen; // Open a node AND surface it in Operations: the attention queue / topology / hangar all jump // into the detail view, so a cross-view click lands where you can inspect it. const open = (id: string) => { setChangeSet(null); // leaving the change-set takeover for a selected node + setNotesOpen(false); // and the notes reader takeover (selection retained) setSelectedId( id.startsWith("taskdoc:") || id.startsWith("series:") || id.startsWith("lifecycle:") ? id @@ -374,9 +384,22 @@ export function CockpitShell() { // Mode-bar switches exit the takeover too (it is not one of the standing views). const changeView = (next: View) => { setChangeSet(null); + setNotesOpen(false); // exit the notes reader takeover too (selection retained) setView(next); }; + // The Change-Set and Notes takeovers are mutually exclusive full-bleed screens: opening one hides the + // other. `openNotes` retains `notes` after back (the reader stays mounted, so selection survives). + const openChangeSet = (target: ChangeSetTarget) => { + setNotesOpen(false); + setChangeSet(target); + }; + const openNotes = (target: NotesReaderTarget) => { + setChangeSet(null); + setNotes(target); + setNotesOpen(true); + }; + // Gated fade-in when the rails return (reduced-motion / data-effects=off → no tween). Leaving to // a full-bleed view unmounts them for a clean expand; the determinism path stays snapshot-stable. const railEnter = animate ? { initial: { opacity: 0 }, animate: { opacity: 1 } } : {}; @@ -392,6 +415,27 @@ export function CockpitShell() { ) : null} + {/* The Notes Reader (L17) takeover: mounted once opened and kept mounted (hidden via display) even + after Back — like the File Viewer — so its listing + open note survive back/forward. Its own + `notesOpen` toggles visibility; a change-set takeover (if both were somehow set) wins the screen. */} + {notes ? ( +
+
+ setNotes((cur) => (cur ? { ...cur, path } : cur))} + onBack={() => setNotesOpen(false)} + /> +
+
+ ) : null} {/* The railed body is never UNMOUNTED while the change-set takeover shows — only hidden — so the DetailPanel's drill state (which leaf you were reading) survives. The viewer's back link then returns you exactly where you opened it from (a drilled leaf, not a reset to the master @@ -400,13 +444,13 @@ export function CockpitShell() { className={cx(bodyGrid({ bleed: fullBleed }), "shell__body")} data-fullbleed={fullBleed} style={{ - ...(changeSet ? { display: "none" } : {}), + ...(takeover ? { display: "none" } : {}), // The railed grid uses the persisted rail widths; full-bleed keeps the cva's single column. ...(fullBleed ? {} : { gridTemplateColumns: `${leftRailWidth}px minmax(380px, 1fr) ${rightRailWidth}px` }), }} - aria-hidden={changeSet ? true : undefined} + aria-hidden={takeover ? true : undefined} > {!fullBleed && ( @@ -519,6 +564,32 @@ function ViewBody({ view, onOpen }: { view: View; onOpen: (id: string) => void } } } +// The serving-build stamp, muted (260703-L15 — the July-4 ghost-process lesson): commit +// short-hash (or the package version off-checkout) + process boot time, so a STALE serving +// process is visible at a glance. Data rides the snapshot (`servingBuild`, boot-time cached). +function ServingBuildStamp() { + const build = useDashboard((s) => s.servingBuild); + if (!build) return null; + const booted = new Date(build.bootedAt); + const bootLabel = Number.isNaN(booted.getTime()) + ? build.bootedAt + : booted.toLocaleString(undefined, { + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }); + return ( + + {build.commit ?? `v${build.version}`} · up {bootLabel} + + ); +} + function TopBar() { const conn = useDashboard((s) => s.conn); const metrics = useDashboard((s) => s.metrics); @@ -540,6 +611,7 @@ function TopBar() { ) : null} {generatedAt ? @ {generatedAt.slice(11, 19)} : null} + diff --git a/dashboard/src/data/notes.test.ts b/dashboard/src/data/notes.test.ts new file mode 100644 index 00000000..e11e054c --- /dev/null +++ b/dashboard/src/data/notes.test.ts @@ -0,0 +1,83 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { FilesApiError } from "./files"; +import { listNotes, readNote, resolveNoteReference } from "./notes"; + +function stubFetch(payload: unknown, ok = true, status = 200) { + const fn = vi.fn( + async () => ({ ok, status, statusText: "", json: async () => payload }) as unknown as Response, + ); + vi.stubGlobal("fetch", fn); + return fn; +} + +afterEach(() => vi.unstubAllGlobals()); + +describe("data/notes client", () => { + it("builds the list / read URLs", async () => { + const fn = stubFetch({}); + await listNotes("agents-remember", "260703_agent-orchestration"); + await readNote("agents-remember", "260703_agent-orchestration", "reports/260703-L1.md"); + const urls = (fn.mock.calls as unknown as string[][]).map((c) => c[0]); + expect(urls[0]).toBe("/api/notes/list?repo=agents-remember&master=260703_agent-orchestration"); + expect(urls[1]).toBe( + "/api/notes/read?repo=agents-remember&master=260703_agent-orchestration&path=reports%2F260703-L1.md", + ); + }); + + it("throws the shared FilesApiError on a non-ok response", async () => { + stubFetch({ status: "bad-path" }, false, 400); + await expect(readNote("r", "m", "../escape.md")).rejects.toBeInstanceOf(FilesApiError); + }); +}); + +describe("resolveNoteReference", () => { + const notePaths = [ + "design-agent-orchestration.md", + "friction-ledger.md", + "reports/260703-L1-worker-report.md", + ]; + + it("resolves a notes/-prefixed reference with trailing prose", () => { + expect( + resolveNoteReference("notes/friction-ledger.md (F-M — the finding this leaf closes)", notePaths), + ).toBe("friction-ledger.md"); + }); + + it("resolves a nested notes-relative path with or without the notes/ prefix", () => { + expect(resolveNoteReference("notes/reports/260703-L1-worker-report.md", notePaths)).toBe( + "reports/260703-L1-worker-report.md", + ); + expect(resolveNoteReference("reports/260703-L1-worker-report.md", notePaths)).toBe( + "reports/260703-L1-worker-report.md", + ); + }); + + it("resolves an unambiguous bare filename", () => { + expect(resolveNoteReference("see friction-ledger.md for the row", notePaths)).toBe( + "friction-ledger.md", + ); + }); + + it("does not resolve an ambiguous bare filename", () => { + const ambiguous = ["a/summary.md", "b/summary.md"]; + expect(resolveNoteReference("summary.md", ambiguous)).toBeUndefined(); + }); + + it("leaves a code-path reference unresolved", () => { + expect( + resolveNoteReference( + "mcp/src/agents_remember/serving/files.py (the confinement idiom to reuse)", + notePaths, + ), + ).toBeUndefined(); + expect( + resolveNoteReference("dashboard/src/panels/DetailPanel.tsx (task reader home)", notePaths), + ).toBeUndefined(); + }); + + it("leaves plain prose and empty note lists unresolved", () => { + expect(resolveNoteReference("the doctrine chapter on gates", notePaths)).toBeUndefined(); + expect(resolveNoteReference("notes/friction-ledger.md", [])).toBeUndefined(); + }); +}); diff --git a/dashboard/src/data/notes.ts b/dashboard/src/data/notes.ts new file mode 100644 index 00000000..43bffd67 --- /dev/null +++ b/dashboard/src/data/notes.ts @@ -0,0 +1,65 @@ +// Same-origin client for the L9 read-only coordination-notes API (mcp/.../serving/notes.py). +// House style mirrors data/files.ts: a `base` arg (same-origin default), typed results, the +// shared getJson error mapping, and NO store mutation — the task reader's notes view owns its +// own component state. Endpoints (all GET, camelCase JSON): +// /api/notes/list?repo&master -> every note file under tasks///notes/ +// /api/notes/read?repo&master&path -> one note: content + language (binary-tolerant, size-capped) + +import { getJson, qs } from "./files"; + +export interface NoteEntry { + name: string; + path: string; // posix path relative to the series' notes/ root (e.g. "reports/…-report.md") + size: number; + language: string; +} +export interface NotesListing { + repo: string; + master: string; + notes: NoteEntry[]; + truncated: boolean; // the server's walk depth cap pruned something — the list is honest about it +} +export interface NoteContent { + repo: string; + master: string; + path: string; + language: string; // "binary" for an undecodable file (content is then empty) + size: number; + truncated: boolean; + content: string; +} + +export const listNotes = (repo: string, master: string, base = ""): Promise => + getJson(`${base}/api/notes/list?${qs({ repo, master })}`); + +export const readNote = ( + repo: string, + master: string, + path: string, + base = "", +): Promise => + getJson(`${base}/api/notes/read?${qs({ repo, master, path })}`); + +// A task-doc reference is free prose that may NAME a notes file — "notes/friction-ledger.md +// (F-M — the finding this leaf closes)". Path-like tokens: contiguous path characters ending +// in a dotted extension, so surrounding prose never bleeds into the candidate. +const PATH_TOKEN = /[\w./-]+\.[A-Za-z0-9]+/g; + +// Resolve a reference string against the series' note paths: the first token that names an +// existing notes file — by notes-relative path (with or without the "notes/" prefix) or by an +// UNAMBIGUOUS bare filename — wins. Anything else resolves to undefined, so a non-matching +// reference stays plain text (never a dead link, never a guessed one). +export function resolveNoteReference( + reference: string, + notePaths: readonly string[], +): string | undefined { + for (const token of reference.match(PATH_TOKEN) ?? []) { + const relative = token.startsWith("notes/") ? token.slice("notes/".length) : token; + if (notePaths.includes(relative)) return relative; + if (!token.includes("/")) { + const byName = notePaths.filter((path) => path.split("/").pop() === token); + if (byName.length === 1) return byName[0]; + } + } + return undefined; +} diff --git a/dashboard/src/data/operatorInbox.ts b/dashboard/src/data/operatorInbox.ts index 4f83274b..2ee3d856 100644 --- a/dashboard/src/data/operatorInbox.ts +++ b/dashboard/src/data/operatorInbox.ts @@ -4,7 +4,13 @@ export type OperatorInboxDismissStatus = "dismissed" | "not-found" | "error"; export interface OperatorInboxPostRequest { lifecycleId?: string; agentId?: string; + senderAgentId?: string; + senderRole?: string; + recipientRole?: string; gateId?: string; + messageKind?: string; + artifactPath?: string; + deliverToHosted?: boolean; ask: string; response: string; } diff --git a/dashboard/src/data/selectors.test.ts b/dashboard/src/data/selectors.test.ts index 8ad4fc5e..2217db92 100644 --- a/dashboard/src/data/selectors.test.ts +++ b/dashboard/src/data/selectors.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import type { DashboardState } from "./store"; import type { AttentionItem, LifecycleProjection, Phase } from "../types/projection"; -import { buildTree, fmtWait, selectQueue } from "./selectors"; +import { buildTree, fmtWait, hasLiveWorktree, selectQueue } from "./selectors"; const lifecycle = (id: string, repoId?: string, phase: Phase = "build"): LifecycleProjection => { const base: LifecycleProjection = { @@ -49,6 +49,16 @@ describe("buildTree", () => { }); }); +describe("hasLiveWorktree", () => { + it("is the stat'ed existence truth (L11): either physical worktree admits, neither hides", () => { + // Never a cleanup-state proxy — the flags alone decide tasks-surface visibility. + expect(hasLiveWorktree({ codeWorktreeExists: true, memoryWorktreeExists: true })).toBe(true); + expect(hasLiveWorktree({ codeWorktreeExists: true, memoryWorktreeExists: false })).toBe(true); + expect(hasLiveWorktree({ codeWorktreeExists: false, memoryWorktreeExists: true })).toBe(true); + expect(hasLiveWorktree({ codeWorktreeExists: false, memoryWorktreeExists: false })).toBe(false); + }); +}); + describe("fmtWait", () => { it("scales seconds → s/m/h/d and renders unknown as a dash", () => { expect(fmtWait(45)).toBe("45s"); diff --git a/dashboard/src/data/selectors.ts b/dashboard/src/data/selectors.ts index 0512ea47..d51e34bf 100644 --- a/dashboard/src/data/selectors.ts +++ b/dashboard/src/data/selectors.ts @@ -7,12 +7,26 @@ import type { AttentionItem, DriftSnapshotNode, + EnclosureNode, LifecycleProjection, Phase, ProviderNode, } from "../types/projection"; import type { DashboardState } from "./store"; +// ── The tasks-surface visibility rule (L11) ───────────────────────────────────── +// A leaf renders as a task entry ONLY while a worktree physically exists (an active worktree = +// something is being built). The projection stats this server-side (codeWorktreeExists / +// memoryWorktreeExists), so the client filters on truth — never on a cleanup-state proxy. A +// completed/abandoned enclosure's worktrees are gone (hidden, as before); a reopened contract +// (cleanup=reopened: contract-reset-awaiting-restart) stays hidden until worktree_start +// recreates its worktrees. Identity is the complementary rule: one row per enclosureId. +export function hasLiveWorktree( + enclosure: Pick, +): boolean { + return enclosure.codeWorktreeExists || enclosure.memoryWorktreeExists; +} + // Stable empty reference: a fresh `[]` each call would make useSyncExternalStore (Zustand's // useStore) see a new snapshot every render and loop ("getSnapshot should be cached"). const EMPTY_QUEUE: readonly AttentionItem[] = []; diff --git a/dashboard/src/data/servedAges.test.ts b/dashboard/src/data/servedAges.test.ts new file mode 100644 index 00000000..f1d06fb0 --- /dev/null +++ b/dashboard/src/data/servedAges.test.ts @@ -0,0 +1,79 @@ +import { describe, expect, it } from "vitest"; + +import { servedAgeSeconds, stableEquals, stampServed, VOLATILE_AGE_FIELDS } from "./servedAges"; + +describe("VOLATILE_AGE_FIELDS", () => { + it("mirrors serving/delta.py exactly (keep the two sets in lockstep)", () => { + expect([...VOLATILE_AGE_FIELDS].sort()).toEqual([ + "ageSeconds", + "heartbeatAgeSeconds", + "snapshotStaleSeconds", + "staleSeconds", + "waitSeconds", + ]); + }); +}); + +describe("stableEquals", () => { + it("treats nodes differing only in volatile ages as equal", () => { + const a = { id: "L1", tokens: 3, staleSeconds: 1.5 }; + const b = { id: "L1", tokens: 3, staleSeconds: 99.5 }; + expect(stableEquals(a, b)).toBe(true); + }); + + it("ignores volatile ages nested in arrays and objects", () => { + const a = { queue: [{ id: "q1", waitSeconds: 10 }], doc: { ageSeconds: 5, title: "t" } }; + const b = { queue: [{ id: "q1", waitSeconds: 600 }], doc: { ageSeconds: 900, title: "t" } }; + expect(stableEquals(a, b)).toBe(true); + }); + + it("treats a volatile field appearing or disappearing as equal (exclude_none wire form)", () => { + // The server omits None fields, so a node can gain/lose `staleSeconds` between emissions + // without any real change. + expect(stableEquals({ id: "L1" }, { id: "L1", staleSeconds: 4 })).toBe(true); + }); + + it("detects real changes", () => { + expect(stableEquals({ id: "L1", tokens: 3 }, { id: "L1", tokens: 4 })).toBe(false); + expect(stableEquals({ items: [1, 2] }, { items: [1, 2, 3] })).toBe(false); + expect(stableEquals({ a: 1 }, { a: 1, b: 2 })).toBe(false); + expect(stableEquals({ gate: null }, { gate: { id: "g" } })).toBe(false); + }); + + it("handles primitives and null", () => { + expect(stableEquals(null, null)).toBe(true); + expect(stableEquals(null, {})).toBe(false); + expect(stableEquals("x", "x")).toBe(true); + expect(stableEquals(1, "1")).toBe(false); + }); +}); + +describe("servedAgeSeconds", () => { + it("advances a stamped node's served age by the elapsed wall-clock", () => { + const node = { id: "L1" }; + stampServed(node, 1_000_000); + expect(servedAgeSeconds(node, 30, 1_045_000)).toBe(75); // 30 s served + 45 s elapsed + }); + + it("never advances backwards on clock skew", () => { + const node = { id: "L1" }; + stampServed(node, 1_000_000); + expect(servedAgeSeconds(node, 30, 999_000)).toBe(30); + }); + + it("serves an unstamped node's value as-is (fixtures, tests)", () => { + expect(servedAgeSeconds({ id: "L1" }, 30, Date.now())).toBe(30); + }); + + it("never fabricates a missing served value", () => { + const node = { id: "L1" }; + stampServed(node, 1_000_000); + expect(servedAgeSeconds(node, undefined, 2_000_000)).toBeUndefined(); + expect(servedAgeSeconds(node, null, 2_000_000)).toBeUndefined(); + }); + + it("handles a missing node (optional chains at call sites)", () => { + expect(servedAgeSeconds(undefined, 30, Date.now())).toBe(30); + expect(servedAgeSeconds(null, undefined, Date.now())).toBeUndefined(); + }); +}); diff --git a/dashboard/src/data/servedAges.ts b/dashboard/src/data/servedAges.ts new file mode 100644 index 00000000..18b4c2f3 --- /dev/null +++ b/dashboard/src/data/servedAges.ts @@ -0,0 +1,85 @@ +// The client half of the change-gate's volatile-age contract (260703-L15). +// +// The server's SSE diff compares STABLE forms: the now-relative age fields listed in +// VOLATILE_AGE_FIELDS are recomputed from the tick clock every projection, so comparing +// them re-emitted ~the full payload every tick (~780 KB/s measured live) even when nothing +// real changed. With them excluded server-side (serving/delta.py), a node's served age is +// only fresh at the moment the node last ARRIVED — so this module (1) mirrors the exact +// field set for the store's stable-equality merge, and (2) anchors every applied node to +// its arrival time so display sites can advance ages locally. "Server-anchored, client- +// advanced": the value is still never *computed* from the render clock, only aged forward +// from the served anchor (localhost clocks; sub-second skew is far below display grain). + +import { useEffect, useState } from "react"; + +/** Mirror of serving/delta.py VOLATILE_AGE_FIELDS — keep the two sets in lockstep. */ +export const VOLATILE_AGE_FIELDS: ReadonlySet = new Set([ + "staleSeconds", + "snapshotStaleSeconds", + "ageSeconds", + "waitSeconds", + "heartbeatAgeSeconds", +]); + +/** + * Deep equality over parsed wire payloads, ignoring the volatile age keys. Used by the + * store merge so an arriving node that only differs in its ages (a reconnect snapshot, a + * redundant delta) is recognized as unchanged and keeps its existing object identity — + * zero store write, zero downstream re-render, and the node keeps its original age anchor. + */ +export function stableEquals(a: unknown, b: unknown): boolean { + if (Object.is(a, b)) return true; + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false; + return a.every((item, index) => stableEquals(item, b[index])); + } + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false; + const left = a as Record; + const right = b as Record; + const leftKeys = Object.keys(left).filter((key) => !VOLATILE_AGE_FIELDS.has(key)); + const rightKeys = Object.keys(right).filter((key) => !VOLATILE_AGE_FIELDS.has(key)); + if (leftKeys.length !== rightKeys.length) return false; + return leftKeys.every( + (key) => Object.prototype.hasOwnProperty.call(right, key) && stableEquals(left[key], right[key]), + ); +} + +// Arrival anchors, keyed by node object identity. A WeakMap so anchors never retain nodes +// the store has dropped (the long-session rule: no side table may outlive its subject). +const anchors = new WeakMap(); + +/** Anchor one applied node to its arrival time. The store calls this for every node it applies. */ +export function stampServed(node: object, atMs: number = Date.now()): void { + anchors.set(node, atMs); +} + +/** + * A served age advanced to `nowMs`: the node's served seconds plus the time elapsed since + * the node arrived. An unanchored node (fixtures, tests) serves its value as-is; a missing + * served value stays missing (never fabricated). + */ +export function servedAgeSeconds( + node: object | undefined | null, + servedSeconds: number | undefined | null, + nowMs: number, +): number | undefined { + if (servedSeconds == null) return undefined; + if (node == null) return servedSeconds; + const at = anchors.get(node); + if (at == null) return servedSeconds; + return servedSeconds + Math.max(0, (nowMs - at) / 1000); +} + +/** + * A coarse ticking clock for age display. Panels that render served ages re-render on this + * step (default 10 s) instead of riding the old per-second full-payload churn; fmtWait's + * display grain (s → m → h → d) makes a 10 s step visually seamless above the first minute. + */ +export function useNowMs(stepMs = 10_000): number { + const [now, setNow] = useState(() => Date.now()); + useEffect(() => { + const id = window.setInterval(() => setNow(Date.now()), stepMs); + return () => window.clearInterval(id); + }, [stepMs]); + return now; +} diff --git a/dashboard/src/data/sessionGroups.test.ts b/dashboard/src/data/sessionGroups.test.ts new file mode 100644 index 00000000..b8f40964 --- /dev/null +++ b/dashboard/src/data/sessionGroups.test.ts @@ -0,0 +1,243 @@ +import { describe, expect, it } from "vitest"; + +import type { EnclosureNode, TaskDocNode } from "../types/projection"; +import { groupSessions } from "./sessionGroups"; +import type { OpenSession } from "./sessions"; + +// The G1 command-tree derivation (L14): membership is claim + spawn-role provenance, the deck +// exists only when an orchestration task exists (D3), landed work rolls into one archive, and a +// flat run derives zero groups so the sidebar renders exactly as before. + +function doc(over: Partial & Pick): TaskDocNode { + return { + id: "doc", + repository: "agents-remember", + status: "inProgress", + kind: "subTask", + stepsDone: 0, + stepsTotal: 0, + steps: [], + objective: "", + requirements: [], + codeExamples: [], + decisions: [], + openQuestions: [], + references: [], + subTasks: [], + sections: [], + ...over, + }; +} + +function enclosure( + over: Partial & Pick, +): EnclosureNode { + return { + enclosureId: over.enclosure, + taskId: "T", + taskName: "t", + repoName: "agents-remember", + lifecycleId: "", + worktreeGroup: "/worktrees/g", + humanReviewStatus: "pending-review", + closeoutStatus: "not-started", + integrationStatus: "not-started", + cleanup: "pending", + codeWorktreeExists: true, + memoryWorktreeExists: true, + actions: [], + ...over, + }; +} + +function session(over: Partial & Pick): OpenSession { + return { label: over.id, status: "running", ...over }; +} + +const SPRINT = doc({ + id: "SPRINT-02", + kind: "master", + title: "SPRINT 02 · management-repo rollout", + docPath: "/tasks/agents-remember/sprint-02/task.json", + orchestrates: ["260706_management-repo"], + createdAt: "2026-07-01T09:00:00+00:00", +}); +const COMMANDED_MASTER = doc({ + id: "260706", + kind: "master", + title: "260706 management-repo", + docPath: "/tasks/agents-remember/260706_management-repo/task.json", + createdAt: "2026-07-02T09:00:00+00:00", +}); +const FREE_MASTER = doc({ + id: "260707", + kind: "master", + title: "260707 settings page", + docPath: "/tasks/agents-remember/260707_settings-page/task.json", + createdAt: "2026-07-03T09:00:00+00:00", +}); +const LIVE_ENCLOSURE = enclosure({ + enclosure: "/contracts/l1", + leafId: "260706-l1", + taskRoot: "/tasks/agents-remember/260706_management-repo", +}); +const FREE_ENCLOSURE = enclosure({ + enclosure: "/contracts/s0", + leafId: "260707-l0", + taskRoot: "/tasks/agents-remember/260707_settings-page", +}); + +describe("groupSessions (L14 G1 command tree)", () => { + it("groups command-role provenance onto the deck together with the orchestration-claiming chat", () => { + const grouped = groupSessions({ + sessions: [ + session({ id: "dev", leafKey: "agents-remember/sprint-02/SPRINT-02" }), + session({ id: "strat", spawnRole: "strategist" }), + session({ id: "mgr", spawnRole: "manager", leafKey: "agents-remember/260706_management-repo/260706" }), + session({ id: "worker", spawnRole: "worker", leafKey: "agents-remember/260706_management-repo/260706-L1" }), + ], + taskDocuments: [SPRINT, COMMANDED_MASTER], + enclosures: [LIVE_ENCLOSURE], + }); + + const deck = grouped.groups.find((group) => group.kind === "command"); + expect(deck).toBeTruthy(); + expect(deck?.label).toBe("SPRINT 02 · management-repo rollout · command deck"); + expect(deck?.tier).toBe("orchestration"); + // The developer-facing orchestrator chat (the orchestration task's own leaf claim) sits on the + // deck with the spawned command seats; the worker does NOT (role provenance is the gate). + expect(deck?.sessions.map((member) => member.id)).toEqual(["dev", "strat", "mgr"]); + expect(deck?.countLabel).toBe("3 chats · 3 live"); + + const master = grouped.groups.find((group) => group.key === "master:260706_management-repo"); + expect(master?.sessions.map((member) => member.id)).toEqual(["worker"]); + expect(master?.tier).toBe("management"); // commanded by the sprint → purple badge + expect(master?.nested).toBe(true); // + one indent step + }); + + it("groups by leaf claim under the master, unmarked and un-nested when no orchestration commands it", () => { + const grouped = groupSessions({ + sessions: [ + session({ id: "builder", spawnRole: "worker", leafKey: "agents-remember/260707_settings-page/260707-L0" }), + ], + taskDocuments: [FREE_MASTER], + enclosures: [FREE_ENCLOSURE], + }); + expect(grouped.groups).toHaveLength(1); + const master = grouped.groups[0]; + expect(master.key).toBe("master:260707_settings-page"); + expect(master.label).toBe("260707 settings page"); + expect(master.tier).toBeUndefined(); + expect(master.nested).toBe(false); + expect(grouped.ungrouped).toEqual([]); + }); + + it("keeps command-role sessions out of the deck when NO orchestration task exists (D3 flat run)", () => { + const grouped = groupSessions({ + sessions: [ + session({ id: "mgr", spawnRole: "manager" }), + session({ id: "plain" }), + ], + taskDocuments: [FREE_MASTER], + enclosures: [], + }); + expect(grouped.groups).toEqual([]); // no deck, no master claims → zero groups + expect(grouped.ungrouped.map((member) => member.id)).toEqual(["mgr", "plain"]); + }); + + it("rolls sessions on landed or absent enclosures into one archive group, collapsed by default", () => { + const landedEnclosure = enclosure({ + enclosure: "/contracts/landed", + leafId: "260706-l0", + taskRoot: "/tasks/agents-remember/260706_management-repo", + codeWorktreeExists: false, + memoryWorktreeExists: false, + }); + const grouped = groupSessions({ + sessions: [ + session({ id: "landed-chat", leafKey: "agents-remember/260706_management-repo/260706-L0", status: "exited" }), + session({ id: "absent-chat", leafKey: "agents-remember/260799_unknown/260799-L9" }), + ], + taskDocuments: [COMMANDED_MASTER], + enclosures: [landedEnclosure], + }); + expect(grouped.groups).toHaveLength(1); + const archive = grouped.groups[0]; + expect(archive.kind).toBe("landed"); + expect(archive.tier).toBeUndefined(); // unmarked + expect(archive.defaultCollapsed).toBe(true); + expect(archive.sessions.map((member) => member.id)).toEqual(["landed-chat", "absent-chat"]); + expect(archive.countLabel).toBe("2 chats · archived"); + }); + + it("matches enclosure leaf ids case-insensitively (doc ids are uppercase, enclosure ids slugified)", () => { + const grouped = groupSessions({ + sessions: [session({ id: "w", leafKey: "agents-remember/260706_management-repo/260706-L1" })], + taskDocuments: [COMMANDED_MASTER], + enclosures: [LIVE_ENCLOSURE], // leafId "260706-l1" + }); + expect(grouped.groups[0]?.key).toBe("master:260706_management-repo"); + }); + + it("reads at a glance at 30-chat scale: deck + per-master groups + one archive", () => { + const sessions: OpenSession[] = [ + session({ id: "orch", spawnRole: "orchestrator" }), + session({ id: "strategist", spawnRole: "strategist", status: "exited" }), + session({ id: "m1", spawnRole: "manager" }), + session({ id: "m2", spawnRole: "manager", status: "exited" }), + ]; + for (let i = 0; i < 6; i += 1) { + sessions.push( + session({ + id: `a${i}`, + spawnRole: i % 2 ? "reviewer" : "worker", + leafKey: "agents-remember/260706_management-repo/260706-L1", + status: i < 2 ? "running" : "exited", + }), + ); + } + for (let i = 0; i < 7; i += 1) { + sessions.push( + session({ + id: `b${i}`, + spawnRole: "worker", + leafKey: "agents-remember/260707_settings-page/260707-L0", + status: i < 1 ? "running" : "exited", + }), + ); + } + for (let i = 0; i < 13; i += 1) { + sessions.push( + session({ id: `old${i}`, leafKey: `agents-remember/260650_landed/260650-L${i}`, status: "exited" }), + ); + } + expect(sessions).toHaveLength(30); + + const grouped = groupSessions({ + sessions, + taskDocuments: [ + SPRINT, + COMMANDED_MASTER, + FREE_MASTER, + ], + enclosures: [LIVE_ENCLOSURE, FREE_ENCLOSURE], + }); + + expect(grouped.groups.map((group) => group.key)).toEqual([ + "command", + "master:260706_management-repo", + "master:260707_settings-page", + "landed", + ]); + const [deck, masterA, masterB, archive] = grouped.groups; + expect(deck.sessions).toHaveLength(4); + expect(deck.countLabel).toBe("4 chats · 2 live"); + expect(masterA.sessions).toHaveLength(6); + expect(masterA.countLabel).toBe("6 chats · 2 live"); + expect(masterB.sessions).toHaveLength(7); + expect(masterB.countLabel).toBe("7 chats · 1 live"); + expect(archive.sessions).toHaveLength(13); + expect(archive.countLabel).toBe("13 chats · archived"); + expect(grouped.ungrouped).toEqual([]); + }); +}); diff --git a/dashboard/src/data/sessionGroups.ts b/dashboard/src/data/sessionGroups.ts new file mode 100644 index 00000000..e8c52239 --- /dev/null +++ b/dashboard/src/data/sessionGroups.ts @@ -0,0 +1,189 @@ +import type { EnclosureNode, TaskDocNode } from "../types/projection"; +import { hasLiveWorktree } from "./selectors"; +import type { OpenSession } from "./sessions"; +import { + isOrchestrationDoc, + masterCommandNames, + orchestratorParentKey, + pathDir, +} from "./taskHierarchy"; +import { qualifiedLeafKey } from "./taskIdentity"; + +// The G1 COMMAND TREE for the Chats pane (L14): the chats sidebar mirrors operations. Membership, +// in precedence order, per session: +// 1. COMMAND DECK (gold, top; exists ONLY when an orchestration task exists — D3): sessions with +// command-role spawn provenance (AR_SPAWN_ROLE orchestrator/strategist/manager recorded on the +// catalog row) plus any session whose leaf claim resolves INTO the orchestration task itself +// (its own qualified leaf, or a leaf in its folder) — the developer-facing orchestrator chat. +// 2. MASTER GROUPS (one per claimed master folder): sessions whose qualified leaf key +// (`repo/master/leaf-id`) resolves to a live enclosure of that master; the group takes the +// purple management badge + one 22px indent step only when that master is commanded by an +// orchestration task — mirroring the tasks-tab grammar exactly. +// 3. LANDED ARCHIVE (one group, collapsed by default, unmarked): sessions attached to a leaf +// whose enclosure is gone or absent — landed work rolls up instead of cluttering the rail. +// 4. UNGROUPED: sessions with no leaf claim keep today's flat placement below the groups. +// Pure derivation — no persistence; collapse state is UI-local in the SessionList. + +/** The l-01 seats whose chats belong on the command deck. */ +const COMMAND_ROLES = new Set(["orchestrator", "strategist", "manager"]); + +export interface SessionGroup { + key: string; // "command" | `master:${folder}` | "landed" + kind: "command" | "master" | "landed"; + label: string; + /** Rank insignia tier for the group header; unset = unmarked (landed / uncommanded master). */ + tier?: "orchestration" | "management"; + /** One 22px indent step (a master group commanded by the orchestration task). */ + nested: boolean; + defaultCollapsed: boolean; + sessions: OpenSession[]; + /** "n chats · n live" (live from the existing session state; archive groups read "· archived"). */ + countLabel: string; +} + +export interface GroupedSessions { + groups: SessionGroup[]; + /** Sessions with no claim and no command provenance — today's flat placement below the groups. */ + ungrouped: OpenSession[]; +} + +function isLive(session: OpenSession): boolean { + return (session.status ?? "running") === "running"; +} + +function countLabel(sessions: OpenSession[], kind: SessionGroup["kind"]): string { + const chats = `${sessions.length} chat${sessions.length === 1 ? "" : "s"}`; + if (kind === "landed") return `${chats} · archived`; + const live = sessions.filter(isLive).length; + return live > 0 ? `${chats} · ${live} live` : chats; +} + +function folderOf(path: string): string { + return path.split("/").filter(Boolean).pop() ?? ""; +} + +/** The `repo/master/leaf-id` segments of a leaf claim, or undefined when malformed. */ +function leafKeySegments( + leafKey: string, +): { repo: string; master: string; leafId: string } | undefined { + const parts = leafKey.split("/").filter(Boolean); + if (parts.length < 3) return undefined; + return { repo: parts[0], master: parts[1], leafId: parts[parts.length - 1] }; +} + +// The enclosure a leaf claim resolves to: master folder = basename(taskRoot), leaf ids compared +// case-insensitively (enclosure leaf ids are slugified lowercase, doc ids authored uppercase — +// the same normalization the tasks tab uses), repo checked when the enclosure carries one. +function enclosureForLeafKey( + leafKey: string, + enclosures: EnclosureNode[], +): EnclosureNode | undefined { + const segments = leafKeySegments(leafKey); + if (!segments) return undefined; + return enclosures.find((enclosure) => { + if (folderOf(enclosure.taskRoot) !== segments.master) return false; + if (enclosure.repoName && enclosure.repoName !== segments.repo) return false; + return enclosure.leafId.toLowerCase() === segments.leafId.toLowerCase(); + }); +} + +export function groupSessions(input: { + sessions: OpenSession[]; + taskDocuments: TaskDocNode[]; + enclosures: EnclosureNode[]; +}): GroupedSessions { + const docs = input.taskDocuments; + const orchestrationDocs = docs.filter(isOrchestrationDoc); + const deckExists = orchestrationDocs.length > 0; + const orchestrationFolders = new Set(orchestrationDocs.map((doc) => folderOf(pathDir(doc.docPath)))); + const orchestrationLeafKeys = new Set( + orchestrationDocs.map((doc) => qualifiedLeafKey(doc)).filter(Boolean), + ); + const masterDocsByFolder = new Map(); + for (const doc of docs) { + if (doc.kind !== "master") continue; + const folder = folderOf(pathDir(doc.docPath)); + if (folder && !masterDocsByFolder.has(folder)) masterDocsByFolder.set(folder, doc); + } + + const deck: OpenSession[] = []; + const landed: OpenSession[] = []; + const ungrouped: OpenSession[] = []; + const byMaster = new Map(); + + for (const session of input.sessions) { + const segments = session.leafKey ? leafKeySegments(session.leafKey) : undefined; + const claimsOrchestration = + (session.leafKey !== undefined && orchestrationLeafKeys.has(session.leafKey)) || + (segments !== undefined && orchestrationFolders.has(segments.master)); + if ( + deckExists && + ((session.spawnRole !== undefined && COMMAND_ROLES.has(session.spawnRole)) || + claimsOrchestration) + ) { + deck.push(session); + continue; + } + if (!segments) { + ungrouped.push(session); + continue; + } + const enclosure = enclosureForLeafKey(session.leafKey as string, input.enclosures); + if (enclosure && hasLiveWorktree(enclosure)) { + const members = byMaster.get(segments.master); + if (members) members.push(session); + else byMaster.set(segments.master, [session]); + } else { + // Landed or absent enclosure: the work left the hangar, the chat rolls into the archive. + landed.push(session); + } + } + + const groups: SessionGroup[] = []; + if (deck.length > 0) { + const sprint = orchestrationDocs[0]; + groups.push({ + key: "command", + kind: "command", + label: sprint?.title ? `${sprint.title} · command deck` : "command deck", + tier: "orchestration", + nested: false, + defaultCollapsed: false, + sessions: deck, + countLabel: countLabel(deck, "command"), + }); + } + const masterGroups = [...byMaster.entries()].map(([folder, members]) => { + const masterDoc = masterDocsByFolder.get(folder); + const commanded = masterDoc + ? orchestratorParentKey(masterCommandNames(masterDoc), docs, masterDoc.docPath) !== undefined + : orchestrationDocs.some((doc) => (doc.orchestrates ?? []).includes(folder)); + const group: SessionGroup = { + key: `master:${folder}`, + kind: "master", + label: masterDoc?.title || folder, + ...(commanded ? { tier: "management" as const } : {}), + nested: commanded, + defaultCollapsed: false, + sessions: members, + countLabel: countLabel(members, "master"), + }; + return { order: masterDoc?.createdAt ?? "", folder, group }; + }); + masterGroups.sort( + (left, right) => left.order.localeCompare(right.order) || left.folder.localeCompare(right.folder), + ); + for (const entry of masterGroups) groups.push(entry.group); + if (landed.length > 0) { + groups.push({ + key: "landed", + kind: "landed", + label: "landed", + nested: false, + defaultCollapsed: true, + sessions: landed, + countLabel: countLabel(landed, "landed"), + }); + } + return { groups, ungrouped }; +} diff --git a/dashboard/src/data/sessions.ts b/dashboard/src/data/sessions.ts index 51d97130..c00bb483 100644 --- a/dashboard/src/data/sessions.ts +++ b/dashboard/src/data/sessions.ts @@ -27,6 +27,8 @@ export interface OpenSession { lifecycleId?: string; /** The durable leaf-identity key (qualified leaf id `repo/master/leaf-id`) this chat is bound to. */ leafKey?: string; + /** The AR_SPAWN_ROLE recorded at spawn (L14) — the Chats command-tree grouping key. */ + spawnRole?: string; status?: TerminalSessionStatus; } @@ -350,6 +352,7 @@ export function fromTerminalSessionInfo(info: TerminalSessionInfo): OpenSession ...(info.harness ? { harness: info.harness } : {}), ...(info.lifecycleId ? { lifecycleId: info.lifecycleId } : {}), ...(info.leafKey ? { leafKey: info.leafKey } : {}), + ...(info.spawnRole ? { spawnRole: info.spawnRole } : {}), status: info.status, }; } diff --git a/dashboard/src/data/store.test.ts b/dashboard/src/data/store.test.ts index 59752c1e..3ebdfb5d 100644 --- a/dashboard/src/data/store.test.ts +++ b/dashboard/src/data/store.test.ts @@ -15,6 +15,7 @@ beforeEach(() => { providers: {}, metrics: null, analytics: null, + servingBuild: null, }); }); @@ -67,3 +68,118 @@ describe("dashboard store", () => { expect(dashboardStore.getState().conn).toBe("signal-lost"); }); }); + +// ── The change gate (260703-L15) ─────────────────────────────────────────────── +// A payload whose only movement is its volatile ages (or a byte-fresh but content-equal +// reconnect snapshot) must cost NOTHING: no store write, no new object graph, no re-render. + +/** A byte-fresh copy of the projection (like a real wire parse) with volatile ages bumped. */ +function volatileBump(source: WorkspaceProjection, tick: number): WorkspaceProjection { + const copy = JSON.parse(JSON.stringify(source)) as WorkspaceProjection; + copy.generatedAt = `2026-07-07T05:00:${String(tick % 60).padStart(2, "0")}+00:00`; + for (const lifecycle of copy.lifecycles) lifecycle.staleSeconds = 10 + tick; + for (const doc of copy.analytics?.taskDocuments ?? []) doc.ageSeconds = 100 + tick; + for (const item of copy.analytics?.attentionQueue ?? []) item.waitSeconds = 5 + tick; + return copy; +} + +describe("dashboard store change gate (260703-L15)", () => { + it("applies N idle re-snapshots with zero store writes and stable identity", () => { + dashboardStore.getState().applySnapshot(volatileBump(projection, 0)); + const before = dashboardStore.getState(); + let notifications = 0; + const unsubscribe = dashboardStore.subscribe(() => { + notifications += 1; + }); + for (let tick = 1; tick <= 50; tick += 1) { + dashboardStore.getState().applySnapshot(volatileBump(projection, tick)); + } + unsubscribe(); + const after = dashboardStore.getState(); + expect(notifications).toBe(0); // zero store writes — set() was never called + expect(after).toBe(before); // the state OBJECT is untouched + expect(after.lifecycles).toBe(before.lifecycles); + expect(after.analytics).toBe(before.analytics); + expect(after.generatedAt).toBe(before.generatedAt); // ages/stamp coherence: no new content, no new stamp + }); + + it("skips a redundant delta (volatile-only node) without a store write", () => { + dashboardStore.getState().applySnapshot(projection); + const before = dashboardStore.getState(); + const node = JSON.parse(JSON.stringify(before.lifecycles["sim-replay-lifecycle"])); + node.staleSeconds = 12345; + dashboardStore.getState().applyDelta("lifecycle", node); + expect(dashboardStore.getState()).toBe(before); + expect(dashboardStore.getState().lifecycles).toBe(before.lifecycles); + }); + + it("skips a removed-marker for an absent node without a store write", () => { + dashboardStore.getState().applySnapshot(projection); + const before = dashboardStore.getState(); + dashboardStore.getState().applyDelta("lifecycle.removed", { id: "no-such-lifecycle" }); + expect(dashboardStore.getState()).toBe(before); + }); + + it("still applies a real delta exactly as before", () => { + dashboardStore.getState().applySnapshot(projection); + const before = dashboardStore.getState(); + const node = JSON.parse(JSON.stringify(before.lifecycles["sim-replay-lifecycle"])); + node.tokens = 999999; + node.staleSeconds = 1; // fresh ages ride along with real changes + dashboardStore.getState().applyDelta("lifecycle", node); + const after = dashboardStore.getState(); + expect(after).not.toBe(before); + expect(after.lifecycles["sim-replay-lifecycle"].tokens).toBe(999999); + }); + + it("reuses unchanged nodes by identity when a snapshot carries one real change", () => { + dashboardStore.getState().applySnapshot(projection); + const untouched = dashboardStore.getState().lifecycles["fleeting-001"]; + const next = volatileBump(projection, 7); + const changed = next.lifecycles.find((x) => x.id === "sim-replay-lifecycle"); + if (!changed) throw new Error("fixture lifecycle missing"); + changed.tokens = 424242; + dashboardStore.getState().applySnapshot(next); + const state = dashboardStore.getState(); + expect(state.lifecycles["sim-replay-lifecycle"].tokens).toBe(424242); + expect(state.lifecycles["fleeting-001"]).toBe(untouched); // identity preserved + }); + + it("carries the serving-build stamp and keeps its identity across snapshots", () => { + const build = { version: "9.9.9", commit: "abc1234", bootedAt: "2026-07-07T05:00:00Z" }; + dashboardStore.getState().applySnapshot({ ...projection, servingBuild: build }); + const first = dashboardStore.getState().servingBuild; + expect(first).toEqual(build); + const next = volatileBump({ ...projection, servingBuild: { ...build } }, 3); + const changed = next.lifecycles[0]; + changed.tokens = 111; // force a real apply + dashboardStore.getState().applySnapshot(next); + expect(dashboardStore.getState().servingBuild).toBe(first); // equal stamp -> same object + }); +}); + +// ── The long-session guard (260703-L15) ──────────────────────────────────────── +// A working day of ticks must not grow the store: identical polls keep identity, the event +// window stays bounded, and no collection accumulates. + +describe("long-session guard", () => { + it("stays flat across 500 simulated idle ticks with event traffic", () => { + dashboardStore.setState({ events: [], eventsHydrated: false }); + dashboardStore.getState().applySnapshot(volatileBump(projection, 0)); + const lifecyclesRef = dashboardStore.getState().lifecycles; + const analyticsRef = dashboardStore.getState().analytics; + for (let tick = 1; tick <= 500; tick += 1) { + dashboardStore.getState().applySnapshot(volatileBump(projection, tick)); + for (let i = 0; i < 5; i += 1) { + dashboardStore + .getState() + .pushEvent(JSON.stringify({ id: `t${tick}-${i}`, kind: "tool.completed", data: {} })); + } + } + const state = dashboardStore.getState(); + expect(state.lifecycles).toBe(lifecyclesRef); // no per-tick object churn + expect(state.analytics).toBe(analyticsRef); + expect(state.events.length).toBeLessThanOrEqual(2000); // the sliding window bound + expect(Object.keys(state.lifecycles).length).toBe(2); // nothing accumulates + }); +}); diff --git a/dashboard/src/data/store.ts b/dashboard/src/data/store.ts index 22023a66..e6e9212c 100644 --- a/dashboard/src/data/store.ts +++ b/dashboard/src/data/store.ts @@ -8,8 +8,10 @@ import type { LifecycleProjection, Metrics, ProviderNode, + ServingBuild, WorkspaceProjection, } from "../types/projection"; +import { stableEquals, stampServed } from "./servedAges"; export type ConnState = "connecting" | "live" | "signal-lost"; @@ -27,6 +29,9 @@ export interface DashboardState { activeWorktreeGroups: string[]; // worktree-group basenames with a live enclosure (Topology scope) metrics: Metrics | null; analytics: Analytics | null; + // The boot-time serving stamp (260703-L15): which build/process is answering. Rides the + // snapshot; rendered muted in the top bar so a stale server is visible at a glance. + servingBuild: ServingBuild | null; events: ObserverEvent[]; // raw observer feed retained client-side until reset/reload eventsHydrated: boolean; suppressedAttentionIds: Record; @@ -46,8 +51,64 @@ export interface DashboardState { // is the real history bound, and EventRiver virtualizes the window so render cost stays flat. const EVENT_WINDOW = 2000; -const byKey = (items: T[], key: (item: T) => string): Record => - Object.fromEntries(items.map((item) => [key(item), item])); +// ── The change gate (260703-L15) ──────────────────────────────────────────────────────── +// Both apply paths are IDENTITY-PRESERVING: an arriving node that stable-equals the stored +// one (volatile age fields ignored — data/servedAges.ts mirrors serving/delta.py) keeps the +// EXISTING object, and an apply in which nothing changed performs NO store write at all. A +// long-lived tab receiving reconnect snapshots or redundant deltas therefore allocates +// nothing and re-renders nothing; applied nodes are age-anchored via `stampServed` so +// staleness displays advance locally between real emissions. + +/** Reuse the current value when the incoming one is stable-equal (keeps identity + anchor). */ +const reuse = (current: T, incoming: T): T => (stableEquals(current, incoming) ? current : incoming); + +/** + * Merge an incoming collection into the id-keyed map, reusing every stable-equal node. + * Returns the EXISTING map object when nothing changed (added/updated/removed). + */ +const mergeKeyed = ( + existing: Record, + incoming: T[], + key: (item: T) => string, +): Record => { + const next: Record = {}; + let changed = false; + for (const item of incoming) { + const ident = key(item); + const current = existing[ident]; + if (current !== undefined && stableEquals(current, item)) { + next[ident] = current; + } else { + stampServed(item); + next[ident] = item; + changed = true; + } + } + if (!changed && Object.keys(existing).length === incoming.length) return existing; + return next; +}; + +// The analytics object replaces wholesale (matching the wire protocol), so each replacement +// re-anchors every age-bearing node it carries — their served ages are fresh at that moment. +const stampAnalytics = (analytics: Analytics | null): void => { + if (!analytics) return; + const at = Date.now(); + const collections: (readonly object[] | undefined)[] = [ + analytics.driftSnapshots, + analytics.stalestSidecars, + analytics.setupSummaries, + analytics.setupProgress, + analytics.toolReports, + analytics.agentPickups, + analytics.taskDocuments, + analytics.series, + analytics.attentionQueue, + analytics.engineProcesses, + ]; + for (const list of collections) { + for (const node of list ?? []) stampServed(node, at); + } +}; const upsert = ( collection: Record, @@ -56,7 +117,6 @@ const upsert = ( ): Record => ({ ...collection, [key(item)]: item }); const remove = (collection: Record, id: string): Record => { - if (!(id in collection)) return collection; const next = { ...collection }; delete next[id]; return next; @@ -75,44 +135,72 @@ const pruneSuppressedAttention = ( }; // The state channel's named deltas, merged into the flat id-keyed maps. The server diffs -// consecutive projections (serving/delta.py) and emits upserts / `*.removed` markers; -// `metrics` / `analytics` arrive as whole-object replacements. +// consecutive projections on their STABLE forms (serving/delta.py) and emits upserts / +// `*.removed` markers; `metrics` / `analytics` arrive as whole-object replacements. Returns +// `null` when the delta would not change the store — the caller then skips the write. function reduceDelta( state: DashboardState, event: string, data: unknown, -): Partial { +): Partial | null { switch (event) { - case "lifecycle": - return { lifecycles: upsert(state.lifecycles, data as LifecycleProjection, (x) => x.id) }; - case "lifecycle.removed": - return { lifecycles: remove(state.lifecycles, (data as { id: string }).id) }; - case "enclosure": - return { enclosures: upsert(state.enclosures, data as EnclosureNode, (x) => x.enclosure) }; - case "enclosure.removed": - return { enclosures: remove(state.enclosures, (data as { enclosure: string }).enclosure) }; - case "provider": - return { providers: upsert(state.providers, data as ProviderNode, (x) => x.id) }; - case "provider.removed": - return { providers: remove(state.providers, (data as { id: string }).id) }; - case "activeWorktreeGroups": + case "lifecycle": { + const node = data as LifecycleProjection; + if (stableEquals(state.lifecycles[node.id], node)) return null; + stampServed(node); + return { lifecycles: upsert(state.lifecycles, node, (x) => x.id) }; + } + case "lifecycle.removed": { + const { id } = data as { id: string }; + return id in state.lifecycles ? { lifecycles: remove(state.lifecycles, id) } : null; + } + case "enclosure": { + const node = data as EnclosureNode; + if (stableEquals(state.enclosures[node.enclosure], node)) return null; + stampServed(node); + return { enclosures: upsert(state.enclosures, node, (x) => x.enclosure) }; + } + case "enclosure.removed": { + const { enclosure } = data as { enclosure: string }; + return enclosure in state.enclosures + ? { enclosures: remove(state.enclosures, enclosure) } + : null; + } + case "provider": { + const node = data as ProviderNode; + if (stableEquals(state.providers[node.id], node)) return null; + stampServed(node); + return { providers: upsert(state.providers, node, (x) => x.id) }; + } + case "provider.removed": { + const { id } = data as { id: string }; + return id in state.providers ? { providers: remove(state.providers, id) } : null; + } + case "activeWorktreeGroups": { // Whole-value replacement (a bare list, no key) — see serving/delta.py. - return { activeWorktreeGroups: (data as { activeWorktreeGroups: string[] }).activeWorktreeGroups }; - case "metrics": - return { metrics: data as Metrics }; + const { activeWorktreeGroups } = data as { activeWorktreeGroups: string[] }; + if (stableEquals(state.activeWorktreeGroups, activeWorktreeGroups)) return null; + return { activeWorktreeGroups }; + } + case "metrics": { + const metrics = data as Metrics; + return stableEquals(state.metrics, metrics) ? null : { metrics }; + } case "analytics": { const analytics = data as Analytics; + if (stableEquals(state.analytics, analytics)) return null; + stampAnalytics(analytics); return { analytics, suppressedAttentionIds: pruneSuppressedAttention(state.suppressedAttentionIds, analytics), }; } default: - return {}; + return null; } } -export const dashboardStore = createStore((set) => ({ +export const dashboardStore = createStore((set, get) => ({ conn: "connecting", generatedAt: null, gen: 0, @@ -122,26 +210,60 @@ export const dashboardStore = createStore((set) => ({ activeWorktreeGroups: [], metrics: null, analytics: null, + servingBuild: null, events: [], eventsHydrated: false, suppressedAttentionIds: {}, - setConn: (conn) => set({ conn }), - applySnapshot: (projection) => - set((state) => ({ + setConn: (conn) => { + if (get().conn !== conn) set({ conn }); + }, + applySnapshot: (projection) => { + const state = get(); + const lifecycles = mergeKeyed(state.lifecycles, projection.lifecycles, (x) => x.id); + const enclosures = mergeKeyed(state.enclosures, projection.enclosures, (x) => x.enclosure); + const providers = mergeKeyed(state.providers, projection.providers, (x) => x.id); + const activeWorktreeGroups = reuse( + state.activeWorktreeGroups, + projection.activeWorktreeGroups ?? [], + ); + const metrics = reuse(state.metrics, projection.metrics); + const analytics = reuse(state.analytics, projection.analytics); + if (analytics !== state.analytics) stampAnalytics(analytics); + const servingBuild = reuse(state.servingBuild, projection.servingBuild ?? null); + const suppressedAttentionIds = pruneSuppressedAttention( + state.suppressedAttentionIds, + analytics, + ); + const unchanged = + lifecycles === state.lifecycles && + enclosures === state.enclosures && + providers === state.providers && + activeWorktreeGroups === state.activeWorktreeGroups && + metrics === state.metrics && + analytics === state.analytics && + servingBuild === state.servingBuild && + suppressedAttentionIds === state.suppressedAttentionIds; + // An unchanged snapshot (a reconnect while idle) is a NO-OP: no store write at all. + if (unchanged && state.conn === "live") return; + set({ conn: "live", - generatedAt: projection.generatedAt, - lifecycles: byKey(projection.lifecycles, (x) => x.id), - enclosures: byKey(projection.enclosures, (x) => x.enclosure), - providers: byKey(projection.providers, (x) => x.id), - activeWorktreeGroups: projection.activeWorktreeGroups ?? [], - metrics: projection.metrics, - analytics: projection.analytics, - suppressedAttentionIds: pruneSuppressedAttention( - state.suppressedAttentionIds, - projection.analytics, - ), - })), - applyDelta: (event, data) => set((state) => reduceDelta(state, event, data)), + // `generatedAt` is the stamp of the last APPLIED content (the top bar's "@ hh:mm:ss"), + // so an unchanged re-snapshot must not advance it — ages and stamp stay coherent. + generatedAt: unchanged ? state.generatedAt : projection.generatedAt, + lifecycles, + enclosures, + providers, + activeWorktreeGroups, + metrics, + analytics, + servingBuild, + suppressedAttentionIds, + }); + }, + applyDelta: (event, data) => { + const partial = reduceDelta(get(), event, data); + if (partial !== null) set(partial); + }, pushEvent: (line) => set((state) => { try { @@ -181,6 +303,7 @@ export const dashboardStore = createStore((set) => ({ activeWorktreeGroups: [], metrics: null, analytics: null, + servingBuild: null, events: [], eventsHydrated: false, suppressedAttentionIds: {}, diff --git a/dashboard/src/data/taskHierarchy.ts b/dashboard/src/data/taskHierarchy.ts index b8cc7948..170fce3f 100644 --- a/dashboard/src/data/taskHierarchy.ts +++ b/dashboard/src/data/taskHierarchy.ts @@ -58,6 +58,46 @@ export function parentTaskLinkForDoc( }; } +// --- the orchestration-command relation (L14) -------------------------------------------------- +// An ORCHESTRATION TASK is a `kind:"master"` doc carrying a non-empty top-level `orchestrates` +// list — the master task NAMES it commands (owner data-model ruling; no new task kind). A master +// is "commanded" when any orchestration doc's list contains one of the names it answers to: its +// task folder (the durable series key), its doc id, or its title — forgiving but exact-string. +// Masters named nowhere stay top-level exactly as today (D3: flat runs stay flat). + +export function isOrchestrationDoc( + doc: Pick, +): boolean { + return doc.kind === "master" && (doc.orchestrates?.length ?? 0) > 0; +} + +/** The names a master answers to when matched against an `orchestrates` list. */ +export function masterCommandNames( + doc: Pick, +): string[] { + const folder = pathDir(doc.docPath).split("/").filter(Boolean).pop() ?? ""; + return [folder, doc.id, doc.title].filter(Boolean); +} + +/** + * The selection key of the orchestration doc commanding a master that answers to `names`, + * or undefined when no orchestration task names it. A doc never commands itself. + */ +export function orchestratorParentKey( + names: string[], + docs: TaskDocNode[], + selfDocPath?: string, +): string | undefined { + const nameSet = new Set(names); + const commander = docs.find( + (doc) => + isOrchestrationDoc(doc) && + doc.docPath !== selfDocPath && + (doc.orchestrates ?? []).some((name) => nameSet.has(name)), + ); + return commander ? taskDocSelectionKey(commander.docPath) : undefined; +} + export function pathDir(path: string): string { return path.split("/").slice(0, -1).join("/"); } diff --git a/dashboard/src/data/terminal.ts b/dashboard/src/data/terminal.ts index 8a1a1760..99fd5139 100644 --- a/dashboard/src/data/terminal.ts +++ b/dashboard/src/data/terminal.ts @@ -280,6 +280,9 @@ export interface TerminalSessionInfo { lifecycleId?: string; /** The durable leaf-identity key (qualified leaf id `repo/master/leaf-id`) this chat claims. */ leafKey?: string; + /** The AR_SPAWN_ROLE recorded at spawn (L14): the l-01 role this session was dispatched AS + * (orchestrator/strategist/manager/worker/reviewer/designer). Absent on hand-opened sessions. */ + spawnRole?: string; cwd: string; tmuxName: string; createdAt: string; diff --git a/dashboard/src/dev/DevApp.tsx b/dashboard/src/dev/DevApp.tsx index 197d5c90..33beec5a 100644 --- a/dashboard/src/dev/DevApp.tsx +++ b/dashboard/src/dev/DevApp.tsx @@ -1,14 +1,24 @@ +import { FlowTab } from "../panels/FlowTab"; import { Bench } from "./Bench"; import { Reference } from "./Reference"; import "./dev.css"; // The dev harness router (DEV-only, lazy-loaded from App so it is dead-code-eliminated in the -// production bundle). `/dev/bench` = the component gallery; `/dev/reference` = the mc2 mount. +// production bundle). `/dev/bench` = the component gallery; `/dev/reference` = the mc2 mount; +// `/dev/flows` = the lifecycle-design canvas (orchestration L0; all models in `panels/flowModels.ts`) +// — kept out of the cockpit mode bar per task 29, reachable here for design sittings. export default function DevApp() { const path = window.location.pathname; if (path.startsWith("/dev/reference")) return ; if (path.startsWith("/dev/bench")) return ; + if (path.startsWith("/dev/flows")) { + return ( +
+ +
+ ); + } return (
@@ -21,6 +31,9 @@ export default function DevApp() {
  • /dev/reference — mc2 design endpoint, read-only
  • +
  • + /dev/flows — lifecycle flow canvas (router · designer · orchestrator · manager · worker · reviewer · comms) +
  • ); diff --git a/dashboard/src/dev/fixtures.ts b/dashboard/src/dev/fixtures.ts index 8e5e2fc0..4f5527a3 100644 --- a/dashboard/src/dev/fixtures.ts +++ b/dashboard/src/dev/fixtures.ts @@ -109,6 +109,9 @@ function enclosure( closeoutStatus: "pending", integrationStatus: "not-started", cleanup: "pending", + // Live by default: the tasks surface renders a leaf only while a worktree exists (L11). + codeWorktreeExists: true, + memoryWorktreeExists: true, actions: [], ...over, }; diff --git a/dashboard/src/grammar/RankBadge.test.tsx b/dashboard/src/grammar/RankBadge.test.tsx new file mode 100644 index 00000000..f8a02676 --- /dev/null +++ b/dashboard/src/grammar/RankBadge.test.tsx @@ -0,0 +1,51 @@ +import { cleanup, render } from "@testing-library/react"; +import { afterEach, describe, expect, it } from "vitest"; + +import { RankBadge } from "./RankBadge"; + +afterEach(cleanup); + +// The V4 rank insignia (L14): the glyph anatomy is the contract — three gold chevrons under a +// filled command pip for the orchestration seat, two purple chevrons for management — because the +// sketch the developer approved is pinned to exactly these shapes at 16px row / ~13px sm sizes. +describe("RankBadge (L14 V4 chevrons)", () => { + it("renders the orchestration tier as a command pip over three chevrons", () => { + const { container } = render(); + const svg = container.querySelector("svg"); + expect(svg?.getAttribute("data-rank-tier")).toBe("orchestration"); + expect(svg?.getAttribute("aria-hidden")).toBe("true"); + const paths = [...(svg?.querySelectorAll("path") ?? [])]; + expect(paths).toHaveLength(4); // pip + 3 chevrons + expect(paths[0].style.fill).toBe("currentColor"); // the pip is filled, not stroked + expect(paths.slice(1).every((path) => path.getAttribute("stroke") === "currentColor")).toBe( + true, + ); + }); + + it("renders the management tier as two chevrons with no pip", () => { + const { container } = render(); + const svg = container.querySelector("svg"); + expect(svg?.getAttribute("data-rank-tier")).toBe("management"); + expect(svg?.querySelectorAll("path")).toHaveLength(2); + }); + + it("keeps the viewBox fixed and shrinks only the rendered box for the sm size", () => { + const { container: row } = render(); + const { container: sm } = render(); + const rowSvg = row.querySelector("svg"); + const smSvg = sm.querySelector("svg"); + expect(rowSvg?.getAttribute("width")).toBe("16"); + expect(rowSvg?.getAttribute("height")).toBe("17"); + expect(smSvg?.getAttribute("width")).toBe("13"); + expect(smSvg?.getAttribute("height")).toBe("14"); + expect(smSvg?.getAttribute("viewBox")).toBe(rowSvg?.getAttribute("viewBox")); + expect(smSvg?.getAttribute("data-rank-size")).toBe("sm"); + }); + + it("colours by tier token class (gold vs purple)", () => { + const { container: orch } = render(); + const { container: mgmt } = render(); + expect(orch.querySelector("svg")?.className.baseVal).toContain("c_gold"); + expect(mgmt.querySelector("svg")?.className.baseVal).toContain("c_purple"); + }); +}); diff --git a/dashboard/src/grammar/RankBadge.tsx b/dashboard/src/grammar/RankBadge.tsx new file mode 100644 index 00000000..f899249c --- /dev/null +++ b/dashboard/src/grammar/RankBadge.tsx @@ -0,0 +1,79 @@ +import { cva } from "../../styled-system/css"; + +// The rank insignia (L14, developer-picked V4): military CHEVRON badges carried by the two command +// tiers of an orchestrated run — three gold chevrons under a command pip for the ORCHESTRATION seat +// (the sprint task), two purple chevrons for MANAGEMENT (a commanded master). Crisp inline SVG with a +// soft drop-shadow glow; `row` (16px) is the tasks-list/row size, `sm` (~13px) the rail/group-header +// size. Insignia are never decoration on a leaf: the tier encodes the real hierarchy, so the badge +// renders only where an orchestration task exists (D3 — flat runs carry no insignia at all). +const badge = cva({ + base: { + flex: "none", + display: "block", + alignSelf: "center", + "& path": { + fill: "none", + strokeWidth: "1.9", + strokeLinecap: "round", + strokeLinejoin: "round", + }, + }, + variants: { + tier: { + orchestration: { + color: "gold", + filter: "drop-shadow(0 0 3px color-mix(in oklch, token(colors.gold) 60%, transparent))", + }, + management: { + color: "purple", + filter: "drop-shadow(0 0 3px color-mix(in oklch, token(colors.purple) 55%, transparent))", + }, + }, + }, +}); + +export type RankTier = "orchestration" | "management"; +export type RankBadgeSize = "row" | "sm"; + +// Rendered width/height per tier and size; the viewBox stays fixed so the glyph scales crisply. +const DIMENSIONS: Record> = { + orchestration: { row: { width: 16, height: 17 }, sm: { width: 13, height: 14 } }, + management: { row: { width: 16, height: 12 }, sm: { width: 13, height: 10 } }, +}; + +export function RankBadge({ tier, size = "row" }: { tier: RankTier; size?: RankBadgeSize }) { + const { width, height } = DIMENSIONS[tier][size]; + if (tier === "orchestration") { + return ( + + ); + } + return ( + + ); +} diff --git a/dashboard/src/panels/AgentPickupIndicator.test.tsx b/dashboard/src/panels/AgentPickupIndicator.test.tsx index 1a26c5f3..c2e9dd55 100644 --- a/dashboard/src/panels/AgentPickupIndicator.test.tsx +++ b/dashboard/src/panels/AgentPickupIndicator.test.tsx @@ -19,6 +19,8 @@ describe("AgentPickupIndicator", () => { id: "pickup:I1", entryId: "I1", lifecycleId: "LC1", + messageKind: "message", + deliveryState: "queued", state: "waiting-for-agent", ttlSeconds: 300, }} @@ -37,6 +39,8 @@ describe("AgentPickupIndicator", () => { id: "pickup:I1", entryId: "I1", lifecycleId: "LC1", + messageKind: "message", + deliveryState: "queued", state: "check-chat", ttlSeconds: 300, }} diff --git a/dashboard/src/panels/AttentionQueue.tsx b/dashboard/src/panels/AttentionQueue.tsx index 7c5991e8..ccc1409b 100644 --- a/dashboard/src/panels/AttentionQueue.tsx +++ b/dashboard/src/panels/AttentionQueue.tsx @@ -4,6 +4,7 @@ import { useState } from "react"; import { css, cva } from "../../styled-system/css"; import { postAttentionDismiss } from "../data/actions"; import { fmtWait, selectQueue } from "../data/selectors"; +import { servedAgeSeconds, useNowMs } from "../data/servedAges"; import { dashboardStore, useDashboard } from "../data/store"; import { Dot } from "../grammar/Dot"; import { Panel } from "../grammar/Panel"; @@ -120,6 +121,9 @@ function canDismiss(item: AttentionItem): boolean { export function AttentionQueue({ onSelect }: { onSelect: (lifecycleId: string) => void }) { const queue = useDashboard(selectQueue); const docs = useDashboard((state) => state.analytics?.taskDocuments ?? EMPTY_TASK_DOCS); + // Wait times advance locally between emissions — the change gate (260703-L15) no longer + // re-serves the queue every tick just because the waits aged. + const nowMs = useNowMs(); const [clearing, setClearing] = useState(false); const [dismissing, setDismissing] = useState>(() => new Set()); const dismissableQueue = queue.filter(canDismiss); @@ -204,7 +208,7 @@ export function AttentionQueue({ onSelect }: { onSelect: (lifecycleId: string) =
    {displayTitle}
    {displayDetail ?
    {displayDetail}
    : null}
    - {q.lane} · {fmtWait(q.waitSeconds)} + {q.lane} · {fmtWait(servedAgeSeconds(q, q.waitSeconds, nowMs))}
    diff --git a/dashboard/src/panels/Chats.tsx b/dashboard/src/panels/Chats.tsx index a5e0edc0..499472d3 100644 --- a/dashboard/src/panels/Chats.tsx +++ b/dashboard/src/panels/Chats.tsx @@ -20,6 +20,8 @@ import { terminateTerminalSession, type HarnessInfo, } from "../data/terminal"; +import { groupSessions } from "../data/sessionGroups"; +import { useDashboard } from "../data/store"; import { buildTaskTree, leafIdFromKey, leafTitleForKey } from "../data/taskIdentity"; import type { TaskDocNode } from "../types/projection"; import { EmptyStateBackdrop } from "./EmptyStateBackdrop"; @@ -332,6 +334,16 @@ export function Chats({ } }; + // The G1 command tree (L14): group the sidebar by claim + spawn-role provenance. Enclosures come + // from the projection store (live-vs-landed truth); with no orchestration task and no leaf claims + // this derives zero groups and the SessionList renders today's flat list unchanged. + const enclosureById = useDashboard((state) => state.enclosures); + const grouped = groupSessions({ + sessions, + taskDocuments, + enclosures: Object.values(enclosureById), + }); + return (
    @@ -401,6 +413,7 @@ export function Chats({ onSelect={(id) => sessionStore.getState().setActive(id)} onTerminate={(id) => void terminateSession(id)} leafNameFor={leafNameFor} + grouped={grouped} /> )} diff --git a/dashboard/src/panels/DetailPanel.test.tsx b/dashboard/src/panels/DetailPanel.test.tsx index a82d4455..6798f749 100644 --- a/dashboard/src/panels/DetailPanel.test.tsx +++ b/dashboard/src/panels/DetailPanel.test.tsx @@ -71,6 +71,8 @@ function enclosure(over: Partial & Pick { }); }); +// The L9 notes API stub: /api/notes/list answers a fixed listing, /api/notes/read a fixed body. +// Everything else (e.g. change-set counters) answers a bare ok so unrelated fetches stay inert. +function stubNotes( + notes: Array<{ name: string; path: string; size: number; language: string }>, + body = "note body", +) { + const fn = vi.fn(async (url: string) => { + if (url.startsWith("/api/notes/list")) { + const payload = { repo: "agents-remember", master: "m", notes, truncated: false }; + return { ok: true, status: 200, json: async () => payload } as unknown as Response; + } + if (url.startsWith("/api/notes/read")) { + const payload = { + path: "x", + language: "markdown", + size: body.length, + truncated: false, + content: body, + }; + return { ok: true, status: 200, json: async () => payload } as unknown as Response; + } + return { ok: true, status: 200, json: async () => ({}) } as unknown as Response; + }); + vi.stubGlobal("fetch", fn); + return fn; +} + +describe("DetailPanel series notes (L9)", () => { + const leafPath = "/tasks/agents-remember/260703_agent-orchestration/09_notes-dashboard.json"; + + it("lists the master's notes on a leaf reader and resolves a notes reference to a link", async () => { + const fn = stubNotes( + [ + { name: "friction-ledger.md", path: "friction-ledger.md", size: 10, language: "markdown" }, + { + name: "260703-L1-worker-report.md", + path: "reports/260703-L1-worker-report.md", + size: 10, + language: "markdown", + }, + ], + "the **ledger** body", + ); + const doc = taskDoc({ + id: "260703-L9", + lifecycleId: undefined, + kind: "subTask", + title: "Notes on the dashboard", + repository: "agents-remember", + docPath: leafPath, + references: [ + "notes/friction-ledger.md (F-M — the finding this leaf closes)", + "mcp/src/agents_remember/serving/files.py (the confinement idiom to reuse)", + ], + }); + seedTaskDocuments([doc]); + const onOpenNotes = vi.fn(); + const view = render(); + + // The list is fetched for the doc's OWN series (repo + master derived from the doc node). + await view.findByText("Series notes"); + const urls = (fn.mock.calls as unknown as string[][]).map((c) => c[0]); + expect(urls).toContain( + "/api/notes/list?repo=agents-remember&master=260703_agent-orchestration", + ); + expect(view.getByText("reports/260703-L1-worker-report.md")).toBeTruthy(); + + // The notes-file reference is an openable link into the L17 reader; the code-path reference stays + // plain text. Reading itself now happens in the reader takeover, so the click opens it (no inline pane). + fireEvent.click(await view.findByTestId("note-ref-1")); + expect(onOpenNotes).toHaveBeenCalledWith({ + repo: "agents-remember", + master: "260703_agent-orchestration", + path: "friction-ledger.md", + }); + expect(view.queryByTestId("note-ref-2")).toBeNull(); + }); + + it("shows the series notes on a master overview", async () => { + stubNotes([{ name: "design.md", path: "design.md", size: 10, language: "markdown" }]); + const master = taskDoc({ + lifecycleId: undefined, + kind: "master", + title: "Agent Orchestration", + repository: "agents-remember", + docPath: "/tasks/agents-remember/260703_agent-orchestration/task.json", + objective: "Master objective.", + }); + seedTaskDocuments([master]); + const view = render( + , + ); + await view.findByText("Series notes"); + expect((await view.findByTestId("note-open-1")).textContent).toContain("design.md"); + }); +}); + describe("DetailPanel doc-reader change-set bar (L4a)", () => { const leafPath = "/tasks/agents-remember/260628_operations-integration/04a_changeset-everywhere.json"; diff --git a/dashboard/src/panels/DetailPanel.tsx b/dashboard/src/panels/DetailPanel.tsx index df7e78f3..24fe7cf8 100644 --- a/dashboard/src/panels/DetailPanel.tsx +++ b/dashboard/src/panels/DetailPanel.tsx @@ -31,8 +31,10 @@ import type { } from "../types/projection"; import type { ChangeSetTarget } from "./changeset/ChangeSetViewer"; +import type { NotesReaderTarget } from "./notes-reader/NotesReaderViewer"; import { EmptyStateBackdrop } from "./EmptyStateBackdrop"; import { GateResponder } from "./GateResponder"; +import { TaskNotes } from "./TaskNotes"; // The l-01 phase vocabulary, in order (mcp/.../lifecycle_state.py). The stepper marks phases before // the current as done — mc2's Request→Close mini-map. @@ -314,18 +316,20 @@ const taskdocDecisions = css({ const taskdocDecision = css({ fontSize: "0.84rem" }); const taskdocDecisionMeta = css({ fontSize: "0.76rem", color: "muted" }); -// The selected lifecycle: phase stepper, the chat-routed Gate Respond drawer or ask fallback, the +// The selected lifecycle: phase stepper, the canonical Gate Respond surface (durable gates only), the // task-document content (analytics.taskDocuments), the lifecycle → worktree → provider spine, and tokens. export function DetailPanel({ selectedId, onOpenLifecycle, onOpenChangeSet, + onOpenNotes, onViewLeaf, }: { selectedId: string | null; onOpenLifecycle?: (id: string) => void; // Open the Change-Set Viewer takeover: an enclosure scope, a series master, or a leaf view (L4a). onOpenChangeSet?: (target: ChangeSetTarget) => void; + onOpenNotes?: (target: NotesReaderTarget) => void; // Report the QUALIFIED LEAF ID of the leaf the panel is actually SHOWING — a drilled sub-task or a // directly-opened leaf doc — so the rail chat + "attach to leaf" key by that leaf, not the master // (L5 fix 1). `undefined` while only a master/series overview (or the empty state) is shown. @@ -422,18 +426,18 @@ export function DetailPanel({
    task document · {selectedTaskDoc.repository}
    {selectedTaskDoc.kind === "master" ? ( openDoc ? ( - + ) : ( ) ) : ( - + )} ); @@ -475,14 +479,14 @@ export function DetailPanel({
    series master · {selectedSeries.repository}
    {openDoc ? ( - + ) : ( )}
    @@ -581,14 +585,14 @@ export function DetailPanel({ ) : null} {openDoc ? ( - + ) : seriesDoc ? ( ) : master ? ( ) : ( - + )} {enclosure ? ( @@ -864,11 +868,13 @@ function TaskContent({ onOpen, onJump, onOpenChangeSet, + onOpenNotes, }: { docs: TaskDocNode[]; onOpen: (slug: string) => void; onJump: (id: string) => void; onOpenChangeSet?: (target: ChangeSetTarget) => void; + onOpenNotes?: (target: NotesReaderTarget) => void; }) { if (docs.length === 0) { return

    No task document bound to this task.

    ; @@ -882,12 +888,12 @@ function TaskContent({ sliceDocs={sliceDocs} onOpen={onOpen} onJump={onJump} - onOpenChangeSet={onOpenChangeSet} + onOpenChangeSet={onOpenChangeSet} onOpenNotes={onOpenNotes} /> ); } if (sliceDocs.length === 1) { - return ; + return ; } return ; } @@ -901,12 +907,14 @@ function MasterOverview({ onOpen, onJump, onOpenChangeSet, + onOpenNotes, }: { doc: MasterDocView; sliceDocs: TaskDocNode[]; onOpen: (slug: string) => void; onJump: (id: string) => void; onOpenChangeSet?: (target: ChangeSetTarget) => void; + onOpenNotes?: (target: NotesReaderTarget) => void; }) { return (
    @@ -944,6 +952,14 @@ function MasterOverview({ onJump={onJump} /> ))} + {/* L9: the series' coordination notes (design records, friction ledger, reports/) — + browsable from the master overview too, not only from a drilled leaf reader. */} +
    ); } @@ -1149,9 +1165,11 @@ function SpineLane({ function TaskReader({ doc, onOpenChangeSet, + onOpenNotes, }: { doc: TaskDocNode; onOpenChangeSet?: (target: ChangeSetTarget) => void; + onOpenNotes?: (target: NotesReaderTarget) => void; }) { const progress = topLevelStepProgress(doc); const leafKey = qualifiedLeafKey(doc); @@ -1217,11 +1235,14 @@ function TaskReader({ {section.body ? {section.body} : null}
    ))} - {doc.references.length > 0 ? ( -
    - -
    - ) : null} + {/* L9: References moved into TaskNotes so a reference naming an existing notes/ file + renders as an openable link into the series-notes view (plain text otherwise). */} +
    ); } diff --git a/dashboard/src/panels/EventRiver.test.tsx b/dashboard/src/panels/EventRiver.test.tsx index f47d5809..f0384ec0 100644 --- a/dashboard/src/panels/EventRiver.test.tsx +++ b/dashboard/src/panels/EventRiver.test.tsx @@ -78,6 +78,8 @@ function enclosure(partial: Partial & { enclosure: string }): Enc actions: [], cleanup: "pending", closeoutStatus: "not-started", + codeWorktreeExists: true, + memoryWorktreeExists: true, enclosure: enclosurePath, enclosureId: enclosurePath, humanReviewStatus: "pending-review", diff --git a/dashboard/src/panels/FlowTab.test.tsx b/dashboard/src/panels/FlowTab.test.tsx new file mode 100644 index 00000000..b77defb0 --- /dev/null +++ b/dashboard/src/panels/FlowTab.test.tsx @@ -0,0 +1,167 @@ +import { cleanup, fireEvent, render } from "@testing-library/react"; +import { afterEach, describe, expect, it } from "vitest"; + +import { FLOW_MODELS } from "./flowModels"; +import { FlowTab } from "./FlowTab"; + +afterEach(cleanup); + +describe("FlowTab canvas (unified l-01-agent-lifecycles)", () => { + it("renders the router model by default — the unified skill's spine", () => { + const { getByTestId, getByText } = render(); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe("router"); + expect(getByText(/one skill, one lifecycle per agent type/)).not.toBeNull(); + expect(getByTestId("flow-nav")).not.toBeNull(); + // The retired models are gone from the nav. + expect(document.querySelector('[data-testid="flow-nav-build-job"]')).toBeNull(); + expect(document.querySelector('[data-testid="flow-nav-frame"]')).toBeNull(); + }); + + it("switches models through the nav radiogroup", () => { + const { getByTestId, getByText } = render(); + fireEvent.click(getByTestId("flow-nav-orchestrator")); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe("orchestrator"); + expect(getByText(/the event loop, drawn on its biggest run/)).not.toBeNull(); + expect(getByTestId("flow-nav-orchestrator").getAttribute("aria-checked")).toBe("true"); + expect(getByTestId("flow-nav-router").getAttribute("aria-checked")).toBe("false"); + fireEvent.click(getByTestId("flow-nav-comms")); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe("comms"); + }); + + it("honors initialModel and falls back to the first model for unknown ids", () => { + const { getByTestId, unmount } = render(); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe("manager"); + unmount(); + const { getByTestId: second } = render(); + expect(second("flow-tab").getAttribute("data-model")).toBe("router"); + }); + + it("renders every registered model without crashing (nodes, gates, rundowns)", () => { + for (const model of FLOW_MODELS) { + const { getAllByTestId, getByTestId, queryAllByTestId, unmount } = render( + , + ); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe(model.id); + const nodes = model.segments.filter((s) => s.kind === "node"); + const gates = nodes.filter((s) => s.kind === "node" && s.rides); + if (gates.length > 0) expect(getAllByTestId("flow-gate").length).toBe(gates.length); + if (nodes.length - gates.length > 0) { + expect(getAllByTestId("flow-node").length).toBe(nodes.length - gates.length); + } + const rundowns = model.segments.filter((s) => s.kind === "rundown"); + expect(queryAllByTestId("flow-rundown").length).toBe(rundowns.length); + unmount(); + } + }); + + it("encodes the router invariants: three conditions, the ladder, no chat builds", () => { + const { getByText } = render(); + expect(getByText(/the three conditions — in order, no fourth entry/)).not.toBeNull(); + expect( + getByText(/task doc \(approved\) → branch \(intent\) → worktree \(only where something is built\)/), + ).not.toBeNull(); + expect(getByText(/⟁ chat is never a build route — small code work takes the minimal w-02 artifact/)).not.toBeNull(); + }); + + it("encodes the agreed orchestration invariants on the drawn models", () => { + const { getByTestId, getByText } = render(); + // Master-granular DAG + the branch-not-worktree intent + the delegated handover decision. + expect(getByText(/reshape master boundaries — NEVER interleave dispatch/)).not.toBeNull(); + expect(getByText(/creates a BRANCH off main, nothing more/)).not.toBeNull(); + expect( + getByText(/the ORCHESTRATOR decides by the packet-carried gateId \(own ambient identity/), + ).not.toBeNull(); + // The escalation ladder lives on the comms drawing; the spirit test is ORCHESTRATOR-ONLY. + fireEvent.click(getByTestId("flow-nav-comms")); + expect(getByText(/escalation · worker → manager → orchestrator → developer/)).not.toBeNull(); + expect(getByText(/spirit test — ORCHESTRATOR-ONLY/)).not.toBeNull(); + // Managers escalate plan deltas instead of judging them, and reopen wrong deliverables. + fireEvent.click(getByTestId("flow-nav-manager")); + expect(getByText(/managers don't reshape plans \(no bird's-eye\)/)).not.toBeNull(); + expect(getByText(/task_reopen the SAME leaf, reshape — never a redo sibling/)).not.toBeNull(); + // The ruled seam channel: non-blocking raise addressed by enclosure, the gateId rides the packet. + expect( + getByText(/enclosure="" — the exact address integration enforcement matches the gate by/), + ).not.toBeNull(); + expect( + getByText(/the returned gateId rides the packet via inbox \+ push · the ORCHESTRATOR decides the gate by that id/), + ).not.toBeNull(); + }); + + it("draws the worker as brief-started with no lifecycle machinery", () => { + const { getByTestId, getByText } = render(); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe("worker"); + expect(getByText(/one leaf, one session, one report/)).not.toBeNull(); + expect(getByText(/NEVER git commit/)).not.toBeNull(); + expect( + getByText(/the owning seat runs closeout → integrate → finalize/), + ).not.toBeNull(); + }); + + it("draws the strategist as the mandatory spawn-first sprint planner", () => { + const { getByTestId, getByText } = render(); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe("strategist"); + expect(getByText(/the sprint planner, spawn-first/)).not.toBeNull(); + expect(getByText(/the mandatory pre-run gate — no orchestration task, no orchestrated run/)).not.toBeNull(); + expect(getByText(/even a single master gets the pass — impact must be understood; its leaves may still shuffle/)).not.toBeNull(); + expect( + getByText(/4 doctrine edges, cited — an uncited edge is refutable by default · 5 blast-radius register \(low\/med\/high — feeds the loop-tier scoring\)/), + ).not.toBeNull(); + expect( + getByText(/⟁ a leaf naming neither existing surfaces nor a parent anchor → finding: unplannable as scoped — never a silent guess/), + ).not.toBeNull(); + expect( + getByText(/reader-not-mutator: the strategist drafts; the ORCHESTRATOR adopts it into durable task form \(decision-log entry\)/), + ).not.toBeNull(); + }); + + it("encodes the three-party-loop invariants across the drawn models", () => { + const { getByTestId, getByText } = render(); + expect( + getByText(/score each leaf's loop tier at dispatch — direct · builder-verified · full loop/), + ).not.toBeNull(); + expect( + getByText(/⟁ full-loop leaves: HARD cap 3 full rounds \(delta-verifies don't count\) · a non-shrinking round escalates NOW with the round history/), + ).not.toBeNull(); + fireEvent.click(getByTestId("flow-nav-comms")); + expect( + getByText(/⟁ quo-vadis — a high-blast-radius TRUTH \(answered wrong = big rewrites later\) goes to the developer IMMEDIATELY; presentation-grade \(2px vs 3px\) never does/), + ).not.toBeNull(); + fireEvent.click(getByTestId("flow-nav-reviewer")); + expect( + getByText(/criteria catalogs bound per review type \(criteria\/: code-seam · doctrine · onboarding-memory · report-verification · plan-review\)/), + ).not.toBeNull(); + expect( + getByText(/loop-seat reuse: delta-verifies resume the SAME reviewer \(they close rounds, never open them\); fresh reviewer only for a full round/), + ).not.toBeNull(); + fireEvent.click(getByTestId("flow-nav-worker")); + expect( + getByText(/loop position: the BUILDER seat — fix rounds resume the SAME session; round-2\+ reports APPEND \(loop history stays legible\)/), + ).not.toBeNull(); + fireEvent.click(getByTestId("flow-nav-orchestrator")); + expect( + getByText(/STRATEGIST pre-run — spawn-first, MANDATORY before any orchestrated run → the ORCHESTRATION TASK = sprint plan \+ scope/), + ).not.toBeNull(); + expect( + getByText(/visible-behavior-first in a REVIEWABLE ENVIRONMENT \(the dashboard\) with demo notes \(what changed visibly\), code second/), + ).not.toBeNull(); + }); + + it("draws the designer as the hat the orchestrator pulls", () => { + const { getByTestId, getByText } = render(); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe("designer"); + expect(getByText(/the hat the orchestrator pulls/)).not.toBeNull(); + expect(getByText(/ORCHESTRATOR adversarially reviews the design/)).not.toBeNull(); + expect(getByText(/ask — never fill silently/)).not.toBeNull(); + }); + + it("draws the reviewer with verdicts as evidence and the ruled deciders", () => { + const { getByTestId, getByText } = render(); + expect(getByTestId("flow-tab").getAttribute("data-model")).toBe("reviewer"); + expect( + getByText(/verdicts are evidence, not decisions — requireReviewerVerdictAtSeams binds delegated seam decisions/), + ).not.toBeNull(); + expect(getByText(/the ORCHESTRATOR at master-exit \(master-handover-approval\)/)).not.toBeNull(); + expect(getByText(/⟁ block\? → decomposable fix leaves/)).not.toBeNull(); + }); +}); diff --git a/dashboard/src/panels/FlowTab.tsx b/dashboard/src/panels/FlowTab.tsx index e4ee0941..2448f87b 100644 --- a/dashboard/src/panels/FlowTab.tsx +++ b/dashboard/src/panels/FlowTab.tsx @@ -1,60 +1,16 @@ +import { useState } from "react"; + import { css, cva } from "../../styled-system/css"; +import { FLOW_MODELS, type FlowModel, type FlowNode, type FlowSegment, type Status } from "./flowModels"; -// The Lifecycle Flow tab (task 26): the BUILD-job lifecycle in TWO regimes (dev, task 26). -// -// • FRONT HALF (non-linear) — a one-time PROSE RUNDOWN emitted by `lifecycle_start`: -// reframe → research → job-selection → task-file-exists? → task_doc. -// It's prose, not per-tool hints, because the research tools (read_ar_files / grepai / cgc) fire -// unpredictably and the `task-file-exists?` junction isn't a tool call at all. +// The Lifecycle Flow canvas (task 26; orchestration L0 generalizes it): STATIC design drawings of +// lifecycles/interactions, switched by a nav — the surface where a new lifecycle (any model in the +// `flowModels.ts` registry) is DRAWN and reviewed with the developer before it is built. Content lives +// in `flowModels.ts` (module-level data, no store reads); this file owns only the segment renderer +// and the model nav. Mounted dev-only at `/dev/flows` (dead-code-eliminated in production) — task 29 +// removed it from the cockpit mode bar, and that stays true. // -// • LINEAR HALF — from worktree_start on, the lifecycle is linear and the turn-end notification -// RIDES the tool: it auto-fires when a gate tool (dry-run / preview / task_doc-create) is called, -// so the agent never fires it explicitly and literally can't forget. Auto-dismiss composes: the -// next AR tool clears it, so it only sticks when the agent actually stops. -// -// Arrow colour: mint = wired today (guidance.lifecycle_guidance chains apply→next-dry-run); amber -// dashed = this series (the prose rundown + every auto-fired notification + the linear nextStep wiring). - -type Status = "current" | "proposed"; - -// Front-half roadmap lines emitted by lifecycle_start (the `junction` line is the one non-tool step). -const RUNDOWN: { line: string; junction?: boolean }[] = [ - { line: "reframe — restate the request as agreed work" }, - { line: "research — read_ar_files · grepai · cgc (fire unpredictably → not hint anchors)" }, - { line: "job selection — bug / feature → build · triage / research → research-only exit" }, - { line: "⟁ task file exists? (build/fix) yes → worktree_start no ↓", junction: true }, - { line: "task_doc — persist the chat task proposal as a durable file (+ approval), then ↓" }, -]; - -interface Node { - phase: string; - tool: string; - detail?: string; - rides?: string; // the gate whose notification auto-fires when this tool is called - next?: string; - nextStatus?: Status; -} - -// Head: trust-checkpoint tools that precede the rundown. -const HEAD: Node[] = [ - { phase: "1 · trust-checkpoint", tool: "context_packet", detail: "providers · drift · freshness", next: "lifecycle_start", nextStatus: "proposed" }, - { phase: "1 · trust-checkpoint", tool: "lifecycle_start", detail: "promote the lifecycle — and emit the front-half rundown ↓", next: "(prose rundown)", nextStatus: "proposed" }, -]; - -// Linear half: from worktree_start on. `rides` = the gate tool auto-fires its notification on call. -const LINEAR: Node[] = [ - { phase: "3 · decide", tool: "worktree_start --dry-run", detail: "verify the worktree-intent dry-run (self-fix first)", rides: "worktree-intent", next: "worktree_start (apply)", nextStatus: "proposed" }, - { phase: "3→4 · build", tool: "worktree_start (apply)", detail: "open the worktree — lifecycle promotes to persistent", next: "implement + run checks", nextStatus: "proposed" }, - { phase: "4 · build", tool: "implement + run checks", detail: "edit · tests · quality wrapper", next: "worktree_closeout_preview", nextStatus: "proposed" }, - { phase: "4 · build", tool: "worktree_closeout_preview", detail: "verify the closeout preview (self-fix first)", rides: "commit / closeout-approval", next: "worktree_closeout_apply", nextStatus: "proposed" }, - { phase: "4 · build", tool: "worktree_closeout_apply", detail: "commit code · memory · ledger", next: "worktree_integrate --dry-run", nextStatus: "current" }, - { phase: "4 · build", tool: "worktree_integrate --dry-run", detail: "verify the integration dry-run", rides: "integration-approval", next: "worktree_integrate (apply)", nextStatus: "proposed" }, - { phase: "4 · build", tool: "worktree_integrate (apply)", detail: "land into the source branch", next: "memory_carryover_apply", nextStatus: "current" }, - { phase: "5 · close", tool: "memory_carryover_apply", detail: "carry parked memory home", next: "lifecycle_finalize_task --dry-run", nextStatus: "current" }, - { phase: "5 · close", tool: "lifecycle_finalize_task --dry-run", detail: "verify the landed-edge + cleanup plan", rides: "cleanup / finalization", next: "lifecycle_finalize_task (apply)", nextStatus: "proposed" }, - { phase: "5 · close", tool: "lifecycle_finalize_task (apply)", detail: "prove the edge · reclaim worktrees", next: "lifecycle_end", nextStatus: "current" }, - { phase: "5 · close", tool: "lifecycle_end", detail: "terminal" }, -]; +// Arrow colour: mint = wired today; amber dashed = proposed by the active series (per model legend). const root = css({ display: "flex", flexDirection: "column", flex: "1", minHeight: "0", overflow: "auto", padding: "0.4rem 0.2rem 2rem", gap: "0.55rem" }); const header = css({ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: "1rem", flexWrap: "wrap" }); @@ -63,10 +19,29 @@ const legend = css({ display: "flex", gap: "1.1rem", fontSize: "0.72rem", color: const swatch = cva({ base: { display: "inline-block", width: "1.6rem", height: "0", marginRight: "0.35rem", verticalAlign: "middle", borderTopWidth: "2px" }, variants: { status: { current: { borderTopStyle: "solid", borderTopColor: "mint" }, proposed: { borderTopStyle: "dashed", borderTopColor: "amber" } } } }); const takeaway = css({ fontSize: "0.76rem", color: "ink", opacity: "0.9", borderLeftWidth: "2px", borderLeftStyle: "solid", borderLeftColor: "amber", paddingLeft: "0.6rem", maxWidth: "82ch", lineHeight: "1.45" }); +// The model nav: a two-plus-segment radiogroup mirroring the RailToggle/EffectsToggle idiom. +const nav = css({ display: "inline-flex", alignItems: "center", gap: "0", borderWidth: "1px", borderStyle: "solid", borderColor: "grid", borderRadius: "3px", overflow: "hidden", alignSelf: "flex-start" }); +const navButton = cva({ + base: { + font: "inherit", + fontSize: "0.72rem", + letterSpacing: "0.05em", + paddingInline: "0.7rem", + paddingBlock: "0.24rem", + background: "transparent", + color: "muted", + border: "none", + cursor: "pointer", + _hover: { color: "ink" }, + _focusVisible: { outline: "1px solid token(colors.amber)", outlineOffset: "-1px" }, + }, + variants: { on: { true: { color: "amber", background: "rgba(232, 193, 112, 0.12)" }, false: {} } }, +}); + const chain = css({ display: "flex", flexDirection: "column", alignItems: "stretch", maxWidth: "640px", width: "100%", marginInline: "auto", marginTop: "0.3rem" }); const startNode = css({ alignSelf: "center", fontSize: "0.74rem", color: "muted", borderWidth: "1px", borderStyle: "dotted", borderColor: "grid", borderRadius: "999px", paddingInline: "0.7rem", paddingBlock: "0.2rem" }); const toolNode = css({ display: "flex", flexDirection: "column", gap: "0.1rem", background: "bg", borderWidth: "1px", borderStyle: "solid", borderColor: "grid", borderRadius: "3px", paddingInline: "0.7rem", paddingBlock: "0.45rem" }); -// A gate tool: a normal call with the notification fused as an auto-fired rider (amber left bar). +// A gate node: a normal call with an approval/notification fused as a rider (amber left bar). const ridesNode = css({ display: "flex", flexDirection: "column", gap: "0.1rem", background: "bg", borderWidth: "1px", borderStyle: "solid", borderColor: "grid", borderLeftWidth: "3px", borderLeftStyle: "solid", borderLeftColor: "amber", borderRadius: "3px", paddingInline: "0.7rem", paddingBlock: "0.45rem" }); const phaseTag = css({ fontSize: "0.63rem", letterSpacing: "0.08em", color: "muted", textTransform: "uppercase" }); const toolName = css({ fontFamily: "monospace", fontSize: "0.82rem", fontWeight: "600", color: "ink" }); @@ -74,22 +49,22 @@ const detailLine = css({ fontSize: "0.72rem", color: "muted" }); const ridesLine = css({ fontSize: "0.69rem", color: "amber", fontStyle: "italic", marginTop: "0.16rem" }); const connector = cva({ base: { display: "flex", alignItems: "center", gap: "0.4rem", alignSelf: "center", paddingBlock: "0.2rem", fontSize: "0.7rem", fontFamily: "monospace" }, variants: { status: { current: { color: "mint" }, proposed: { color: "amber" } } } }); const wire = cva({ base: { width: "0", height: "0.95rem", borderLeftWidth: "2px" }, variants: { status: { current: { borderLeftStyle: "solid", borderLeftColor: "mint" }, proposed: { borderLeftStyle: "dashed", borderLeftColor: "amber" } } } }); -// The prose-rundown card (the front half, emitted by lifecycle_start). const rundownCard = css({ display: "flex", flexDirection: "column", gap: "0.25rem", background: "bg", borderWidth: "1px", borderStyle: "dashed", borderColor: "amber", borderRadius: "3px", paddingInline: "0.8rem", paddingBlock: "0.55rem", marginBlock: "0.2rem" }); const rundownTitle = css({ fontSize: "0.7rem", letterSpacing: "0.06em", color: "amber", textTransform: "uppercase" }); const rundownLine = cva({ base: { fontSize: "0.74rem", color: "ink", paddingLeft: "0.6rem", borderLeftWidth: "2px", borderLeftStyle: "solid", borderLeftColor: "grid", paddingBlock: "0.08rem" }, variants: { junction: { true: { borderLeftColor: "cyan", color: "cyan", fontFamily: "monospace", fontSize: "0.72rem" }, false: {} } } }); const divider = css({ alignSelf: "center", fontSize: "0.7rem", color: "muted", fontStyle: "italic", paddingBlock: "0.3rem", textAlign: "center" }); -function ToolNode({ n }: { n: Node }) { +const DEFAULT_RIDES_NOTE = (rides: string) => + `⊘ auto-fires lifecycle_turn_end_notification · ${rides} — rides this call (agent never fires it); next AR tool clears it`; + +function ToolNode({ n }: { n: FlowNode }) { const Cls = n.rides ? ridesNode : toolNode; return (
    {n.phase}{n.rides ? " · gate" : ""} {n.tool} {n.detail ? {n.detail} : null} - {n.rides ? ( - ⊘ auto-fires lifecycle_turn_end_notification · {n.rides} — rides this call (agent never fires it); next AR tool clears it - ) : null} + {n.rides ? {n.ridesNote ?? DEFAULT_RIDES_NOTE(n.rides)} : null}
    ); } @@ -103,50 +78,71 @@ function Arrow({ to, status }: { to: string; status: Status }) { ); } -export function FlowTab() { +function Segment({ segment }: { segment: FlowSegment }) { + switch (segment.kind) { + case "start": + return ( + <> +
    {segment.label}
    + {segment.next ? : null} + + ); + case "node": + return ( + <> + + {segment.next ? : null} + + ); + case "rundown": + return ( +
    + {segment.title} + {segment.lines.map((r, i) => ( + {r.line} + ))} +
    + ); + case "divider": + return
    {segment.label}
    ; + } +} + +export function FlowTab({ initialModel }: { initialModel?: string } = {}) { + const fallback = FLOW_MODELS[0]; + const [modelId, setModelId] = useState( + FLOW_MODELS.some((m) => m.id === initialModel) ? (initialModel as string) : fallback.id, + ); + const model: FlowModel = FLOW_MODELS.find((m) => m.id === modelId) ?? fallback; return ( -
    +
    +
    + {FLOW_MODELS.map((m) => ( + + ))} +
    -

    LIFECYCLE FLOW · build job — the hint chain

    +

    LIFECYCLE FLOW · {model.title}

    wired today this series
    -

    - The turn-end notification is not a tool the agent calls — it auto-fires when a - gate tool (dry-run / preview / task_doc-create) is called, so the agent can't forget it - (amber left-bar nodes below). The front half is non-linear (research fires - unpredictably; task-file-exists? isn't a tool), so lifecycle_start - emits a one-time prose rundown instead of per-tool hints. From{" "} - worktree_start on it's linear; mint edges already chain - (guidance.lifecycle_guidance), amber is this series. -

    +

    {model.takeaway}

    -
    ▸ developer request — stated in chat
    - - {HEAD.map((n) => ( -
    - - {n.next ? : null} -
    - ))} - -
    - front half · prose rundown from lifecycle_start (not per-tool hints) - {RUNDOWN.map((r, i) => ( - {r.line} - ))} -
    - -
    ↓ from here the lifecycle is linear — each gate tool auto-fires its notification ↓
    - - {LINEAR.map((n) => ( -
    - - {n.next ? : null} -
    + {model.segments.map((segment, i) => ( + ))}
    diff --git a/dashboard/src/panels/Hangar.test.tsx b/dashboard/src/panels/Hangar.test.tsx index 17e9bc4e..3a5ce66f 100644 --- a/dashboard/src/panels/Hangar.test.tsx +++ b/dashboard/src/panels/Hangar.test.tsx @@ -11,6 +11,8 @@ function enclosure(partial: Partial & { enclosure: string }): Enc actions: [], cleanup: "pending", closeoutStatus: "not-started", + codeWorktreeExists: true, + memoryWorktreeExists: true, enclosure: enclosurePath, enclosureId: enclosurePath, humanReviewStatus: "pending-review", @@ -31,31 +33,101 @@ afterEach(() => { dashboardStore.getState().reset(); }); -describe("Hangar lists only live worktrees", () => { - it("hides archived (cleanup completed/abandoned) enclosures so the count reflects physical worktrees", () => { - // A finalized worktree keeps its enclosure contract on disk — the hangar must not count those, or it - // only ever piles up. Two of these three are archived; only the live one survives. +describe("Hangar renders worktree truth (L11)", () => { + it("renders a row ONLY while a worktree physically exists — never from a cleanup-state proxy", () => { + // A finalized worktree keeps its enclosure contract on disk after its directories are reaped, + // and a reopened contract (cleanup=reopened) has no worktrees until worktree_start recreates + // them. Visibility is the projection's stat'ed existence truth: of these four, only the two + // with a physically existing worktree survive. dashboardStore.setState({ lifecycles: {}, enclosures: { live: enclosure({ enclosure: "live", cleanup: "pending" }), - done: enclosure({ enclosure: "done", cleanup: "completed" }), - gone: enclosure({ enclosure: "gone", cleanup: "abandoned" }), + "memory-only": enclosure({ + enclosure: "memory-only", + cleanup: "pending", + codeWorktreeExists: false, + memoryWorktreeExists: true, + }), + done: enclosure({ + enclosure: "done", + cleanup: "completed", + codeWorktreeExists: false, + memoryWorktreeExists: false, + }), + gone: enclosure({ + enclosure: "gone", + cleanup: "abandoned", + codeWorktreeExists: false, + memoryWorktreeExists: false, + }), }, }); const { getByTestId, getAllByTestId } = render(); + expect(getAllByTestId("hangar-row")).toHaveLength(2); + expect(getByTestId("hangar").textContent).toContain("Hangar · 2 worktrees"); + }); + + it("hides a reopened contract with no worktrees on disk (reset-awaiting-restart, not live work)", () => { + // The L9 reopen defect: cleanup=reopened outflanked the old {completed, abandoned} proxy and + // the leaf rendered as a live worktree. With existence truth it stays hidden until restart. + dashboardStore.setState({ + lifecycles: {}, + enclosures: { + reopened: enclosure({ + enclosure: "reopened", + cleanup: "reopened", + lifecycleId: "", + codeWorktreeExists: false, + memoryWorktreeExists: false, + }), + }, + }); + + const { queryAllByTestId, getByText } = render(); + + expect(queryAllByTestId("hangar-row")).toHaveLength(0); + expect(getByText(/no live persistent worktrees/i)).not.toBeNull(); + }); + + it("shows a reopened leaf again once worktree_start recreates its worktrees", () => { + // After restart the worktrees physically exist again; existence — not the cleanup label — + // is what re-admits the row, so even a not-yet-rewritten contract renders. + dashboardStore.setState({ + lifecycles: {}, + enclosures: { + restarted: enclosure({ + enclosure: "restarted", + cleanup: "reopened", + codeWorktreeExists: true, + memoryWorktreeExists: true, + }), + }, + }); + + const { getAllByTestId } = render(); + expect(getAllByTestId("hangar-row")).toHaveLength(1); - expect(getByTestId("hangar").textContent).toContain("Hangar · 1 worktrees"); }); - it("fully reduces to the empty state once every worktree is archived", () => { + it("fully reduces to the empty state once every worktree is physically gone", () => { dashboardStore.setState({ lifecycles: {}, enclosures: { - a: enclosure({ enclosure: "a", cleanup: "completed" }), - b: enclosure({ enclosure: "b", cleanup: "completed" }), + a: enclosure({ + enclosure: "a", + cleanup: "completed", + codeWorktreeExists: false, + memoryWorktreeExists: false, + }), + b: enclosure({ + enclosure: "b", + cleanup: "completed", + codeWorktreeExists: false, + memoryWorktreeExists: false, + }), }, }); diff --git a/dashboard/src/panels/Hangar.tsx b/dashboard/src/panels/Hangar.tsx index 162d5309..50e6d2d4 100644 --- a/dashboard/src/panels/Hangar.tsx +++ b/dashboard/src/panels/Hangar.tsx @@ -1,5 +1,6 @@ import { css, cva } from "../../styled-system/css"; -import { fmtWait } from "../data/selectors"; +import { fmtWait, hasLiveWorktree } from "../data/selectors"; +import { servedAgeSeconds, useNowMs } from "../data/servedAges"; import { useDashboard } from "../data/store"; import { Affordance } from "../grammar/Affordance"; import { Panel } from "../grammar/Panel"; @@ -13,13 +14,11 @@ import { GateResponder, isWorktreeGateKind } from "./GateResponder"; // // A finalized worktree keeps its enclosure CONTRACT on disk (it records the landed state for memory // lineage) even after its directory is reaped, so the raw enclosure set only ever grows. The hangar is -// about worktrees that still physically exist / need action, so it hides the archived ones — a -// completed/abandoned cleanup means there is no worktree left to integrate, clean up, or rot. -const ARCHIVED_CLEANUP = new Set(["completed", "abandoned"]); - -function isArchived(enclosure: EnclosureNode): boolean { - return ARCHIVED_CLEANUP.has(enclosure.cleanup); -} +// about worktrees that still physically exist / need action, so it renders a row ONLY while a worktree +// physically exists — the projection's stat'ed hasLiveWorktree truth (L11), never a cleanup-state +// proxy. Completed/abandoned enclosures drop out by that same rule (their worktrees were reaped), and +// a reopened contract (cleanup=reopened: contract-reset-awaiting-restart) stays hidden until +// worktree_start recreates its worktrees. function isStale(enclosure: EnclosureNode, lifecycle: LifecycleProjection | undefined): boolean { if (enclosure.cleanup === "pending" || enclosure.integrationStatus === "completed") return true; @@ -73,8 +72,11 @@ const actions = css({ display: "flex", gap: "0.3rem" }); export function Hangar({ onSelect }: { onSelect: (id: string) => void }) { const enclosures = useDashboard((s) => s.enclosures); const lifecycles = useDashboard((s) => s.lifecycles); + // Served ages advance locally between emissions — the change gate (260703-L15) no longer + // re-serves a node whose only movement is its age, so the display ticks here instead. + const nowMs = useNowMs(); const rows = Object.values(enclosures) - .filter((enclosure) => !isArchived(enclosure)) + .filter(hasLiveWorktree) .sort((a, b) => a.enclosure.localeCompare(b.enclosure)); return ( @@ -100,7 +102,9 @@ export function Hangar({ onSelect }: { onSelect: (id: string) => void }) { > {enclosure.repoName} · {enclosure.taskName} - {fmtWait(lifecycle?.staleSeconds)} + + {fmtWait(servedAgeSeconds(lifecycle, lifecycle?.staleSeconds, nowMs))} +
    review {enclosure.humanReviewStatus} diff --git a/dashboard/src/panels/LifecycleList.test.tsx b/dashboard/src/panels/LifecycleList.test.tsx index 00d4676b..e7db8329 100644 --- a/dashboard/src/panels/LifecycleList.test.tsx +++ b/dashboard/src/panels/LifecycleList.test.tsx @@ -54,6 +54,8 @@ function enclosure(over: Partial & Pick { lifecycleId: "LC-16", leafId: "16_engine-room-stack-entry-height", cleanup: "completed", + codeWorktreeExists: false, + memoryWorktreeExists: false, }), enclosure({ enclosure: "/contracts/empty", @@ -358,10 +362,11 @@ describe("LifecycleList task labels", () => { ); }); - it("renders a reopened leaf (cleanup=reopened, no lifecycle yet) as its planned doc row", () => { - // task_reopen (L11) reuses the EXACT leaf id: the enclosure returns to planning with its - // lifecycle binding cleared, and the doc row must render like any other planned leaf — the old - // `-rN` suffix admission heuristic is gone because reopened leaf ids never fork anymore. + it("hides a reopened leaf (cleanup=reopened, no worktrees on disk) until worktree_start recreates them", () => { + // The tasks-surface visibility rule (L11): a leaf appears ONLY while a worktree physically + // exists. A reopened contract is a reset awaiting restart — its worktrees are gone — so it + // must NOT render as live work, even though its cleanup state is not completed/abandoned + // (the proxy that cleanup=reopened outflanked). const onSelect = vi.fn(); seed( projection({ @@ -372,6 +377,65 @@ describe("LifecycleList task labels", () => { lifecycleId: "", leafId: "29_event-river-retention-and-projection-freshness", cleanup: "reopened", + codeWorktreeExists: false, + memoryWorktreeExists: false, + }), + ], + analytics: { + ...EMPTY_ANALYTICS, + taskDocuments: [ + taskDoc({ + kind: "master", + title: "Browser Dashboard Series", + docPath: "/tasks/260610_browser-dashboard/task.json", + }), + taskDoc({ + id: "29", + lifecycleId: undefined, + title: "Event-River Retention and Projection Freshness", + docPath: + "/tasks/260610_browser-dashboard/29_event-river-retention-and-projection-freshness.json", + }), + ], + series: [ + seriesNode({ + seriesId: "260610_browser-dashboard", + subTasks: [ + { + number: "29", + name: "Event-River Retention and Projection Freshness", + file: "29_event-river-retention-and-projection-freshness.md", + status: "planning", + scope: "", + createdAt: "2026-06-27T22:33:00+00:00", + }, + ], + }), + ], + }, + }), + ); + + const { getByText, queryByText } = render(); + expect(getByText("Tasks · 1")).toBeTruthy(); // the master alone — the reopened leaf is hidden + expect(queryByText(/Event-River Retention and Projection Freshness/)).toBeNull(); + }); + + it("re-admits a reopened leaf once its worktrees physically exist again (after worktree_start)", () => { + // Existence — not the cleanup label — is the visibility rule, so the row returns the moment + // the projection stats the recreated worktrees. + const onSelect = vi.fn(); + seed( + projection({ + lifecycles: [], + enclosures: [ + enclosure({ + enclosure: "/contracts/29", + lifecycleId: "", + leafId: "29_event-river-retention-and-projection-freshness", + cleanup: "reopened", + codeWorktreeExists: true, + memoryWorktreeExists: true, }), ], analytics: { @@ -411,12 +475,106 @@ describe("LifecycleList task labels", () => { const { getByText } = render(); const row = getByText("29. Event-River Retention and Projection Freshness"); + expect(getByText("Tasks · 2")).toBeTruthy(); expect(row.closest("[data-depth='1']")).toBeTruthy(); expect(row.closest("[data-parent-key]")?.getAttribute("data-parent-key")).toBe( "taskdoc:/tasks/260610_browser-dashboard/task.json", ); }); + it("renders ONE task entry per enclosureId: a bound lifecycle annotates the doc row, never duplicates it", () => { + // The L9-reopen defect's second half (L11): the doc row and the live lifecycle's card both + // rendered for the same leaf. The identity rule is one row per enclosureId — the lifecycle + // bound to the enclosure (by the contract's lifecycleId, or by its own enclosure anchor) + // annotates the doc row with its state/gate/staleness instead of adding a card. + const onSelect = vi.fn(); + seed( + projection({ + lifecycles: [ + // Bound through the contract's recorded lifecycleId; the doc itself carries no stamp. + lifecycle({ + id: "LC-CONTRACT", + repoId: "agents-remember", + state: "blocked", + staleSeconds: 120, + gate: { + id: "gate-11", + kind: "closeout-approval", + state: "open", + decisions: ["approve", "revise"], + packet: {}, + ts: "2026-06-24T06:00:40+00:00", + }, + }), + // Bound only by its own anchor (lifecycle.enclosure); the contract binding is unset. + lifecycle({ + id: "LC-ANCHOR", + repoId: "agents-remember", + state: "running", + enclosure: "/contracts/12", + }), + ], + enclosures: [ + enclosure({ + enclosure: "/contracts/11", + lifecycleId: "LC-CONTRACT", + leafId: "11_hangar-worktree-truth", + }), + enclosure({ + enclosure: "/contracts/12", + lifecycleId: "", + leafId: "12_three-party-loops", + }), + ], + analytics: { + ...EMPTY_ANALYTICS, + taskDocuments: [ + taskDoc({ + id: "11", + lifecycleId: undefined, + title: "Hangar Worktree Truth", + docPath: "/tasks/260610_browser-dashboard/11_hangar-worktree-truth.json", + }), + taskDoc({ + id: "12", + lifecycleId: undefined, + title: "Three Party Loops", + docPath: "/tasks/260610_browser-dashboard/12_three-party-loops.json", + }), + ], + }, + }), + ); + + const { getByText, getAllByRole, queryByText } = render( + , + ); + + // One entry per enclosureId — the two doc rows and nothing else (no bare lifecycle cards). + expect(getByText("Tasks · 2")).toBeTruthy(); + expect(getAllByRole("option")).toHaveLength(2); + expect(queryByText("11_hangar-worktree-truth")).toBeNull(); // the would-be duplicate's label + expect(queryByText("12_three-party-loops")).toBeNull(); + + // The bound lifecycle ANNOTATES the single row: state, gate, and staleness flow through it. + const contractRow = getByText("Hangar Worktree Truth"); + expect(contractRow.getAttribute("title")).toContain("Lifecycle: LC-CONTRACT"); + expect(contractRow.getAttribute("title")).toContain("State: blocked"); + expect(contractRow.getAttribute("title")).toContain("Gate: closeout-approval"); + expect(getByText("closeout-approval")).toBeTruthy(); + expect(getByText(/2m/)).toBeTruthy(); // staleSeconds: 120 formatted into the row meta + + const anchorRow = getByText("Three Party Loops"); + expect(anchorRow.getAttribute("title")).toContain("Lifecycle: LC-ANCHOR"); + expect(anchorRow.getAttribute("title")).toContain("State: running"); + + // Selecting the single row selects the task document — the leaf's durable identity. + fireEvent.click(contractRow); + expect(onSelect).toHaveBeenCalledWith( + "taskdoc:/tasks/260610_browser-dashboard/11_hangar-worktree-truth.json", + ); + }); + it("hides an abandoned enclosure from the active operations rows", () => { // worktree_abandon discards the worktrees and records cleanup=abandoned; the enclosure is // history, not active work, so neither a lifecycle row nor a doc row may render for it (L11). @@ -432,6 +590,8 @@ describe("LifecycleList task labels", () => { lifecycleId: "LC-DEAD", leafId: "260628-l10-r1", cleanup: "abandoned", + codeWorktreeExists: false, + memoryWorktreeExists: false, }), ], analytics: { @@ -526,6 +686,159 @@ describe("LifecycleList task labels", () => { expect(onSelect).toHaveBeenCalledWith("taskdoc:/tasks/repo-a/plan/task.json"); }); + it("renders the orchestration tier above its commanded masters with the V4 treatment (L14)", () => { + // An orchestration task is a master doc carrying `orchestrates` (the owner data-model ruling). + // It renders gold-tier at depth 0; a master it names nests one step with the purple tier; that + // master's leaves keep today's rendering one step further; an uncommanded master is unchanged. + const onSelect = vi.fn(); + seed( + projection({ + lifecycles: [], + enclosures: [ + enclosure({ + enclosure: "/contracts/15", + lifecycleId: "", + leafId: "15_parallel-leaf-enclosure-workflow", + }), + ], + analytics: { + ...EMPTY_ANALYTICS, + taskDocuments: [ + taskDoc({ + id: "SPRINT-02", + kind: "master", + title: "SPRINT 02 · rollout", + docPath: "/tasks/sprint-02/task.json", + orchestrates: ["260610_browser-dashboard"], + createdAt: "2026-06-19T09:00:00+00:00", + }), + taskDoc({ + kind: "master", + title: "Browser Dashboard Series", + docPath: "/tasks/260610_browser-dashboard/task.json", + createdAt: "2026-06-20T08:00:00+00:00", + }), + taskDoc({ + kind: "master", + title: "Free Standing Series", + docPath: "/tasks/260620_free-standing/task.json", + createdAt: "2026-06-21T08:00:00+00:00", + }), + taskDoc({ + id: "15", + title: "Parallel Leaf Enclosure Workflow", + docPath: "/tasks/260610_browser-dashboard/15_parallel-leaf-enclosure-workflow.json", + createdAt: "2026-06-22T08:00:00+00:00", + }), + ], + series: [ + seriesNode({ + seriesId: "260610_browser-dashboard", + subTasks: [ + { + number: "15", + name: "Parallel Leaf Enclosure Workflow", + file: "15_parallel-leaf-enclosure-workflow.md", + status: "inProgress", + scope: "", + createdAt: "2026-06-20T09:00:00+00:00", + }, + ], + }), + ], + }, + }), + ); + + const { getByText } = render(); + + // Gold tier: the orchestration row, top-level, chevron badge rendered. + const sprintRow = getByText("SPRINT 02 · rollout").closest("[role='option']"); + expect(sprintRow?.getAttribute("data-tier")).toBe("orchestration"); + expect(sprintRow?.getAttribute("data-depth")).toBe("0"); + expect(sprintRow?.querySelector("[data-rank-tier='orchestration']")).not.toBeNull(); + + // Purple tier: the commanded master nests under the orchestration row at 22px. + const masterRow = getByText("Browser Dashboard Series").closest("[role='option']"); + expect(masterRow?.getAttribute("data-tier")).toBe("management"); + expect(masterRow?.getAttribute("data-depth")).toBe("1"); + expect(masterRow?.getAttribute("data-parent-key")).toBe("taskdoc:/tasks/sprint-02/task.json"); + expect((masterRow as HTMLElement).style.marginLeft).toBe("22px"); + expect(masterRow?.querySelector("[data-rank-tier='management']")).not.toBeNull(); + + // Leaves keep today's rendering one step further (depth 2, one 22px margin step + nested look). + const leafRow = getByText("15. Parallel Leaf Enclosure Workflow").closest("[role='option']"); + expect(leafRow?.getAttribute("data-depth")).toBe("2"); + expect(leafRow?.getAttribute("data-tier")).toBeNull(); + expect((leafRow as HTMLElement).style.marginLeft).toBe("22px"); + expect(leafRow?.querySelector("[data-rank-tier]")).toBeNull(); + + // The uncommanded master is untouched: top-level, no tier, no badge, no margin. + const freeRow = getByText("Free Standing Series").closest("[role='option']"); + expect(freeRow?.getAttribute("data-tier")).toBeNull(); + expect(freeRow?.getAttribute("data-depth")).toBe("0"); + expect((freeRow as HTMLElement).style.marginLeft).toBe(""); + expect(freeRow?.querySelector("[data-rank-tier]")).toBeNull(); + }); + + it("renders NO orchestration row or insignia in a flat run (D3 regression)", () => { + // No doc carries `orchestrates` ⇒ the list is byte-identical to the pre-L14 rendering: + // masters top-level, leaves one nested step, zero tier attributes, zero badges. + const onSelect = vi.fn(); + seed( + projection({ + lifecycles: [], + enclosures: [ + enclosure({ + enclosure: "/contracts/15", + lifecycleId: "", + leafId: "15_parallel-leaf-enclosure-workflow", + }), + ], + analytics: { + ...EMPTY_ANALYTICS, + taskDocuments: [ + taskDoc({ + kind: "master", + title: "Browser Dashboard Series", + docPath: "/tasks/260610_browser-dashboard/task.json", + }), + taskDoc({ + id: "15", + title: "Parallel Leaf Enclosure Workflow", + docPath: "/tasks/260610_browser-dashboard/15_parallel-leaf-enclosure-workflow.json", + }), + ], + series: [ + seriesNode({ + seriesId: "260610_browser-dashboard", + subTasks: [ + { + number: "15", + name: "Parallel Leaf Enclosure Workflow", + file: "15_parallel-leaf-enclosure-workflow.md", + status: "inProgress", + scope: "", + createdAt: "2026-06-20T09:00:00+00:00", + }, + ], + }), + ], + }, + }), + ); + + const { container, getByText } = render(); + expect(container.querySelector("[data-tier]")).toBeNull(); + expect(container.querySelector("[data-rank-tier]")).toBeNull(); + const masterRow = getByText("Browser Dashboard Series").closest("[role='option']"); + expect(masterRow?.getAttribute("data-depth")).toBe("0"); + expect((masterRow as HTMLElement).style.marginLeft).toBe(""); + const leafRow = getByText("15. Parallel Leaf Enclosure Workflow").closest("[role='option']"); + expect(leafRow?.getAttribute("data-depth")).toBe("1"); + expect((leafRow as HTMLElement).style.marginLeft).toBe(""); + }); + it("exposes the full long task title and row context on title hover", () => { const longTitle = "Operations task reader row title that is intentionally long enough to require ellipsis in the left rail"; @@ -589,3 +902,43 @@ describe("LifecycleList task labels", () => { ); }); }); + +describe("LifecycleList gate hint (L17 — no bare-ask affordance)", () => { + it("renders no gate hint for a lifecycle carrying a bare ask but no durable gate", () => { + seed( + projection({ + lifecycles: [ + lifecycle({ + id: "LC-ASK", + repoId: "agents-remember", + state: "running", + // A wait-loop-era `ask` payload with NO durable gate: under notify-and-continue this must + // NOT resurface as a gate affordance in the row (the retired fallback showed the question). + ask: { question: "Approve the plan?" }, + }), + ], + enclosures: [ + enclosure({ enclosure: "/contracts/ask", lifecycleId: "LC-ASK", leafId: "01_ask-only" }), + ], + analytics: { + ...EMPTY_ANALYTICS, + taskDocuments: [ + taskDoc({ + id: "01", + lifecycleId: undefined, + title: "Ask Only Leaf", + docPath: "/tasks/260610_browser-dashboard/01_ask-only.json", + }), + ], + }, + }), + ); + const { getByText } = render(); + const row = getByText("Ask Only Leaf"); + // The lifecycle IS bound (its state annotates the row) — so the absent gate line is the contract, + // not a missing binding. Neither a "Gate:" line nor the ask question leaks into the row. + expect(row.getAttribute("title")).toContain("State: running"); + expect(row.getAttribute("title")).not.toContain("Gate:"); + expect(row.getAttribute("title")).not.toContain("Approve the plan?"); + }); +}); diff --git a/dashboard/src/panels/LifecycleList.tsx b/dashboard/src/panels/LifecycleList.tsx index ac4b52e3..9720a8e8 100644 --- a/dashboard/src/panels/LifecycleList.tsx +++ b/dashboard/src/panels/LifecycleList.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, type CSSProperties } from "react"; import { Header, @@ -10,9 +10,13 @@ import { } from "react-aria-components"; import { css, cva } from "../../styled-system/css"; -import { fmtWait, type Pivot } from "../data/selectors"; +import { fmtWait, hasLiveWorktree, type Pivot } from "../data/selectors"; +import { servedAgeSeconds, useNowMs } from "../data/servedAges"; import { useDashboard } from "../data/store"; import { + isOrchestrationDoc, + masterCommandNames, + orchestratorParentKey, pathDir, pathStem, taskDocHierarchyLabel, @@ -29,6 +33,7 @@ import { } from "../data/taskIdentity"; import { Dot } from "../grammar/Dot"; import { Panel } from "../grammar/Panel"; +import { RankBadge, type RankTier } from "../grammar/RankBadge"; import type { AgentPickupNode, EnclosureNode, LifecycleProjection, SeriesNode, TaskDocNode } from "../types/projection"; import { AgentPickupIndicator } from "./AgentPickupIndicator"; @@ -93,6 +98,7 @@ const groupHeader = css({ }); const row = cva({ base: { + position: "relative", // anchors the tier fold-corner pseudo-element (L14) display: "flex", alignItems: "baseline", gap: "0.3rem", @@ -118,6 +124,40 @@ const row = cva({ borderLeftColor: "grid", }, }, + // The V4 command treatment (L14 sketch): a folded corner top-left, a tier ghost wash fading + // into the row bg, and — orchestration only — a gold top hairline. Renders ONLY on rows whose + // tier is set, i.e. when an orchestration task exists (D3); flat runs never see it. + tier: { + orchestration: { + borderTopWidth: "1px", + borderTopStyle: "solid", + borderTopColor: "goldDim", + backgroundImage: + "linear-gradient(90deg, token(colors.goldGhost), token(colors.bg) 34%)", + _before: { + content: '""', + position: "absolute", + top: "0", + left: "0", + borderStyle: "solid", + borderWidth: "13px 13px 0 0", + borderColor: "token(colors.gold) transparent transparent transparent", + }, + }, + management: { + backgroundImage: + "linear-gradient(90deg, token(colors.purpleGhost), token(colors.bg) 30%)", + _before: { + content: '""', + position: "absolute", + top: "0", + left: "0", + borderStyle: "solid", + borderWidth: "13px 13px 0 0", + borderColor: "token(colors.purpleDim) transparent transparent transparent", + }, + }, + }, }, }); const rowId = css({ @@ -176,6 +216,9 @@ export function LifecycleList({ const lifecycles = useDashboard((s) => s.lifecycles); const enclosures = useDashboard((s) => s.enclosures); const analytics = useDashboard((s) => s.analytics); + // Row staleness advances locally between emissions — the change gate (260703-L15) no longer + // re-serves a lifecycle every tick just because its age moved. + const nowMs = useNowMs(); const docs = analytics?.taskDocuments ?? []; const series = analytics?.series ?? []; const agentPickups = analytics?.agentPickups ?? []; @@ -188,6 +231,7 @@ export function LifecycleList({ docs, series, agentPickups, + nowMs, }); const groups = groupRows(rows, pivot); const selectedSelection = parseTaskSelection(selectedId, lifecycles, analytics); @@ -242,11 +286,20 @@ export function LifecycleList({ key={item.key} id={item.key} textValue={item.label} - className={row({ fleeting: item.fleeting, nested: item.depth > 0 })} + className={row({ + fleeting: item.fleeting, + // Tier rows carry the V4 treatment and indent by margin (below); non-tier + // nesting keeps today's leaf look untouched (the flat-run regression rule). + nested: item.depth > 0 && !item.tier, + tier: item.tier, + })} + style={indentStyle(item)} data-depth={item.depth} data-parent-key={item.parentKey} + data-tier={item.tier} > + {item.tier ? : null} {item.label} @@ -276,6 +329,7 @@ interface OperationRowsInput { docs: TaskDocNode[]; series: SeriesNode[]; agentPickups: AgentPickupNode[]; + nowMs: number; // the age-display clock — served staleness advances locally (260703-L15) } interface OperationRow { @@ -293,10 +347,21 @@ interface OperationRow { fallbackOrder: string; parentKey?: string; depth: number; + // The command tier (L14): "orchestration" for a master doc carrying `orchestrates`, + // "management" for a master commanded by one. Unset (no insignia) everywhere else. + tier?: RankTier; fleeting: boolean; inferred: boolean; } +// The 22px indent grammar (L14 sketch): tier rows indent by their full depth; a non-tier row's +// first level of nesting is today's `nested` padding (unchanged — the flat-run regression rule), +// so only levels beyond it add margin (a leaf under a commanded master sits one step further). +function indentStyle(item: Pick): CSSProperties | undefined { + const steps = item.tier ? item.depth : Math.max(0, item.depth - 1); + return steps > 0 ? { marginLeft: `${steps * 22}px` } : undefined; +} + interface OperationGroup { key: string; label: string; @@ -305,11 +370,19 @@ interface OperationGroup { function operationRows(input: OperationRowsInput): OperationRow[] { const representedLifecycleIds = new Set(); + // The identity rule (L11): one task entry per enclosureId. A doc row that resolved through an + // enclosure CLAIMS that leaf; a lifecycle bound to the same enclosure annotates the claimed row + // (via the lifecycleForEnclosure fallback below) instead of rendering a second entry. + const representedEnclosureIds = new Set(); const docPaths = new Set(input.docs.map((doc) => doc.docPath)); const docsByLifecycle = groupDocs(input.docs); const pickupsByLifecycle = groupPickups(input.agentPickups); const enclosureList = Object.values(input.enclosures); - const activeEnclosureList = enclosureList.filter(isActiveEnclosure); + // The visibility rule (L11): a leaf is active while its worktree physically exists — the + // projection's stat'ed truth, never a cleanup-state proxy. Completed/abandoned worktrees are + // gone (hidden, as before), and a reopened contract (cleanup=reopened) has none until + // worktree_start recreates them, so it stays hidden like any other planned leaf. + const activeEnclosureList = enclosureList.filter(hasLiveWorktree); const activeEnclosures = Object.fromEntries( activeEnclosureList.map((item) => [item.enclosure, item]), ); @@ -319,16 +392,39 @@ function operationRows(input: OperationRowsInput): OperationRow[] { for (const doc of input.docs) { const enclosure = enclosureForDoc(doc, activeEnclosureList); if (!isRootTaskDoc(doc) && !enclosure) continue; - const lifecycle = runtimeForDoc(doc, input.lifecycleById, enclosureList); + const lifecycle = + runtimeForDoc(doc, input.lifecycleById, enclosureList) ?? + (enclosure + ? lifecycleForEnclosure(enclosure, input.lifecycles, input.lifecycleById) + : undefined); if (lifecycle) representedLifecycleIds.add(lifecycle.id); - rows.push(docRow(doc, lifecycle, input.series, docPaths, pickupForLifecycle(lifecycle, pickupsByLifecycle))); + if (enclosure) representedEnclosureIds.add(enclosure.enclosureId); + rows.push( + docRow( + doc, + lifecycle, + input.series, + docPaths, + pickupForLifecycle(lifecycle, pickupsByLifecycle), + input.docs, + input.nowMs, + ), + ); } for (const series of input.series) { if (docPaths.has(series.docPath)) continue; const lifecycle = runtimeForDoc(series, input.lifecycleById, enclosureList); if (lifecycle) representedLifecycleIds.add(lifecycle.id); - rows.push(seriesRow(series, lifecycle, pickupForLifecycle(lifecycle, pickupsByLifecycle))); + rows.push( + seriesRow( + series, + lifecycle, + pickupForLifecycle(lifecycle, pickupsByLifecycle), + input.docs, + input.nowMs, + ), + ); } for (const lifecycle of input.lifecycles) { @@ -339,7 +435,10 @@ function operationRows(input: OperationRowsInput): OperationRow[] { activeEnclosures, activeEnclosuresByLifecycle, ); - if (!enclosure) continue; + // No live-worktree enclosure -> no task entry; an already-claimed enclosureId -> the doc row + // above IS this leaf's single entry (the lifecycle already annotates it). + if (!enclosure || representedEnclosureIds.has(enclosure.enclosureId)) continue; + representedEnclosureIds.add(enclosure.enclosureId); rows.push( lifecycleRow( lifecycle, @@ -348,6 +447,7 @@ function operationRows(input: OperationRowsInput): OperationRow[] { pickupForLifecycle(lifecycle, pickupsByLifecycle), input.series, docPaths, + input.nowMs, ), ); } @@ -355,19 +455,35 @@ function operationRows(input: OperationRowsInput): OperationRow[] { return rows.sort(compareRows); } +// The command facts for a master-shaped row (L14): an orchestration doc IS the gold tier; a master +// named in some orchestration doc's `orchestrates` takes the purple tier and nests under it. Docs +// commanded by nothing carry neither — the whole treatment vanishes in a flat run (D3). +function commandFacts( + doc: Pick, + allDocs: TaskDocNode[], +): { tier?: RankTier; parentKey?: string } { + if (doc.kind !== "master") return {}; + if (isOrchestrationDoc(doc)) return { tier: "orchestration" }; + const commander = orchestratorParentKey(masterCommandNames(doc), allDocs, doc.docPath); + return commander ? { tier: "management", parentKey: commander } : {}; +} + function docRow( doc: TaskDocNode, lifecycle: LifecycleProjection | undefined, seriesList: SeriesNode[], masterDocPaths: Set, pickup: AgentPickupNode | undefined, + allDocs: TaskDocNode[], + nowMs: number, ): OperationRow { const progress = doc.kind === "master" ? subTaskProgress(doc.subTasks) : topLevelStepProgress(doc); const label = taskDocHierarchyLabel(doc, seriesList); const repo = doc.repository || lifecycle?.repoId || "—"; const phase = lifecycle?.phase ?? doc.status; const variant = lifecycle?.state ?? statusVariant(doc.status); - const gate = gateHint(lifecycle?.gate?.kind, lifecycle?.ask); + const gate = gateHint(lifecycle?.gate?.kind); + const command = commandFacts(doc, allDocs); return { key: taskDocSelectionKey(doc.docPath), label, @@ -384,13 +500,18 @@ function docRow( phase, secondary: doc.kind, variant, - meta: rowMetaText(progressHint(progress), doc.status, lifecycle?.staleSeconds), + meta: rowMetaText( + progressHint(progress), + doc.status, + servedAgeSeconds(lifecycle, lifecycle?.staleSeconds, nowMs), + ), gate, pickup, createdAt: doc.createdAt ?? "", fallbackOrder: doc.docPath, - parentKey: taskDocParentKey(doc, seriesList, masterDocPaths), + parentKey: command.parentKey ?? taskDocParentKey(doc, seriesList, masterDocPaths), depth: 0, + tier: command.tier, fleeting: lifecycle?.fleeting ?? false, inferred: lifecycle?.inferred ?? false, }; @@ -400,11 +521,23 @@ function seriesRow( series: SeriesNode, lifecycle: LifecycleProjection | undefined, pickup: AgentPickupNode | undefined, + allDocs: TaskDocNode[], + nowMs: number, ): OperationRow { const repo = series.repository || lifecycle?.repoId || "—"; const phase = lifecycle?.phase ?? series.status; const variant = lifecycle?.state ?? statusVariant(series.status); - const gate = gateHint(lifecycle?.gate?.kind, lifecycle?.ask); + const gate = gateHint(lifecycle?.gate?.kind); + // A folder-keyed series fallback row is still a master seat: it answers to its seriesId (the + // task folder), its title, or its doc folder when an orchestration doc names it (L14). + const commander = orchestratorParentKey( + [ + series.seriesId, + series.title, + pathDir(series.docPath).split("/").filter(Boolean).pop() ?? "", + ].filter(Boolean), + allDocs, + ); return { key: seriesSelectionKey(series.seriesId), label: series.title, @@ -423,13 +556,15 @@ function seriesRow( meta: rowMetaText( progressHint({ done: series.doneCount, total: series.totalCount }), series.status, - lifecycle?.staleSeconds, + servedAgeSeconds(lifecycle, lifecycle?.staleSeconds, nowMs), ), gate, pickup, createdAt: series.createdAt ?? "", fallbackOrder: series.docPath, + parentKey: commander, depth: 0, + tier: commander ? "management" : undefined, fleeting: lifecycle?.fleeting ?? false, inferred: lifecycle?.inferred ?? false, }; @@ -442,10 +577,11 @@ function lifecycleRow( pickup: AgentPickupNode | undefined, seriesList: SeriesNode[], masterDocPaths: Set, + nowMs: number, ): OperationRow { const label = taskLabel(lifecycle, docs, enclosure); const repo = lifecycle.repoId ?? "—"; - const gate = gateHint(lifecycle.gate?.kind, lifecycle.ask); + const gate = gateHint(lifecycle.gate?.kind); const currentStep = docs.length === 1 ? docs[0].currentStep : undefined; return { key: lifecycleSelectionKey(lifecycle.id), @@ -463,7 +599,7 @@ function lifecycleRow( phase: lifecycle.phase, secondary: lifecycle.phase, variant: lifecycle.state, - meta: rowMetaText(taskHint(docs), "", lifecycle.staleSeconds), + meta: rowMetaText(taskHint(docs), "", servedAgeSeconds(lifecycle, lifecycle.staleSeconds, nowMs)), gate, pickup, createdAt: lifecycle.startedAt, @@ -510,22 +646,37 @@ function groupRows(rows: OperationRow[], pivot: Pivot): OperationGroup[] { })); } +// Depth-first hierarchy flatten. Historically two levels (master > leaf); the L14 orchestration +// tier adds a third (orchestration > master > leaf), so this walks parent links to any depth. +// A `seen` guard plus the trailing sweep keep pathological parent data (a cycle, e.g. two +// orchestration docs naming each other) from dropping rows: unreachable rows append top-level. function hierarchyRows(rows: OperationRow[]): OperationRow[] { const byParent = new Map(); const byKey = new Map(rows.map((item) => [item.key, item])); for (const item of rows) { - if (!item.parentKey || !byKey.has(item.parentKey)) continue; + if (!item.parentKey || !byKey.has(item.parentKey) || item.parentKey === item.key) continue; const children = byParent.get(item.parentKey); if (children) children.push(item); else byParent.set(item.parentKey, [item]); } const roots = rows - .filter((item) => !item.parentKey || !byKey.has(item.parentKey)) + .filter((item) => !item.parentKey || !byKey.has(item.parentKey) || item.parentKey === item.key) .sort(compareRows); - return roots.flatMap((root) => [ - { ...root, depth: 0 }, - ...(byParent.get(root.key) ?? []).sort(compareRows).map((child) => ({ ...child, depth: 1 })), - ]); + const out: OperationRow[] = []; + const seen = new Set(); + const visit = (item: OperationRow, depth: number) => { + if (seen.has(item.key)) return; + seen.add(item.key); + out.push({ ...item, depth }); + for (const child of (byParent.get(item.key) ?? []).sort(compareRows)) { + visit(child, depth + 1); + } + }; + for (const root of roots) visit(root, 0); + for (const item of [...rows].sort(compareRows)) { + if (!seen.has(item.key)) visit(item, 0); + } + return out; } function selectionKey(selection: ReturnType): string | null { @@ -535,11 +686,12 @@ function selectionKey(selection: ReturnType): string return lifecycleSelectionKey(selection.lifecycleId); } -function gateHint(kind: string | undefined, ask: Record | undefined): string { - if (kind) return kind; - const question = ask?.question; - if (typeof question === "string" && question.trim()) return question; - return ask ? "ask" : ""; +// The row's gate chip is the DURABLE gate kind only. The wait-loop-era fallback to the lifecycle's bare +// `ask` payload (the question string, else the literal "ask") was retired with notify-and-continue: the +// attention queue carries the notification and GateResponder owns durable gates, so a bare `ask` no +// longer renders a gate affordance in the tasks row (L17 supplement). +function gateHint(kind: string | undefined): string { + return kind ?? ""; } function taskTitle(facts: { @@ -635,11 +787,29 @@ function enclosureForDoc( }); } -function isActiveEnclosure(enclosure: Pick): boolean { - // "completed" is a retired leaf, "abandoned" a discarded one — neither is active work. - // A "reopened" enclosure (L11) IS active: the leaf is back in planning awaiting its - // worktree_start, and its doc row must render like any other planned leaf. - return enclosure.cleanup !== "completed" && enclosure.cleanup !== "abandoned"; +// The lifecycle bound to an enclosure, following the cross-ref in either direction: the +// contract's recorded lifecycleId, or a live lifecycle still anchored to the enclosure +// (lifecycle.enclosure). This is the annotation source for a doc row whose own lifecycleId is +// unset or stale: the bound lifecycle's gate/staleness enrich the leaf's single row instead +// of rendering a duplicate lifecycle card for the same enclosureId (L11). +function lifecycleForEnclosure( + enclosure: EnclosureNode, + lifecycles: LifecycleProjection[], + lifecycleById: Record, +): LifecycleProjection | undefined { + if (enclosure.lifecycleId && lifecycleById[enclosure.lifecycleId]) { + return lifecycleById[enclosure.lifecycleId]; + } + // Anchor fallback: several lifecycles may anchor one enclosure with no contract + // lifecycleId — the most recently active one annotates the row (ISO timestamps + // compare lexicographically), never whichever happened to project first. + return lifecycles + .filter((lifecycle) => lifecycle.enclosure === enclosure.enclosure) + .reduce( + (latest, lifecycle) => + !latest || lifecycle.lastEventTs > latest.lastEventTs ? lifecycle : latest, + undefined, + ); } function topLevelStepProgress(doc: TaskDocNode): { done: number; total: number } { diff --git a/dashboard/src/panels/MemoryMirror.tsx b/dashboard/src/panels/MemoryMirror.tsx index 3eca67be..65870ee5 100644 --- a/dashboard/src/panels/MemoryMirror.tsx +++ b/dashboard/src/panels/MemoryMirror.tsx @@ -1,11 +1,13 @@ import { css, cx } from "../../styled-system/css"; import { driftSegments, fmtWait } from "../data/selectors"; +import { servedAgeSeconds, useNowMs } from "../data/servedAges"; import { useDashboard } from "../data/store"; import { Panel } from "../grammar/Panel"; // The memory mirror (mc2 harvest #2 — "a 1-to-1 mirror of the code"): a coverage/drift segmented // bar per repo + ledger currency + the stalest-sidecar leaderboard. All read from the slice-3b -// analytics nodes — no reducer work. Ages are server-computed (`snapshotStaleSeconds`/`ageSeconds`). +// analytics nodes — no reducer work. Ages are server-anchored (`snapshotStaleSeconds`/`ageSeconds`) +// and advanced locally between emissions (the 260703-L15 change gate — data/servedAges.ts). const sizing = css({ flex: "1" }); const repo = css({ marginBottom: "0.7rem" }); const row = css({ @@ -51,6 +53,7 @@ const SEG_BG: Record = { export function MemoryMirror() { const analytics = useDashboard((s) => s.analytics); + const nowMs = useNowMs(); const drift = analytics?.driftSnapshots ?? []; const ledgers = analytics?.ledgers ?? []; const stalest = analytics?.stalestSidecars ?? []; @@ -72,7 +75,8 @@ export function MemoryMirror() {
    {snapshot.repository} 0 ? actionable : "muted"}> - {snapshot.actionableCount} actionable · {fmtWait(snapshot.snapshotStaleSeconds)} + {snapshot.actionableCount} actionable ·{" "} + {fmtWait(servedAgeSeconds(snapshot, snapshot.snapshotStaleSeconds, nowMs))}
    (
  • {sidecar.onboardingFile} - {fmtWait(sidecar.ageSeconds)} + + {fmtWait(servedAgeSeconds(sidecar, sidecar.ageSeconds, nowMs))} +
  • ))} diff --git a/dashboard/src/panels/SessionList.test.tsx b/dashboard/src/panels/SessionList.test.tsx index 9e6f5772..5cec124b 100644 --- a/dashboard/src/panels/SessionList.test.tsx +++ b/dashboard/src/panels/SessionList.test.tsx @@ -1,6 +1,7 @@ import { cleanup, fireEvent, render } from "@testing-library/react"; import { afterEach, describe, expect, it, vi } from "vitest"; +import type { SessionGroup } from "../data/sessionGroups"; import type { OpenSession } from "../data/sessions"; import { SessionList } from "./SessionList"; @@ -109,3 +110,178 @@ describe("SessionList (6e-2c)", () => { expect(onSelect).not.toHaveBeenCalled(); }); }); + +// The G1 command tree (L14): grouped rendering — collapsible headers with insignia + counts, the +// landed archive collapsed by default, unattached sessions flat below, and a group-less model +// falling back to today's flat list. +describe("SessionList command tree (L14)", () => { + const group = (over: Partial) => ({ + key: "master:m", + kind: "master" as const, + label: "260706 management-repo", + nested: false, + defaultCollapsed: false, + sessions: [] as OpenSession[], + countLabel: "0 chats", + ...over, + }); + + it("renders group headers with chevron, insignia, name and counts", () => { + const { getByTestId } = render( + {}} + onTerminate={() => {}} + grouped={{ + groups: [ + group({ + key: "command", + kind: "command", + label: "SPRINT 02 · command deck", + tier: "orchestration", + sessions: [{ id: "a", label: "Terminal 1" }], + countLabel: "1 chat · 1 live", + }), + group({ + key: "master:260706", + tier: "management", + nested: true, + sessions: [{ id: "b", label: "Claude Code 2" }], + countLabel: "1 chat · 1 live", + }), + ], + ungrouped: [], + }} + />, + ); + const deckToggle = getByTestId("chats-group-toggle-command"); + expect(deckToggle.textContent).toContain("SPRINT 02 · command deck"); + expect(deckToggle.textContent).toContain("1 chat · 1 live"); + expect(deckToggle.getAttribute("aria-expanded")).toBe("true"); + expect(deckToggle.querySelector("[data-rank-tier='orchestration']")).not.toBeNull(); + expect(deckToggle.querySelector("[data-rank-size='sm']")).not.toBeNull(); + // The commanded master group nests one step and carries the purple insignia. + const master = getByTestId("chats-group-master:260706"); + expect(master.getAttribute("data-nested")).toBe("true"); + expect(master.querySelector("[data-rank-tier='management']")).not.toBeNull(); + // Members render inside their group. + expect(master.contains(getByTestId("chats-session-b"))).toBe(true); + }); + + it("collapses the landed archive by default and toggles collapse per header click (UI-local)", () => { + const { getByTestId, queryByTestId } = render( + {}} + onTerminate={() => {}} + grouped={{ + groups: [ + group({ + key: "landed", + kind: "landed", + label: "landed", + defaultCollapsed: true, + sessions: [{ id: "a", label: "Terminal 1", status: "exited" }], + countLabel: "1 chat · archived", + }), + ], + ungrouped: [], + }} + />, + ); + const toggle = getByTestId("chats-group-toggle-landed"); + expect(toggle.getAttribute("aria-expanded")).toBe("false"); + expect(toggle.querySelector("[data-rank-tier]")).toBeNull(); // the archive is unmarked + expect(queryByTestId("chats-session-a")).toBeNull(); // collapsed ⇒ rows unmounted + + fireEvent.click(toggle); + expect(toggle.getAttribute("aria-expanded")).toBe("true"); + expect(queryByTestId("chats-session-a")).not.toBeNull(); + + fireEvent.click(toggle); + expect(queryByTestId("chats-session-a")).toBeNull(); + }); + + it("auto-expands a default-collapsed group that holds the ACTIVE session", () => { + // The active chat must never be hidden by a collapse default (an explicit user toggle still wins). + const { getByTestId, queryByTestId } = render( + {}} + onTerminate={() => {}} + grouped={{ + groups: [ + group({ + key: "landed", + kind: "landed", + label: "landed", + defaultCollapsed: true, + sessions: [{ id: "a", label: "Terminal 1", status: "exited" }], + countLabel: "1 chat · archived", + }), + ], + ungrouped: [], + }} + />, + ); + expect(getByTestId("chats-group-toggle-landed").getAttribute("aria-expanded")).toBe("true"); + expect(queryByTestId("chats-session-a")).not.toBeNull(); + + fireEvent.click(getByTestId("chats-group-toggle-landed")); // the user's collapse still wins + expect(queryByTestId("chats-session-a")).toBeNull(); + }); + + it("keeps unattached sessions in a flat list below the groups", () => { + const { getByTestId } = render( + {}} + onTerminate={() => {}} + grouped={{ + groups: [ + group({ sessions: [{ id: "b", label: "Claude Code 2" }], countLabel: "1 chat" }), + ], + ungrouped: [{ id: "a", label: "Terminal 1" }], + }} + />, + ); + const tree = getByTestId("chats-session-tree"); + const flatRow = getByTestId("chats-session-a"); + expect(tree.contains(flatRow)).toBe(true); + expect(flatRow.closest("[data-testid^='chats-group-']")).toBeNull(); // outside every group + }); + + it("renders today's flat list when the grouped model derives zero groups", () => { + const { getByTestId, queryByTestId } = render( + {}} + onTerminate={() => {}} + grouped={{ groups: [], ungrouped: sessions }} + />, + ); + expect(queryByTestId("chats-session-tree")).toBeNull(); + expect(getByTestId("chats-session-a").getAttribute("data-selected")).not.toBeNull(); + }); + + it("shows a spawn-role chip on rows with role provenance", () => { + const { getByTestId, queryByTestId } = render( + {}} + onTerminate={() => {}} + />, + ); + expect(getByTestId("chats-session-role-a").textContent).toBe("manager"); + expect(queryByTestId("chats-session-role-b")).toBeNull(); + }); +}); diff --git a/dashboard/src/panels/SessionList.tsx b/dashboard/src/panels/SessionList.tsx index 1b89f032..419dcb81 100644 --- a/dashboard/src/panels/SessionList.tsx +++ b/dashboard/src/panels/SessionList.tsx @@ -1,8 +1,10 @@ -import type { MouseEvent, PointerEvent } from "react"; +import { useState, type MouseEvent, type PointerEvent, type ReactNode } from "react"; import { GridList, GridListItem } from "react-aria-components"; -import { css } from "../../styled-system/css"; +import { css, cva, cx } from "../../styled-system/css"; +import type { GroupedSessions, SessionGroup } from "../data/sessionGroups"; import type { OpenSession } from "../data/sessions"; +import { RankBadge } from "../grammar/RankBadge"; // The session switcher (slice 6e-2c): the open terminal/chat sessions as a left-rail list, replacing // the old horizontal tab strip. A React Aria GridList — not a ListBox — because each row carries a @@ -12,6 +14,12 @@ import type { OpenSession } from "../data/sessions"; // is Panda's `_selected`/`_focusVisible` state conditions (coding-guidelines: React Aria owns // behavior, Panda owns looks), and the row's selected colour cascades to the label so selection state // is never re-derived in JSX. +// +// L14 adds the G1 COMMAND TREE: when a `grouped` model is supplied (data/sessionGroups), sessions +// render inside collapsible groups — the command deck (gold insignia) on top, one group per claimed +// master (purple insignia + 22px indent when commanded), landed work in one collapsed archive — +// while unattached sessions keep today's flat placement below. Collapse state is UI-local (no +// persistence); each group is its own GridList so arrow-nav stays within the group. const list = css({ display: "grid", gap: "0.3rem", @@ -72,6 +80,39 @@ const statusBadge = css({ borderRadius: "2px", paddingInline: "0.25rem", }); +// The spawn-role chip (L14, sketch vocabulary): who this chat IS in the run. Colour keys the l-01 +// seat — command seats glow gold/purple to match their insignia; the worker/reviewer lanes reuse the +// existing progress/attention hues. Unknown roles fall through to the muted base (never throw). +const roleChip = cva({ + base: { + flexShrink: 0, + fontSize: "0.6rem", + textTransform: "uppercase", + letterSpacing: "0.08em", + color: "muted", + borderWidth: "1px", + borderStyle: "solid", + borderColor: "grid", + borderRadius: "2px", + paddingInline: "0.3rem", + }, + variants: { + role: { + orchestrator: { + color: "gold", + borderColor: "color-mix(in oklch, token(colors.gold) 45%, transparent)", + }, + strategist: { color: "gold" }, + manager: { + color: "purple", + borderColor: "color-mix(in oklch, token(colors.purple) 45%, transparent)", + }, + worker: { color: "cyan" }, + reviewer: { color: "amber" }, + }, + }, +}); +const KNOWN_ROLES = new Set(["orchestrator", "strategist", "manager", "worker", "reviewer"]); const actions = css({ display: "flex", alignItems: "stretch", @@ -92,6 +133,64 @@ const terminateButton = css({ _hover: { color: "alarm" }, _focusVisible: { outline: "1px solid token(colors.amber)", outlineOffset: "1px" }, }); +const tree = css({ + display: "flex", + flexDirection: "column", + gap: "0.35rem", + minHeight: "0", + overflowY: "auto", +}); +const groupBox = css({ + borderWidth: "1px", + borderStyle: "solid", + borderColor: "grid", + background: "bgPanel", +}); +const groupNested = css({ marginLeft: "22px" }); // the shared indent grammar (L14 sketch) +const groupHeader = css({ + display: "flex", + alignItems: "center", + gap: "0.4rem", + width: "100%", + font: "inherit", + fontSize: "0.74rem", + color: "ink", + background: "transparent", + border: "none", + paddingInline: "0.5rem", + paddingBlock: "0.35rem", + cursor: "pointer", + userSelect: "none", + textAlign: "left", + _focusVisible: { outline: "1px solid token(colors.cyan)", outlineOffset: "-1px" }, +}); +const groupChevron = css({ + color: "muted", + fontSize: "0.6rem", + flex: "none", + transition: "transform 0.12s ease", + "&[data-expanded=true]": { transform: "rotate(90deg)" }, + _motionReduce: { transition: "none" }, +}); +const groupName = css({ + flex: "1", + minWidth: "0", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", +}); +const groupCount = css({ + flex: "none", + color: "muted", + fontSize: "0.66rem", + fontVariantNumeric: "tabular-nums", +}); +const groupRows = css({ + borderTopWidth: "1px", + borderTopStyle: "solid", + borderTopColor: "grid", + padding: "0.3rem", +}); export function SessionList({ sessions, @@ -99,6 +198,7 @@ export function SessionList({ onSelect, onTerminate, leafNameFor, + grouped, }: { sessions: OpenSession[]; activeId: string | null; @@ -106,14 +206,75 @@ export function SessionList({ onTerminate: (id: string) => void; /** Resolve a bound session's leaf name (task-doc title, fallback leaf id) for the "who works on what" label. */ leafNameFor?: (leafKey: string) => string; + /** The G1 command-tree model (L14). Absent or group-less ⇒ today's flat list, unchanged. */ + grouped?: GroupedSessions; }) { + // Collapse state, keyed by group key — UI-local by design (L14: no persistence this leaf). + const [collapsed, setCollapsed] = useState>({}); const stopRowSelection = (event: MouseEvent | PointerEvent) => { event.stopPropagation(); }; - return ( + const renderRow = (session: OpenSession) => { + const leafName = session.leafKey + ? (leafNameFor?.(session.leafKey) ?? session.leafKey) + : undefined; + // The full, untruncated name for the hover title (the label, plus its bound leaf) — the row + // text-overflow-ellipses, so the title is how a long name stays readable (fix 4). + const fullName = leafName ? `${session.label} · ${leafName}` : session.label; + return ( + + {session.spawnRole ? ( + + {session.spawnRole} + + ) : null} + + {session.label} + {leafName ? ( + + {" · "} + {leafName} + + ) : null} + + {session.lifecycleId ? {session.lifecycleId} : null} + {session.status && session.status !== "running" ? ( + {session.status} + ) : null} + + + + + ); + }; + + const gridListFor = (members: OpenSession[], ariaLabel: string): ReactNode => ( - {(session) => { - const leafName = session.leafKey - ? (leafNameFor?.(session.leafKey) ?? session.leafKey) - : undefined; - // The full, untruncated name for the hover title (the label, plus its bound leaf) — the row - // text-overflow-ellipses, so the title is how a long name stays readable (fix 4). - const fullName = leafName ? `${session.label} · ${leafName}` : session.label; + {renderRow} + + ); + + // No grouping model (the rail) or nothing grouped ⇒ the pre-L14 flat list, byte-identical. + if (!grouped || grouped.groups.length === 0) { + return gridListFor(sessions, "Open sessions"); + } + + // Explicit user toggles win; otherwise a default-collapsed group (the landed archive) still + // opens when it holds the ACTIVE session — the active chat must never be hidden by a default. + const isCollapsed = (group: SessionGroup) => + collapsed[group.key] ?? + (group.defaultCollapsed && !group.sessions.some((member) => member.id === activeId)); + return ( +
    + {grouped.groups.map((group) => { + const open = !isCollapsed(group); return ( - - - {session.label} - {leafName ? ( - - {" · "} - {leafName} - - ) : null} - - {session.lifecycleId ? {session.lifecycleId} : null} - {session.status && session.status !== "running" ? ( - {session.status} - ) : null} - +
    - - + {open ? ( +
    {gridListFor(group.sessions, `Open sessions — ${group.label}`)}
    + ) : null} +
    ); - }} - + })} + {grouped.ungrouped.length > 0 + ? gridListFor(grouped.ungrouped, "Open sessions") + : null} +
    ); } diff --git a/dashboard/src/panels/TaskNotes.test.tsx b/dashboard/src/panels/TaskNotes.test.tsx new file mode 100644 index 00000000..5c9c4c2d --- /dev/null +++ b/dashboard/src/panels/TaskNotes.test.tsx @@ -0,0 +1,110 @@ +import { cleanup, fireEvent, render } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +import type { NoteEntry } from "../data/notes"; +import { TaskNotes } from "./TaskNotes"; + +// L17: TaskNotes is now the compact ENTRY SURFACE — a list + resolved references that OPEN the notes +// reader via `onOpenNotes`. The inline reading pane was retired; note CONTENT rendering (markdown / +// text fallback / binary placeholder / truncation) is now covered by NotesReaderViewer.test.tsx. +const REPO = "agents-remember"; +const MASTER = "260703_agent-orchestration"; + +function entry(path: string, over: Partial = {}): NoteEntry { + return { name: path.split("/").pop() ?? path, path, size: 100, language: "markdown", ...over }; +} + +// The notes API stub: /api/notes/list answers the seeded listing (the reader owns /api/notes/read now). +function stubNotesApi(notes: NoteEntry[], truncated = false) { + vi.stubGlobal( + "fetch", + vi.fn(async (url: string) => { + const params = new URLSearchParams(url.split("?")[1] ?? ""); + if (url.startsWith("/api/notes/list")) { + const payload = { repo: params.get("repo"), master: params.get("master"), notes, truncated }; + return { ok: true, status: 200, json: async () => payload } as unknown as Response; + } + return { ok: false, status: 404, json: async () => ({ status: "not-found" }) } as unknown as Response; + }), + ); +} + +afterEach(() => { + cleanup(); + vi.restoreAllMocks(); + vi.unstubAllGlobals(); +}); + +describe("TaskNotes entry surface", () => { + it("lists the series notes including reports/ subfolder entries", async () => { + stubNotesApi([entry("friction-ledger.md"), entry("reports/260703-L1-worker-report.md")]); + const view = render(); + expect((await view.findByTestId("note-open-1")).textContent).toContain("friction-ledger.md"); + expect(view.getByText("Series notes")).toBeTruthy(); + expect(view.getByText("reports/260703-L1-worker-report.md")).toBeTruthy(); + }); + + it("opens the notes reader on the clicked note when a list row is clicked", async () => { + stubNotesApi([entry("friction-ledger.md"), entry("reports/260703-L1-worker-report.md")]); + const onOpenNotes = vi.fn(); + const view = render(); + fireEvent.click(await view.findByTestId("note-open-2")); + expect(onOpenNotes).toHaveBeenCalledWith({ + repo: REPO, + master: MASTER, + path: "reports/260703-L1-worker-report.md", + }); + }); + + it("says when the server's depth cap pruned the listing", async () => { + stubNotesApi([entry("a.md")], true); + const view = render(); + await view.findByTestId("note-open-1"); + expect(view.getByText(/beyond the list cap/)).toBeTruthy(); + }); + + it("renders no notes surface when the API is unreachable", async () => { + vi.stubGlobal("fetch", vi.fn(async () => Promise.reject(new TypeError("unreachable")))); + const view = render( + , + ); + // The reference stays plain text; nothing to list, nothing to open. + expect(await view.findByText("notes/friction-ledger.md")).toBeTruthy(); + expect(view.queryByTestId("note-ref-1")).toBeNull(); + expect(view.queryByText("Series notes")).toBeNull(); + }); +}); + +describe("TaskNotes reference resolution", () => { + it("turns a reference naming an existing notes file into a link that opens the reader on it", async () => { + stubNotesApi([entry("friction-ledger.md")]); + const onOpenNotes = vi.fn(); + const view = render( + , + ); + const link = await view.findByTestId("note-ref-1"); + expect(link.tagName.toLowerCase()).toBe("button"); + fireEvent.click(link); + expect(onOpenNotes).toHaveBeenCalledWith({ repo: REPO, master: MASTER, path: "friction-ledger.md" }); + }); + + it("keeps a non-matching reference as plain text", async () => { + stubNotesApi([entry("friction-ledger.md")]); + const view = render( + , + ); + await view.findByTestId("note-open-1"); // the listing has arrived — resolution is settled + expect(view.queryByTestId("note-ref-1")).toBeNull(); + expect(view.getByText(/the confinement idiom to reuse/)).toBeTruthy(); + }); +}); diff --git a/dashboard/src/panels/TaskNotes.tsx b/dashboard/src/panels/TaskNotes.tsx new file mode 100644 index 00000000..30d7f7b9 --- /dev/null +++ b/dashboard/src/panels/TaskNotes.tsx @@ -0,0 +1,161 @@ +// L9 → L17: the compact coordination-notes ENTRY SURFACE inside the task reader. It lists the +// selected master's tasks///notes/** tree (reports/ included) and resolves task-doc +// reference strings that name an existing notes file into openable links. Both surfaces OPEN THE +// NOTES READER (the L17 file-viewer-style takeover) via `onOpenNotes`; the bespoke inline reading +// pane that used to live here was RETIRED — reading a note now happens in the full reader view +// (panels/notes-reader/NotesReaderViewer.tsx), with the master's whole notes tree in its rail. +// Everything here is still GET-only component state: no store mutation, no write surface. +import { useEffect, useState } from "react"; + +import { css } from "../../styled-system/css"; +import { listNotes, resolveNoteReference, type NotesListing } from "../data/notes"; +import { Markdown } from "../grammar/Markdown"; +import type { NotesReaderTarget } from "./notes-reader/NotesReaderViewer"; + +const section = css({ display: "grid", gap: "0.3rem" }); +const heading = css({ + margin: "0", + fontSize: "0.72rem", + letterSpacing: "0.08em", + textTransform: "uppercase", + color: "amber", +}); +const bullets = css({ + margin: "0", + paddingLeft: "1.1rem", + maxWidth: "78ch", + display: "grid", + gap: "0.2rem", + fontSize: "0.84rem", + lineHeight: "1.45", +}); +// A resolved reference: the whole reference string becomes the openable link into the notes reader. +const refLink = css({ + font: "inherit", + textAlign: "left", + color: "cyan", + background: "transparent", + border: "0", + padding: "0", + cursor: "pointer", + textDecoration: "underline", + _hover: { color: "ink" }, + _focusVisible: { outline: "1px solid token(colors.amber)", outlineOffset: "1px" }, +}); +const noteList = css({ listStyle: "none", margin: "0", padding: "0", display: "grid", gap: "0.15rem" }); +const noteRow = css({ + display: "flex", + justifyContent: "space-between", + gap: "0.5rem", + width: "100%", + textAlign: "left", + font: "inherit", + fontSize: "0.78rem", + paddingInline: "0.4rem", + paddingBlock: "0.2rem", + background: "bg", + border: "0", + borderLeftWidth: "2px", + borderLeftStyle: "solid", + borderLeftColor: "grid", + color: "ink", + cursor: "pointer", + _hover: { background: "oklch(0.7 0.1 200 / 0.12)", borderLeftColor: "amber" }, + _focusVisible: { outline: "1px solid token(colors.amber)", outlineOffset: "1px" }, +}); +const noteMeta = css({ color: "muted", fontSize: "0.72rem" }); +const listCapHint = css({ color: "muted", fontSize: "0.72rem" }); + +// The series' notes surface + the doc's reference list, sharing one notes listing so a resolved +// reference and a list row both open the reader on the right note. An unreachable notes API (or a +// series without a notes/ folder — the server answers an empty list) simply renders no notes section; +// references then all stay plain text. Reading itself is delegated to `onOpenNotes` (the L17 reader). +export function TaskNotes({ + repo, + master, + references, + onOpenNotes, +}: { + repo: string; + master: string; + references: string[]; + // Open the L17 notes reader on a note. Optional so a context without the takeover (some tests / + // the master-overview list) still renders the surface; the rows are then inert. + onOpenNotes?: (target: NotesReaderTarget) => void; +}) { + const [listing, setListing] = useState(null); + + useEffect(() => { + let live = true; + setListing(null); + void listNotes(repo, master).then( + (data) => { + if (live) setListing(data); + }, + () => {}, // unreachable API: no notes surface, references stay plain text + ); + return () => { + live = false; + }; + }, [repo, master]); + + const notes = listing?.notes ?? []; + const notePaths = notes.map((note) => note.path); + const open = (path: string) => onOpenNotes?.({ repo, master, path }); + + return ( + <> + {references.length > 0 ? ( +
    +

    References

    +
      + {references.map((reference, index) => { + const target = resolveNoteReference(reference, notePaths); + return ( +
    • + {target ? ( + + ) : ( + {reference} + )} +
    • + ); + })} +
    +
    + ) : null} + {notes.length > 0 ? ( +
    +

    Series notes

    +
      + {notes.map((note, index) => ( +
    • + +
    • + ))} +
    + {listing?.truncated ? ( + deeper subfolders exist but are beyond the list cap + ) : null} +
    + ) : null} + + ); +} diff --git a/dashboard/src/panels/flowModels.ts b/dashboard/src/panels/flowModels.ts new file mode 100644 index 00000000..3e24f7e8 --- /dev/null +++ b/dashboard/src/panels/flowModels.ts @@ -0,0 +1,400 @@ +// The flow-model registry for the FlowTab canvas: each model is one drawable lifecycle design, +// rendered by FlowTab's segment renderer and switched by its nav. Models are STATIC design +// artifacts (no store reads) — the canvas is where a lifecycle is drawn, reviewed with the +// developer, and kept in step with the doctrine (visuals ride every doctrine change). The drawn +// truth is the unified l-01-agent-lifecycles skill: ROUTER + per-role lifecycles; the retired +// FRAME and BUILD-JOB models died with the l-01/l-02 convergence. `current` = wired today; +// `proposed` = doctrine not yet exercised end-to-end. + +export type Status = "current" | "proposed"; + +export interface FlowStart { + kind: "start"; + label: string; + next?: string; + nextStatus?: Status; +} + +export interface FlowNode { + kind: "node"; + phase: string; + tool: string; + detail?: string; + /** The gate whose notification/approval rides this call (renders the amber left-bar + rider line). */ + rides?: string; + /** Override the rider line (the default describes the auto-fired turn-end notification). */ + ridesNote?: string; + next?: string; + nextStatus?: Status; +} + +export interface FlowRundown { + kind: "rundown"; + title: string; + lines: { line: string; junction?: boolean }[]; +} + +export interface FlowDivider { + kind: "divider"; + label: string; +} + +export type FlowSegment = FlowStart | FlowNode | FlowRundown | FlowDivider; + +export interface FlowModel { + id: string; + /** Short nav label. */ + label: string; + /** Header title after "LIFECYCLE FLOW · ". */ + title: string; + takeaway: string; + segments: FlowSegment[]; +} + +// --- the router (the unified skill's spine) ------------------------------------------------------ + +const ROUTER: FlowModel = { + id: "router", + label: "Router", + title: "router — one skill, one lifecycle per agent type", + takeaway: + "l-01-agent-lifecycles routes every session by EXACTLY three conditions: AR_SPAWN_ROLE set → " + + "run that role's lifecycle; else a role brief as first message → that role (the brief IS the " + + "session start); else the session is developer-facing → the ORCHESTRATOR. Edge cases are " + + "decided: an unresolvable role value falls through to the brief; a brief that never arrives " + + "means announce-and-wait, never improvise. The invariant ladder binds every path: approved " + + "task doc → branch (intent) → worktree only where something is built — and chat is never a " + + "build route.", + segments: [ + { kind: "start", label: "▸ a session boots — which lifecycle am I?", next: "condition 1", nextStatus: "current" }, + { + kind: "rundown", + title: "the three conditions — in order, no fourth entry", + lines: [ + { line: "1 · AR_SPAWN_ROLE set → run roles/.md (designer = the same hat in another chair)" }, + { line: "⟁ unresolvable value → fall through to condition 2 · no brief arrives → announce on the inbox and WAIT", junction: true }, + { line: "2 · first message is a role brief (templates/*-brief.md shape, or `ROLE BRIEF — `) → that role" }, + { line: "3 · otherwise: developer-facing session → roles/orchestrator.md (solo = the jobs with hats collapsed)" }, + ], + }, + { kind: "divider", label: "— the event loop (orchestrator): route each event into a job —" }, + { + kind: "rundown", + title: "jobs — Design · Portfolio · Orchestrate (+ research-only exit)", + lines: [ + { line: "no task doc for the ask → JOB D — pull the designer hat (no git surface)" }, + { line: "docs exist, coherence/order in question → JOB P — bulwark · reshape · the planner master (no git surface)" }, + { line: "approved series ready to implement → JOB O — super-branch INTENT (a branch, not a worktree) → dispatch" }, + { line: "no code change → research-only exit — chat is the right medium" }, + ], + }, + { + kind: "rundown", + title: "the invariant ladder — every path, every role", + lines: [ + { line: "task doc (approved) → branch (intent) → worktree (only where something is built)" }, + { line: "⟁ chat is never a build route — small code work takes the minimal w-02 artifact", junction: true }, + { line: "hat-collapse: flat run → the orchestrator wears the manager hat · session scale → hands-on build" }, + ], + }, + ], +}; + +// --- strategist (the sprint planner, spawn-first) ------------------------------------------------ + +const STRATEGIST: FlowModel = { + id: "strategist", + label: "Strategist", + title: "strategist — the sprint planner, spawn-first", + takeaway: + "A strategist run is a MANDATORY precondition for any orchestrated run — even a single master " + + "gets the pass. Spawn-first by design: portfolio analysis is token-heavy, so it runs as its " + + "own process (the designer stays an inline hat; the strategist never is one). The orchestrator " + + "dispatches it with a portfolio brief carrying REFS to durable state, never pasted state. It " + + "runs an eight-phase method — inventory, two-sided touch surfaces, evidence-cited dependency " + + "edges, blast-radius register, coherence sweep, ordering — and delivers the ORCHESTRATION " + + "TASK: the sprint plan and the sprint scope. The plan is adversarially reviewed (plan-review " + + "catalog), then converges over drawing-board rounds with the developer. The strategist READS " + + "everything and MUTATES nothing — the orchestrator adopts the draft.", + segments: [ + { kind: "start", label: "▸ spawned before an orchestrated run may begin (AR_SPAWN_ROLE=strategist) — portfolio brief = session start", next: "the mandatory pre-run gate", nextStatus: "proposed" }, + { + kind: "rundown", + title: "the mandatory pre-run gate — no orchestration task, no orchestrated run", + lines: [ + { line: "without the pass the portfolio operates blindly, waiting for issues to surface mid-implementation" }, + { line: "even a single master gets the pass — impact must be understood; its leaves may still shuffle" }, + { line: "⟁ re-evaluation: in-sprint master added before implementation starts → re-plan · out-of-sprint → next sprint", junction: true }, + ], + }, + { + kind: "rundown", + title: "the eight-phase method — mechanical phases use real tools; judgment phases cite", + lines: [ + { line: "1 inventory (task docs · contracts · notes) · 2 touch surfaces, TWO-SIDED: existing → route map; NEW → declared parent + shape" }, + { line: "3 structural edges — cgc_dependencies/callers/callees · grepai search/trace → ORDER / CONFLICT / INDEPENDENT (new surfaces: declaration cross-reference)" }, + { line: "4 doctrine edges, cited — an uncited edge is refutable by default · 5 blast-radius register (low/med/high — feeds the loop-tier scoring)" }, + { line: "6 cross-master coherence/contradiction sweep · 7 topological order + leaf moves (from→to + rationale) + parallel waves" }, + { line: "⟁ a leaf naming neither existing surfaces nor a parent anchor → finding: unplannable as scoped — never a silent guess", junction: true }, + ], + }, + { kind: "node", phase: "deliver", tool: "the ORCHESTRATION TASK", detail: "sprint scope · dependency graph with per-edge evidence · blast-radius register · coherence findings · leaf moves · waves · re-evaluation triggers — drafted as a notes artifact", next: "plan review", nextStatus: "proposed" }, + { kind: "node", phase: "loop", tool: "plan review (plan-review catalog)", detail: "the portfolio three-party loop: owner = orchestrator · builder = strategist · reviewer refutes uncited edges, hunts missed shared surfaces, re-derives blast radii", rides: "portfolio loop", ridesNote: "⊘ verdicts are evidence — the orchestrator rules; 3 full rounds max, convergence required", next: "drawing-board rounds", nextStatus: "proposed" }, + { kind: "node", phase: "converge", tool: "drawing-board rounds (developer)", detail: "multi-round convergence EXPECTED — the orchestrator relays · ⟁ quo-vadis (masters heavily disagreeing) → straight to the developer", next: "adoption", nextStatus: "proposed" }, + { kind: "node", phase: "handover", tool: "orchestrator adopts the plan", detail: "reader-not-mutator: the strategist drafts; the ORCHESTRATOR adopts it into durable task form (decision-log entry)", next: "session ends", nextStatus: "proposed" }, + { kind: "node", phase: "close", tool: "session ends", detail: "the orchestration task remains the sprint's standing scope" }, + ], +}; + +// --- orchestrator (260703-ORCH) ---------------------------------------------------------------- + +const ORCHESTRATOR: FlowModel = { + id: "orchestrator", + label: "Orchestrator", + title: "orchestrator — the event loop, drawn on its biggest run (Job O)", + takeaway: + "The developer-facing lifecycle is an EVENT LOOP over durable portfolio state: every session " + + "(resumption is the common case) opens with the trust checkpoint + PORTFOLIO ORIENTATION, then " + + "routes the event — Design (the hat), Portfolio, Orchestrate, or a research-only exit. Below is " + + "the biggest shape, an orchestrated run: streamline → portfolio gate → super-branch INTENT (a " + + "branch, not a worktree) → dependency-ordered dispatch → decide each master-handover gate → " + + "integrate per-edge in a transient worktree → super-exit review → developer handover. Human " + + "review concentrates at the SUPER gate; the orchestrator closes with grounded self-improvement " + + "proposals — never automated self-modification.", + segments: [ + { kind: "start", label: "▸ event: \"orchestrate these masters\" — after trust checkpoint + portfolio orientation", next: "profile-fit check", nextStatus: "proposed" }, + { + kind: "rundown", + title: "seat · profile — before any analysis", + lines: [ + { line: "profile-fit check — right harness/model/effort for the orchestrator job?" }, + { line: "⟁ wrong profile? → spawn_agent_session(orchestrator) + conversation-handover packet → takeover", junction: true }, + { line: "seat = FIRST coordination leaf (task_doc, no enclosure) · chat attached by leaf id" }, + ], + }, + { + kind: "rundown", + title: "portfolio phase · streamline before sequencing (non-linear)", + lines: [ + { line: "route-coherence scan — route indexes · onboarding · grepai · cgc; sub-agents write durable reports" }, + { line: "conflict / regression scan — planned-vs-planned AND planned-vs-past (the integrity bulwark)" }, + { line: "reshape proposals — leaf moves (planning-status only) · foundation-master extraction · mixed masters first-or-last" }, + { line: "⟁ interleaved leaf-level cross-deps? → reshape master boundaries — NEVER interleave dispatch", junction: true }, + { line: "dependency DAG — must be expressible at MASTER granularity" }, + { line: "STRATEGIST pre-run — spawn-first, MANDATORY before any orchestrated run → the ORCHESTRATION TASK = sprint plan + scope (drawing-board rounds; the orchestrator adopts)" }, + ], + }, + { kind: "node", phase: "portfolio · gate", tool: "portfolio plan gate", detail: "developer approves the reshaped portfolio + the orchestration task (sprint scope + DAG + dispatch order) — one wholesale review", rides: "plan-approval", ridesNote: "⊘ the streamlining output is a PROPOSAL — no silent rewrites of dev-accepted tasks", next: "create super integration branch", nextStatus: "proposed" }, + { kind: "node", phase: "topology", tool: "super-branch INTENT", detail: "creates a BRANCH off main, nothing more — masters base off IT; the orchestrator worktree exists only per integration edge", next: "dispatch loop", nextStatus: "proposed" }, + { kind: "divider", label: "↺ dependency-ordered dispatch loop — send out the next READY master's manager ↺" }, + { kind: "node", phase: "dispatch", tool: "spawn_agent_session (manager)", detail: "manager-brief.md · AR_SPAWN_ROLE=manager · qualified leaf key · base = the CURRENT super tip", next: "monitor", nextStatus: "proposed" }, + { kind: "node", phase: "monitor", tool: "monitor + steer", detail: "turn reports · nudges · escalations · spirit test on deltas · a wrong deliverable REOPENS its leaf (task_reopen) — never a redo sibling", next: "master handover", nextStatus: "proposed" }, + { kind: "node", phase: "handover", tool: "decide master-handover-approval", detail: "the manager RAISED it (wait=false) with the verdict attached — the ORCHESTRATOR decides by the packet-carried gateId (own ambient identity; owner-never-self-approves holds; the policy may require the verdict)", rides: "master-handover-approval", ridesNote: "⊘ seam 1 of 2 — happy path through the orchestrator; a handover it cannot honestly decide escalates to the developer", next: "integrate master → super", nextStatus: "proposed" }, + { kind: "node", phase: "integrate", tool: "integrate master → super (C-11)", detail: "orchestrator WORKTREE with super as source · merge/carry-over · memory single-siding · ledger maps every commit", next: "↺ next ready master — until the DAG is drained", nextStatus: "proposed" }, + { kind: "divider", label: "↓ DAG drained — the super branch holds the accumulated change set ↓" }, + { kind: "node", phase: "seam 2", tool: "super-exit adversarial review", detail: "wholesale verdict on the super branch: completion vs tasks · quality · onboarding-vs-code", rides: "super-exit seam", ridesNote: "⊘ adversarial review seam 2 of 2 — before the orchestrator hands over to the developer", next: "developer handover", nextStatus: "proposed" }, + { kind: "node", phase: "handover", tool: "developer review — super level", detail: "the developer's SINGLE review point (integrations below are orchestrator-delegated): visible-behavior-first in a REVIEWABLE ENVIRONMENT (the dashboard) with demo notes (what changed visibly), code second · ⟁ rejected? → decompose feedback into fix leaves ↺ reactive dispatch", rides: "integration-approval", next: "super → main PR", nextStatus: "proposed" }, + { kind: "node", phase: "land", tool: "super → main PR + carry-over", detail: "remote merge · memory carried to main-memory · push (git-workflow.md tail)", next: "close + propose", nextStatus: "current" }, + { kind: "node", phase: "close", tool: "self-improvement report", detail: "did x/y/z · hit a/b/c · a,b solved on the spot · c PROPOSES this change — grounded in the accumulated backdrop", next: "lifecycle_end", nextStatus: "proposed" }, + { kind: "node", phase: "close", tool: "lifecycle_end", detail: "terminal — durable notes/reports remain the record" }, + ], +}; + +// --- manager (one per master) ------------------------------------------------------------------ + +const MANAGER: FlowModel = { + id: "manager", + label: "Manager", + title: "manager — one master, leaf loop → master-exit handover", + takeaway: + "Spawned by the orchestrator with a manager brief (its entire session start). Owns exactly one " + + "master: dispatches a fresh worker per leaf, reviews turn reports, decides DELEGATED leaf gates " + + "(plan · closeout — the owning agent never self-approves), owns the leaf lifecycle end-to-end " + + "(worktree_start → closeout → integrate → finalize), and REOPENS a leaf whose deliverable came " + + "out wrong. At master exit it spawns the reviewer, then RAISES master-handover-approval with " + + "the verdict attached — the ORCHESTRATOR decides it. In a flat run the orchestrator wears this " + + "hat. Escalation: to the orchestrator, never straight to the developer.", + segments: [ + { kind: "start", label: "▸ spawned by the orchestrator — manager-brief.md pasted + submitted (the brief is the session start)", next: "seat", nextStatus: "proposed" }, + { + kind: "rundown", + title: "seat · intake", + lines: [ + { line: "seat = own coordination leaf (task_doc, no enclosure) · chat attached — the dev can walk in any time" }, + { line: "read the master task_doc + leaf docs · order leaves (parallel where safe — C-11 reconcile absorbs a moved base)" }, + { line: "default behavior stands: fulfill the task, fill small blanks — no extra creative-liberty prompting either way" }, + { line: "⟁ plan delta beyond filling blanks? → escalate to the ORCHESTRATOR — managers don't reshape plans (no bird's-eye)", junction: true }, + { line: "score each leaf's loop tier at dispatch — direct · builder-verified · full loop (the strategist's blast-radius register is the input; all-direct = workflow-free manager)" }, + { line: "⟁ full-loop leaves: HARD cap 3 full rounds (delta-verifies don't count) · a non-shrinking round escalates NOW with the round history", junction: true }, + ], + }, + { kind: "divider", label: "↺ leaf dispatch loop — next leaf ↺" }, + { kind: "node", phase: "dispatch", tool: "spawn_agent_session (worker)", detail: "fresh session · worker-brief.md pasted + submitted · AR_SPAWN_ROLE=worker · the worker edits inside the worktrees the brief names", next: "monitor worker", nextStatus: "proposed" }, + { kind: "node", phase: "monitor", tool: "monitor worker", detail: "turn-report artifacts expected at every hand-off · inactivity or missing artifact → rate-limited stdin nudge · escalation intake via inbox", next: "review artifact", nextStatus: "proposed" }, + { kind: "node", phase: "review", tool: "review artifact vs task_doc", detail: "completion vs requirements/steps · checks green · onboarding same-pass · ⟁ wrong deliverable? → task_reopen the SAME leaf, reshape — never a redo sibling", next: "delegated gates", nextStatus: "proposed" }, + { kind: "node", phase: "gate", tool: "delegated leaf gates (plan · closeout)", detail: "decidedBy: manager lifecycle · decidedVia: orchestration · appended, dashboard-visible", rides: "delegated gate", ridesNote: "⊘ policy-configured delegation — the OWNING agent never self-approves; a distinct configured role may", next: "integrate leaf → master", nextStatus: "proposed" }, + { kind: "node", phase: "integrate", tool: "integrate leaf → master branch (C-11)", detail: "ff-only / replay per c-09 · a durable gate here is integration-approval — HUMAN-pinned · ↺ next leaf until done", next: "master-exit review", nextStatus: "current" }, + { kind: "divider", label: "↓ all leaves landed on the master integration branch ↓" }, + { kind: "node", phase: "seam 1", tool: "master-exit adversarial review", detail: "spawn reviewer (AR_SPAWN_ROLE=reviewer) · verdict: completion · quality · onboarding-vs-code · ⟁ blocked? → fix leaves ↺", rides: "master-exit seam", next: "handover to orchestrator", nextStatus: "proposed" }, + { kind: "node", phase: "handover", tool: "RAISE master-handover-approval (wait=false) + packet", detail: "gate raised without blocking (wait=false) with enclosure=\"\" — the exact address integration enforcement matches the gate by — and the verdict attached (evidenceRefs) · the returned gateId rides the packet via inbox + push · the ORCHESTRATOR decides the gate by that id", rides: "master-handover-approval", ridesNote: "⊘ delegable, never human-pinned — human review concentrates at the super gate", next: "seat stays reachable", nextStatus: "proposed" }, + { kind: "node", phase: "close", tool: "seat remains", detail: "chat + coordination leaf stay reachable until the series retires" }, + ], +}; + +// --- worker (one per leaf, short-lived) ---------------------------------------------------------- + +const WORKER: FlowModel = { + id: "worker", + label: "Worker", + title: "worker — one leaf, one session, one report", + takeaway: + "Self-contained and short-lived: the brief IS the session start (it replaces the front half the " + + "spawner already ran). The worker orients with paired reads, builds exactly the leaf plan with " + + "same-pass onboarding, gets the checks green, and ends at the MANDATORY turn report. It owns no " + + "lifecycle machinery — closeout, integration, finalization, and gates belong to the owning " + + "seat — and it never git-commits. A plan delta beyond blank-filling escalates one rung to the " + + "owning seat; the spirit test lives with the orchestrator, not here.", + segments: [ + { kind: "start", label: "▸ spawned on a leaf — worker-brief.md pasted + submitted (the brief is the session start)", next: "orient", nextStatus: "current" }, + { + kind: "rundown", + title: "the worker loop — roles/worker.md, self-contained", + lines: [ + { line: "intake — the brief + leaf task_doc + predecessor report; never a transcript" }, + { line: "orient — paired reads of the files you will touch (read_ar_files = official baseline; native reads in the worktree)" }, + { line: "build — exactly the leaf plan · same-pass c-05 onboarding · local build_route_indexes · NEVER git commit" }, + { line: "checks green — the brief-prescribed focused suite + full wrapper" }, + { line: "loop position: the BUILDER seat — fix rounds resume the SAME session; round-2+ reports APPEND (loop history stays legible)" }, + { line: "⟁ blocked, or a plan delta beyond blank-filling? → escalate ONE rung to the owning seat — never the developer", junction: true }, + ], + }, + { kind: "node", phase: "handover", tool: "turn-report artifact", detail: "MANDATORY templated report — what/issues/solved/left · evidence tally · respawn state · written even when blocked", next: "session ends", nextStatus: "current" }, + { kind: "node", phase: "close", tool: "session ends", detail: "terminal state = checks green + report; the owning seat runs closeout → integrate → finalize" }, + ], +}; + +// --- comms & escalation --------------------------------------------------------------------------- + +const COMMS: FlowModel = { + id: "comms", + label: "Comms", + title: "comms & escalation — channels, nudges, the ladder", + takeaway: + "Three channels compose: the inbox is the durable, dashboard-visible QUEUE; stdin push is the " + + "DELIVERY for AR-hosted sessions (no poll loops); turn-report artifacts are the REPORTING that " + + "survives compaction and session death. Nudges ride trustworthy inactivity signals (the reform " + + "series). Escalation ladders worker → manager → orchestrator → developer with no skipping, and " + + "the spirit test decides autonomy at every level. One handover-packet schema serves master " + + "handover, role takeover, and worker respawn.", + segments: [ + { + kind: "rundown", + title: "channels — inbox (queue) · stdin push (delivery) · artifacts (reporting) · chats (walk-in)", + lines: [ + { line: "inbox — operator_inbox generalized to agent→agent addressing; every message durable + dashboard-visible" }, + { line: "stdin push — echo-confirmed PTY injection delivers queued messages to hosted sessions (poll = fallback only)" }, + { line: "turn-report artifacts — templated, durable; the orchestrator's own reports are the most important in the system" }, + { line: "chats — every seat has a leaf-attached chat; the developer can walk into any conversation at any level" }, + ], + }, + { kind: "node", phase: "message", tool: "inbox post", detail: "sender writes the durable row (addressed by lifecycle/agent identity)", next: "push delivery", nextStatus: "proposed" }, + { kind: "node", phase: "message", tool: "stdin push delivery", detail: "serving injects the message (or a mail hint) into the target PTY · delivery status recorded", next: "target acts → artifact / response", nextStatus: "proposed" }, + { kind: "node", phase: "message", tool: "response / artifact", detail: "the reply is itself an inbox row or a turn-report artifact — never an untracked side channel", next: "(loop)", nextStatus: "proposed" }, + { kind: "divider", label: "— the nudge loop (needs trustworthy staleness — the attention/river reform series) —" }, + { + kind: "rundown", + title: "nudge policy", + lines: [ + { line: "inactivity (heartbeat-aware, provably-stopped) OR turn end without an artifact → manager stdin nudge" }, + { line: "nudges are rate-limited and logged as events — observable, never spammy" }, + ], + }, + { kind: "divider", label: "— the escalation ladder — no level skipped —" }, + { + kind: "rundown", + title: "escalation · worker → manager → orchestrator → developer", + lines: [ + { line: "each level resolves within its own view first; what reaches the developer is decided by the quo-vadis test" }, + { line: "workers/managers: fulfill the task, fill small blanks — plan deltas ESCALATE; no spirit judgment below the bird's-eye" }, + { line: "loops: HARD cap 3 full rounds (delta-verifies close rounds) · convergence rule — a round that does not shrink the finding set escalates NOW, with the full round history attached" }, + { line: "⟁ quo-vadis — a high-blast-radius TRUTH (answered wrong = big rewrites later) goes to the developer IMMEDIATELY; presentation-grade (2px vs 3px) never does", junction: true }, + { line: "⟁ spirit test — ORCHESTRATOR-ONLY: within the spirit of accepted plans → act + decision-log entry", junction: true }, + { line: "⟁ against the spirit → JOINT decision with the developer (the unanticipated-wrench case)", junction: true }, + ], + }, + { kind: "node", phase: "handover", tool: "handover packet (one schema)", detail: "master-complete handover · role takeover (profile-fit) · worker respawn — request, decisions, constraints, links, open questions", next: "receiver onboards from state, not transcript", nextStatus: "proposed" }, + ], +}; + +// --- designer (task design as its own job) -------------------------------------------------------- + +const DESIGNER: FlowModel = { + id: "designer", + label: "Designer", + title: "designer — the hat the orchestrator pulls", + takeaway: + "Task design is its own job, worn as a HAT: it cannot sit in a coordination leaf because the " + + "task is what it exists to create — the orchestrator runs roles/designer.md inline, at the " + + "front of the pipeline AND mid-flight, helping the developer think a master through — the tasks/AGENTS.md doctrine (meta-questioning, reframe before execution, " + + "evidence-first) given a distinct, optimized shape. It shares the orchestrator's bird's-eye " + + "toolkit (route indexes · onboarding · grepai · cgc · blast radius) but is SCOPED to one master — " + + "collisions with other or FUTURE masters can slip. That residual risk is owned downstream: at " + + "portfolio streamlining the ORCHESTRATOR doubles as the designer's adversarial reviewer.", + segments: [ + { kind: "start", label: "▸ developer intent, no task doc yet — the orchestrator pulls the designer hat (Job D)", next: "co-design loop", nextStatus: "current" }, + { + kind: "rundown", + title: "co-design loop · the tasks/AGENTS.md doctrine, as a job", + lines: [ + { line: "meta-question the ask — surface request · deeper objective · highest-leverage framing" }, + { line: "evidence-first — route indexes · onboarding · grepai · cgc; sub-agents write durable reports" }, + { line: "blast-radius analysis WITHIN the master's scope — routes touched · invariants · regressions" }, + { line: "⟁ assumptions / truth gaps only the developer can resolve → ask — never fill silently", junction: true }, + ], + }, + { kind: "node", phase: "reframe", tool: "reframe agreement", detail: "the developer agrees the frame before structure exists", rides: "reframe", ridesNote: "⊘ material scope/intent/sequencing changes are played back and WAIT for confirmation (tasks/AGENTS.md)", next: "task_doc authoring", nextStatus: "proposed" }, + { kind: "node", phase: "author", tool: "task_doc authoring", detail: "master + leaves · requirements · steps · code examples (w-02 shape) · leaves scoped around routes/areas", next: "declare the limits", nextStatus: "current" }, + { kind: "node", phase: "limits", tool: "designer limits note", detail: "master-scoped bird's-eye: cross-master and FUTURE-master collisions can slip — declared on the doc, never hidden", next: "handover → portfolio", nextStatus: "proposed" }, + { kind: "node", phase: "handover", tool: "join the portfolio", detail: "at streamlining the ORCHESTRATOR adversarially reviews the design — planned-vs-planned AND planned-vs-past", next: "(orchestrator · portfolio phase)", nextStatus: "proposed" }, + ], +}; + +// --- adversarial reviewer (the two seams) --------------------------------------------------------- + +const REVIEWER: FlowModel = { + id: "reviewer", + label: "Reviewer", + title: "adversarial reviewer — verdicts are evidence, not decisions", + takeaway: + "Spawned at exactly two seams: MASTER-EXIT (before a manager hands its integration branch to the " + + "orchestrator) and SUPER-EXIT (before the orchestrator hands the super branch to the developer). " + + "It reviews the accumulated change set through three lenses — completion vs task docs, code " + + "quality per tools.md, and onboarding-vs-code — fanning out sub-agents that write durable " + + "reports. Its verdict is a templated artifact that attaches to the handover gate as JUDGE " + + "evidence; the decider decides — the ORCHESTRATOR at master-exit (master-handover-approval), " + + "the DEVELOPER at super-exit. A blocking verdict must decompose into fix leaves — findings, " + + "never prose complaints. The same seat serves every three-party loop's review (leaf full-loop, " + + "portfolio plan review) with its type's criteria catalog — criteria are never made up on the spot.", + segments: [ + { kind: "start", label: "▸ spawned at a seam (AR_SPAWN_ROLE=reviewer) — master-exit or super-exit + change-set context", next: "intake", nextStatus: "proposed" }, + { kind: "node", phase: "intake", tool: "scope the review", detail: "integration branch diff · the master's/portfolio's task docs · the seam's rubric", next: "three-lens review", nextStatus: "proposed" }, + { + kind: "rundown", + title: "three-lens review — sub-agents fan out, reports are durable", + lines: [ + { line: "criteria catalogs bound per review type (criteria/: code-seam · doctrine · onboarding-memory · report-verification · plan-review) — standing floor + exploratory mandate + promotion ratchet" }, + { line: "completion — every requirement/step addressed vs the task docs; deltas justified in decision logs" }, + { line: "code quality — the resolved tools.md suite (lint · typecheck · tests · complexity); regressions vs the past" }, + { line: "onboarding-vs-code — changed files' sidecars updated in the same pass · drift clean · route overviews current" }, + { line: "⟁ refute-or-confirm posture — findings must survive an attempt to refute them", junction: true }, + { line: "loop-seat reuse: delta-verifies resume the SAME reviewer (they close rounds, never open them); fresh reviewer only for a full round" }, + ], + }, + { kind: "node", phase: "verdict", tool: "verdict artifact", detail: "templated · findings ranked · explicit pass/block recommendation · durable under the series notes", next: "attach as judge evidence", nextStatus: "proposed" }, + { kind: "node", phase: "seam", tool: "attach to the handover gate", detail: "JUDGE evidence on the gate record — the decider (per the gate delegation policy) decides; the reviewer never does", rides: "judge evidence", ridesNote: "⊘ verdicts are evidence, not decisions — requireReviewerVerdictAtSeams binds delegated seam decisions to the verdict", next: "pass or block", nextStatus: "proposed" }, + { kind: "node", phase: "outcome", tool: "⟁ block? → decomposable fix leaves", detail: "a blocking verdict names concrete, leaf-shaped findings the owning manager/orchestrator can dispatch — never prose-only", next: "session ends", nextStatus: "proposed" }, + { kind: "node", phase: "close", tool: "session ends", detail: "short-lived by design — the verdict artifact and sub-agent reports remain the record" }, + ], +}; + +export const FLOW_MODELS: FlowModel[] = [ROUTER, DESIGNER, STRATEGIST, ORCHESTRATOR, MANAGER, WORKER, REVIEWER, COMMS]; diff --git a/dashboard/src/panels/notes-reader/NotesReaderViewer.test.tsx b/dashboard/src/panels/notes-reader/NotesReaderViewer.test.tsx new file mode 100644 index 00000000..a39a0168 --- /dev/null +++ b/dashboard/src/panels/notes-reader/NotesReaderViewer.test.tsx @@ -0,0 +1,247 @@ +import { cleanup, fireEvent, render } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { CockpitShell } from "../../cockpit/Cockpit"; +import { dashboardStore } from "../../data/store"; +import type { NoteContent, NoteEntry } from "../../data/notes"; +import type { TaskDocNode, WorkspaceProjection } from "../../types/projection"; +import { NotesReaderViewer } from "./NotesReaderViewer"; + +// Mock the CodeMirror text leaf so a text note renders in jsdom without a live EditorView — the house +// pattern (ChangeSetViewer.test mocks ChangeSetPane; the File Viewer tests never open a file). This is +// the ONLY file-viewer leaf we stub; DualPane's own branching + the shared Markdown render for real. +vi.mock("../file-viewer/FilePane", () => ({ + FilePane: ({ content }: { content: string }) =>
    {content}
    , +})); + +const REPO = "agents-remember"; +const MASTER = "260703_agent-orchestration"; + +function entry(path: string, over: Partial = {}): NoteEntry { + return { name: path.split("/").pop() ?? path, path, size: 100, language: "markdown", ...over }; +} +function content(path: string, over: Partial = {}): NoteContent { + return { repo: REPO, master: MASTER, path, language: "markdown", size: 100, truncated: false, content: `# ${path}`, ...over }; +} + +// /api/notes/list → the seeded listing; /api/notes/read → the seeded per-path content (404 otherwise). +function stubNotesApi(notes: NoteEntry[], contents: Record = {}, truncated = false) { + vi.stubGlobal( + "fetch", + vi.fn(async (url: string) => { + const params = new URLSearchParams(url.split("?")[1] ?? ""); + if (url.startsWith("/api/notes/list")) { + const payload = { repo: params.get("repo"), master: params.get("master"), notes, truncated }; + return { ok: true, status: 200, json: async () => payload } as unknown as Response; + } + if (url.startsWith("/api/notes/read")) { + const body = contents[params.get("path") ?? ""]; + if (body) return { ok: true, status: 200, json: async () => body } as unknown as Response; + return { ok: false, status: 404, json: async () => ({ status: "not-found" }) } as unknown as Response; + } + // Unrelated cockpit fetches (e.g. the hidden File Viewer layer's repo catalog) — a `{repos:[]}` + // shape keeps that panel happy without a network hit. + return { ok: true, status: 200, json: async () => ({ repos: [] }) } as unknown as Response; + }), + ); +} + +afterEach(() => { + cleanup(); + vi.restoreAllMocks(); + vi.unstubAllGlobals(); +}); + +describe("NotesReaderViewer rail", () => { + it("lists the master's notes tree (reports/ included) with the open note highlighted", async () => { + stubNotesApi( + [entry("friction-ledger.md"), entry("reports/260703-L1-worker-report.md")], + { "friction-ledger.md": content("friction-ledger.md") }, + ); + const view = render( + , + ); + const first = await view.findByTestId("note-rail-1"); + expect(first.textContent).toContain("friction-ledger.md"); + // reports/ subfolder entries are listed, honestly showing their path. + expect(view.getByText("reports/260703-L1-worker-report.md")).toBeTruthy(); + // The open note is highlighted in the rail; the other row is not. + expect(first.getAttribute("data-active")).toBe("true"); + expect(view.getByTestId("note-rail-2").getAttribute("data-active")).toBe("false"); + }); + + it("moves the highlight to follow the open note when the selection changes", async () => { + stubNotesApi( + [entry("a.md"), entry("b.md")], + { "a.md": content("a.md"), "b.md": content("b.md") }, + ); + const view = render( + , + ); + await view.findByTestId("note-rail-1"); + expect(view.getByTestId("note-rail-1").getAttribute("data-active")).toBe("true"); + view.rerender( + , + ); + expect(view.getByTestId("note-rail-1").getAttribute("data-active")).toBe("false"); + expect(view.getByTestId("note-rail-2").getAttribute("data-active")).toBe("true"); + await view.findByTestId("sidecar-pane"); // flush the b.md content fetch + }); + + it("asks the parent to switch the open note when a rail row is clicked (switch in place)", async () => { + stubNotesApi([entry("a.md"), entry("b.md")], { "a.md": content("a.md") }); + const onSelectNote = vi.fn(); + const view = render( + , + ); + fireEvent.click(await view.findByTestId("note-rail-2")); + expect(onSelectNote).toHaveBeenCalledWith("b.md"); + }); +}); + +describe("NotesReaderViewer content pane (reuses the File Viewer DualPane)", () => { + it("renders an opened markdown note formatted (not raw) via the shared Markdown", async () => { + stubNotesApi([entry("friction-ledger.md")], { + "friction-ledger.md": content("friction-ledger.md", { content: "The **F-M** row." }), + }); + const view = render( + , + ); + await view.findByTestId("sidecar-pane"); + expect((await view.findByText("F-M")).tagName.toLowerCase()).toBe("strong"); // formatted, not raw + expect(view.queryByText("The **F-M** row.")).toBeNull(); + }); + + it("renders a non-markdown text note through the shared file pane (the text fallback)", async () => { + stubNotesApi([entry("trace.txt", { language: "text" })], { + "trace.txt": content("trace.txt", { language: "text", content: "line one\nline two" }), + }); + const view = render( + , + ); + expect((await view.findByTestId("file-pane")).textContent).toBe("line one\nline two"); + }); + + it("degrades a binary note to a byte-count placeholder instead of raw bytes", async () => { + stubNotesApi([entry("scan.png", { language: "text" })], { + "scan.png": content("scan.png", { language: "binary", size: 2048, content: "" }), + }); + const view = render( + , + ); + expect((await view.findByTestId("pane-placeholder")).textContent).toContain( + "Binary file — 2,048 bytes (not shown)", + ); + }); + + it("shows the 2-MiB truncation banner for a truncated markdown note (L18 finding 2)", async () => { + // Markdown is the dominant note type but takes DualPane's partnerless-markdown path, which has + // no banner (only CodeSide does) -- so without this a truncated markdown note would silently drop + // the "showing the first 2 MiB" contract. The banner renders here, above the rendered markdown. + stubNotesApi([entry("big.md")], { + "big.md": content("big.md", { truncated: true, size: 2_097_162, content: "# big\n\nlots" }), + }); + const view = render( + , + ); + const banner = await view.findByTestId("notes-trunc-banner"); + expect(banner.textContent).toContain("Showing the first 2 MiB of 2,097,162 bytes"); + // The markdown still renders (the banner is ABOVE the pane, not instead of it). + await view.findByTestId("sidecar-pane"); + }); + + it("shows no truncation banner for a normal (untruncated) markdown note", async () => { + stubNotesApi([entry("small.md")], { "small.md": content("small.md") }); + const view = render( + , + ); + await view.findByTestId("sidecar-pane"); + expect(view.queryByTestId("notes-trunc-banner")).toBeNull(); + }); + + it("calls onBack when the back control is clicked", async () => { + stubNotesApi([entry("a.md")], { "a.md": content("a.md") }); + const onBack = vi.fn(); + const view = render( + , + ); + fireEvent.click(await view.findByTestId("notes-reader-back")); + expect(onBack).toHaveBeenCalledTimes(1); + }); +}); + +// A minimal projection carrying one selectable master task document so the cockpit sidebar has a row. +function masterDoc(): TaskDocNode { + return { + id: "task", + lifecycleId: undefined, + repository: REPO, + title: "Agent Orchestration", + status: "inProgress", + kind: "master", + docPath: `/tasks/${REPO}/${MASTER}/task.json`, + createdAt: "2026-07-07T09:00:00+00:00", + stepsDone: 0, + stepsTotal: 0, + steps: [], + objective: "Master objective.", + requirements: [], + codeExamples: [], + decisions: [], + openQuestions: [], + references: [], + subTasks: [], + sections: [], + } as unknown as TaskDocNode; +} +function seedMaster() { + const projection = { + version: 2, + generatedAt: "2026-07-07T09:01:00+00:00", + lifecycles: [], + enclosures: [], + providers: [], + activeWorktreeGroups: [], + metrics: { lifecycleCount: 0, runningCount: 0, blockedCount: 0, pausedCount: 0, totalTokens: 0, stalenessHistogram: {} }, + analytics: { + driftSnapshots: [], stalestSidecars: [], setupSummaries: [], setupProgress: [], routeCoverage: [], + toolReports: [], ledgers: [], taskDocuments: [masterDoc()], series: [], attentionQueue: [], engineProcesses: [], + }, + } as unknown as WorkspaceProjection; + dashboardStore.getState().applySnapshot(projection); +} + +describe("Cockpit notes reader takeover", () => { + it("does not show the notes reader initially and keeps the Operations rails", () => { + stubNotesApi([entry("a.md")]); + seedMaster(); + const { container } = render(); + expect(container.querySelector('[data-testid="notes-reader-viewer"]')).toBeNull(); + expect(container.querySelector(".rail--left")).not.toBeNull(); + expect(container.querySelector(".shell__body")?.getAttribute("data-fullbleed")).toBe("false"); + }); + + it("opens the reader from the notes list and keeps it MOUNTED across back (state survives back/forward, like the File Viewer)", async () => { + stubNotesApi([entry("a.md"), entry("b.md")], { "a.md": content("a.md"), "b.md": content("b.md") }); + seedMaster(); + const view = render(); + + // Select the master in the sidebar, then open a note from its compact Series-notes list. + fireEvent.click(view.getByText("Agent Orchestration")); + fireEvent.click(await view.findByTestId("note-open-1")); + + // The takeover shows the notes reader; the railed body is hidden (not unmounted). + const reader = await view.findByTestId("notes-reader-viewer"); + const railedBody = reader.closest(".shell__body")!.parentElement!.querySelector('[aria-hidden="true"].shell__body'); + expect(railedBody).not.toBeNull(); + + // Back hides the takeover but does NOT unmount it — the SAME node persists (its listing/selection + // survive), exactly like the File Viewer's hidden-not-unmounted layer. + fireEvent.click(view.getByTestId("notes-reader-back")); + expect(view.getByTestId("notes-reader-viewer")).toBe(reader); + + // Re-opening surfaces the SAME mounted reader instance (never a fresh remount). + fireEvent.click(await view.findByTestId("note-open-1")); + expect(view.getByTestId("notes-reader-viewer")).toBe(reader); + }); +}); diff --git a/dashboard/src/panels/notes-reader/NotesReaderViewer.tsx b/dashboard/src/panels/notes-reader/NotesReaderViewer.tsx new file mode 100644 index 00000000..c829e5ff --- /dev/null +++ b/dashboard/src/panels/notes-reader/NotesReaderViewer.tsx @@ -0,0 +1,238 @@ +// The Notes Reader screen (L17): the L9 coordination-notes reading experience rebuilt on the SAME +// full-view pattern the Change-Set / File Viewer use — a task-scoped takeover whose LEFT RAIL is the +// master's notes tree (from /api/notes/list, reports/ included) with the open note highlighted, and +// whose content pane renders the opened note by REUSING the File Viewer's `DualPane` primitive: +// - a markdown note takes DualPane's partnerless-markdown path (code=null, sidecar=markdown) — the +// exact path the File Viewer uses to render a partnerless route overview full-pane; +// - a text note takes DualPane's CodeSide (read-only CodeMirror), same as any code file; +// - a binary note degrades to DualPane's byte-count placeholder. +// There is no second bespoke reader: the layout is the ChangeSetViewer rail+pane+back idiom and the +// content is `DualPane`. The view is CONTROLLED — the open `path` and rail `onSelectNote` are lifted +// to CockpitShell (like the File Viewer's persisted state) so selection survives back/forward. +import { useEffect, useState } from "react"; +import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; + +import { css } from "../../../styled-system/css"; +import type { FileContent } from "../../data/files"; +import { listNotes, readNote, type NoteContent, type NotesListing } from "../../data/notes"; +import { DualPane, type SidecarView } from "../file-viewer/DualPane"; + +// The target a notes entry point opens: a note file inside a master's notes/ tree. Shared with the +// entry surfaces (TaskNotes) and CockpitShell, which holds it as the takeover's lifted selection. +export interface NotesReaderTarget { + repo: string; + master: string; + path: string; // posix path relative to the series' notes/ root (e.g. "reports/…-report.md") +} + +// Screen chrome — the ChangeSetViewer takeover idiom (flex column · sticky back header · rail+pane). +const screen = css({ height: "100%", minHeight: "0", display: "flex", flexDirection: "column", background: "bg" }); +const header = css({ + flexShrink: 0, + display: "flex", + alignItems: "center", + gap: "0.8rem", + paddingInline: "0.8rem", + paddingBlock: "0.4rem", + borderBottomWidth: "1px", + borderBottomStyle: "solid", + borderBottomColor: "grid", + background: "bgPanel", +}); +const back = css({ + fontFamily: "mono", + fontSize: "0.74rem", + color: "amber", + background: "transparent", + borderWidth: "1px", + borderStyle: "solid", + borderColor: "grid", + borderRadius: "2px", + paddingInline: "0.5rem", + paddingBlock: "0.15rem", + cursor: "pointer", + _hover: { borderColor: "amber" }, +}); +const title = css({ fontSize: "0.82rem", color: "ink", fontWeight: "600" }); +const openPath = css({ marginLeft: "auto", fontSize: "0.74rem", fontFamily: "mono", color: "cyan", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: "50%" }); +// Rail — the ChangeSetViewer changed-files column idiom (sticky section head + amber-wash active row). +const railCol = css({ height: "100%", minHeight: "0", display: "flex", flexDirection: "column", background: "bgPanel" }); +const railScroll = css({ flex: "1", minHeight: "0", overflow: "auto" }); +const railHead = css({ + position: "sticky", + top: "0", + background: "bg", + paddingInline: "0.6rem", + paddingBlock: "0.25rem", + fontSize: "0.68rem", + letterSpacing: "0.05em", + textTransform: "uppercase", + color: "amber", + borderBottomWidth: "1px", + borderBottomStyle: "solid", + borderBottomColor: "grid", +}); +const railRow = css({ + display: "flex", + alignItems: "center", + gap: "0.4rem", + width: "100%", + textAlign: "left", + font: "inherit", + fontSize: "0.74rem", + fontFamily: "mono", + color: "ink", + background: "transparent", + border: "0", + paddingInline: "0.6rem", + paddingBlock: "0.2rem", + cursor: "pointer", + _hover: { background: "color-mix(in oklab, var(--amber) 12%, transparent)", color: "amber" }, + "&[data-active=true]": { background: "color-mix(in oklab, var(--amber) 20%, transparent)", color: "cyan" }, +}); +const railPath = css({ flex: "1", minWidth: "0", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }); +const railSize = css({ flexShrink: 0, color: "muted", fontSize: "0.68rem" }); +const railHint = css({ paddingInline: "0.6rem", paddingBlock: "0.25rem", color: "muted", fontSize: "0.68rem" }); +const handle = css({ width: "3px", flexShrink: "0", background: "grid", cursor: "col-resize", _hover: { background: "amber" } }); +const placeholder = css({ height: "100%", display: "grid", placeItems: "center", padding: "1rem", color: "muted", fontSize: "0.8rem", textAlign: "center" }); +// Content-pane fill + the truncation banner (mirrors DualPane's own `fill`/`banner`): a truncated +// MARKDOWN note takes DualPane's partnerless-markdown path, which has no banner (only CodeSide does), +// so a >2-MiB markdown note -- the dominant note type -- would silently drop its "showing the first +// 2 MiB" contract. We render the same banner here, above the pane, for that case (L18 finding 2). +const paneFill = css({ height: "100%", minHeight: "0", display: "flex", flexDirection: "column" }); +const paneBody = css({ flex: "1", minHeight: "0" }); +const truncBanner = css({ + flexShrink: 0, + paddingInline: "0.6rem", + paddingBlock: "0.2rem", + fontSize: "0.72rem", + color: "amber", + background: "bgPanel", + borderBottomWidth: "1px", + borderBottomStyle: "solid", + borderBottomColor: "grid", +}); + +// A fetched note mapped to DualPane's props: markdown renders full-pane as a partnerless markdown doc +// (the File Viewer's overview treatment); other text / binary render through CodeSide. +function noteAsFileContent(note: NoteContent): FileContent { + // CodeSide reads only language/size/truncated/content; scope/onboarding are inert for a note. + return { + scope: "", + path: note.path, + language: note.language, + size: note.size, + truncated: note.truncated, + content: note.content, + onboarding: { status: "missing" }, + }; +} + +function dualPaneProps(note: NoteContent): { code: FileContent | null; sidecar: SidecarView } { + return note.language === "markdown" + ? { code: null, sidecar: { state: "markdown", body: note.content } } + : { code: noteAsFileContent(note), sidecar: { state: "empty" } }; +} + +export function NotesReaderViewer({ + repo, + master, + path, + onSelectNote, + onBack, +}: NotesReaderTarget & { onSelectNote: (path: string) => void; onBack: () => void }) { + const [listing, setListing] = useState(null); + const [note, setNote] = useState(null); + const [failed, setFailed] = useState(false); + + // The rail listing: fetched per (repo, master). An unreachable API leaves an empty rail rather than + // crashing — the entry point already proved a note exists, so this only guards a transient failure. + useEffect(() => { + let live = true; + setListing(null); + void listNotes(repo, master).then( + (data) => live && setListing(data), + () => {}, + ); + return () => { + live = false; + }; + }, [repo, master]); + + // The opened note: re-fetched whenever the lifted `path` changes (rail click or a fresh entry) — the + // "switch the pane in place" path. null = loading; `failed` = the read errored. + useEffect(() => { + let live = true; + setNote(null); + setFailed(false); + void readNote(repo, master, path).then( + (data) => live && setNote(data), + () => live && setFailed(true), + ); + return () => { + live = false; + }; + }, [repo, master, path]); + + const notes = listing?.notes ?? []; + + return ( +
    +
    + + notes · {master} + notes/{path} +
    + + +
    +
    +
    notes ({notes.length})
    + {notes.map((entry, index) => ( + + ))} + {listing?.truncated ? ( +
    deeper subfolders exist but are beyond the list cap
    + ) : null} +
    +
    +
    + + + {failed ? ( +
    + Could not load this note. +
    + ) : note === null ? ( +
    + Loading… +
    + ) : ( +
    + {note.truncated && note.language === "markdown" ? ( +
    + Showing the first 2 MiB of {note.size.toLocaleString()} bytes +
    + ) : null} +
    + +
    +
    + )} +
    +
    +
    + ); +} diff --git a/dashboard/src/styles/tokens.css b/dashboard/src/styles/tokens.css index 26c30a5b..45a4f221 100644 --- a/dashboard/src/styles/tokens.css +++ b/dashboard/src/styles/tokens.css @@ -16,6 +16,14 @@ --mint: oklch(0.88 0.16 165); /* fresh-online / live */ --dormant: oklch(0.45 0.06 25); /* skeletal dark-red dormant */ + /* Rank-insignia tiers (L14): gold = orchestration seat, purple = management. */ + --gold: oklch(0.87 0.15 95); + --gold-dim: oklch(0.55 0.09 95); + --gold-ghost: oklch(0.32 0.05 95); + --purple: oklch(0.76 0.14 305); + --purple-dim: oklch(0.5 0.09 305); + --purple-ghost: oklch(0.3 0.05 305); + --font-mono: ui-monospace, "JetBrains Mono", "SFMono-Regular", Menlo, monospace; --glow-strength: 1; } diff --git a/dashboard/src/topology/model.test.ts b/dashboard/src/topology/model.test.ts index 7a3fbfc8..5d9e8279 100644 --- a/dashboard/src/topology/model.test.ts +++ b/dashboard/src/topology/model.test.ts @@ -17,6 +17,8 @@ const enclosure = (overrides: Partial = {}): EnclosureNode => ({ closeoutStatus: "not-started", integrationStatus: "not-started", cleanup: "pending", + codeWorktreeExists: true, + memoryWorktreeExists: true, actions: [], ...overrides, }); diff --git a/dashboard/src/types/projection.ts b/dashboard/src/types/projection.ts index 624115d8..76a615c1 100644 --- a/dashboard/src/types/projection.ts +++ b/dashboard/src/types/projection.ts @@ -70,6 +70,11 @@ export interface EnclosureNode { closeoutStatus: string; integrationStatus: string; cleanup: string; + // Worktree-existence truth (L11): stat'ed server-side at snapshot time (never inferred from + // cleanup state). The tasks surface renders a leaf ONLY while a worktree physically exists — + // cleanup=reopened means contract-reset-awaiting-restart, not live work. + codeWorktreeExists: boolean; + memoryWorktreeExists: boolean; actions: ActionAvailability[]; } @@ -238,6 +243,9 @@ export interface TaskDocNode { subTasks: TaskSubTaskRefNode[]; // master-only; empty for light/subTask sections: TaskSectionNode[]; // master render plan or non-master freeform sections masterLifecycleId?: string; // parent master's lifecycle (cross-series) → "↑ parent series" breadcrumb + // The orchestration-command relation (L14): non-empty only on a master doc that IS an orchestration + // task — the master task names it commands. Optional so projections persisted before L14 still parse. + orchestrates?: string[]; } export interface SeriesNode { @@ -278,7 +286,14 @@ export interface AgentPickupNode { entryId: string; lifecycleId?: string; agentId?: string; + senderAgentId?: string; + senderRole?: string; + recipientRole?: string; gateId?: string; + messageKind: string; + artifactPath?: string; + deliveryState: "queued" | "no-hosted-session" | "delivered" | "unconfirmed" | string; + deliveredToSession?: string; state: "waiting-for-agent" | "check-chat" | string; ageSeconds?: number; ttlSeconds: number; @@ -407,6 +422,16 @@ export interface Analytics { engineProcesses: EngineProcessNode[]; // derived surface — the Engine Room process map (slice 5e) } +// The boot-time serving stamp (260703-L15, serving/build_info.py): which build/process is +// answering. Injected app-side onto /api/state and the SSE snapshot (NOT reducer truth, so it +// is optional here and absent from persisted latest-state.json). `commit` is best-effort — +// omitted when the server runs off-checkout (an installed wheel). +export interface ServingBuild { + version: string; + bootedAt: string; + commit?: string; +} + export interface WorkspaceProjection { version: number; generatedAt: string; @@ -420,4 +445,5 @@ export interface WorkspaceProjection { activeWorktreeGroups: string[]; metrics: Metrics; analytics: Analytics; + servingBuild?: ServingBuild; // app-injected on the wire only — see ServingBuild } diff --git a/docs/FAQ.md b/docs/FAQ.md index 31804900..f30b8c23 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -15,7 +15,7 @@ The core rules are: 3. implementation waits for developer approval 4. onboarding records approved current state, not plans -Read-only answers, chat builds, and durable `w-02-light-task-workflow` tasks are different weights of the same discipline. +Research-only answers, minimal `w-02-light-task-workflow` tasks, and master + light sub-task series are different weights of the same discipline. ### How does an agent find the right memory? @@ -69,15 +69,15 @@ Repo-wide context belongs in `overview.md`. Larger repos can use route-local ove ### Do I need a durable task? -Often no. A chat build is the default for changes that fit in one session. +Yes, but it can be thin. Chat is never a build route: every code change lives under an approved task document, and a change that fits in one session takes the minimal `w-02-light-task-workflow` artifact — a thin doc with a title and a few steps. -Use a `w-02-light-task-workflow` light task when the work needs a durable task file or checklist. When it outgrows a single-page plan — broad, high-risk, or many distinct slices — escalate to a master + light sub-task series. +Use a full `w-02-light-task-workflow` light task when the work needs a durable task file or checklist. When it outgrows a single-page plan — broad, high-risk, or many distinct slices — escalate to a master + light sub-task series. ### Is this overengineered? The memory layer is intentionally small: Markdown files, Git metadata, and deterministic paths. The workflow layer can be heavier, but it is optional and should match task risk. -If a change fits in one session, use a chat build. If it needs a durable plan, use a `w-02-light-task-workflow` light task. If it outgrows one page or spans several slices, use a master + light sub-task series. +If a change fits in one session, use a minimal `w-02-light-task-workflow` task. If it needs a durable plan, use a full `w-02-light-task-workflow` light task. If it outgrows one page or spans several slices, use a master + light sub-task series. ### What happens when the agent discovers something during implementation? diff --git a/docs/README.md b/docs/README.md index 1242c01f..9637fa33 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,7 +26,7 @@ The default setup stores durable memory in the target repository under `ar-memor - [Features](features.md) - the concentrated product tour: by-path memory, drift, providers, worktrees, harness setup, and operational guardrails. - [Concepts](concepts.md) - the memory model and the terms used throughout the project. - [Architecture](architecture.md) - how the source checkout, installed runtime, coordination root, and memory roots fit together. -- [Workflows](workflows.md) - the `l-01-session-job-lifecycle` lifecycle, its build modes, and worktrees. +- [Workflows](workflows.md) - the `l-01-agent-lifecycles` skill (the role router and the orchestrator lifecycle), its build modes, and worktrees. - [Benchmark Methodology](benchmarks-methodology.md) - paired benchmark runs, metrics, validity checks, and limitations. - [FAQ](FAQ.md) - design principles, objections, and comparisons. @@ -56,6 +56,7 @@ The default setup stores durable memory in the target repository under `ar-memor - [MCP Tool Reference](reference/mcp-tools.md) - [Runtime Layout](reference/runtime-layout.md) - [settings.json](reference/settings-json.md) +- [Harnesses & Spawn Knobs](reference/harnesses.md) - [Path Rules](reference/path-rules.md) - [Skills](reference/skills.md) - [c-08-ar-coordination-context-resolver Resolver](reference/resolver-c08.md) diff --git a/docs/concepts.md b/docs/concepts.md index 6d8cd1d0..3aa5cfbd 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -102,7 +102,6 @@ Onboarding records approved current state. It does not record speculation. That means: -- chat builds wait for developer approval before implementation - `w-02-light-task-workflow` tasks wait for task approval before implementation - a master + light sub-task series gates each slice's approval and commit in turn - onboarding updates happen after approved changes, not before diff --git a/docs/features.md b/docs/features.md index 2517234d..f865dbd8 100644 --- a/docs/features.md +++ b/docs/features.md @@ -293,11 +293,13 @@ worktree and thrown away with it. ## How it works in a session: judgment up front, determinism underneath Memory is only as good as the discipline that keeps it honest, and that -discipline is the second half of the product. Every session runs through one -lifecycle: +discipline is the second half of the product. Sessions route by role through +one skill (`l-01-agent-lifecycles`): a spawned agent follows the role brief +that spawned it, and a developer-facing session is the **orchestrator**, whose +lifecycle runs ```text -request → trust → reframe & research → decide → build → close +request → trust-checkpoint → reframe-research → decide → build → close ``` Before any code changes, the agent resolves context, checks drift and provider @@ -305,10 +307,11 @@ state, reframes the request into the best version of the task, gathers evidence, and waits for the developer to agree on that framing. Only then does it decide *how* to build: -- a **read-only** answer that changes no code, -- a **chat build** carried inline this session, or -- a **durable task** with its own plan, checklist, and decision log when the work - warrants it. +- a **research-only** answer that changes no code, or +- a **durable task** with its own plan, checklist, and decision log — chat is + never a build route, so even small code work takes the minimal + `w-02-light-task-workflow` artifact, and larger work escalates to a master + + light sub-task series. Two principles run through the whole arc. The first is **evidence-first reasoning**: for anything where correctness depends on interpretation, the agent @@ -465,7 +468,7 @@ what your team already knows. providers. - [External Memory](guides/use-external-memory.md) — separate memory repos and the ledger. -- [Workflows](workflows.md) — the session lifecycle and its build modes. +- [Workflows](workflows.md) — the agent lifecycles and their build modes. - [Install Guides](install/README.md) — harness-native starter packages. - [Settings Reference](reference/settings-json.md) — MCP authority settings. - [Getting Started](getting-started.md) — set it up in your own workspace. diff --git a/docs/getting-started.md b/docs/getting-started.md index 33e3fbbe..dec6b5da 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -190,7 +190,7 @@ Providers are optional — memory, onboarding, drift, and task workflows all wor ## Start Working -Normal tasks run through the `l-01-session-job-lifecycle` session job lifecycle (orient → ground → frame → decide → build → close). The agent should: +Sessions route by role through the `l-01-agent-lifecycles` skill: a developer-facing session is the **orchestrator** and runs the orchestrator lifecycle (request → trust-checkpoint → reframe-research → decide → build → close); a spawned agent follows the role brief that spawned it. For normal tasks the agent should: 1. resolve the repository context with `c-08-ar-coordination-context-resolver` 2. run `c-02-memory-quality-control` before planning against onboarding diff --git a/docs/install/claude-code.md b/docs/install/claude-code.md index 306ce999..7a81e387 100644 --- a/docs/install/claude-code.md +++ b/docs/install/claude-code.md @@ -67,12 +67,25 @@ The starter package includes `.claude/hooks/agents-remember-session-start.md` with the directive text: ```markdown -MANDATORY FIRST ACTION for this workspace - -You are not allowed to read, write, or execute code on any repository -until you read `ar-coordination/AGENTS.md` and started its `l-01` procedure! +**Agents Remember — session start.** + +If `AR_SPAWN_ROLE` is set, or your first user message is a role brief from an +orchestrating agent: **ignore this notice entirely — your brief is your session +start.** + +Otherwise you are the developer-facing session, i.e. the **orchestrator**: read +`ar-coordination/AGENTS.md`, then run your lifecycle at +`skills/l-01-agent-lifecycles/roles/orchestrator.md` — trust checkpoint before +relying on memory, `read_ar_files` (paired source+onboarding) until the build +decision, retrieval-strategy tally as evidence, notify-and-stop at every +developer hand-off. ``` +The directive is orchestrator-exclusive by design: a spawned role's session +start is the role brief its orchestrating agent compiled, so the hook tells +spawned sessions to ignore it in one sentence and addresses only the +developer-facing session. + The starter package registers the hook in `.claude/settings.json`: ```json diff --git a/docs/llms.txt b/docs/llms.txt index 40d1e3c0..13a1bbec 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -295,11 +295,13 @@ worktree and thrown away with it. ## How it works in a session: judgment up front, determinism underneath Memory is only as good as the discipline that keeps it honest, and that -discipline is the second half of the product. Every session runs through one -lifecycle: +discipline is the second half of the product. Sessions route by role through +one skill (`l-01-agent-lifecycles`): a spawned agent follows the role brief +that spawned it, and a developer-facing session is the **orchestrator**, whose +lifecycle runs ```text -request → trust → reframe & research → decide → build → close +request → trust-checkpoint → reframe-research → decide → build → close ``` Before any code changes, the agent resolves context, checks drift and provider @@ -307,10 +309,11 @@ state, reframes the request into the best version of the task, gathers evidence, and waits for the developer to agree on that framing. Only then does it decide *how* to build: -- a **read-only** answer that changes no code, -- a **chat build** carried inline this session, or -- a **durable task** with its own plan, checklist, and decision log when the work - warrants it. +- a **research-only** answer that changes no code, or +- a **durable task** with its own plan, checklist, and decision log — chat is + never a build route, so even small code work takes the minimal + `w-02-light-task-workflow` artifact, and larger work escalates to a master + + light sub-task series. Two principles run through the whole arc. The first is **evidence-first reasoning**: for anything where correctness depends on interpretation, the agent @@ -467,7 +470,7 @@ what your team already knows. providers. - [External Memory](guides/use-external-memory.md) — separate memory repos and the ledger. -- [Workflows](workflows.md) — the session lifecycle and its build modes. +- [Workflows](workflows.md) — the agent lifecycles and their build modes. - [Install Guides](install/README.md) — harness-native starter packages. - [Settings Reference](reference/settings-json.md) — MCP authority settings. - [Getting Started](getting-started.md) — set it up in your own workspace. diff --git a/docs/reference/README.md b/docs/reference/README.md index 3254c7ee..5e97870b 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -5,6 +5,7 @@ Use these pages when you need exact file layout, settings, or skill behavior. - [MCP Tools](mcp-tools.md) - [Runtime Layout](runtime-layout.md) - [settings.json](settings-json.md) +- [Harnesses & Spawn Knobs](harnesses.md) - [Path Rules](path-rules.md) - [Skills](skills.md) - [c-08-ar-coordination-context-resolver Resolver](resolver-c08.md) diff --git a/docs/reference/harnesses.md b/docs/reference/harnesses.md new file mode 100644 index 00000000..b491ade6 --- /dev/null +++ b/docs/reference/harnesses.md @@ -0,0 +1,231 @@ +# Harnesses & Spawn Knobs Reference + +The single manual for the spawn surface (260703-L16): what a harness is to +Agents Remember, every role-knob parameter and its delivery vehicle, the +per-harness vocabularies as built, detection and refusal behavior, and a +worked example that teaches the system a brand-new harness through settings. + +Related references: `settings-json.md` (the settings families and merge +rules), `skills/l-01-agent-lifecycles` (the role doctrine the knobs +parameterize). + +## What A Harness Is + +A **harness** is a TUI coding agent the framework can spawn into a hosted +tmux session — via the dashboard's launch buttons or the agent-facing +`spawn_agent_session` MCP tool (one shared opener; no parallel spawn path). +Each harness is described by an entry with: + +| Field | Meaning | +| --- | --- | +| `id` | The stable identifier callers use (`harness="claude"`). Never a command. | +| `name` | Display name (dashboard buttons). | +| `command` | The executable probed on `PATH` for detection. | +| `argv` | The exact launch command array, e.g. `["claude"]`. Fixed server-side. | +| `modelFlag` | The launch flag the model knob maps onto (`--model `), if any. | +| `effortFlag` + `effortFlagValues` | The launch flag the effort knob maps onto, and the values that flag ACCEPTS. Declared together. | +| `effortSessionValues` + `effortSessionCommand` | Effort values the launch flag rejects but the RUNNING session accepts as a command; the command template (`{value}` placeholder) that delivers them post-launch. Declared together. | + +### Built-in registry (good defaults, not a wall) + +The curated defaults live in `mcp/src/agents_remember/serving/harnesses.py`: + +| id | argv | modelFlag | effortFlag (values) | session effort (command) | +| --- | --- | --- | --- | --- | +| `claude` (Claude Code) | `["claude"]` | `--model` | `--effort` (`low`, `medium`, `high`, `xhigh`, `max`) | `ultracode` → `/effort ultracode` | +| `codex` (Codex) | `["codex"]` | — (env-only) | — (env-only) | — | +| `pi` (Pi.dev) | `["pi"]` | — (env-only) | — (env-only) | — | + +**Env-only** means: the model/effort knobs still ride the spawn env as +`AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT` (session-start visibility), but nothing is +put on the command line and no effort vocabulary is enforced. Growing a +mapping for a builtin is a one-line registry edit — or a settings override, +below. + +### Extending or overriding via settings (`orchestration.harnesses`) + +The registry is **good defaults, never a rigid wall** (developer ruling +2026-07-07). The `orchestration.harnesses` settings family — global +`/system/settings.json`, repo-local +`/system/settings.json`, standard L13 merge and fail-loud rules — +merges over the registry **by id**: + +- A **new id ADDS a harness** the framework never enumerated. It must declare + `command` and/or `argv` (`command` defaults to `argv[0]`; `argv` defaults to + `[command]`). +- An **existing id OVERRIDES the defaults per field**: its `argv` array + REPLACES ours — launch the harness exactly the way you would run it + yourself (our curated knob mapping survives unless you override it too). +- Detection still applies: the `command` is probed on `PATH` at dispatch; an + undetected harness refuses with `harness-not-detected`. +- Vocabulary fields come in delivery-vehicle pairs and must resolve together: + `effortFlag` with `effortFlagValues`, `effortSessionValues` with + `effortSessionCommand`. A flag without a vocabulary would reintroduce the + silent-degrade risk, so the loader refuses it. +- The `effortSessionCommand` **template** must render with `{value}` and + reference no other placeholder: a stray field (`/set {mode}={value}`), a + positional `{}`, or an unmatched brace is refused by the loader naming the + harness. The check runs post-merge (a builtin override may supply just the + command), so a bad template surfaces the same structured refusal every other + bad knob gets instead of crashing the spawn with a raw `str.format` error. + +An id known neither in the registry nor in settings refuses **loudly** at +dispatch, naming the known set and pointing here — never a crash. + +## The Role Knobs, Parameter By Parameter + +Role knobs live in `orchestration.roles.` (flat defaults) and +`orchestration.rolesPerLevel..` (per-level overrides); a spawning +seat may also pass any of them explicitly to `spawn_agent_session`. Three +layers with distinct validation postures: + +### Layer 1 — validated enum knobs + +| Knob | Delivery vehicle | Validation | +| --- | --- | --- | +| `harness` | Selects the harness entry (argv comes from it). | Must be a known id: builtin or `orchestration.harnesses`-defined. Checked at settings load AND at dispatch. | +| `model` | The harness's `modelFlag` on the launch argv, e.g. `--model opus`; also rides env as `AR_SPAWN_MODEL`. | Model names are NOT enum-validated (they evolve faster than any registry). A settings-defined harness with no `modelFlag` refuses the knob with guidance (`model-invalid`). | +| `effort` | Per value: a flag value rides the harness's `effortFlag` on the argv; a session value rides a post-launch session command; either way it rides env as `AR_SPAWN_EFFORT`. | Validated at DISPATCH against the harness's vocabulary (flag values ∪ session values). Unknown values refuse (`effort-invalid`) naming the harness and BOTH sets. Mapping-less builtins (codex, pi) accept anything env-only; a mapping-less settings-defined harness refuses with guidance. | + +Why dispatch-time effort validation exists: the installed claude CLI accepts +`--effort low|medium|high|xhigh|max` and **warns-then-silently-degrades** on +anything else (probed 2026-07-07 with `ultracode`). Without the refusal, an +out-of-vocabulary value would quietly downgrade the most reasoning-hungry +seats. The two-vehicle split exists because claude's interactive `/effort` +command accepts `ultracode` ("xhigh + workflows") while the launch flag +rejects it — one harness, two vocabularies, each value carrying its own +delivery vehicle. + +### Layer 2 — launch free-form: `launchArgs` + +A list of strings appended VERBATIM to the harness launch argv, after the +mapped knob flags. Never validated (it is the escape hatch for flags we never +enumerated); recorded in spawn provenance (the session catalog row and the +tool payload). Example: `["--dangerously-skip-permissions"]`. + +### Layer 3 — session free-form: `sessionCommands` and `promptKeywords` + +- `sessionCommands`: a list of lines, each pasted into the freshly spawned + session as its OWN echo-confirmed paste and submitted, BEFORE the dispatch + brief — the vehicle for any session-level harness feature (a + session-vocabulary effort like claude's `ultracode` is delivered this way + automatically, ahead of your own session commands). Never validated; + recorded in spawn provenance. +- `promptKeywords`: a list of keywords prepended as the first line of the + dispatch-brief paste (session modes the model interprets, e.g. a prompt + keyword like `ultracode`). Never validated; recorded in spawn provenance. + +Delivery order at spawn: **launch argv → session commands (effort vehicle +first, then yours) → the brief paste (keywords first)**. + +### The dispatch level: `level` and `orchestration.rolesPerLevel` + +The L12 doctrine runs each level with its own agent set; `rolesPerLevel` +makes that expressible (ruling 2026-07-07T08:15): + +```jsonc +"orchestration": { + "roles": { // flat DEFAULTS (existing files unchanged) + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" } + }, + "rolesPerLevel": { // per-level overrides; vocabulary = leaf|master|portfolio + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + } +} +``` + +`spawn_agent_session(level=...)` declares the dispatch level (`leaf` | +`master` | `portfolio`, default `leaf`); the dispatcher knows its level — a +manager dispatching leaf seats passes `leaf`, the master-seam reviewer +`master`, portfolio/end-to-end seats `portfolio`. The level override +deep-merges over the flat default at leaf-key granularity (unset fields +inherit; lists replace). Full resolution chain: + +**explicit args > repo-local level override > global level override > +repo-local role default > global role default > spawn preference/detection.** + +The resolution walk for the reviewer economics above (role riding the spawn +env as `AR_SPAWN_ROLE=reviewer`): + +| Dispatch | harness | model | effort | effort vehicle | +| --- | --- | --- | --- | --- | +| `level="leaf"` (or omitted) | claude (flat) | sonnet (flat) | high (flat) | `--effort high` | +| `level="master"` | claude (inherited) | opus (master override) | xhigh (master override) | `--effort xhigh` | +| `level="portfolio"` | claude (inherited) | fable (portfolio override) | ultracode (portfolio override) | `/effort ultracode` session command | + +The RESOLVED level and its source (`explicit`/`default`) are recorded in +spawn provenance (`spawnLevel`/`spawnLevelSource` on the catalog row and the +payload). + +## Detection + +A harness is launchable only when its `command` resolves on `PATH` +(`shutil.which`). `GET /api/harnesses` reports the effective set with +per-harness detection; harness resolution order when `spawn_agent_session` +gets no explicit id: role knobs (level-merged) > `orchestration.spawn.harness` +preference > the first detected effective-registry harness. + +## Refusals (never crashes) + +All pre-spawn, nothing mutated: + +| Status | Trigger | Message carries | +| --- | --- | --- | +| `harness-unknown` | id known neither in the registry nor in settings | the id, the known set, and a pointer to `orchestration.harnesses` + this manual | +| `harness-not-detected` | known id whose command is not on `PATH` | the id (and the settings source when a configured preference caused it) | +| `effort-invalid` | effort outside the harness's vocabulary, or any effort for a mapping-less settings-defined harness | the harness, BOTH value sets (flag + session), and the launchArgs/sessionCommands guidance | +| `model-invalid` | model knob for a settings-defined harness with no `modelFlag` | the harness and the declare-or-launchArgs guidance | +| `level-invalid` | dispatch level outside `leaf|master|portfolio` | the value and the valid set | +| `leaf-taken` | the target leaf already has a running same-role session | the owning session (server-arbitrated, never overridden) | + +## Worked Example: Teaching The System `hermes` + +Suppose you use a TUI agent called `hermes` that nobody registered. A bare +`spawn_agent_session(harness="hermes")` refuses: + +> unknown harness: 'hermes'; known harnesses: [claude, codex, pi]. Define a +> new one under orchestration.harnesses in the agentic settings (see +> docs/reference/harnesses.md). + +Teach it in the GLOBAL agentic settings +(`/system/settings.json`): + +```jsonc +{ + "orchestration": { + "harnesses": { + "hermes": { + "name": "Hermes", + "command": "hermes", // probed on PATH for detection + "argv": ["hermes", "--tui"], // launched exactly like this + "modelFlag": "--model", + "effortFlag": "--reasoning", // hermes's own effort flag... + "effortFlagValues": ["low", "high"] // ...and the values it accepts + } + }, + "roles": { + "worker": { "harness": "hermes", "model": "h-1", "effort": "high" } + } + } +} +``` + +Now `spawn_agent_session(env={"AR_SPAWN_ROLE": "worker"})` launches +`hermes --tui --model h-1 --reasoning high` (knobs also riding the env), and +`effort: "turbo"` refuses naming `[low, high]`. Had you declared NO +`effortFlag`/vocabulary, the effort knob itself would refuse with guidance — +declare the mapping or pass the value through `launchArgs` — explicit over +guessing a flag that might mean something else. A repo-local +`/system/settings.json` may override any leaf of the entry (e.g. a +different `argv`) for that repo's dispatches. + +Pre-customizing a BUILTIN works the same way — override by id: + +```jsonc +"orchestration": { + "harnesses": { + "claude": { "argv": ["claude", "--continue"] } // replaces our argv; knob mapping survives + } +} +``` diff --git a/docs/reference/mcp-tools.md b/docs/reference/mcp-tools.md index 0d521e9c..83f8dbc3 100644 --- a/docs/reference/mcp-tools.md +++ b/docs/reference/mcp-tools.md @@ -42,7 +42,7 @@ surrounding procedure. See the [Skills reference](skills.md). | `drift_check` | Task-start onboarding drift classification; writes a temp drift report. | `repo_id`, `detail_limit=50` | | `memory_quality_check` | Closeout memory-quality gate (drift integrity + style checks). | `repo_id`, `checks=None`, `detail_limit=50` | | `route_index_refresh` | Regenerate `overview.index.json` route indexes to match the onboarding tree. | `repo_id`, `dry_run=false` | -| `read_ar_files` | Batch read up to 5 repo-relative source paths in a managed repo, each paired with its file-level onboarding, plus the repository + governing route overviews (auto-attached, session-deduped); emits a facts-only `read.packet`. **The research-phase read** — use it instead of a native read up to the build/job decision; a native read remains the edit precondition during build. | `repo_id`, `files:[{path, source:"full"\|{startLine,endLine}, onboarding?}]`, `refresh=false` | +| `read_ar_files` | Batch read up to 5 repo-relative source paths in a managed repo, each paired with its file-level onboarding, plus the repository + governing route overviews (auto-attached, session-deduped); emits a facts-only `read.packet`. **The research-phase read** — use it instead of a native read up to the build decision; a native read remains the edit precondition during build. | `repo_id`, `files:[{path, source:"full"\|{startLine,endLine}, onboarding?}]`, `refresh=false` | ## Memory baseline & carryover diff --git a/docs/reference/runtime-layout.md b/docs/reference/runtime-layout.md index 727a6706..42b1d58a 100644 --- a/docs/reference/runtime-layout.md +++ b/docs/reference/runtime-layout.md @@ -26,7 +26,7 @@ agents-remember/ patches/ skills/ c-00-initialize-memory-repo/ # generated copy of root skills/ - l-01-session-job-lifecycle/ + l-01-agent-lifecycles/ w-02-light-task-workflow/ system/defaults/examples/ benchmarks/ diff --git a/docs/reference/settings-json.md b/docs/reference/settings-json.md index a0af64d2..059c8c62 100644 --- a/docs/reference/settings-json.md +++ b/docs/reference/settings-json.md @@ -1,12 +1,22 @@ # settings.json Reference -`system/settings.json` is the machine-readable memory settings file for a -memory root. `system/settings.md` remains the human and agent prose guidance -file. +Agents Remember has FOUR settings families, each with exactly one home: -Coordinator roots should not carry a `system/settings.json` authority file for -MCP/provider behavior. MCP authority settings live outside the coordinator root; -see `examples/mcp/settings.example.json`. +| Family | Home | Read cadence | +| --- | --- | --- | +| Boot infrastructure (repos, providers, transport, timeoutCaps, dashboard) | MCP authority settings file (outside the coordinator root) | boot | +| Memory topology (`onboarding.storage`, `pathRules`, `crossRepo`) | memory-root `system/settings.json` (beside `settings.md`) | per resolution | +| **Agentic settings** (`orchestration.*`: gate delegation, loops, roles + rolesPerLevel, concurrency, spawn preference, harness definitions) | **coordinator `system/settings.json`** (global), `/system/settings.json` (local override) | per use (`gateDelegation`: boot snapshot) | +| Provider lifecycle settings | server-generated from the authority config (`--from-settings`) | per command | + +`system/settings.md` remains the human and agent prose guidance file beside a +memory root's `settings.json`. + +The coordinator root's `system/settings.json` is the GLOBAL agentic settings +file — it is NOT an MCP authority file (the server refuses it as `--config`) +and NOT a provider settings source (the old implicit fallback to it is +removed; an explicit `--from-settings` path is still read wherever it points). MCP authority settings +live outside the coordinator root; see `examples/mcp/settings.example.json`. ## Internal Memory Example @@ -107,7 +117,6 @@ watch settings internally. "transcriptRoot": "C:/absolute/path/to/ar-coordination/logs/mcp", "repositories": { "agents-remember": { - "memorySettingsIncludes": [], "contractPath": null } }, @@ -173,11 +182,10 @@ harness starter package and does not need this field. `repositories` is an allow-list keyed by repo id. The MCP server derives each code repository path from `workspaceRoot/` and each memory root from -`coordinationRoot/memory-repos/ar-`. - -`repositories..memorySettingsIncludes` may list extra absolute settings -files, but every include must stay inside either the configured code repository -or its configured memory root. +`coordinationRoot/memory-repos/ar-`. (The former +`repositories..memorySettingsIncludes` key was dead plumbing — parsed, +never consumed — and was removed with 260703-L13; a leftover key in an existing +file is tolerated and ignored.) `repositories..contractPath` may point at a coordination-root-local contract file. It must not point outside the coordinator root. @@ -202,3 +210,243 @@ next session's boot. Daemon state and logs live under `/logs/dashboard/`; `agents-remember dashboard --status` / `--stop` manage the same daemon from the CLI. Unknown `dashboard` keys are rejected. + +`orchestration` in the authority file is LEGACY territory (260703-L13): the +agentic family moved to the global agentic settings file documented below. For +one migration cycle the authority file may still carry +`orchestration.gateDelegation` — it is honored as a fallback when the global +file does not set the key, with a boot warning naming the new home (and it is +ignored, with a warning, when the global file does set it). Any other +`orchestration.*` key in the authority file (`loops`, `roles`, `rolesPerLevel`, +`concurrency`, `spawn`, `harnesses`) fails the boot loudly, pointing at the +global file. + +## Agentic Settings (global + repo-local) + +The agentic settings family — everything under the top-level `orchestration` +key — lives in TWO JSON files merged on every read (260703-L13): + +- **Global:** `/system/settings.json`. Seeded by + `runtime_install()` copy-if-missing with every knob at its documented + default; the c-13 install skill interviews the developer and writes it. + User-owned: an install never overwrites an existing file. +- **Repo-local override:** `/system/settings.json` (optional). The + same `orchestration.*` shape; repo-local values supersede global ones. + +**Merge semantics.** Deep merge at leaf-key granularity: a local scalar or +object leaf overrides the global one, sibling keys survive; arrays REPLACE +(never concatenate). + +**Fail-loud rule.** Unknown keys anywhere inside the `orchestration.*` family +are rejected naming the offending file — a typo can never be silently ignored. +Unknown TOP-LEVEL families in the same file are tolerated-not-parsed (see +Reserved Families below). + +**Null rule.** A JSON `null` at a known `orchestration.*` family key +(`gateDelegation` · `loops` · `roles` · `rolesPerLevel` · `concurrency` · +`spawn` · `harnesses`), in EITHER layer, is REFUSED naming the offending file. +`null` reads as *absent* to every family parser and the deep merge REPLACES a +non-object, so `"concurrency": null` in the repo-local layer would otherwise +SILENTLY wipe the global caps — the one scalar collision that used to defeat +both the deep-merge and fail-loud invariants. Remove the key to inherit the +global value (or give it a real object); `null` never means reset-to-default. + +**Read cadence.** Read PER-USE through the kernel agentic-settings loader +(`kernel/agentic_settings.py`): an edit takes effect on the next use with no +restart. The ONE exception is `orchestration.gateDelegation`, which the MCP +server snapshots at boot (enforcement plumbing is boot-cached): a change needs +a harness/MCP restart. + +**Defaults.** An absent file, or an absent key, means: all-human gate +delegation, the loop defaults below, no role overrides, no concurrency caps, +no spawn harness preference (detection-gated spawns). + +### orchestration.gateDelegation + +GLOBAL-LAYER ONLY: the boot snapshot reads the coordinator file exclusively, and the +loader REFUSES a `gateDelegation` key in a repo-local settings file (a local value +would otherwise validate and silently do nothing — a fail-open shape). Gate posture +is workspace-wide enforcement state, never a per-repo preference. + +Configures server-enforced lifecycle gate delegation. If omitted, the policy is +`all-human`: every gate requires the existing human/developer decision path. +The built-in `manager-decides-leaf-gates` policy adds the manager role for leaf +`plan-approval` and `closeout-approval` gates and routes the master-exit +`master-handover-approval` gate to the orchestrator, while leaving human +decisions valid. `kinds` may override individual delegable gate kinds with +`role: "human" | "manager" | "orchestrator"` and +`requireReviewerVerdict: true`; verdict requirements only apply to delegated +decisions. `requireReviewerVerdictAtSeams: true` additionally binds every +delegated seam-kind rule (`master-handover-approval`) to attached +reviewer-verdict evidence. The delegable kinds are `plan-approval`, +`closeout-approval`, and `master-handover-approval`; +`integration-approval`, `push-approval`, and `cleanup-approval` are +human-pinned and cannot be delegated. Boot-snapshot: restart required (see +Read cadence above). + +### orchestration.roles, orchestration.rolesPerLevel + +`orchestration.roles.` overrides a role file's knob block per role +(`orchestrator`, `designer`, `strategist`, `manager`, `worker`, `reviewer`). +Precedence: role-file defaults < global settings < repo-local settings. The +knobs come in a THREE-LAYER model (260703-L16; the full spawn-surface manual +with every parameter, vocabulary, and refusal is +**`docs/reference/harnesses.md`**): + +1. **Validated enum knobs** — `harness` (a known harness id: builtin + `claude`/`codex`/`pi` or an `orchestration.harnesses`-defined one), + `model`, `effort`. The spawn path seeds `model`/`effort` into the spawn env + (`AR_SPAWN_MODEL`/`AR_SPAWN_EFFORT`) AND applies them onto the harness + launch argv per-harness (claude: `--model`/`--effort`; a mapping-less + harness stays env-only). `effort` is validated per-harness at DISPATCH: + unknown values refuse loudly naming the harness and its valid sets. +2. **`launchArgs`** (list of strings) — appended VERBATIM to the harness + launch argv. Never validated; recorded in spawn provenance. +3. **`sessionCommands`** (list of strings; each line pasted + submitted into + the fresh session BEFORE the brief) and **`promptKeywords`** (list of + strings prepended as the first line of the dispatch-brief paste). Never + validated; recorded in spawn provenance. + +The claude effort vocabulary (empirical, 2026-07-07) is TWO-VEHICLE: + +| Value | Delivery vehicle | +| --- | --- | +| `low`, `medium`, `high`, `xhigh`, `max` | the `--effort` launch flag | +| `ultracode` | the `/effort ultracode` session command, pasted post-launch before the brief | + +Rationale: the installed claude CLI **warns-then-silently-degrades** on +unknown `--effort` values (probed with `ultracode`, which its interactive +`/effort` command DOES accept), so unvalidated values would quietly downgrade +the most reasoning-hungry seats — dispatch accepts the union of both sets and +refuses anything in neither. + +`orchestration.rolesPerLevel..` (ruling 2026-07-07T08:15) adds +the per-LEVEL agent sets the L12 doctrine promises: `leaf` | `master` | +`portfolio` (the `loops.perLevel` vocabulary), each holding the same +knob-override shape. A level override deep-merges over the flat +`orchestration.roles` default at leaf-key granularity (harness inherited +unless overridden; arrays replace). The dispatcher declares its level via +`spawn_agent_session(level=...)`, default `leaf`. Full resolution chain: +explicit args > repo-local level override > global level override > +repo-local role default > global role default > detection-gated default. The +resolved level rides spawn provenance (`spawnLevel`/`spawnLevelSource`). + +### orchestration.harnesses + +Extends/overrides the builtin harness registry (developer ruling 2026-07-07: +the registry is good defaults, not a wall). Entries are keyed by harness id: +a NEW id adds a harness (`command` and/or `argv` required — the command array +launches it exactly the way you would run it yourself), an EXISTING id +pre-customizes the builtin defaults (its `argv` replaces ours). Optional +knob-mapping fields: `name`, `modelFlag`, `effortFlag` + `effortFlagValues`, +`effortSessionValues` + `effortSessionCommand` (pairs required together). +Detection still gates dispatch; an id known nowhere refuses loudly pointing +at the manual. Schema, semantics, and a worked add-`hermes` example: +`docs/reference/harnesses.md`. + +### orchestration.concurrency, orchestration.spawn + +`orchestration.concurrency` caps parallel orchestration fan-out: +`maxParallelMasters`, `maxParallelLeaves`, `maxSubAgents` (positive integers; +omitted means uncapped). The caps are doctrine input for the spawning seats. + +`orchestration.spawn.harness` names the default harness `spawn_agent_session` +uses when the caller passes none and no role knob supplies one. Resolution +order at the spawn seam: explicit argument > role knobs (level-merged) > +repo-local settings > global settings > detection-gated default (the first +effective-registry harness found on PATH; the repo-local layer is selected by +the qualified leaf key's repository segment). Values are validated against +the effective harness ids (builtin + `orchestration.harnesses`) and gated by +detection — a settings value can never inject a command through a reference; +argv is definable only in the explicit `orchestration.harnesses` family. + +```jsonc +"orchestration": { + "roles": { + "orchestrator": { "harness": "claude", "effort": "high" }, + "strategist": { "effort": "ultracode" }, // session-vocabulary value → "/effort ultracode" post-launch + "reviewer": { "harness": "claude", "model": "sonnet", "effort": "high" }, + "worker": { "harness": "codex", "effort": "medium" } + }, + "rolesPerLevel": { + "master": { "reviewer": { "model": "opus", "effort": "xhigh" } }, + "portfolio": { "reviewer": { "model": "fable", "effort": "ultracode" } } + }, + "concurrency": { "maxParallelMasters": 2, "maxParallelLeaves": 3, "maxSubAgents": 4 }, + "spawn": { "harness": "claude" } +} +``` + +### orchestration.loops + +`orchestration.loops` configures the three-party review loops (OWNER → BUILDER → +REVIEWER) the `l-01-agent-lifecycles` skill runs at every level that owns work. +Parsed by the agentic-settings loader into typed models; stored in the global +file with repo-local precedence like every agentic key. + +```jsonc +"orchestration": { + "loops": { + "defaults": { + "maxRounds": 3, // the HARD cap — only FULL end-to-end rounds count + "reviewerReuse": "delta-verify", // residuals of a passing round are delta-verified by the SAME reviewer + "complexity": { "fullLoopAt": "high", "builderAt": "medium" } + }, + "perLevel": { + "leaf": { "loop": "scored" }, // tier scored per leaf at dispatch (direct | builder-verified | full loop) + "master": { "loop": "seam-required" }, // loop posture only; "none" = workflow-free manager (the master-exit SEAM stays unconditional) + "portfolio": { "loop": "strategist" } // owner = orchestrator · builder = strategist · reviewer with the plan-review catalog + } + // local override example (tight mode): + // "perMaster": { "260703_agent-orchestration": { "leaf": { "loop": "builder-verified" } } } + } +} +``` + +Semantics, as the loop doctrine defines them +(`skills/l-01-agent-lifecycles/SKILL.md`, The Three-Party Loop): + +- `defaults.maxRounds` (default `3`) is the hard cap per loop. **Only full + end-to-end rounds count against it**; delta-verifies close rounds, they do + not open them. The real control is the convergence rule — every round must + shrink the open finding set, and a non-shrinking round escalates immediately + regardless of the count — so the cap is the backstop, not the driver. +- `defaults.reviewerReuse: "delta-verify"` names the ruled reuse: the SAME + reviewer instance is resumed via a follow-up message to verify a passing + round's landed residuals, and fix rounds resume the SAME builder. A fresh + reviewer is spawned only for a full round or when new scope opens. +- `defaults.complexity` maps the dispatch-time complexity score (blast radius · + novelty · size) to tiers: at/above `fullLoopAt` a leaf runs the full loop + (builder + independent reviewer); at/above `builderAt` it runs + builder-verified (builder + owner report-vs-artifact check, no reviewer); + below both it is direct (the level's ordinary build channel implements — + no loop machinery). +- `perLevel.leaf.loop: "scored"` — the owning seat scores each leaf at + dispatch. `perLevel.master.loop: "seam-required"` names the default loop + posture; `"none"` configures the workflow-free manager (a master whose + leaves all score direct carries no loop machinery). **This knob governs the + LOOP only (review rounds / workflow-free manager): the master-exit SEAM gate + is unconditional doctrine — no knob value touches it.** Loop posture names + are model-interpreted doctrine (validated as non-empty strings, not a closed + set). Each level runs its loop with its own agent set + (`orchestration.roles` knobs per role). +- `perLevel.portfolio.loop: "strategist"` names the portfolio loop's parties. + **The strategist's mandatory pre-run is doctrine, not a knob** — no + configuration can waive it: an orchestrated run requires the adopted + orchestration task, unconditionally (`roles/strategist.md`). + +### Reserved Families (the global file's future) + +The global agentic file is the earmarked durable settings home beyond the +`orchestration.*` family. The fail-loud rule is deliberately scoped to +`orchestration.*` only, so reserved top-level families cost nothing today: + +- **`contextProviders` — reserved; returns here in a follow-up** (developer + direction, 2026-07-06). Today provider configuration is authority-file + territory (the server derives lifecycle settings from `providers.*`), and + the OLD implicit fallback that read `contextProviders` from this file was + retired with L13. A future `contextProviders` key at the top level of the + global file is tolerated-not-parsed until that migration lands. +- Other top-level keys (`$comment`, `version`, and any future family) are + likewise tolerated-not-parsed by the agentic loader; only documented + `orchestration.*` keys are read, and only they fail loud. diff --git a/docs/reference/skills.md b/docs/reference/skills.md index 38805107..451c7bef 100644 --- a/docs/reference/skills.md +++ b/docs/reference/skills.md @@ -26,7 +26,7 @@ package skill folder. The pre-push hook runs | Skill | Purpose | | --- | --- | -| `l-01-session-job-lifecycle` | The session job lifecycle the coordinator routes every session into (orient → ground → frame → decide → build → close); owns the read-only exit and the build-mode decision. | +| `l-01-agent-lifecycles` | The agent lifecycles, one per agent type under one roof. Routes every session by exactly three conditions (spawn-role env → role brief → otherwise orchestrator), carries the minimal lifecycle frame (the six lifecycle signals every session shares), and houses the self-contained per-role lifecycles (orchestrator · designer · strategist · manager · worker · adversarial reviewer) plus the report-template library and the reviewer criteria catalogs. The orchestrator lifecycle (request → trust-checkpoint → reframe-research → decide → build → close) owns the research-only exit and the build-mode decision; a developer-facing session IS the orchestrator. | | `w-02-light-task-workflow` | Durable one-page task plan with approval gate and live checklist; escalates to a master + light sub-task series for larger work. | ## Core Skills diff --git a/docs/workflows.md b/docs/workflows.md index 428eb827..45657af7 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -1,8 +1,12 @@ # Workflows -Every session runs through the **`l-01-session-job-lifecycle` session job lifecycle**: orient → ground → frame → decide → -build → close. The job type (bug / feature / triage / research) is a lens during framing, not a gate. -The only task-format decision is the `l-01-session-job-lifecycle` skill's build-mode step. +Sessions route by role through the **`l-01-agent-lifecycles`** skill — one lifecycle per agent +type, selected by exactly three conditions: a spawn-role environment variable runs that role's +lifecycle, otherwise a role brief as the first message runs that role, otherwise the session is +developer-facing and runs the **orchestrator** lifecycle. The orchestrator's phase axis is +request → trust-checkpoint → reframe-research → decide → build → close. The job type +(bug / feature / triage / research) is a lens during reframe-research, not a gate. +The only task-format decision is the orchestrator lifecycle's build-mode step. ## Shared Discipline @@ -10,28 +14,25 @@ Every build keeps these rules: 1. Resolve the active context with `c-08-ar-coordination-context-resolver`. 2. Run drift detection before planning against onboarding. -3. Wait for developer approval before implementation (the `l-01-session-job-lifecycle` skill's `frame` plan gate). +3. Wait for developer approval before implementation (the orchestrator lifecycle's plan gate). 4. Update onboarding only after approved changes, live per completed plan-section. 5. Run the checks listed in the resolved memory layer's `system/tools.md` when available. ## Build Modes -At `decide`, the `l-01-session-job-lifecycle` skill picks one of: +At `decide`, the orchestrator lifecycle picks one of: -### Read-only exit +### Research-only exit The job answers a question or assesses something and changes no code — no worktree, no task file, no -closeout. Research and triage jobs usually exit here; they may recommend or spawn a build job. - -### Chat build - -A code change small enough to carry inline this session: worktree-backed, with no durable task file. -After approval, the build closes through the `c-12-closeout` worktree closeout, which commits code -first, refreshes onboarding metadata to that code commit, commits memory, then updates the ledger. +closeout. Research and triage jobs usually exit here; chat is the right medium for the answer, and +the exit may recommend or spawn a build task. ### Durable task (`w-02-light-task-workflow`) -Use `w-02-light-task-workflow` when the work needs a durable task file but still fits a compact plan: +Chat is never a build route: every code change lives under an approved task document. Small code +work takes the minimal `w-02-light-task-workflow` artifact; use the full form when the work needs a +durable task file but still fits a compact plan: ```text ar-coordination/tasks///task.md @@ -41,6 +42,8 @@ The task file holds requirements, implementation steps, proposed examples, decis and references; the checklist is the live execution state. Use it for documentation restructures, medium refactors, multi-step cleanup, and work that might survive more than one session. +### Master + light sub-task series + When the work outgrows a single-page plan — broad cross-repo or high-risk changes, or several distinct slices that each need their own checklist and commit — escalate to a **master + light sub-task series** (`master-template.md`): one wrapper folder with a master `task.md` plus flat, numbered sub-task files, @@ -49,7 +52,9 @@ retired heavy workflow. ## Worktree-Backed Tasks -Every build is worktree-backed (only read-only exits skip the worktree). The `c-09-git-worktree-manager` skill creates the task +Every build is worktree-backed (only research-only exits skip the worktree); the invariant ladder is +task doc (approved) → branch (intent) → worktree (only where something is built). The +`c-09-git-worktree-manager` skill creates the task worktree; a worktree-backed task has a `contract.md` beside the task file. The `c-09-git-worktree-manager` skill owns the worktree lifecycle, integration, and cleanup; `c-12-closeout` runs the closeout itself. A master series runs in **one** shared worktree for the whole series. @@ -62,8 +67,8 @@ deferred to the repo's `system/git-workflow.md` when present. | Situation | Build mode | | --- | --- | -| Answer or assessment, no code change | Read-only exit | -| One-session code change, low risk | Chat build (worktree, no task file) | +| Answer or assessment, no code change | Research-only exit | +| One-session code change, low risk | Minimal `w-02-light-task-workflow` task (thin doc, worktree-backed) | | Needs a durable plan or checklist | `w-02-light-task-workflow` light task | | Outgrows a single-page plan, or broad/high-risk | Master + light sub-task series | | Parallel implementation or explicit closeout tracking | Any build mode — all builds are worktree-backed via the `c-09-git-worktree-manager` skill | diff --git a/examples/mcp/settings.example.json b/examples/mcp/settings.example.json index 3624865e..87883c0c 100644 --- a/examples/mcp/settings.example.json +++ b/examples/mcp/settings.example.json @@ -5,7 +5,6 @@ "transcriptRoot": "C:/absolute/path/to/ar-coordination/logs/mcp", "repositories": { "agents-remember": { - "memorySettingsIncludes": [], "contractPath": null } }, diff --git a/mcp/pyproject.toml b/mcp/pyproject.toml index e4c667e0..58fa1f8b 100644 --- a/mcp/pyproject.toml +++ b/mcp/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "agents-remember-mcp" -version = "3.0.0rc2" +version = "3.0.0rc3" description = "Model Context Protocol server for Agents Remember." readme = "README.md" requires-python = ">=3.11" diff --git a/mcp/src/agents_remember/controllers/task_doc_tools.py b/mcp/src/agents_remember/controllers/task_doc_tools.py index 372ccd2c..06e04415 100644 --- a/mcp/src/agents_remember/controllers/task_doc_tools.py +++ b/mcp/src/agents_remember/controllers/task_doc_tools.py @@ -74,6 +74,7 @@ "master", "codeExamplesNote", "statusNote", + "orchestrates", } ) diff --git a/mcp/src/agents_remember/controllers/worktree_tools.py b/mcp/src/agents_remember/controllers/worktree_tools.py index 57f49602..4a1c23b7 100644 --- a/mcp/src/agents_remember/controllers/worktree_tools.py +++ b/mcp/src/agents_remember/controllers/worktree_tools.py @@ -258,6 +258,10 @@ def worktree_integrate_tool( approved=not dry_run, ledger_commit_message=ledger_commit_message, dry_run=dry_run, + # The configured policy MUST reach the seam guard (mirror of the closeout + # path below): the dataclass default is all-human, which would refuse the + # exact delegated approval the master-handover channel produces. + gate_policy=config.orchestration.gate_policy, ) return _worktree_result("worktree_integrate", git_worktree_manager.integrate_result(args)) @@ -379,5 +383,6 @@ def _worktree_closeout( approval_note=intent_note, approved=not dry_run, dry_run=dry_run, + gate_policy=config.orchestration.gate_policy, ) return _worktree_result(operation, git_worktree_manager.closeout_result(args)) diff --git a/mcp/src/agents_remember/controlplane/__init__.py b/mcp/src/agents_remember/controlplane/__init__.py index e1d678f0..d2cfb376 100644 --- a/mcp/src/agents_remember/controlplane/__init__.py +++ b/mcp/src/agents_remember/controlplane/__init__.py @@ -3,10 +3,10 @@ Slice 6a is the substrate -- the ``GateRecord`` entity and an append-only ``GateStore`` co-located with the observer event log -- plus the ``gate_*`` MCP tools (in ``agents_remember.mcp.tools.gates``) that create, decide, wait on, and -list gates. Slice 6b adds enforcement: ``apply_gate`` (the ``applied`` transition -a mutating tool writes once it consumes an approval) and ``evaluate_closeout_gate`` -(the pure policy ``worktree_closeout_apply`` obeys). Projection surfacing lands in -a later slice. +list gates. Enforcement uses the kind-generic gate policy: ``apply_gate`` (the +``applied`` transition a mutating tool writes once it consumes an approval) and +``evaluate_gate`` / ``evaluate_closeout_gate`` (the pure policy mutating tools +obey). The external-chat inbox substrate is the pull-based counterpart: an append-only ``OperatorInboxEntry`` log plus ``OperatorInboxStore`` for posting, polling, and @@ -17,7 +17,14 @@ from agents_remember.controlplane.enforcement import ( CloseoutGuard, + GateGuard, evaluate_closeout_gate, + evaluate_gate, +) +from agents_remember.controlplane.gate_policy import ( + DEFAULT_GATE_POLICY, + GatePolicy, + GatePolicyRule, ) from agents_remember.controlplane.operator_inbox_records import ( OPERATOR_INBOX_RECORD_SCHEMA, @@ -32,6 +39,7 @@ DECISION_STATES, GATE_RECORD_SCHEMA, DecidedVia, + GateEvidenceRef, GateKind, GateRecord, GateState, @@ -43,11 +51,16 @@ __all__ = [ "DECISION_STATES", + "DEFAULT_GATE_POLICY", "GATE_RECORD_SCHEMA", "OPERATOR_INBOX_RECORD_SCHEMA", "CloseoutGuard", "DecidedVia", + "GateEvidenceRef", + "GateGuard", "GateKind", + "GatePolicy", + "GatePolicyRule", "GateRecord", "GateState", "GateStore", @@ -61,4 +74,5 @@ "create_operator_inbox_entry", "decide_gate", "evaluate_closeout_gate", + "evaluate_gate", ] diff --git a/mcp/src/agents_remember/controlplane/enforcement.py b/mcp/src/agents_remember/controlplane/enforcement.py index 1dbfb463..efcb4e73 100644 --- a/mcp/src/agents_remember/controlplane/enforcement.py +++ b/mcp/src/agents_remember/controlplane/enforcement.py @@ -1,17 +1,19 @@ -"""Closeout-gate enforcement policy: does an approved gate permit this closeout? (slice 6b). +"""Gate enforcement policy: does an approved gate permit a server-side mutation? -6a recorded gates honestly; 6b makes a ``closeout-approval`` gate *binding*. This -module owns the pure decision -- given a lifecycle's current gate set, may its -closeout proceed? -- kept free of I/O so the mutating worktree tool and any future -caller share one policy and it is unit-testable without a store. +6a recorded gates honestly; 6b made a ``closeout-approval`` gate *binding*. This +module owns the pure decision -- given a lifecycle's current gate set and the +configured gate policy, may the corresponding server-side mutation proceed? -- +kept free of I/O so mutating tools share one policy and it is unit-testable +without a store. The load-bearing rule is the **anti-self-approval** invariant: the agent's own ``gate_decide`` is attributed ``decidedBy="model"`` (see ``mcp/tools/gates.py``), -so a model-decided ``approved`` snapshot does **not** satisfy enforcement. Only a -``decidedBy="developer"`` approval -- which only the dashboard serving path writes --- is binding. A lifecycle with no closeout-approval gate is *gateless*: the chat -commit gate (``--approved`` + note) still governs, so every pre-6b flow is -unbroken and enforcement is purely additive. +so a model-decided ``approved`` snapshot does **not** satisfy enforcement. A +human approval is always binding; a non-human orchestration approval is binding +only when the policy explicitly delegates that gate kind to the deciding role and +the decider is not the gate-owning lifecycle. A lifecycle with no gate of the +requested kind is *gateless*: the existing chat/commit gate still governs, so +legacy flows remain additive. """ from __future__ import annotations @@ -19,62 +21,82 @@ from collections.abc import Mapping from dataclasses import dataclass -from agents_remember.controlplane.records import GateRecord +from agents_remember.controlplane.gate_policy import ( + DEFAULT_GATE_POLICY, + GatePolicy, + approval_failure_reason, +) +from agents_remember.controlplane.records import GateKind, GateRecord CLOSEOUT_GATE_KIND = "closeout-approval" -BINDING_DECIDER = "developer" @dataclass(frozen=True) -class CloseoutGuard: - """The closeout admissibility verdict for one lifecycle's gate set. +class GateGuard: + """The admissibility verdict for one lifecycle's gate set. ``permitted`` is the decision; ``reason`` is the operator/agent-facing message (the refusal text a blocked closeout raises); ``gate_id`` is the governing gate when one exists, so the caller can mark it ``applied`` on success. """ + kind: GateKind permitted: bool reason: str gate_id: str | None = None -def evaluate_closeout_gate(gates: Mapping[str, GateRecord]) -> CloseoutGuard: - """Decide whether a lifecycle's current gate set permits closeout. Pure. +CloseoutGuard = GateGuard + + +def evaluate_gate( + gates: Mapping[str, GateRecord], + *, + kind: GateKind, + policy: GatePolicy = DEFAULT_GATE_POLICY, +) -> GateGuard: + """Decide whether a lifecycle's current gate set permits a gate kind. Pure. ``gates`` is the folded live set (:meth:`GateStore.current`, already last-wins - by id). Absent a closeout-approval gate the verdict is permitted-gateless; - otherwise the latest closeout-approval snapshot governs and only a - developer-decided ``approved`` state lets closeout through. + by id). Absent a matching gate the verdict is permitted-gateless; otherwise + the latest matching snapshot governs and only a policy-valid ``approved`` + state lets the mutation through. """ - relevant = [gate for gate in gates.values() if gate.kind == CLOSEOUT_GATE_KIND] + relevant = [gate for gate in gates.values() if gate.kind == kind] if not relevant: - return CloseoutGuard(True, "no closeout-approval gate; chat commit approval governs") + return GateGuard(kind, True, f"no {kind} gate; existing approval channel governs") gate = max(relevant, key=lambda candidate: candidate.ts) - if gate.state == "approved" and gate.decidedBy == BINDING_DECIDER: - return CloseoutGuard(True, "closeout-approval gate approved by the developer", gate.id) if gate.state == "approved": - return CloseoutGuard( - False, - f"closeout gate {gate.id} was approved by {gate.decidedBy!r}, not the developer; " - "a self-approval is not binding -- a developer must approve it via the dashboard", - gate.id, - ) + failure = approval_failure_reason(gate, policy) + if failure is None: + return GateGuard(kind, True, f"{kind} gate approved by policy-valid decider", gate.id) + return GateGuard(kind, False, failure, gate.id) if gate.state == "open": - return CloseoutGuard( + return GateGuard( + kind, False, - f"closeout gate {gate.id} is open; await the developer's decision " - "through the lifecycle gate channel -- do not self-approve", + f"{kind} gate {gate.id} is open; await a policy-valid decision " + "through the lifecycle gate channel", gate.id, ) if gate.state == "applied": - return CloseoutGuard( + return GateGuard( + kind, False, - f"closeout gate {gate.id} was already applied; open a fresh gate for a new closeout", + f"{kind} gate {gate.id} was already applied; open a fresh gate for a new mutation", gate.id, ) - return CloseoutGuard( + return GateGuard( + kind, False, - f"closeout gate {gate.id} is {gate.state}: {gate.decisionNote or gate.state}", + f"{kind} gate {gate.id} is {gate.state}: {gate.decisionNote or gate.state}", gate.id, ) + + +def evaluate_closeout_gate( + gates: Mapping[str, GateRecord], + policy: GatePolicy = DEFAULT_GATE_POLICY, +) -> CloseoutGuard: + """Compatibility wrapper for closeout enforcement.""" + return evaluate_gate(gates, kind=CLOSEOUT_GATE_KIND, policy=policy) diff --git a/mcp/src/agents_remember/controlplane/gate_policy.py b/mcp/src/agents_remember/controlplane/gate_policy.py new file mode 100644 index 00000000..56a20489 --- /dev/null +++ b/mcp/src/agents_remember/controlplane/gate_policy.py @@ -0,0 +1,199 @@ +"""Gate delegation policy for durable lifecycle gates. + +The default policy is intentionally today's behavior: every gate is human +decided. Orchestration delegation adds one configured role for specific gate +kinds; it never removes the human path and it never changes human-pinned kinds. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Literal, cast, get_args + +from agents_remember.controlplane.records import GateKind, GateRecord + +DecisionRole = Literal["human", "manager", "orchestrator"] + +DECISION_ROLES: tuple[DecisionRole, ...] = get_args(DecisionRole) +HUMAN_ROLE: DecisionRole = "human" +HUMAN_DECIDER = "developer" +ORCHESTRATION_DECIDED_VIA = "orchestration" +REVIEWER_VERDICT_EVIDENCE_KIND = "reviewer-verdict" + +HUMAN_PINNED_GATE_KINDS: frozenset[GateKind] = frozenset( + {"integration-approval", "push-approval", "cleanup-approval"} +) +DELEGABLE_GATE_KINDS: frozenset[GateKind] = frozenset( + {"plan-approval", "closeout-approval", "master-handover-approval"} +) +# The seam kinds `requireReviewerVerdictAtSeams` binds: delegated decisions on these kinds +# demand reviewer-verdict evidence. (The super-exit seam stays human via the pinned +# integration/push kinds, where the human sees the attached verdict directly.) +SEAM_GATE_KINDS: frozenset[GateKind] = frozenset({"master-handover-approval"}) + + +@dataclass(frozen=True) +class GatePolicyRule: + """The configured delegation rule for one gate kind. + + ``delegated_role`` is additive: humans remain allowed, and a non-human role + becomes allowed only for kinds that are explicitly safe to delegate. + """ + + kind: GateKind + delegated_role: DecisionRole | None = None + require_reviewer_verdict: bool = False + + def allows_role(self, role: DecisionRole) -> bool: + return role in (HUMAN_ROLE, self.delegated_role) + + +@dataclass(frozen=True) +class GatePolicy: + """Validated gate policy, defaulting every unlisted kind to human-only.""" + + rules: tuple[GatePolicyRule, ...] = () + + def rule_for(self, kind: GateKind) -> GatePolicyRule: + for rule in self.rules: + if rule.kind == kind: + return rule + return GatePolicyRule(kind=kind) + + +DEFAULT_GATE_POLICY = GatePolicy() + + +def coerce_decision_role(raw: str) -> DecisionRole: + if raw not in DECISION_ROLES: + raise ValueError( + f"unknown decision role {raw!r}; expected one of {list(DECISION_ROLES)}" + ) + return cast(DecisionRole, raw) + + +def make_gate_policy(rules: list[GatePolicyRule] | tuple[GatePolicyRule, ...]) -> GatePolicy: + """Validate and canonicalize policy rules. + + Human-pinned kinds reject non-human delegation. Other non-human delegation is + currently limited to the leaf gate kinds this orchestration leaf implements. + That fail-loud boundary prevents a typo or over-broad policy from silently + weakening a gate. + """ + by_kind: dict[GateKind, GatePolicyRule] = {} + for rule in rules: + normalized = rule + if rule.delegated_role == HUMAN_ROLE: + normalized = GatePolicyRule( + kind=rule.kind, + delegated_role=None, + require_reviewer_verdict=rule.require_reviewer_verdict, + ) + if normalized.delegated_role is not None and normalized.kind in HUMAN_PINNED_GATE_KINDS: + raise ValueError( + f"{normalized.kind} is human-pinned and cannot delegate to " + f"{normalized.delegated_role}" + ) + if normalized.delegated_role is not None and normalized.kind not in DELEGABLE_GATE_KINDS: + allowed = ", ".join(sorted(DELEGABLE_GATE_KINDS)) + raise ValueError( + f"{normalized.kind} cannot be delegated; allowed delegated kinds: {allowed}" + ) + if normalized.require_reviewer_verdict and normalized.delegated_role is None: + raise ValueError( + f"{normalized.kind} cannot require reviewer verdicts without a delegated role" + ) + by_kind[normalized.kind] = normalized + return GatePolicy(tuple(by_kind[key] for key in sorted(by_kind))) + + +def named_gate_policy(name: str) -> GatePolicy: + """Built-in policy names accepted by MCP authority settings.""" + if name == "all-human": + return DEFAULT_GATE_POLICY + if name == "manager-decides-leaf-gates": + # Leaf gates -> the manager; the master-exit handover -> the orchestrator (developer + # ruling 2026-07-05: happy path through the orchestrator, human review at the super gate). + return make_gate_policy( + [ + GatePolicyRule(kind="plan-approval", delegated_role="manager"), + GatePolicyRule(kind="closeout-approval", delegated_role="manager"), + GatePolicyRule(kind="master-handover-approval", delegated_role="orchestrator"), + ] + ) + raise ValueError( + "unknown gate delegation policy " + f"{name!r}; expected one of ['all-human', 'manager-decides-leaf-gates']" + ) + + +def apply_seam_verdict_requirement(policy: GatePolicy) -> GatePolicy: + """Bind reviewer-verdict evidence to every DELEGATED seam-kind rule. + + The `requireReviewerVerdictAtSeams` switch: seam kinds without a delegated role stay + human-decided (the human sees the attached verdict on the gate), so only delegated seam + rules gain the hard requirement. + """ + rules = [] + for rule in policy.rules: + if rule.kind in SEAM_GATE_KINDS and rule.delegated_role is not None: + rules.append( + GatePolicyRule( + kind=rule.kind, + delegated_role=rule.delegated_role, + require_reviewer_verdict=True, + ) + ) + else: + rules.append(rule) + return GatePolicy(tuple(rules)) + + +def has_reviewer_verdict_evidence(gate: GateRecord) -> bool: + return any(ref.kind == REVIEWER_VERDICT_EVIDENCE_KIND for ref in gate.evidenceRefs) + + +def decision_role_for_gate(gate: GateRecord) -> DecisionRole | None: + if gate.decidedBy == HUMAN_DECIDER: + return HUMAN_ROLE + if gate.decidedVia == ORCHESTRATION_DECIDED_VIA and gate.decidingRole is not None: + return coerce_decision_role(gate.decidingRole) + return None + + +def delegated_decision_failure_reason(gate: GateRecord, policy: GatePolicy) -> str | None: + """Return a refusal reason when an orchestration decision is not policy-valid.""" + if gate.decidedVia != ORCHESTRATION_DECIDED_VIA: + return f"gate {gate.id} was not decided through orchestration" + if not gate.decidedBy: + return f"gate {gate.id} has no deciding lifecycle identity" + if gate.lifecycleId and gate.decidedBy == gate.lifecycleId: + return f"gate {gate.id} cannot be decided by its owning lifecycle {gate.lifecycleId!r}" + if gate.decidingRole is None: + return f"gate {gate.id} has no deciding role" + role = coerce_decision_role(gate.decidingRole) + rule = policy.rule_for(gate.kind) + if not rule.allows_role(role) or role == HUMAN_ROLE: + return f"{gate.kind} is not delegated to role {role!r}" + if rule.require_reviewer_verdict and not has_reviewer_verdict_evidence(gate): + return f"{gate.kind} requires reviewer verdict evidence before delegated decisions" + return None + + +def approval_failure_reason(gate: GateRecord, policy: GatePolicy) -> str | None: + """Return why an approved gate does not satisfy the configured policy.""" + try: + role = decision_role_for_gate(gate) + except ValueError as error: + return str(error) + if role == HUMAN_ROLE: + return None + if role is None: + return ( + f"{gate.kind} gate {gate.id} was approved by {gate.decidedBy!r}, " + "not the developer or a configured orchestration role" + ) + try: + return delegated_decision_failure_reason(gate, policy) + except ValueError as error: + return str(error) diff --git a/mcp/src/agents_remember/controlplane/operator_inbox_records.py b/mcp/src/agents_remember/controlplane/operator_inbox_records.py index b6fea2cf..54db11d9 100644 --- a/mcp/src/agents_remember/controlplane/operator_inbox_records.py +++ b/mcp/src/agents_remember/controlplane/operator_inbox_records.py @@ -10,12 +10,38 @@ OperatorInboxState = Literal["pending", "consumed"] OperatorInboxVia = Literal["chat", "dashboard", "cli"] +AgentRole = Literal[ + "developer", + "operator", + "designer", + "strategist", + "orchestrator", + "manager", + "worker", + "reviewer", + "agent", + "system", +] +InboxMessageKind = Literal[ + "message", + "gate-response", + "turn-report", + "master-handover", + "nudge", + "escalation", +] +InboxDeliveryState = Literal["queued", "no-hosted-session", "delivered", "unconfirmed"] -def require_inbox_address(*, lifecycle_id: str | None, agent_id: str | None) -> None: +def require_inbox_address( + *, + lifecycle_id: str | None, + agent_id: str | None, + recipient_role: AgentRole | None = None, +) -> None: """Require at least one mailbox key before writing or polling inbox entries.""" - if lifecycle_id is None and agent_id is None: - raise ValueError("operator inbox requires lifecycle_id or agent_id") + if lifecycle_id is None and agent_id is None and recipient_role is None: + raise ValueError("operator inbox requires lifecycle_id, agent_id, or recipient_role") class OperatorInboxEntry(BaseModel): @@ -29,12 +55,21 @@ class OperatorInboxEntry(BaseModel): state: OperatorInboxState lifecycleId: str | None = None agentId: str | None = None + senderAgentId: str | None = None + senderRole: AgentRole | None = None + recipientRole: AgentRole | None = None gateId: str | None = None + messageKind: InboxMessageKind = "message" + artifactPath: str | None = None ask: str response: str createdAt: str createdBy: str createdVia: OperatorInboxVia + deliveryState: InboxDeliveryState = "queued" + deliveredAt: str | None = None + deliveredToSession: str | None = None + deliveryDetail: str | None = None consumedAt: str | None = None consumedBy: str | None = None consumedVia: OperatorInboxVia | None = None @@ -51,16 +86,30 @@ def create_operator_inbox_entry( created_by: str, created_via: OperatorInboxVia, gate_id: str | None = None, + sender_agent_id: str | None = None, + sender_role: AgentRole | None = None, + recipient_role: AgentRole | None = None, + message_kind: InboxMessageKind = "message", + artifact_path: str | None = None, ) -> OperatorInboxEntry: """Create a pending inbox entry. Pure: the caller mints ``entry_id`` and ``now``.""" - require_inbox_address(lifecycle_id=lifecycle_id, agent_id=agent_id) + require_inbox_address( + lifecycle_id=lifecycle_id, + agent_id=agent_id, + recipient_role=recipient_role, + ) return OperatorInboxEntry( id=entry_id, ts=now, state="pending", lifecycleId=lifecycle_id, agentId=agent_id, + senderAgentId=sender_agent_id, + senderRole=sender_role, + recipientRole=recipient_role, gateId=gate_id, + messageKind=message_kind, + artifactPath=artifact_path, ask=ask, response=response, createdAt=now, diff --git a/mcp/src/agents_remember/controlplane/operator_inbox_store.py b/mcp/src/agents_remember/controlplane/operator_inbox_store.py index c4d384a8..91cd140b 100644 --- a/mcp/src/agents_remember/controlplane/operator_inbox_store.py +++ b/mcp/src/agents_remember/controlplane/operator_inbox_store.py @@ -8,6 +8,8 @@ from agents_remember.controlplane.interaction_retention import inbox_keep_ids from agents_remember.controlplane.operator_inbox_records import ( + AgentRole, + InboxDeliveryState, OperatorInboxEntry, OperatorInboxVia, consume_operator_inbox_entry, @@ -60,18 +62,49 @@ def list_pending( *, lifecycle_id: str | None, agent_id: str | None, + recipient_role: AgentRole | None = None, ) -> list[OperatorInboxEntry]: """Return pending entries matching all supplied mailbox keys.""" - require_inbox_address(lifecycle_id=lifecycle_id, agent_id=agent_id) + require_inbox_address( + lifecycle_id=lifecycle_id, + agent_id=agent_id, + recipient_role=recipient_role, + ) entries = [ record for record in self.current().values() if record.state == "pending" and (lifecycle_id is None or record.lifecycleId == lifecycle_id) and (agent_id is None or record.agentId == agent_id) + and (recipient_role is None or record.recipientRole == recipient_role) ] return sorted(entries, key=lambda record: record.createdAt) + def record_delivery( + self, + entry_id: str, + *, + now: str, + delivery_state: InboxDeliveryState, + delivered_to_session: str | None = None, + delivery_detail: str | None = None, + ) -> OperatorInboxEntry: + """Append a delivery-status snapshot for one pending entry.""" + current = self.current().get(entry_id) + if current is None: + raise KeyError(f"no operator inbox entry {entry_id!r}") + delivered = current.model_copy( + update={ + "ts": now, + "deliveryState": delivery_state, + "deliveredAt": now if delivery_state == "delivered" else current.deliveredAt, + "deliveredToSession": delivered_to_session, + "deliveryDetail": delivery_detail, + } + ) + self.append(delivered) + return delivered + def consume( self, entry_id: str, diff --git a/mcp/src/agents_remember/controlplane/orchestration_artifacts.py b/mcp/src/agents_remember/controlplane/orchestration_artifacts.py new file mode 100644 index 00000000..cce52d7f --- /dev/null +++ b/mcp/src/agents_remember/controlplane/orchestration_artifacts.py @@ -0,0 +1,137 @@ +"""Orchestration artifact and escalation packet helpers.""" + +from __future__ import annotations + +import re +from pathlib import Path +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field + +OrchestrationRole = Literal["designer", "strategist", "orchestrator", "manager", "worker", "reviewer"] +EscalationReason = Literal["blocked", "plan-delta", "quality-failure", "missing-artifact"] + +_ROLE_ESCALATION: dict[OrchestrationRole, OrchestrationRole | Literal["developer"]] = { + "worker": "manager", + "manager": "orchestrator", + "orchestrator": "developer", + "designer": "orchestrator", + "strategist": "orchestrator", + "reviewer": "orchestrator", +} +_SAFE_STEM = re.compile(r"[^A-Za-z0-9_.-]+") + + +class TurnReportArtifact(BaseModel): + """The durable worker hand-off artifact required by the L2 worker job.""" + + model_config = ConfigDict(extra="forbid") + + leafId: str + title: str + path: str + templatePath: str + + +class MasterHandoverPacket(BaseModel): + """Manager-to-orchestrator handover packet shaped like the L2 template.""" + + model_config = ConfigDict(extra="forbid") + + masterId: str + title: str + manager: str + integrationBranch: str + base: str + verdict: str + verdictOutcome: Literal["pass", "pass-with-notes"] + written: str + changeSetSummary: list[str] = Field(default_factory=list) + leavesLanded: list[str] = Field(default_factory=list) + requirementsAddressed: str + carryOverState: list[str] = Field(default_factory=list) + knownFollowUps: list[str] = Field(default_factory=list) + + +class EscalationPacket(BaseModel): + """Structured escalation that preserves the worker -> manager -> orchestrator ladder.""" + + model_config = ConfigDict(extra="forbid") + + fromRole: OrchestrationRole + toRole: OrchestrationRole | Literal["developer"] + reason: EscalationReason + subject: str + summary: str + artifactPath: str | None = None + + +def template_path(runtime_root: Path, name: str) -> Path: + """Return one orchestration template path under the runtime skill tree.""" + return runtime_root / "skills" / "l-01-agent-lifecycles" / "templates" / name + + +def turn_report_artifact(task_root: Path, leaf_id: str, title: str, runtime_root: Path) -> TurnReportArtifact: + """Build the standard worker turn-report artifact location.""" + stem = _SAFE_STEM.sub("-", leaf_id).strip("-") or "leaf" + return TurnReportArtifact( + leafId=leaf_id, + title=title, + path=str(task_root / "notes" / "reports" / f"{stem}-worker-report.md"), + templatePath=str(template_path(runtime_root, "turn-report.md")), + ) + + +def escalation_packet( + *, + from_role: OrchestrationRole, + reason: EscalationReason, + subject: str, + summary: str, + artifact_path: str | None = None, +) -> EscalationPacket: + """Route an escalation exactly one rung up the ladder.""" + return EscalationPacket( + fromRole=from_role, + toRole=_ROLE_ESCALATION[from_role], + reason=reason, + subject=subject, + summary=summary, + artifactPath=artifact_path, + ) + + +def render_master_handover_packet(packet: MasterHandoverPacket) -> str: + """Render a manager handover packet in the shape of the L2 template.""" + return "\n".join( + [ + f"# Master Handover - {packet.masterId} - {packet.title}", + "", + "| Field | Value |", + "| --- | --- |", + f"| master | {packet.masterId} |", + f"| manager | {packet.manager} |", + f"| integration branch | {packet.integrationBranch} |", + f"| base | {packet.base} |", + f"| verdict | {packet.verdict} |", + f"| verdict outcome | {packet.verdictOutcome} |", + f"| written | {packet.written} |", + "", + "## Change-Set Summary", + *[f"- {item}" for item in packet.changeSetSummary], + f"- Leaves landed: {', '.join(packet.leavesLanded) if packet.leavesLanded else 'none'}", + "", + "## Requirements / Steps Completion", + f"- All master requirements addressed: {packet.requirementsAddressed}", + "", + "## Carry-Over State (for the orchestrator's master -> super C-11)", + *[f"- {item}" for item in packet.carryOverState], + "", + "## Known Follow-Ups", + *[f"- {item}" for item in (packet.knownFollowUps or ['none'])], + "", + "## Reachability", + "- Manager seat stays reachable until the series retires.", + "", + ] + ) diff --git a/mcp/src/agents_remember/controlplane/orchestration_nudges.py b/mcp/src/agents_remember/controlplane/orchestration_nudges.py new file mode 100644 index 00000000..1e61b066 --- /dev/null +++ b/mcp/src/agents_remember/controlplane/orchestration_nudges.py @@ -0,0 +1,135 @@ +"""Rate-limited orchestration nudge records.""" + +from __future__ import annotations + +import os +from datetime import datetime +from pathlib import Path +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field + +ORCHESTRATION_NUDGE_SCHEMA = "ar-orchestration-nudge/v1" +NudgeReason = Literal["inactive", "missing-turn-report", "manual"] +NudgeState = Literal["sent", "rate-limited"] + + +class OrchestrationNudgeRecord(BaseModel): + """One durable nudge attempt keyed by target, subject, and reason.""" + + model_config = ConfigDict(extra="forbid") + + schema_version: str = Field(default=ORCHESTRATION_NUDGE_SCHEMA, alias="schema") + id: str + ts: str + state: NudgeState + reason: NudgeReason + targetAgentId: str | None = None + targetLifecycleId: str | None = None + subjectAgentId: str | None = None + subjectLifecycleId: str | None = None + artifactPath: str | None = None + message: str + + +class OrchestrationNudgeStore: + """Append-only nudge log with per-target rate limiting.""" + + def __init__(self, observer_root: Path) -> None: + self._root = observer_root + + def log_path(self) -> Path: + return self._root / "workspace" / "orchestration-nudges.jsonl" + + def read(self) -> list[OrchestrationNudgeRecord]: + path = self.log_path() + if not path.exists(): + return [] + return [ + OrchestrationNudgeRecord.model_validate_json(line) + for line in path.read_text(encoding="utf-8").splitlines() + if line.strip() + ] + + def append(self, record: OrchestrationNudgeRecord) -> None: + path = self.log_path() + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("a", encoding="utf-8") as handle: + handle.write(record.model_dump_json(by_alias=True, exclude_none=True) + "\n") + + def last_sent( + self, + *, + target_agent_id: str | None, + target_lifecycle_id: str | None, + subject_agent_id: str | None, + subject_lifecycle_id: str | None, + reason: NudgeReason, + ) -> OrchestrationNudgeRecord | None: + matches = [ + record + for record in self.read() + if record.state == "sent" + and record.reason == reason + and record.targetAgentId == target_agent_id + and record.targetLifecycleId == target_lifecycle_id + and record.subjectAgentId == subject_agent_id + and record.subjectLifecycleId == subject_lifecycle_id + ] + return max(matches, key=lambda record: record.ts, default=None) + + def record( + self, + record: OrchestrationNudgeRecord, + *, + rate_limit_seconds: int, + ) -> OrchestrationNudgeRecord: + previous = self.last_sent( + target_agent_id=record.targetAgentId, + target_lifecycle_id=record.targetLifecycleId, + subject_agent_id=record.subjectAgentId, + subject_lifecycle_id=record.subjectLifecycleId, + reason=record.reason, + ) + if previous is not None: + elapsed = _elapsed_seconds(previous.ts, record.ts) + if elapsed is not None and elapsed < rate_limit_seconds: + record = record.model_copy(update={"state": "rate-limited"}) + self.append(record) + return record + + +def nudge_message(reason: NudgeReason, *, subject: str, artifact_path: str | None = None) -> str: + """Format the stdin nudge text sent to the manager session.""" + if reason == "inactive": + return f"Nudge: {subject} appears inactive. Check the worker and record the next action." + if reason == "missing-turn-report": + suffix = f" Expected artifact: {artifact_path}." if artifact_path else "" + return f"Nudge: {subject} ended a turn without its worker turn report.{suffix}" + return f"Nudge: {subject}" + + +def missing_artifact(path: Path) -> bool: + """True when the expected turn-report artifact is absent or empty.""" + return not path.exists() or path.stat().st_size == 0 + + +def replace_records(path: Path, records: list[OrchestrationNudgeRecord]) -> None: + """Rewrite a nudge log after tests or future compaction select records to keep.""" + if not records: + path.unlink(missing_ok=True) + return + path.parent.mkdir(parents=True, exist_ok=True) + tmp = path.with_name(f"{path.name}.{os.getpid()}.tmp") + tmp.write_text( + "\n".join(record.model_dump_json(by_alias=True, exclude_none=True) for record in records) + "\n", + encoding="utf-8", + ) + os.replace(tmp, path) + + +def _elapsed_seconds(previous: str, current: str) -> float | None: + try: + return (datetime.fromisoformat(current) - datetime.fromisoformat(previous)).total_seconds() + except ValueError: + return None diff --git a/mcp/src/agents_remember/controlplane/records.py b/mcp/src/agents_remember/controlplane/records.py index b5e0c223..31c35c41 100644 --- a/mcp/src/agents_remember/controlplane/records.py +++ b/mcp/src/agents_remember/controlplane/records.py @@ -15,6 +15,7 @@ from __future__ import annotations +from collections.abc import Sequence from typing import Any, Literal, cast, get_args from pydantic import BaseModel, ConfigDict, Field @@ -30,6 +31,10 @@ "closeout-approval", "push-approval", "integration-approval", + # `master-handover-approval` is the master-exit seam gate: the manager raises it with the + # reviewer verdict attached as evidence; the orchestrator decides it on the happy path + # (delegable, never human-pinned) — human review concentrates at the super gate. + "master-handover-approval", "cleanup-approval", "agent-question", "provider-retry", @@ -50,7 +55,8 @@ # Through what surface the decision arrived -- kept separate from the actor # (``decidedBy``); "who" and "through what" never share a field, the same rule # the observer event envelope follows. -DecidedVia = Literal["chat", "dashboard", "cli"] +DecidedVia = Literal["chat", "dashboard", "cli", "orchestration"] +GateEvidenceKind = Literal["reviewer-verdict"] GATE_KINDS: tuple[GateKind, ...] = get_args(GateKind) @@ -62,6 +68,16 @@ def coerce_gate_kind(raw: str) -> GateKind: return cast(GateKind, raw) +class GateEvidenceRef(BaseModel): + """A durable external artifact reference attached to a gate snapshot.""" + + model_config = ConfigDict(extra="forbid") + + kind: GateEvidenceKind + ref: str + verdict: str | None = None + + class GateRecord(BaseModel): """One ``ar-gate-record/v1`` snapshot. @@ -87,8 +103,10 @@ class GateRecord(BaseModel): requiredDecision: list[str] | None = None decidedBy: str | None = None # actor: developer | model | system decidedVia: DecidedVia | None = None # through what surface + decidingRole: str | None = None decisionNote: str | None = None decidedAt: str | None = None + evidenceRefs: list[GateEvidenceRef] = Field(default_factory=list) # Decision verbs accepted at the tool boundary, mapped to the resulting state. @@ -110,6 +128,7 @@ def create_gate( repo_id: str | None = None, packet: dict[str, Any] | None = None, required_decision: list[str] | None = None, + evidence_refs: Sequence[GateEvidenceRef | dict[str, Any]] | None = None, ) -> GateRecord: """A freshly opened gate. Pure: the caller mints ``gate_id`` and ``now``.""" return GateRecord( @@ -122,6 +141,7 @@ def create_gate( repoId=repo_id, packet=packet or {}, requiredDecision=required_decision, + evidenceRefs=_coerce_evidence_refs(evidence_refs), ) @@ -133,6 +153,8 @@ def decide_gate( via: DecidedVia, note: str | None, now: str, + deciding_role: str | None = None, + evidence_refs: Sequence[GateEvidenceRef | dict[str, Any]] | None = None, ) -> GateRecord: """A new snapshot carrying the decision (same ``id``, new ``ts``). Pure. @@ -140,14 +162,17 @@ def decide_gate( ``KeyError`` here (the tool boundary validates first for a clean message). """ state = DECISION_STATES[decision] + attached_evidence = [*gate.evidenceRefs, *_coerce_evidence_refs(evidence_refs)] return gate.model_copy( update={ "ts": now, "state": state, "decidedBy": by, "decidedVia": via, + "decidingRole": deciding_role, "decisionNote": note, "decidedAt": now, + "evidenceRefs": attached_evidence, } ) @@ -167,3 +192,14 @@ def apply_gate(gate: GateRecord, *, now: str) -> GateRecord: forward unchanged -- only ``state`` and ``ts`` advance. """ return gate.model_copy(update={"ts": now, "state": "applied"}) + + +def _coerce_evidence_refs( + evidence_refs: Sequence[GateEvidenceRef | dict[str, Any]] | None, +) -> list[GateEvidenceRef]: + if evidence_refs is None: + return [] + return [ + ref if isinstance(ref, GateEvidenceRef) else GateEvidenceRef.model_validate(ref) + for ref in evidence_refs + ] diff --git a/mcp/src/agents_remember/controlplane/store.py b/mcp/src/agents_remember/controlplane/store.py index 8ee35dac..bbee4a62 100644 --- a/mcp/src/agents_remember/controlplane/store.py +++ b/mcp/src/agents_remember/controlplane/store.py @@ -54,6 +54,25 @@ def read(self, lifecycle_id: str | None) -> list[GateRecord]: if line.strip() ] + def find(self, gate_id: str) -> GateRecord | None: + """Resolve one gate id across the workspace log and every lifecycle log. + + The seam-decide path: a deciding seat holds only the gate id (packet-carried); + lifecycle ids stay server-side. Last-wins fold per log, first hit returned + (gate ids are ULIDs — collisions across logs do not occur in practice). + """ + hit = self.current(None).get(gate_id) + if hit is not None: + return hit + lifecycles_dir = self._root / "lifecycles" + if not lifecycles_dir.is_dir(): + return None + for log in sorted(lifecycles_dir.glob("*/gates.jsonl")): + hit = self.current(log.parent.name).get(gate_id) + if hit is not None: + return hit + return None + def current(self, lifecycle_id: str | None) -> dict[str, GateRecord]: """Fold the log by gate id, last-wins -- the live gate set.""" latest: dict[str, GateRecord] = {} @@ -61,6 +80,22 @@ def current(self, lifecycle_id: str | None) -> dict[str, GateRecord]: latest[record.id] = record return latest + def all_current(self) -> dict[str, GateRecord]: + """Fold every gate log (workspace + all lifecycles), last-wins per gate id. + + The cross-lifecycle enforcement fold: a seam gate lives on its raiser's + lifecycle while the consuming contract anchors a different one (e.g. the + manager-raised ``master-handover-approval`` consumed by the orchestrator's + integration), so identity-addressed consumers need the whole workspace + view. A gate's snapshots all live in one log (``append`` routes by + ``record.lifecycleId``) and gate ids are ULIDs, so cross-log collisions do + not occur in practice; within one log the fold stays last-wins. + """ + latest: dict[str, GateRecord] = {} + for lifecycle_id in self.lifecycle_ids(): + latest.update(self.current(lifecycle_id)) + return latest + def delete(self, gate_id: str, lifecycle_id: str | None) -> bool: """Physically remove one gate id from its log.""" records = self.read(lifecycle_id) diff --git a/mcp/src/agents_remember/install/runtime.py b/mcp/src/agents_remember/install/runtime.py index 2a7cdaf0..3f799ff7 100644 --- a/mcp/src/agents_remember/install/runtime.py +++ b/mcp/src/agents_remember/install/runtime.py @@ -20,6 +20,10 @@ stop_provider_watchers_before_refresh, write_temp_provider_settings, ) +from agents_remember.kernel.agentic_settings import ( + agentic_settings_path, + default_agentic_settings_seed_text, +) from agents_remember.mcp.config import DEFAULT_PROVIDER_SETUP_SECONDS, McpRuntimeConfig from agents_remember.providers import lifecycle from agents_remember.providers.settings import lifecycle_settings_from_config @@ -101,6 +105,27 @@ def ensure_dir(path: Path, summary: InstallSummary, dry_run: bool) -> None: summary.created_dirs += 1 +def seed_agentic_settings( + coordination_root: Path, summary: InstallSummary, dry_run: bool +) -> None: + """Seed the GLOBAL agentic settings file, copy-if-missing (260703-L13). + + ``/system/settings.json`` is user-owned coordinator state + (like ``memory-repos/``): an existing file is NEVER touched, whatever it + contains -- the c-13 install interview and the developer own its content. + A missing file gets the documented defaults + (:func:`agents_remember.kernel.agentic_settings.default_agentic_settings_seed`). + """ + target = agentic_settings_path(coordination_root) + if target.exists(): + summary.unchanged_files += 1 + return + ensure_dir(target.parent, summary, dry_run) + if not dry_run: + target.write_text(default_agentic_settings_seed_text(), encoding="utf-8") + summary.copied_files += 1 + + def copy_file(source: Path, destination: Path, summary: InstallSummary, dry_run: bool) -> None: if destination.is_symlink(): if not dry_run: @@ -487,6 +512,10 @@ def install_runtime( ): ensure_dir(coordination_root / user_owned, summary, dry_run) + # The global agentic settings file rides the same user-owned posture: + # seeded once with the documented defaults, never clobbered. + seed_agentic_settings(coordination_root, summary, dry_run) + if include_benchmarks: install_benchmarks(source_root, coordination_root, summary, dry_run) diff --git a/mcp/src/agents_remember/kernel/agentic_settings.py b/mcp/src/agents_remember/kernel/agentic_settings.py new file mode 100644 index 00000000..7b0dddbe --- /dev/null +++ b/mcp/src/agents_remember/kernel/agentic_settings.py @@ -0,0 +1,988 @@ +"""Two-layer AGENTIC settings loader (260703-L13 settings unification). + +The agentic settings family -- everything under the top-level ``orchestration`` +key: gate delegation, the three-party-loop knobs, per-role knob overrides, +concurrency caps, the spawn harness preference, and the harness-definition +extension/override table (``orchestration.harnesses``, 260703-L16) -- lives in +TWO JSON files that are merged on every read: + +- GLOBAL: ``/system/settings.json`` +- LOCAL: ``/system/settings.json`` (optional; merged OVER global) + +Semantics (``docs/reference/settings-json.md`` is the schema reference): + +- Deep merge at leaf-key granularity: a local scalar or object leaf overrides + the global one; arrays REPLACE (never concatenate). +- Unknown keys anywhere inside the ``orchestration.*`` family FAIL LOUD naming + the offending file -- the MCP-authority-file discipline, extended. This also + fixes the historic silent drop of ``orchestration.roles``/``concurrency``. +- Unknown TOP-LEVEL families are tolerated-not-parsed: the same coordinator + file doubles as the c-08 memory-settings fallback, and it is the earmarked + future home of further families (``contextProviders`` first in line, gate + amendment 2026-07-06), so the fail-loud scope must not foreclose them. +- Absent files (or an absent ``orchestration`` key) mean the documented + defaults: all-human gate delegation, the L12 loop defaults, no role + overrides, no concurrency caps, no spawn harness preference. +- Read PER-USE: consumers call :func:`load_agentic_settings` at each use so a + settings edit takes effect on the next use without a server restart. The ONE + boot-snapshot consumer is ``mcp/config.py``'s ``gateDelegation`` (enforcement + plumbing keeps its boot-cached shape; a change needs a restart -- documented). + +Doctrine floors are NOT knobs: no key here touches the master-exit seam gate or +the strategist's mandatory pre-run (L12 ruling; restated in the schema doc). +""" + +from __future__ import annotations + +import json +import string +from dataclasses import dataclass, field, replace +from pathlib import Path +from typing import Any + +from agents_remember.controlplane.gate_policy import ( + DEFAULT_GATE_POLICY, + GatePolicy, + GatePolicyRule, + apply_seam_verdict_requirement, + coerce_decision_role, + make_gate_policy, + named_gate_policy, +) +from agents_remember.controlplane.records import GateKind, coerce_gate_kind +from agents_remember.errors import AgentsRememberError +from agents_remember.serving.harnesses import HARNESSES, Harness + + +class AgenticSettingsError(AgentsRememberError): + """Raised when an agentic settings file is malformed or carries unknown ``orchestration.*`` keys.""" + + +# The fail-loud key families. Every set names the complete schema of its level; +# anything else raises AgenticSettingsError with the offending file's path. +KNOWN_ORCHESTRATION_FIELDS = frozenset( + { + "gateDelegation", + "loops", + "roles", + "rolesPerLevel", + "concurrency", + "spawn", + "harnesses", + } +) +# One ``orchestration.harnesses.`` entry (260703-L16): define a NEW harness or override a +# builtin's defaults. Schema + worked example: ``docs/reference/harnesses.md`` (THE manual). +KNOWN_HARNESS_ENTRY_FIELDS = frozenset( + { + "name", + "command", + "argv", + "modelFlag", + "effortFlag", + "effortFlagValues", + "effortSessionValues", + "effortSessionCommand", + } +) +KNOWN_GATE_DELEGATION_FIELDS = frozenset({"policy", "kinds", "requireReviewerVerdictAtSeams"}) +KNOWN_GATE_POLICY_KIND_FIELDS = frozenset({"role", "requireReviewerVerdict"}) +KNOWN_LOOPS_FIELDS = frozenset({"defaults", "perLevel", "perMaster"}) +KNOWN_LOOP_DEFAULTS_FIELDS = frozenset({"maxRounds", "reviewerReuse", "complexity"}) +KNOWN_LOOP_COMPLEXITY_FIELDS = frozenset({"fullLoopAt", "builderAt"}) +KNOWN_LOOP_LEVELS = frozenset({"leaf", "master", "portfolio"}) +KNOWN_LOOP_LEVEL_FIELDS = frozenset({"loop"}) +# The dispatch-time complexity scale (blast radius x novelty x size) the loop +# thresholds are expressed on (l-01 The Three-Party Loop). +COMPLEXITY_SCALE = ("low", "medium", "high") +# The six portable role lifecycles the l-01 registry defines. +KNOWN_ROLES = frozenset({"orchestrator", "designer", "strategist", "manager", "worker", "reviewer"}) +KNOWN_ROLE_KNOB_FIELDS = frozenset( + {"harness", "model", "effort", "launchArgs", "promptKeywords", "sessionCommands"} +) +KNOWN_CONCURRENCY_FIELDS = frozenset({"maxParallelMasters", "maxParallelLeaves", "maxSubAgents"}) +KNOWN_SPAWN_FIELDS = frozenset({"harness"}) + +# The BUILTIN registry ids (claude|codex|pi). Harness references (roles..harness, +# spawn.harness) are validated against the EFFECTIVE id set -- these plus any +# orchestration.harnesses-defined ids -- so a settings value can never inject argv through a +# reference; argv is definable only through the explicit harnesses family (260703-L16). +HARNESS_IDS = tuple(harness.id for harness in HARNESSES) + +# The L12 loop defaults (docs/reference/settings-json.md, Orchestration Loops). +DEFAULT_LOOP_MAX_ROUNDS = 3 +DEFAULT_REVIEWER_REUSE = "delta-verify" +DEFAULT_LOOP_PER_LEVEL: dict[str, str] = { + "leaf": "scored", + "master": "seam-required", + "portfolio": "strategist", +} + + +@dataclass(frozen=True) +class LoopComplexity: + """The complexity thresholds mapping the dispatch-time score to loop tiers.""" + + full_loop_at: str = "high" + builder_at: str = "medium" + + +@dataclass(frozen=True) +class LoopDefaults: + """``orchestration.loops.defaults`` -- round cap, reviewer reuse, tier thresholds.""" + + max_rounds: int = DEFAULT_LOOP_MAX_ROUNDS + reviewer_reuse: str = DEFAULT_REVIEWER_REUSE + complexity: LoopComplexity = field(default_factory=LoopComplexity) + + +@dataclass(frozen=True) +class LoopSettings: + """``orchestration.loops`` -- the three-party-loop knobs (L12 schema). + + ``per_level`` maps level -> loop posture (loop postures are model-interpreted + doctrine names, validated as non-empty strings, not a closed set); + ``per_master`` maps a master task name -> sparse per-level overrides. + The knobs govern the LOOP only: the master-exit SEAM gate is unconditional. + """ + + defaults: LoopDefaults = field(default_factory=LoopDefaults) + per_level: dict[str, str] = field(default_factory=lambda: dict(DEFAULT_LOOP_PER_LEVEL)) + per_master: dict[str, dict[str, str]] = field(default_factory=dict) + + +@dataclass(frozen=True) +class RoleKnobs: + """One role's knob overrides (``orchestration.roles.``); ``None`` = role-file default. + + ``harness`` must be a registry id; ``model``/``effort`` are free strings HERE -- the per-harness + effort vocabulary is enforced at DISPATCH time by the spawn path (the harness is only known + then), refusing loudly instead of letting the CLI warn-and-silently-degrade (260703-L16). The + free-form escape hatch (``launch_args``/``prompt_keywords``/``session_commands``, JSON keys + ``launchArgs``/``promptKeywords``/``sessionCommands``) is shape-checked only (a list of + non-empty strings) and NEVER content-validated; the spawn path records it in spawn provenance. + Empty tuple = not configured. + """ + + harness: str | None = None + model: str | None = None + effort: str | None = None + launch_args: tuple[str, ...] = () + prompt_keywords: tuple[str, ...] = () + session_commands: tuple[str, ...] = () + + +@dataclass(frozen=True) +class ConcurrencySettings: + """``orchestration.concurrency`` caps; ``None`` = uncapped (the default).""" + + max_parallel_masters: int | None = None + max_parallel_leaves: int | None = None + max_sub_agents: int | None = None + + +@dataclass(frozen=True) +class AgenticSettings: + """The merged, typed agentic settings for one read (global <- local).""" + + gate_policy: GatePolicy = DEFAULT_GATE_POLICY + require_reviewer_verdict_at_seams: bool = False + # Whether a settings file (not the default) set gateDelegation -- the + # boot-snapshot consumer uses this to decide legacy-fallback handling. + gate_delegation_configured: bool = False + loops: LoopSettings = field(default_factory=LoopSettings) + roles: dict[str, RoleKnobs] = field(default_factory=dict) + # 260703-L16 (ruling 2026-07-07T08:15): per-LEVEL role-knob overrides -- the L12 doctrine's + # per-level agent sets, expressible at last. ``roles`` stays the flat DEFAULTS; each + # ``roles_per_level[level][role]`` deep-merges over the flat default at leaf-key granularity + # (see :meth:`resolved_role_knobs`). Level vocabulary matches ``loops.perLevel``. + roles_per_level: dict[str, dict[str, RoleKnobs]] = field(default_factory=dict) + concurrency: ConcurrencySettings = field(default_factory=ConcurrencySettings) + spawn_harness: str | None = None + # The EFFECTIVE harness registry (260703-L16): the builtin defaults merged with the + # ``orchestration.harnesses`` family -- new ids added, builtin ids possibly pre-customized. + # The spawn path resolves harness ids against THIS set, never the builtin table directly. + harnesses: tuple[Harness, ...] = HARNESSES + # The settings files that existed and were merged, global first. + sources: tuple[Path, ...] = () + + def role_knobs(self, role: str) -> RoleKnobs: + return self.roles.get(role, RoleKnobs()) + + def resolved_role_knobs(self, role: str, level: str = "leaf") -> RoleKnobs: + """The effective knobs for ``role`` dispatched at ``level`` (260703-L16). + + The per-level override deep-merges over the flat role default at leaf-key granularity: an + unset override field inherits the default (harness inherited unless overridden), a set one + replaces it (the free-form lists REPLACE, never concatenate -- the array rule). Because + both families were already merged local-over-global per file layer, this realizes the full + dispatch chain: repo-local level override > global level override > repo-local role + default > global role default. + """ + base = self.roles.get(role, RoleKnobs()) + override = self.roles_per_level.get(level, {}).get(role) + if override is None: + return base + return RoleKnobs( + harness=override.harness or base.harness, + model=override.model or base.model, + effort=override.effort or base.effort, + launch_args=override.launch_args or base.launch_args, + prompt_keywords=override.prompt_keywords or base.prompt_keywords, + session_commands=override.session_commands or base.session_commands, + ) + + def find_harness(self, harness_id: str) -> Harness | None: + """The effective :class:`Harness` for ``harness_id`` (builtin merged with settings).""" + return next((harness for harness in self.harnesses if harness.id == harness_id), None) + + +def agentic_settings_path(root: Path) -> Path: + """The agentic settings file under ``root`` (coordination root or code repo).""" + return root / "system" / "settings.json" + + +def default_agentic_settings_seed() -> dict[str, Any]: + """The seeded global-file content: every agentic knob at its documented default. + + ``runtime_install`` writes this copy-if-missing; the c-13 install interview + then edits it with the developer. No spawn harness preference is seeded -- + the spawn seam stays detection-gated until a preference is configured. + """ + return { + "$comment": ( + "Agentic orchestration settings (GLOBAL layer). Schema: agents-remember " + "docs/reference/settings-json.md (Agentic Settings). Repo-local overrides: " + "/system/settings.json. Unknown orchestration.* keys fail loud." + ), + "version": 1, + "orchestration": { + "gateDelegation": {"policy": "all-human"}, + "loops": { + "defaults": { + "maxRounds": DEFAULT_LOOP_MAX_ROUNDS, + "reviewerReuse": DEFAULT_REVIEWER_REUSE, + "complexity": {"fullLoopAt": "high", "builderAt": "medium"}, + }, + "perLevel": { + level: {"loop": posture} for level, posture in DEFAULT_LOOP_PER_LEVEL.items() + }, + }, + }, + } + + +def default_agentic_settings_seed_text() -> str: + return json.dumps(default_agentic_settings_seed(), indent=2) + "\n" + + +def load_agentic_settings( + coordination_root: Path, + repo_root: Path | None = None, +) -> AgenticSettings: + """Read + merge the global (and optional repo-local) agentic settings, per use. + + Each present file's ``orchestration`` block is validated individually first + so key/type errors name the offending file; the merged block is then parsed + into the typed models. Absent files contribute nothing (defaults apply). + """ + layers: list[tuple[Path, dict[str, Any]]] = [] + for layer, root in (("global", coordination_root), ("local", repo_root)): + if root is None: + continue + path = agentic_settings_path(root) + data = _read_settings_file(path) + if data is None: + continue + orchestration = _validated_orchestration_block(data, path) + if layer == "local" and "gateDelegation" in orchestration: + # Gate posture is workspace-wide enforcement state: the boot snapshot + # reads the GLOBAL file only, so a repo-local value would validate and + # then silently do nothing -- a fail-open shape. Refuse it loudly. + raise AgenticSettingsError( + "orchestration.gateDelegation is global-layer only (the boot " + "snapshot reads the coordination file); remove it from the " + f"repo-local settings: {path}" + ) + layers.append((path, orchestration)) + + merged: dict[str, Any] = {} + for _, orchestration in layers: + merged = merge_settings(merged, orchestration) + sources = tuple(path for path, _ in layers) + source = _source_label(sources) + return _parse_orchestration(merged, source=source, sources=sources) + + +def merge_settings(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]: + """Deep merge at leaf-key granularity: object leaves recurse, everything else + (scalars AND arrays) is REPLACED by the override.""" + merged = dict(base) + for key, value in override.items(): + prior = merged.get(key) + if isinstance(prior, dict) and isinstance(value, dict): + merged[key] = merge_settings(prior, value) + else: + merged[key] = value + return merged + + +def _read_settings_file(path: Path) -> dict[str, Any] | None: + if not path.exists(): + return None + try: + data = json.loads(path.read_text(encoding="utf-8")) + except json.JSONDecodeError as error: + raise AgenticSettingsError( + f"cannot parse agentic settings JSON: {path}: {error}" + ) from error + if not isinstance(data, dict): + raise AgenticSettingsError(f"agentic settings must be a JSON object: {path}") + return data + + +def _validated_orchestration_block(data: dict[str, Any], path: Path) -> dict[str, Any]: + """One file's ``orchestration`` block, fully validated so errors name ``path``. + + Top-level keys other than ``orchestration`` are tolerated-not-parsed (other + families own them -- see the module docstring). + """ + raw = data.get("orchestration") + if raw is None: + return {} + source = str(path) + if not isinstance(raw, dict): + raise AgenticSettingsError(f"orchestration settings must be an object: {source}") + _refuse_null_families(raw, source) + # strict=False: one LAYER may legitimately be partial (a repo-local file overriding a single + # leaf of a globally-defined harness entry, or referencing a harness id the OTHER layer + # declares), so per-file validation checks shapes/keys only; cross-reference and completeness + # rules run on the MERGED block in load_agentic_settings. + _parse_orchestration(raw, source=source, sources=(path,), strict=False) + return raw + + +def _refuse_null_families(raw: dict[str, Any], source: str) -> None: + """A JSON ``null`` at a known ``orchestration`` family key is REFUSED (260703-L18 finding 6, + developer-ruled ``null`` = refuse, not reset-to-default). + + ``None`` reads as *absent* to every family parser, and ``merge_settings`` REPLACES (never + deep-merges) a non-dict override -- so ``"concurrency": null`` in the repo-local layer would + SILENTLY wipe the global caps, ``"roles": null`` -> ``{}``, ``"loops": null`` -> the defaults. + It was the one scalar collision that did not fail loud, violating both documented invariants + (deep-merge + fail-loud). Refuse it in EITHER layer, naming the offending file; ``gateDelegation`` + keeps its own stronger repo-local presence refusal (checked after this in ``load_agentic_settings``). + The fix the guidance names: remove the key (absence inherits the global value) or give it a real + object.""" + null_families = sorted(key for key in KNOWN_ORCHESTRATION_FIELDS if raw.get(key) is None and key in raw) + if null_families: + offending = ", ".join(f"orchestration.{key}" for key in null_families) + raise AgenticSettingsError( + f"{offending} is null; a null at a known orchestration family key is refused because it " + f"would silently wipe the merged value. Remove the key to inherit the global value: {source}" + ) + + +def _source_label(sources: tuple[Path, ...]) -> str: + if not sources: + return "agentic settings defaults (no settings file present)" + return " merged with ".join(str(path) for path in sources) + + +def _refuse_unknown(raw: dict[str, Any], known: frozenset[str], owner: str, source: str) -> None: + unknown = sorted(set(raw) - known) + if unknown: + unknown_text = ", ".join(unknown) + allowed = ", ".join(sorted(known)) + raise AgenticSettingsError( + f"unsupported {owner} setting(s): {unknown_text}; allowed: {allowed}; " + f"offending file: {source}" + ) + + +def _require_object(raw: object, owner: str, source: str) -> dict[str, Any]: + if not isinstance(raw, dict): + raise AgenticSettingsError(f"{owner} must be an object: {source}") + return raw + + +def _require_string(raw: object, owner: str, source: str) -> str: + if not isinstance(raw, str) or not raw: + raise AgenticSettingsError(f"{owner} must be a non-empty string: {source}") + return raw + + +def _require_positive_int(raw: object, owner: str, source: str) -> int: + if isinstance(raw, bool) or not isinstance(raw, int) or raw < 1: + raise AgenticSettingsError(f"{owner} must be a positive integer: {source}") + return raw + + +def _require_string_list(raw: object, owner: str, source: str) -> tuple[str, ...]: + """A free-form list of non-empty strings (shape-checked only; content never validated). + + An EMPTY list is refused (PR #100 review, Codex P2): ``RoleKnobs`` cannot distinguish + "absent" from "explicitly cleared" (empty tuple = not configured), so a per-level ``[]`` + meant to clear a flat default would silently INHERIT it instead — the same silent-degrade + shape as a ``null`` family key (260703-L18 finding 6). Omit the key to inherit; list + values to override. + """ + if not isinstance(raw, list): + raise AgenticSettingsError(f"{owner} must be a list of non-empty strings: {source}") + if not raw: + raise AgenticSettingsError( + f"{owner} must not be an empty list (omit the key to inherit, or list the values " + f"to override): {source}" + ) + values: list[str] = [] + for item in raw: + if not isinstance(item, str) or not item: + raise AgenticSettingsError(f"{owner} must be a list of non-empty strings: {source}") + values.append(item) + return tuple(values) + + +def _require_harness_id( + raw: object, owner: str, source: str, harness_ids: tuple[str, ...] | None +) -> str: + """A harness reference: shape-checked always, membership-checked against the EFFECTIVE id set. + + ``harness_ids`` is the effective registry (builtin merged with ``orchestration.harnesses``); + ``None`` skips membership -- the per-file (non-strict) pass, where the other layer may declare + the id. + """ + value = _require_string(raw, owner, source) + if harness_ids is not None and value not in harness_ids: + allowed = ", ".join(harness_ids) + raise AgenticSettingsError( + f"{owner} must be a harness registry id or an orchestration.harnesses-defined id " + f"({allowed}), got {value!r}: {source} (see docs/reference/harnesses.md)" + ) + return value + + +def _parse_orchestration( + raw: dict[str, Any], + *, + source: str, + sources: tuple[Path, ...], + strict: bool = True, +) -> AgenticSettings: + """Parse one ``orchestration`` block into the typed settings. + + ``strict=True`` (the merged block) additionally enforces the cross-layer rules: harness-entry + completeness (a NEW id must resolve a command; declared vocabularies must resolve their + delivery vehicle) and harness-id membership for ``roles..harness``/``spawn.harness`` + against the EFFECTIVE registry. The per-file pass runs ``strict=False`` (shapes + unknown keys + only) because a single layer may be a partial override of the other. + """ + _refuse_unknown(raw, KNOWN_ORCHESTRATION_FIELDS, "orchestration", source) + harnesses = _parse_harnesses(raw.get("harnesses"), source=source, strict=strict) + harness_ids = tuple(harness.id for harness in harnesses) if strict else None + gate_raw = raw.get("gateDelegation") + gate_policy, at_seams = parse_gate_delegation(gate_raw, source=source) + return AgenticSettings( + gate_policy=gate_policy, + require_reviewer_verdict_at_seams=at_seams, + gate_delegation_configured=gate_raw is not None, + loops=_parse_loops(raw.get("loops"), source=source), + roles=_parse_roles(raw.get("roles"), source=source, harness_ids=harness_ids), + roles_per_level=_parse_roles_per_level( + raw.get("rolesPerLevel"), source=source, harness_ids=harness_ids + ), + concurrency=_parse_concurrency(raw.get("concurrency"), source=source), + spawn_harness=_parse_spawn(raw.get("spawn"), source=source, harness_ids=harness_ids), + harnesses=harnesses, + sources=sources, + ) + + +def _parse_harnesses(raw: object, *, source: str, strict: bool) -> tuple[Harness, ...]: + """``orchestration.harnesses`` (260703-L16): the effective registry, builtin merged with settings. + + Entries merge over the builtin table BY ID: a new id ADDS a harness (it must resolve a + ``command`` and/or ``argv``; ``command`` defaults to ``argv[0]``, ``argv`` to ``(command,)``); + a builtin id OVERRIDES the curated defaults per field (its ``argv`` array REPLACES ours -- the + user launches the harness exactly the way they would run it themselves). Vocabulary fields come + in delivery-vehicle pairs and must resolve together post-merge: ``effortFlag`` with + ``effortFlagValues``, ``effortSessionValues`` with ``effortSessionCommand``. Detection still + applies downstream (the command is probed on PATH at dispatch). ``strict=False`` checks shapes + and unknown keys only (a single layer may be partial); the merged pass enforces completeness. + """ + if raw is None: + return HARNESSES + block = _require_object(raw, "orchestration.harnesses", source) + effective: dict[str, Harness] = {harness.id: harness for harness in HARNESSES} + order: list[str] = [harness.id for harness in HARNESSES] + for harness_id, value in block.items(): + if not isinstance(harness_id, str) or not harness_id: + raise AgenticSettingsError( + f"orchestration.harnesses keys must be non-empty harness ids: {source}" + ) + parsed = _parse_harness_entry(harness_id, value, source) + if not strict: + continue + base = effective.get(harness_id) + merged = _merged_harness(harness_id, parsed, base, source) + if base is None: + order.append(harness_id) + effective[harness_id] = merged + if not strict: + return HARNESSES + return tuple(effective[harness_id] for harness_id in order) + + +@dataclass(frozen=True) +class _HarnessEntry: + """One raw ``orchestration.harnesses.`` entry, shape-validated; ``None`` = not declared.""" + + name: str | None + command: str | None + argv: tuple[str, ...] | None + model_flag: str | None + effort_flag: str | None + effort_flag_values: tuple[str, ...] | None + effort_session_values: tuple[str, ...] | None + effort_session_command: str | None + + +def _entry_string(entry: dict[str, Any], key: str, owner: str, source: str) -> str | None: + if key not in entry: + return None + return _require_string(entry[key], f"{owner}.{key}", source) + + +def _entry_string_list( + entry: dict[str, Any], key: str, owner: str, source: str +) -> tuple[str, ...] | None: + if key not in entry: + return None + return _require_string_list(entry[key], f"{owner}.{key}", source) + + +def _parse_harness_entry(harness_id: str, value: object, source: str) -> _HarnessEntry: + """Shape-validate one harness entry (both passes run this; errors name the owner + file).""" + owner = f"orchestration.harnesses.{harness_id}" + entry = _require_object(value, owner, source) + _refuse_unknown(entry, KNOWN_HARNESS_ENTRY_FIELDS, owner, source) + argv = _entry_string_list(entry, "argv", owner, source) + if argv is not None and not argv: + raise AgenticSettingsError(f"{owner}.argv must be a non-empty command array: {source}") + return _HarnessEntry( + name=_entry_string(entry, "name", owner, source), + command=_entry_string(entry, "command", owner, source), + argv=argv, + model_flag=_entry_string(entry, "modelFlag", owner, source), + effort_flag=_entry_string(entry, "effortFlag", owner, source), + effort_flag_values=_entry_string_list(entry, "effortFlagValues", owner, source), + effort_session_values=_entry_string_list(entry, "effortSessionValues", owner, source), + effort_session_command=_entry_string(entry, "effortSessionCommand", owner, source), + ) + + +def _resolved_launch( + parsed: _HarnessEntry, base: Harness | None, owner: str, source: str +) -> tuple[str, tuple[str, ...]]: + """The merged ``(command, argv)``: entry over builtin, each derivable from the other.""" + if base is None and parsed.command is None and parsed.argv is None: + raise AgenticSettingsError( + f"{owner} defines a new harness and must declare command and/or argv " + f"(see docs/reference/harnesses.md): {source}" + ) + argv = parsed.argv if parsed.argv is not None else (base.argv if base else None) + command = parsed.command if parsed.command is not None else (base.command if base else None) + if command is None and argv is not None: + command = argv[0] + if argv is None and command is not None: + argv = (command,) + assert command is not None and argv is not None + return command, argv + + +def _merged_harness( + harness_id: str, parsed: _HarnessEntry, base: Harness | None, source: str +) -> Harness: + """One effective harness: the entry's declared fields over the builtin defaults (or fresh).""" + owner = f"orchestration.harnesses.{harness_id}" + command, argv = _resolved_launch(parsed, base, owner, source) + fallback = ( + base + if base is not None + else Harness( + id=harness_id, name=harness_id, command=command, argv=argv, defined_in="settings" + ) + ) + overrides: dict[str, Any] = {"command": command, "argv": argv} + declared = { + "name": parsed.name, + "model_flag": parsed.model_flag, + "effort_flag": parsed.effort_flag, + "effort_flag_values": parsed.effort_flag_values, + "effort_session_values": parsed.effort_session_values, + "effort_session_command": parsed.effort_session_command, + } + for field_name, declared_value in declared.items(): + if declared_value is not None: + overrides[field_name] = declared_value + merged = replace(fallback, **overrides) + _refuse_unpaired_vehicles(merged, owner, source) + _refuse_bad_effort_template(merged, owner, source) + return merged + + +def _refuse_unpaired_vehicles(merged: Harness, owner: str, source: str) -> None: + """Post-merge pair rules: every declared vocabulary must resolve its delivery vehicle.""" + if bool(merged.effort_flag) != bool(merged.effort_flag_values): + raise AgenticSettingsError( + f"{owner}: effortFlag and effortFlagValues must be declared together " + f"(a flag without a vocabulary reintroduces the silent-degrade risk): {source}" + ) + if bool(merged.effort_session_values) != bool(merged.effort_session_command): + raise AgenticSettingsError( + f"{owner}: effortSessionValues and effortSessionCommand must be declared " + f"together (session values need their delivery command): {source}" + ) + + +def _refuse_bad_effort_template(merged: Harness, owner: str, source: str) -> None: + """The ``effortSessionCommand`` template must render with ONLY ``{value}`` (260703-L18 finding 4). + + ``serving.harnesses.effort_session_commands`` renders it via ``.format(value=…)`` at spawn; a stray + replacement field (``/set {mode}={value}``), a positional ``{}``, or an unmatched brace raises a + RAW ``KeyError``/``ValueError``/``IndexError`` there instead of the structured refusal every other + bad knob gets. A builtin override may supply JUST the command (merged over the builtin's session + values), so the check lives post-merge next to the pairing rule -- once validated here, the raw + error at ``serving/harnesses.py`` is unreachable from settings. Only checked when a template is + present (an absent one has already passed the pairing rule).""" + template = merged.effort_session_command + if template is None: + return + try: + field_names = [name for _, name, _, _ in string.Formatter().parse(template)] + except ValueError as error: # an unmatched / stray brace: not a parseable format template + raise AgenticSettingsError( + f"{owner}: effortSessionCommand {template!r} is not a valid format template " + f"({error}); it may contain no replacement field other than {{value}}: {source}" + ) from error + unexpected = sorted({name for name in field_names if name is not None and name != "value"}) + if unexpected: + shown = ", ".join(repr(name) for name in unexpected) + raise AgenticSettingsError( + f"{owner}: effortSessionCommand {template!r} may reference only the {{value}} field; " + f"unexpected replacement field(s): {shown}: {source}" + ) + try: + template.format(value="probe") + except (KeyError, IndexError, ValueError) as error: + raise AgenticSettingsError( + f"{owner}: effortSessionCommand {template!r} failed to render with value=… " + f"({error!r}): {source}" + ) from error + + +def parse_gate_delegation(raw: object, *, source: str) -> tuple[GatePolicy, bool]: + """Parse ``orchestration.gateDelegation`` into ``(policy, requireReviewerVerdictAtSeams)``. + + Shared by the agentic loader (the key's home) and ``mcp/config.py``'s + one-cycle legacy authority-file fallback. ``None`` means the all-human + default. Errors name ``source`` (the offending file). + """ + if raw is None: + return DEFAULT_GATE_POLICY, False + delegation = _require_object(raw, "orchestration.gateDelegation", source) + _refuse_unknown( + delegation, + KNOWN_GATE_DELEGATION_FIELDS, + "orchestration.gateDelegation", + source, + ) + policy_name = delegation.get("policy", "all-human") + policy_name = _require_string(policy_name, "orchestration.gateDelegation.policy", source) + try: + policy = named_gate_policy(policy_name) + except ValueError as error: + raise AgenticSettingsError(f"{error}; offending file: {source}") from error + require_verdict_at_seams = delegation.get("requireReviewerVerdictAtSeams", False) + if not isinstance(require_verdict_at_seams, bool): + raise AgenticSettingsError( + "orchestration.gateDelegation.requireReviewerVerdictAtSeams must be a " + f"boolean: {source}" + ) + kinds = _require_object( + delegation.get("kinds", {}), "orchestration.gateDelegation.kinds", source + ) + rules = {rule.kind: rule for rule in policy.rules} + for raw_kind, raw_rule in kinds.items(): + if not isinstance(raw_kind, str) or not raw_kind: + raise AgenticSettingsError( + f"gate policy kind names must be non-empty strings: {source}" + ) + try: + kind = coerce_gate_kind(raw_kind) + rules[kind] = _parse_gate_policy_rule( + kind, raw_rule, prior=rules.get(kind), source=source + ) + except AgenticSettingsError: + raise + except ValueError as error: + raise AgenticSettingsError(f"{error}; offending file: {source}") from error + try: + policy = make_gate_policy(list(rules.values())) + except ValueError as error: + raise AgenticSettingsError(f"{error}; offending file: {source}") from error + if require_verdict_at_seams: + policy = apply_seam_verdict_requirement(policy) + return policy, require_verdict_at_seams + + +def _parse_gate_policy_rule( + kind: GateKind, + raw_rule: object, + *, + prior: GatePolicyRule | None, + source: str, +) -> GatePolicyRule: + if isinstance(raw_rule, str): + return GatePolicyRule(kind=kind, delegated_role=coerce_decision_role(raw_rule)) + rule = _require_object(raw_rule, f"orchestration.gateDelegation.kinds.{kind}", source) + _refuse_unknown( + rule, + KNOWN_GATE_POLICY_KIND_FIELDS, + f"orchestration.gateDelegation.kinds.{kind}", + source, + ) + role_raw = rule.get("role") + delegated_role = prior.delegated_role if prior is not None else None + if role_raw is not None: + role_value = _require_string( + role_raw, f"orchestration.gateDelegation.kinds.{kind}.role", source + ) + delegated_role = coerce_decision_role(role_value) + require_verdict = rule.get( + "requireReviewerVerdict", + prior.require_reviewer_verdict if prior is not None else False, + ) + if not isinstance(require_verdict, bool): + raise AgenticSettingsError( + f"orchestration.gateDelegation.kinds.{kind}.requireReviewerVerdict " + f"must be a boolean: {source}" + ) + return GatePolicyRule( + kind=kind, + delegated_role=delegated_role, + require_reviewer_verdict=require_verdict, + ) + + +def _parse_loops(raw: object, *, source: str) -> LoopSettings: + if raw is None: + return LoopSettings() + loops = _require_object(raw, "orchestration.loops", source) + _refuse_unknown(loops, KNOWN_LOOPS_FIELDS, "orchestration.loops", source) + defaults = _parse_loop_defaults(loops.get("defaults"), source=source) + per_level = dict(DEFAULT_LOOP_PER_LEVEL) + per_level.update( + _parse_loop_levels( + loops.get("perLevel"), owner="orchestration.loops.perLevel", source=source + ) + ) + per_master: dict[str, dict[str, str]] = {} + raw_per_master = loops.get("perMaster") + if raw_per_master is not None: + masters = _require_object(raw_per_master, "orchestration.loops.perMaster", source) + for master, levels in masters.items(): + if not isinstance(master, str) or not master: + raise AgenticSettingsError( + f"orchestration.loops.perMaster keys must be non-empty master " + f"task names: {source}" + ) + per_master[master] = _parse_loop_levels( + levels, + owner=f"orchestration.loops.perMaster.{master}", + source=source, + ) + return LoopSettings(defaults=defaults, per_level=per_level, per_master=per_master) + + +def _parse_loop_defaults(raw: object, *, source: str) -> LoopDefaults: + if raw is None: + return LoopDefaults() + defaults = _require_object(raw, "orchestration.loops.defaults", source) + _refuse_unknown(defaults, KNOWN_LOOP_DEFAULTS_FIELDS, "orchestration.loops.defaults", source) + max_rounds = DEFAULT_LOOP_MAX_ROUNDS + if "maxRounds" in defaults: + max_rounds = _require_positive_int( + defaults["maxRounds"], "orchestration.loops.defaults.maxRounds", source + ) + reviewer_reuse = DEFAULT_REVIEWER_REUSE + if "reviewerReuse" in defaults: + reviewer_reuse = _require_string( + defaults["reviewerReuse"], + "orchestration.loops.defaults.reviewerReuse", + source, + ) + complexity = _parse_loop_complexity(defaults.get("complexity"), source=source) + return LoopDefaults(max_rounds=max_rounds, reviewer_reuse=reviewer_reuse, complexity=complexity) + + +def _parse_loop_complexity(raw: object, *, source: str) -> LoopComplexity: + if raw is None: + return LoopComplexity() + complexity = _require_object(raw, "orchestration.loops.defaults.complexity", source) + _refuse_unknown( + complexity, + KNOWN_LOOP_COMPLEXITY_FIELDS, + "orchestration.loops.defaults.complexity", + source, + ) + parsed = LoopComplexity() + values: dict[str, str] = { + "full_loop_at": parsed.full_loop_at, + "builder_at": parsed.builder_at, + } + for json_key, attr in (("fullLoopAt", "full_loop_at"), ("builderAt", "builder_at")): + if json_key not in complexity: + continue + owner = f"orchestration.loops.defaults.complexity.{json_key}" + value = _require_string(complexity[json_key], owner, source) + if value not in COMPLEXITY_SCALE: + allowed = ", ".join(COMPLEXITY_SCALE) + raise AgenticSettingsError( + f"{owner} must be one of: {allowed}; got {value!r}: {source}" + ) + values[attr] = value + return LoopComplexity(**values) + + +def _parse_loop_levels(raw: object, *, owner: str, source: str) -> dict[str, str]: + if raw is None: + return {} + levels = _require_object(raw, owner, source) + _refuse_unknown(levels, KNOWN_LOOP_LEVELS, owner, source) + parsed: dict[str, str] = {} + for level, value in levels.items(): + entry = _require_object(value, f"{owner}.{level}", source) + _refuse_unknown(entry, KNOWN_LOOP_LEVEL_FIELDS, f"{owner}.{level}", source) + # Loop postures are model-interpreted doctrine names (scored, + # seam-required, none, strategist, ...), deliberately not a closed set. + parsed[level] = _require_string(entry.get("loop"), f"{owner}.{level}.loop", source) + return parsed + + +def _parse_roles( + raw: object, + *, + source: str, + harness_ids: tuple[str, ...] | None, + owner: str = "orchestration.roles", +) -> dict[str, RoleKnobs]: + if raw is None: + return {} + roles = _require_object(raw, owner, source) + _refuse_unknown(roles, KNOWN_ROLES, owner, source) + parsed: dict[str, RoleKnobs] = {} + for role, value in roles.items(): + knobs = _require_object(value, f"{owner}.{role}", source) + _refuse_unknown(knobs, KNOWN_ROLE_KNOB_FIELDS, f"{owner}.{role}", source) + harness = None + if "harness" in knobs: + harness = _require_harness_id( + knobs["harness"], + f"{owner}.{role}.harness", + source, + harness_ids, + ) + model = None + if "model" in knobs: + model = _require_string(knobs["model"], f"{owner}.{role}.model", source) + effort = None + if "effort" in knobs: + # Deliberately a free string here: the per-harness effort vocabulary (flag values + + # session values) is enforced at DISPATCH, where the harness is known (260703-L16). + effort = _require_string(knobs["effort"], f"{owner}.{role}.effort", source) + # The free-form escape hatch (260703-L16): shape-checked, never content-validated. + launch_args: tuple[str, ...] = () + if "launchArgs" in knobs: + launch_args = _require_string_list( + knobs["launchArgs"], f"{owner}.{role}.launchArgs", source + ) + prompt_keywords: tuple[str, ...] = () + if "promptKeywords" in knobs: + prompt_keywords = _require_string_list( + knobs["promptKeywords"], + f"{owner}.{role}.promptKeywords", + source, + ) + session_commands: tuple[str, ...] = () + if "sessionCommands" in knobs: + session_commands = _require_string_list( + knobs["sessionCommands"], + f"{owner}.{role}.sessionCommands", + source, + ) + parsed[role] = RoleKnobs( + harness=harness, + model=model, + effort=effort, + launch_args=launch_args, + prompt_keywords=prompt_keywords, + session_commands=session_commands, + ) + return parsed + + +def _parse_roles_per_level( + raw: object, *, source: str, harness_ids: tuple[str, ...] | None +) -> dict[str, dict[str, RoleKnobs]]: + """``orchestration.rolesPerLevel`` (260703-L16, ruling 2026-07-07T08:15): per-level role knobs. + + ``{leaf|master|portfolio: {role: knob-overrides}}`` -- the level vocabulary matches + ``loops.perLevel`` so the two per-level families stay congruent; each override deep-merges over + the flat ``orchestration.roles`` default at dispatch (:meth:`AgenticSettings.resolved_role_knobs`). + Additive: absent key = no per-level overrides (existing files unchanged). + """ + if raw is None: + return {} + levels = _require_object(raw, "orchestration.rolesPerLevel", source) + _refuse_unknown(levels, KNOWN_LOOP_LEVELS, "orchestration.rolesPerLevel", source) + parsed: dict[str, dict[str, RoleKnobs]] = {} + for level, value in levels.items(): + parsed[level] = _parse_roles( + value, + source=source, + harness_ids=harness_ids, + owner=f"orchestration.rolesPerLevel.{level}", + ) + return parsed + + +def _parse_concurrency(raw: object, *, source: str) -> ConcurrencySettings: + if raw is None: + return ConcurrencySettings() + concurrency = _require_object(raw, "orchestration.concurrency", source) + _refuse_unknown(concurrency, KNOWN_CONCURRENCY_FIELDS, "orchestration.concurrency", source) + parsed: dict[str, int | None] = { + "max_parallel_masters": None, + "max_parallel_leaves": None, + "max_sub_agents": None, + } + for json_key, attr in ( + ("maxParallelMasters", "max_parallel_masters"), + ("maxParallelLeaves", "max_parallel_leaves"), + ("maxSubAgents", "max_sub_agents"), + ): + if json_key in concurrency: + parsed[attr] = _require_positive_int( + concurrency[json_key], f"orchestration.concurrency.{json_key}", source + ) + return ConcurrencySettings(**parsed) + + +def _parse_spawn(raw: object, *, source: str, harness_ids: tuple[str, ...] | None) -> str | None: + if raw is None: + return None + spawn = _require_object(raw, "orchestration.spawn", source) + _refuse_unknown(spawn, KNOWN_SPAWN_FIELDS, "orchestration.spawn", source) + if "harness" not in spawn: + return None + return _require_harness_id(spawn["harness"], "orchestration.spawn.harness", source, harness_ids) diff --git a/mcp/src/agents_remember/mcp/__init__.py b/mcp/src/agents_remember/mcp/__init__.py index 6c62b431..95619269 100644 --- a/mcp/src/agents_remember/mcp/__init__.py +++ b/mcp/src/agents_remember/mcp/__init__.py @@ -8,4 +8,4 @@ # Single source of truth: the installed package metadata (mcp/pyproject.toml). SERVER_VERSION = version("agents-remember-mcp") except PackageNotFoundError: # running from a source checkout without an install - SERVER_VERSION = "3.0.0rc2" + SERVER_VERSION = "3.0.0rc3" diff --git a/mcp/src/agents_remember/mcp/config.py b/mcp/src/agents_remember/mcp/config.py index be29794c..5dc698de 100644 --- a/mcp/src/agents_remember/mcp/config.py +++ b/mcp/src/agents_remember/mcp/config.py @@ -3,11 +3,19 @@ from __future__ import annotations import json +import warnings from dataclasses import dataclass, field from pathlib import Path from typing import Any +from agents_remember.controlplane.gate_policy import DEFAULT_GATE_POLICY, GatePolicy from agents_remember.errors import AgentsRememberError +from agents_remember.kernel.agentic_settings import ( + AgenticSettingsError, + agentic_settings_path, + load_agentic_settings, + parse_gate_delegation, +) from agents_remember.providers.identity import ( explicit_provider_instance_id, provider_instance_id, @@ -29,6 +37,12 @@ # Same fail-loud discipline as timeoutCaps: a typo ("autostart") must surface at # boot, not silently leave the daemon unsupervised. KNOWN_DASHBOARD_FIELDS = frozenset({"autoStart", "port"}) +# The agentic orchestration family moved to the coordinator's global settings +# file (260703-L13); the authority file keeps ONLY the one-cycle gateDelegation +# legacy fallback. loops/roles/concurrency/spawn here fail loud, pointing at +# the new home (roles/concurrency were previously reserved-and-silently-dropped +# -- that trap is closed). +KNOWN_AUTHORITY_ORCHESTRATION_FIELDS = frozenset({"gateDelegation"}) class ConfigError(AgentsRememberError): @@ -40,7 +54,6 @@ class RepositoryScope: repo_id: str path: Path memory_root: Path | None = None - memory_settings_includes: tuple[Path, ...] = () contract_path: Path | None = None @@ -61,6 +74,14 @@ class DashboardSettings: port: int = DEFAULT_DASHBOARD_PORT +@dataclass(frozen=True) +class OrchestrationSettings: + """The optional ``orchestration`` settings object.""" + + gate_policy: GatePolicy = DEFAULT_GATE_POLICY + require_reviewer_verdict_at_seams: bool = False + + @dataclass(frozen=True) class McpRuntimeConfig: config_path: Path @@ -73,6 +94,7 @@ class McpRuntimeConfig: timeout_caps: dict[str, int] = field(default_factory=dict) benchmarks_enabled: bool = False dashboard: DashboardSettings = field(default_factory=DashboardSettings) + orchestration: OrchestrationSettings = field(default_factory=OrchestrationSettings) @property def allowed_repo_ids(self) -> tuple[str, ...]: @@ -135,6 +157,11 @@ def config_from_mapping(data: dict[str, Any], config_path: Path) -> McpRuntimeCo timeout_caps = parse_timeout_caps(data.get("timeoutCaps", {})) benchmarks_enabled = parse_benchmarks_enabled(data.get("benchmarksEnabled", False)) dashboard = parse_dashboard_settings(data.get("dashboard")) + orchestration = parse_orchestration_settings( + data.get("orchestration"), + coordination_root=coordination_root, + config_path=config_path, + ) return McpRuntimeConfig( config_path=config_path, @@ -147,6 +174,7 @@ def config_from_mapping(data: dict[str, Any], config_path: Path) -> McpRuntimeCo timeout_caps=timeout_caps, benchmarks_enabled=benchmarks_enabled, dashboard=dashboard, + orchestration=orchestration, ) @@ -169,22 +197,13 @@ def _parse_repository_entry( ) if contract_path is not None and not path_is_relative_to(contract_path, coordination_root): raise ConfigError(f"repository {repo_id} contractPath must be inside the coordinator root") - includes = parse_path_list( - value.get("memorySettingsIncludes", []), - owner=f"repository {repo_id} memorySettingsIncludes", - ) - allowed_roots = (repo_path, memory_root) - for include_path in includes: - if not any(path_is_relative_to(include_path, root) for root in allowed_roots): - raise ConfigError( - f"repository {repo_id} include points outside configured repo " - f"boundaries: {include_path}" - ) + # memorySettingsIncludes was dead plumbing (parsed, never consumed); it was + # removed with 260703-L13. A leftover key in an existing settings file is + # tolerated-ignored like any other unknown repository field. return RepositoryScope( repo_id=repo_id, path=repo_path, memory_root=memory_root, - memory_settings_includes=tuple(includes), contract_path=contract_path, ) @@ -322,6 +341,102 @@ def parse_dashboard_settings(raw: object) -> DashboardSettings: return DashboardSettings(auto_start=auto_start, port=port) +def parse_orchestration_settings( + raw: object, + *, + coordination_root: Path, + config_path: Path, +) -> OrchestrationSettings: + """Resolve the boot-snapshot orchestration settings (260703-L13, GQ1). + + ``orchestration.gateDelegation``'s home is the GLOBAL agentic settings file + (``/system/settings.json``), read once at boot through the + kernel agentic-settings loader -- a change still needs a restart (documented + boot-snapshot semantics; the downstream ``gate_policy`` wiring is + unchanged). An authority-file value is honored as a one-cycle legacy + fallback WITH a boot warning naming the new home; when the global file also + sets the key, the global value wins and the shadowed authority value warns. + Any other ``orchestration.*`` key in the authority file fails loud -- those + knobs never belonged here (loops) or moved home (roles/concurrency/spawn). + """ + legacy = _parse_legacy_authority_gate_delegation(raw, coordination_root, config_path) + try: + agentic = load_agentic_settings(coordination_root) + except AgenticSettingsError as error: + raise ConfigError(str(error)) from error + if agentic.gate_delegation_configured: + if legacy is not None: + _warn_legacy_gate_delegation( + config_path, coordination_root, shadowed=True + ) + return OrchestrationSettings( + gate_policy=agentic.gate_policy, + require_reviewer_verdict_at_seams=agentic.require_reviewer_verdict_at_seams, + ) + if legacy is not None: + _warn_legacy_gate_delegation(config_path, coordination_root, shadowed=False) + return legacy + return OrchestrationSettings() + + +def _parse_legacy_authority_gate_delegation( + raw: object, + coordination_root: Path, + config_path: Path, +) -> OrchestrationSettings | None: + """The authority file's ``orchestration`` block: gateDelegation-only, legacy.""" + if raw is None: + return None + if not isinstance(raw, dict): + raise ConfigError("orchestration settings must be an object") + unknown = sorted(set(raw) - KNOWN_AUTHORITY_ORCHESTRATION_FIELDS) + if unknown: + unknown_text = ", ".join(unknown) + raise ConfigError( + f"unsupported orchestration setting(s): {unknown_text}; the MCP " + "authority file only reads the legacy gateDelegation fallback -- " + "agentic orchestration settings (gateDelegation, loops, roles, " + "rolesPerLevel, concurrency, spawn, harnesses) live in " + f"{agentic_settings_path(coordination_root)}" + ) + gate_raw = raw.get("gateDelegation") + if gate_raw is None: + return None + try: + gate_policy, require_verdict_at_seams = parse_gate_delegation( + gate_raw, source=str(config_path) + ) + except AgenticSettingsError as error: + raise ConfigError(str(error)) from error + return OrchestrationSettings( + gate_policy=gate_policy, + require_reviewer_verdict_at_seams=require_verdict_at_seams, + ) + + +def _warn_legacy_gate_delegation( + config_path: Path, + coordination_root: Path, + *, + shadowed: bool, +) -> None: + """One-cycle migration warning (GQ1): the authority-file key must move home.""" + new_home = agentic_settings_path(coordination_root) + if shadowed: + message = ( + f"orchestration.gateDelegation in the MCP authority file ({config_path}) " + f"is IGNORED: the global agentic settings file ({new_home}) already " + "defines it -- remove the authority-file copy" + ) + else: + message = ( + "orchestration.gateDelegation moved to the global agentic settings " + f"file ({new_home}); the MCP authority file value ({config_path}) is " + "honored as a one-cycle legacy fallback -- move it now" + ) + warnings.warn(message, stacklevel=2) + + def parse_timeout_caps(raw: object) -> dict[str, int]: if not isinstance(raw, dict): raise ConfigError("timeoutCaps must be an object") @@ -375,16 +490,6 @@ def optional_coordination_path( return resolved -def parse_path_list(raw: object, *, owner: str) -> list[Path]: - if raw is None: - return [] - if not isinstance(raw, list): - raise ConfigError(f"{owner} must be a list") - return [ - require_absolute_json_path(value, f"{owner}[{index}]") for index, value in enumerate(raw) - ] - - def require_absolute_json_path(value: object, label: str) -> Path: if not isinstance(value, str) or not value: raise ConfigError(f"{label} must be a non-empty string") diff --git a/mcp/src/agents_remember/mcp/server.py b/mcp/src/agents_remember/mcp/server.py index a4660f2a..8aa0af84 100644 --- a/mcp/src/agents_remember/mcp/server.py +++ b/mcp/src/agents_remember/mcp/server.py @@ -6,6 +6,8 @@ from mcp.server.fastmcp import FastMCP from agents_remember.benchmarks.runner import CODEX_BENCHMARK_SANDBOX +from agents_remember.controlplane.operator_inbox_records import AgentRole, InboxMessageKind +from agents_remember.controlplane.orchestration_nudges import NudgeReason from agents_remember.observer import AmbientLifecycle, EventStore, install_ambient, observer_root from agents_remember.serving.daemon import maybe_autostart_dashboard @@ -43,6 +45,7 @@ operator_inbox_consume_payload, operator_inbox_poll_payload, operator_inbox_post_payload, + orchestration_nudge_manager_payload, ping_payload, provider_diagnostics_payload, provider_status_payload, @@ -53,6 +56,7 @@ runtime_install_payload, server_info_payload, skills_install_payload, + spawn_agent_session_payload, switch_lifecycle_payload, task_doc_payload, task_reopen_payload, @@ -123,7 +127,7 @@ def read_ar_files( per session (served once, re-served only when changed; pass refresh=true to force re-serve, e.g. after a compaction). Route-index rule: a file inside sourceScope but absent from coveredFiles reports missing without probing. In a managed repo this is - the read for the research phase (the lifecycle up to the build/job decision): use it + the read for the research phase (the lifecycle up to the build decision): use it instead of a native read to get each file paired with its onboarding plus the repository and governing route overviews. Native read is the edit precondition once building begins.""" @@ -143,6 +147,75 @@ def attach_terminal_session_to_leaf(session_id: str, leaf_key: str) -> dict[str, leaf_key=leaf_key, ) + @server.tool() + def spawn_agent_session( + harness: str | None = None, + leaf_key: str | None = None, + context: str | None = None, + submit: bool = False, + label: str | None = None, + model: str | None = None, + effort: str | None = None, + env: dict[str, str] | None = None, + launch_args: list[str] | None = None, + prompt_keywords: list[str] | None = None, + session_commands: list[str] | None = None, + level: str | None = None, + spawned_by_session: str | None = None, + spawned_by_lifecycle: str | None = None, + kind: str = "harness", + ) -> dict[str, Any]: + """Spawn a role-configured, leaf-attached, context-primed hosted agent session. + + Composes the EXISTING session primitives so an orchestrator can spawn a manager and a manager + a worker without dashboard clicks: create a hosted session via the serving opener, attach it + to `leaf_key` (server-arbitrated uniqueness — a taken leaf returns status 'leaf-taken', never + overridden), seed the role knobs (`model`/`effort`/`env` injected as spawn env — the terminal + host's `tmux new-session -e KEY=VALUE` seam — AND mapped onto the harness argv per-harness + via the registry: claude gets `--model`/`--effort`; a mapping-less harness stays env-only), + and deliver `context` as an echo-confirmed bracketed paste. `effort` is validated against the + resolved harness's known vocabulary BEFORE spawning: an unknown value returns status + 'effort-invalid' naming the harness and its valid sets (the CLI would warn-and-silently- + degrade); a session-level value (claude 'ultracode') is delivered as a post-launch session + command instead of the flag. The free-form escape hatch is never validated, only recorded in + spawn provenance: `launch_args` (appended to the harness argv verbatim), `session_commands` + (each line pasted + submitted into the fresh session BEFORE the brief), `prompt_keywords` + (prepended as the first line of the brief paste — session modes the model interprets). + `level` declares the dispatch level (leaf|master|portfolio, default leaf — a manager + dispatching leaf seats passes leaf, the seam reviewer master, portfolio seats portfolio): + unset knobs resolve from the agentic settings as `orchestration.rolesPerLevel[level]` + deep-merged over the flat `orchestration.roles` default, keyed by the AR_SPAWN_ROLE riding + `env`; the resolved level + source land in spawn provenance. + `submit=true` presses Enter so a worker auto-starts; leave it false for a + draft. `harness` is optional: explicit values are validated against the detection set; omitted, + it resolves per-use from the agentic settings (role knobs, else repo-local + `/system/settings.json` over the global coordination-root file, + `orchestration.spawn.harness`; the repo comes from the + qualified leaf key), else the first detected registry harness. Each spawned session + is its own harness process (the ambient-lifecycle singleton is untouched). Spawned-by + provenance (`spawned_by_session` + the active/`spawned_by_lifecycle` lifecycle) is recorded on + the catalog row so the dashboard can render the orchestration tree. Status 'spawned' on + success; 'harness-unknown'/'harness-not-detected'/'effort-invalid'/'model-invalid'/ + 'level-invalid'/'bad-kind' are pre-spawn refusals.""" + return spawn_agent_session_payload( + config, + harness=harness, + leaf_key=leaf_key, + context=context, + submit=submit, + label=label, + model=model, + effort=effort, + env=env, + launch_args=launch_args, + prompt_keywords=prompt_keywords, + session_commands=session_commands, + level=level, + spawned_by_session=spawned_by_session, + spawned_by_lifecycle=spawned_by_lifecycle, + kind=kind, + ) + @server.tool() def runtime_install( dry_run: bool = False, @@ -938,13 +1011,20 @@ def lifecycle_gate( repo_id: str | None = None, packet: dict[str, Any] | None = None, required_decision: list[str] | None = None, + evidence_refs: list[dict[str, Any]] | None = None, + wait: bool = True, ) -> dict[str, Any]: """Public lifecycle-gate junction for agents. Creates the durable typed gate, blocks the active lifecycle with the developer-facing ask, and waits for the developer decision or gate-specific response in one operation. kind is the dashboard junction (plan-approval, worktree-intent, closeout-approval, etc.); ask.kind is the answer shape (decision, question, conflict). Do not add a separate wait call - as live gate choreography.""" + as live gate choreography. wait=false raises without blocking — reserved for + delegated seam kinds (master-handover-approval under a delegating policy; any + other kind blocks) and it requires enclosure=, the address + integration enforcement matches the gate by: the call returns the gateId, the + raiser carries it in the handover packet, and the delegated decider resolves + it by id via gate_decide(deciding_role=...).""" return lifecycle_gate_payload( config, kind=kind, @@ -954,6 +1034,8 @@ def lifecycle_gate( repo_id=repo_id, packet=packet, required_decision=required_decision, + evidence_refs=evidence_refs, + wait=wait, ) @server.tool() @@ -962,27 +1044,33 @@ def gate_decide( decision: str, lifecycle_id: str | None = None, note: str | None = None, + deciding_role: str | None = None, + evidence_refs: list[dict[str, Any]] | None = None, ) -> dict[str, Any]: """Record a decision on an open gate (decision: approve | reject | request-revision - | cancel). Append-only -- the decision is a new snapshot, never an overwrite. Over - MCP the decision is attributed to the model via the cli; the dashboard records - developer/dashboard decisions through its own path. That attribution is what a later - enforcement slice checks (a commit gate needs a developer-attributed approval), so an - agent recording a model decision here never counts as developer approval.""" + | cancel). Append-only -- the decision is a new snapshot, never an overwrite. By + default the decision is attributed to the model via the cli; with deciding_role it is + attributed to the active lifecycle via orchestration and checked against the configured + gate policy.""" + decided_via = "orchestration" if deciding_role is not None else "cli" return gate_decide_payload( config, gate_id=gate_id, lifecycle_id=lifecycle_id, decision=decision, - decided_by="model", - decided_via="cli", + decided_by=None if deciding_role is not None else "model", + decided_via=decided_via, + deciding_role=deciding_role, note=note, + evidence_refs=evidence_refs, ) @server.tool() def gate_list(lifecycle_id: str | None = None) -> dict[str, Any]: - """List the current (folded) gates for a lifecycle, or the workspace gates when no - lifecycle id is given. Read-only.""" + """List the current (folded) gates for a lifecycle. With no lifecycle id it + defaults to the ACTIVE (ambient) lifecycle — poll your own raised gate without + handling lifecycle ids — and lists the workspace gates only when no lifecycle + is active. Read-only.""" return gate_list_payload(config, lifecycle_id=lifecycle_id) @server.tool() @@ -992,16 +1080,30 @@ def operator_inbox_post( lifecycle_id: str | None = None, agent_id: str | None = None, gate_id: str | None = None, + sender_agent_id: str | None = None, + sender_role: AgentRole | None = None, + recipient_role: AgentRole | None = None, + message_kind: InboxMessageKind = "message", + artifact_path: str | None = None, + deliver_to_hosted: bool = True, ) -> dict[str, Any]: """Queue an operator response for an external chat to poll. Supply lifecycle_id - and/or agent_id as the mailbox key. Over MCP this route is attributed to the - model via cli; trusted dashboard code can call the payload builder directly with + and/or agent_id as the mailbox key. Agent-to-agent messages can include sender / + recipient role metadata; hosted targets are push-delivered through the terminal paste seam + while the durable inbox row remains dashboard-visible. Over MCP this route is attributed to + the model via cli; trusted dashboard code can call the payload builder directly with developer/dashboard attribution.""" return operator_inbox_post_payload( config, lifecycle_id=lifecycle_id, agent_id=agent_id, gate_id=gate_id, + sender_agent_id=sender_agent_id, + sender_role=sender_role, + recipient_role=recipient_role, + message_kind=message_kind, + artifact_path=artifact_path, + deliver_to_hosted=deliver_to_hosted, ask=ask, response=response, created_by="model", @@ -1012,13 +1114,15 @@ def operator_inbox_post( def operator_inbox_poll( lifecycle_id: str | None = None, agent_id: str | None = None, + recipient_role: AgentRole | None = None, ) -> dict[str, Any]: - """List pending external-chat inbox entries for a lifecycle_id and/or agent_id + """List pending external-chat inbox entries for a lifecycle_id, agent_id, and/or role mailbox key. Consuming an entry is explicit via operator_inbox_consume.""" return operator_inbox_poll_payload( config, lifecycle_id=lifecycle_id, agent_id=agent_id, + recipient_role=recipient_role, ) @server.tool() @@ -1032,6 +1136,30 @@ def operator_inbox_consume(entry_id: str) -> dict[str, Any]: consumed_via="cli", ) + @server.tool() + def orchestration_nudge_manager( + reason: NudgeReason, + subject: str, + manager_agent_id: str | None = None, + manager_lifecycle_id: str | None = None, + subject_agent_id: str | None = None, + subject_lifecycle_id: str | None = None, + artifact_path: str | None = None, + rate_limit_seconds: int = 900, + ) -> dict[str, Any]: + """Rate-limit, log, and push a manager nudge for inactivity or a missing turn report.""" + return orchestration_nudge_manager_payload( + config, + reason=reason, + subject=subject, + manager_agent_id=manager_agent_id, + manager_lifecycle_id=manager_lifecycle_id, + subject_agent_id=subject_agent_id, + subject_lifecycle_id=subject_lifecycle_id, + artifact_path=artifact_path, + rate_limit_seconds=rate_limit_seconds, + ) + return server diff --git a/mcp/src/agents_remember/mcp/tools/__init__.py b/mcp/src/agents_remember/mcp/tools/__init__.py index 8969f3f2..1d9e58f5 100644 --- a/mcp/src/agents_remember/mcp/tools/__init__.py +++ b/mcp/src/agents_remember/mcp/tools/__init__.py @@ -51,6 +51,7 @@ operator_inbox_poll_payload, operator_inbox_post_payload, ) +from .orchestration import orchestration_nudge_manager_payload from .providers import ( cgc_callees_payload, cgc_callers_payload, @@ -66,7 +67,7 @@ ) from .read_files import read_ar_files_payload from .task_doc import task_doc_payload, task_reopen_payload -from .terminal import attach_terminal_session_to_leaf_payload +from .terminal import attach_terminal_session_to_leaf_payload, spawn_agent_session_payload from .worktree import ( worktree_abandon_payload, worktree_attach_payload, @@ -122,6 +123,7 @@ "operator_inbox_consume_payload", "operator_inbox_poll_payload", "operator_inbox_post_payload", + "orchestration_nudge_manager_payload", "ping_payload", "provider_diagnostics_payload", "provider_status_payload", @@ -132,6 +134,7 @@ "runtime_install_payload", "server_info_payload", "skills_install_payload", + "spawn_agent_session_payload", "switch_lifecycle_payload", "task_doc_payload", "task_reopen_payload", diff --git a/mcp/src/agents_remember/mcp/tools/base.py b/mcp/src/agents_remember/mcp/tools/base.py index 66eba3a5..a01da328 100644 --- a/mcp/src/agents_remember/mcp/tools/base.py +++ b/mcp/src/agents_remember/mcp/tools/base.py @@ -17,6 +17,7 @@ "context_packet", "read_ar_files", "attach_terminal_session_to_leaf", + "spawn_agent_session", "runtime_install", "resolve_context", "drift_check", @@ -65,6 +66,7 @@ "operator_inbox_post", "operator_inbox_poll", "operator_inbox_consume", + "orchestration_nudge_manager", ) RESERVED_TOOLS: tuple[str, ...] = () diff --git a/mcp/src/agents_remember/mcp/tools/gates.py b/mcp/src/agents_remember/mcp/tools/gates.py index c083d7fe..b1748655 100644 --- a/mcp/src/agents_remember/mcp/tools/gates.py +++ b/mcp/src/agents_remember/mcp/tools/gates.py @@ -26,6 +26,11 @@ from collections.abc import Callable from typing import TYPE_CHECKING, Any, cast +from agents_remember.controlplane.gate_policy import ( + DEFAULT_GATE_POLICY, + SEAM_GATE_KINDS, + delegated_decision_failure_reason, +) from agents_remember.controlplane.interaction_retention import ( GATE_RESPONSE_WAIT_POLL_SECONDS, GATE_RESPONSE_WAIT_TIMEOUT_SECONDS, @@ -36,6 +41,7 @@ from agents_remember.controlplane.records import ( DECISION_STATES, DecidedVia, + GateEvidenceRef, GateRecord, coerce_gate_kind, create_gate, @@ -87,6 +93,26 @@ def _decision_payload(gate: GateRecord) -> dict[str, Any]: } +def _resolve_deciding_actor(decided_by: str | None, decided_via: DecidedVia) -> str: + if decided_via != "orchestration": + if decided_by is None or not decided_by.strip(): + raise ValueError("gate decision actor must be non-empty") + return decided_by + if decided_by is not None and decided_by.strip(): + return decided_by + amb = ambient() + current = amb.current if amb is not None else None + if current is None: + raise LifecycleError("orchestration gate decisions require an active deciding lifecycle") + return current.id + + +def _evidence_refs(raw: list[dict[str, Any]] | None) -> list[GateEvidenceRef]: + if raw is None: + return [] + return [GateEvidenceRef.model_validate(entry) for entry in raw] + + def _cancelled_wait_payload(operation: str, gate_id: str) -> dict[str, Any]: return _tool_payload( operation, @@ -111,6 +137,7 @@ def gate_create_payload( repo_id: str | None = None, packet: dict[str, Any] | None = None, required_decision: list[str] | None = None, + evidence_refs: list[dict[str, Any]] | None = None, ) -> dict[str, Any]: now = now_iso() store = _store(config) @@ -127,6 +154,7 @@ def gate_create_payload( repo_id=repo_id, packet=packet, required_decision=required_decision, + evidence_refs=evidence_refs, ) store.append(gate) return _tool_payload( @@ -152,8 +180,10 @@ def lifecycle_gate_payload( repo_id: str | None = None, packet: dict[str, Any] | None = None, required_decision: list[str] | None = None, + evidence_refs: list[dict[str, Any]] | None = None, timeout_seconds: float | None = None, poll_seconds: float = GATE_RESPONSE_WAIT_POLL_SECONDS, + wait: bool = True, sleep: Callable[[float], None] = time.sleep, monotonic: Callable[[], float] = time.monotonic, ) -> dict[str, Any]: @@ -189,13 +219,43 @@ def lifecycle_gate_payload( options = cast(list[str] | None, options_raw) structured_ask = build_ask(ask_kind, prompt, options) + gate_kind = coerce_gate_kind(kind) + if not wait: + # Raise-and-continue: reserved for SEAM kinds the active policy delegates. A + # human-decided kind must keep the blocking/notify contract, and a delegated + # non-seam kind (e.g. plan-approval) keeps it too — only the seam gate (the + # master-handover-approval the manager raises for the orchestrator) returns + # immediately so the raiser can post its packet; the gate id is the hand-off. + # The raise also requires the enforcement address: `enclosure` is the master + # task name the integrate guard matches the gate by, so an addressless + # wait=false gate could only ever fail open at the enforcement rung. + # Validate-then-mutate: refuse BEFORE the expire-sweep and append below, so a + # refused raise persists no orphan open gate and expires no sibling. + policy = ( + config.orchestration.gate_policy if config is not None else DEFAULT_GATE_POLICY + ) + if gate_kind not in SEAM_GATE_KINDS: + raise ValueError( + f"lifecycle_gate wait=false is reserved for delegated seam kinds; " + f"{gate_kind} blocks" + ) + if policy.rule_for(gate_kind).delegated_role is None: + raise ValueError( + f"lifecycle_gate wait=false requires a kind the active policy delegates; " + f"{gate_kind} is not delegated" + ) + if enclosure is None or not enclosure.strip(): + raise ValueError( + f"a {gate_kind} raise-and-continue requires " + "enclosure= — the integration guard's address" + ) now = now_iso() store = _store(config) for open_gate in store.current(current.id).values(): if open_gate.state == "open": store.append(expire_gate(open_gate, now=now)) gate = create_gate( - kind=coerce_gate_kind(kind), + kind=gate_kind, lifecycle_id=current.id, gate_id=new_ulid(), now=now, @@ -203,8 +263,37 @@ def lifecycle_gate_payload( repo_id=repo_id, packet=packet, required_decision=required_decision, + evidence_refs=evidence_refs, ) store.append(gate) + if not wait: + return _tool_payload( + "lifecycle_gate", + { + "ok": True, + "operation": "lifecycle_gate", + "gate": { + "id": gate.id, + "kind": gate.kind, + "state": "open", + "lifecycleId": gate.lifecycleId, + }, + "lifecycle": { + "id": current.id, + "state": current.state, + "phase": getattr(current, "phase", None), + }, + "wait": { + "state": "raised", + "gateId": gate.id, + "lifecycleId": current.id, + "timedOut": False, + "waited": False, + "note": "gate raised without blocking; carry the gateId in the " + "handover packet — the delegated decider resolves it by id", + }, + }, + ) blocked = amb.block(kind=ask_kind, prompt=prompt, options=options) wait_result = gate_response_wait_payload( config, @@ -216,7 +305,7 @@ def lifecycle_gate_payload( sleep=sleep, monotonic=monotonic, ) - wait = { + wait_info: dict[str, Any] = { "state": wait_result["state"], "gateId": wait_result["gateId"], "lifecycleId": blocked.id, @@ -228,7 +317,7 @@ def lifecycle_gate_payload( } for key in ("decidedBy", "decidedVia", "decisionNote"): if wait_result.get(key) is not None: - wait[key] = wait_result[key] + wait_info[key] = wait_result[key] payload: dict[str, Any] = { "ok": True, "operation": "lifecycle_gate", @@ -243,7 +332,7 @@ def lifecycle_gate_payload( "state": blocked.state, "phase": blocked.phase, }, - "wait": wait, + "wait": wait_info, } if structured_ask is not None: payload["ask"] = structured_ask @@ -256,9 +345,11 @@ def gate_decide_payload( gate_id: str, lifecycle_id: str | None, decision: str, - decided_by: str, + decided_by: str | None, decided_via: DecidedVia, + deciding_role: str | None = None, note: str | None = None, + evidence_refs: list[dict[str, Any]] | None = None, ) -> dict[str, Any]: if decision not in DECISION_STATES: raise ValueError( @@ -266,19 +357,45 @@ def gate_decide_payload( ) store = _store(config) gate = store.current(lifecycle_id).get(gate_id) + if gate is None and lifecycle_id is None: + # Packet-carried gate ids: the deciding seat holds only the id; resolve it + # across lifecycles server-side (lifecycle ids never pass through the model). + gate = store.find(gate_id) if gate is None: raise KeyError(f"no gate {gate_id!r} on lifecycle {lifecycle_id!r}") + if decided_via == "cli" and decision != "cancel": + policy = ( + config.orchestration.gate_policy if config is not None else DEFAULT_GATE_POLICY + ) + if policy.rule_for(gate.kind).delegated_role is not None: + raise ValueError( + f"{gate.kind} is delegated by the active gate policy; pass deciding_role " + "for an attributed orchestration decision, or leave it to the developer" + ) + actor = _resolve_deciding_actor(decided_by, decided_via) + evidence = _evidence_refs(evidence_refs) updated = decide_gate( gate, decision=decision, - by=decided_by, + by=actor, via=decided_via, + deciding_role=deciding_role, note=note, now=now_iso(), + evidence_refs=evidence, ) + if decided_via == "orchestration": + policy = ( + config.orchestration.gate_policy + if config is not None + else DEFAULT_GATE_POLICY + ) + failure = delegated_decision_failure_reason(updated, policy) + if failure is not None: + raise ValueError(f"gate decision rejected by delegation policy: {failure}") store.append(updated) if decision == "cancel": - store.delete(updated.id, lifecycle_id) + store.delete(updated.id, updated.lifecycleId) _inbox_store(config).delete_by_gate(updated.id) return _tool_payload( "gate_decide", @@ -289,6 +406,10 @@ def gate_decide_payload( "state": updated.state, "decidedBy": updated.decidedBy, "decidedVia": updated.decidedVia, + "decidingRole": updated.decidingRole, + "evidenceRefs": [ + ref.model_dump(mode="json", exclude_none=True) for ref in updated.evidenceRefs + ], }, ) @@ -298,10 +419,12 @@ def gate_decide_for_lifecycle( *, lifecycle_id: str, decision: str, - decided_by: str, + decided_by: str | None, decided_via: DecidedVia, + deciding_role: str | None = None, expected_gate_id: str | None = None, note: str | None = None, + evidence_refs: list[dict[str, Any]] | None = None, ) -> dict[str, Any]: """Decide the lifecycle's latest still-open gate -- the dashboard's write path. @@ -329,28 +452,16 @@ def gate_decide_for_lifecycle( raise KeyError( f"gate {expected_gate_id!r} is {state}; current open gate is {gate.id!r}" ) - updated = decide_gate( - gate, + return gate_decide_payload( + config, + gate_id=gate.id, + lifecycle_id=lifecycle_id, decision=decision, - by=decided_by, - via=decided_via, + decided_by=decided_by, + decided_via=decided_via, + deciding_role=deciding_role, note=note, - now=now_iso(), - ) - store.append(updated) - if decision == "cancel": - store.delete(updated.id, lifecycle_id) - _inbox_store(config).delete_by_gate(updated.id) - return _tool_payload( - "gate_decide", - { - "ok": True, - "operation": "gate_decide", - "gateId": updated.id, - "state": updated.state, - "decidedBy": updated.decidedBy, - "decidedVia": updated.decidedVia, - }, + evidence_refs=evidence_refs, ) @@ -476,6 +587,15 @@ def gate_list_payload( *, lifecycle_id: str | None, ) -> dict[str, Any]: + if lifecycle_id is None: + # Ambient-defaulting (matching the other lifecycle-scoped tools): with no + # explicit id, list the ACTIVE lifecycle's gates — so a raiser can poll its + # own gate without ever handling a lifecycle id (they stay server-side). + # The workspace log is the fallback only when no lifecycle is active. + amb = ambient() + current = amb.current if amb is not None else None + if current is not None: + lifecycle_id = current.id gates = _store(config).current(lifecycle_id) return _tool_payload( "gate_list", diff --git a/mcp/src/agents_remember/mcp/tools/next_step.py b/mcp/src/agents_remember/mcp/tools/next_step.py index 93262554..7e082e2f 100644 --- a/mcp/src/agents_remember/mcp/tools/next_step.py +++ b/mcp/src/agents_remember/mcp/tools/next_step.py @@ -55,12 +55,13 @@ # leaf-26 Lifecycle Flow tab RUNDOWN, with the developer-chosen plan-approval # hand-off appended (S5: ride the first gate tool). FRONT_HALF_RUNDOWN: list[str] = [ - "reframe — restate the request as agreed work, then present it for the developer's agreement.", + "reframe — restate the request as agreed work, then present it for the developer's agreement (the orchestrator lifecycle: l-01-agent-lifecycles roles/orchestrator.md).", "research — read_ar_files · grepai · cgc (they fire unpredictably, so this half is prose-guided, " "not per-tool).", - "job selection — bug / feature → build ; triage / research → research-only exit.", - "task file exists? (build/fix) — yes → worktree_start ; " - "no → task_doc first (persist the proposal + approval), then worktree_start.", + "route the event (the lens tunes it): no task doc → design one ; approved doc + code change " + "→ build ; no code change → research-only exit ; triage may route, spawn, or escalate.", + "task file exists? — no → task_doc first (persist the proposal + approval); worktree_start " + "only AFTER the plan gate: task doc → branch → worktree, in that order.", "when the plan is ready, present it and notify via lifecycle_turn_end_notification, then " "stop — your next AR tool call resumes automatically; from worktree_start on, every tool " "response carries the next step.", @@ -69,7 +70,7 @@ # Front-half generic pointer back to the rundown (every non-``decide`` call). _FRONT_HALF_SUMMARY = ( "Front half (non-linear): follow the lifecycle_start rundown — reframe → research → " - "job-selection → task-file-exists? → task_doc. When the plan is ready, notify via " + "event-routing → task-file-exists? → task_doc. When the plan is ready, notify via " "lifecycle_turn_end_notification and stop; the linear per-tool chain begins at worktree_start." ) diff --git a/mcp/src/agents_remember/mcp/tools/operator_inbox.py b/mcp/src/agents_remember/mcp/tools/operator_inbox.py index c3808932..9a07de56 100644 --- a/mcp/src/agents_remember/mcp/tools/operator_inbox.py +++ b/mcp/src/agents_remember/mcp/tools/operator_inbox.py @@ -6,6 +6,8 @@ from typing import TYPE_CHECKING, Any from agents_remember.controlplane.operator_inbox_records import ( + AgentRole, + InboxMessageKind, OperatorInboxEntry, OperatorInboxVia, create_operator_inbox_entry, @@ -14,6 +16,10 @@ from agents_remember.observer import observer_root from agents_remember.observer.events import now_iso from agents_remember.observer.ulid import new_ulid +from agents_remember.serving.inbox_delivery import deliver_inbox_entry +from agents_remember.serving.terminal import TerminalHost +from agents_remember.serving.terminal_catalog import TerminalCatalog, terminal_catalog_path +from agents_remember.serving.terminal_paste import TerminalPaster from .base import _tool_payload @@ -39,6 +45,15 @@ def operator_inbox_post_payload( created_by: str, created_via: OperatorInboxVia, gate_id: str | None = None, + sender_agent_id: str | None = None, + sender_role: AgentRole | None = None, + recipient_role: AgentRole | None = None, + message_kind: InboxMessageKind = "message", + artifact_path: str | None = None, + deliver_to_hosted: bool = True, + terminal_catalog: TerminalCatalog | None = None, + terminal_host: TerminalHost | None = None, + terminal_paster: TerminalPaster | None = None, ) -> dict[str, Any]: entry = create_operator_inbox_entry( entry_id=new_ulid(), @@ -50,10 +65,24 @@ def operator_inbox_post_payload( response=response, created_by=created_by, created_via=created_via, + sender_agent_id=sender_agent_id, + sender_role=sender_role, + recipient_role=recipient_role, + message_kind=message_kind, + artifact_path=artifact_path, ) store = _store(config) store.append(entry) store.compact(now=datetime.now(UTC)) + if deliver_to_hosted: + entry = deliver_inbox_entry( + store=store, + catalog=terminal_catalog or TerminalCatalog(terminal_catalog_path(config.coordination_root)), + host=terminal_host or TerminalHost(), + paster=terminal_paster or TerminalPaster(), + entry=entry, + submit=True, + ) return _tool_payload( "operator_inbox_post", { @@ -63,7 +92,16 @@ def operator_inbox_post_payload( "state": entry.state, "lifecycleId": entry.lifecycleId, "agentId": entry.agentId, + "senderAgentId": entry.senderAgentId, + "senderRole": entry.senderRole, + "recipientRole": entry.recipientRole, "gateId": entry.gateId, + "messageKind": entry.messageKind, + "artifactPath": entry.artifactPath, + "deliveryState": entry.deliveryState, + "deliveredAt": entry.deliveredAt, + "deliveredToSession": entry.deliveredToSession, + "deliveryDetail": entry.deliveryDetail, }, ) @@ -73,8 +111,13 @@ def operator_inbox_poll_payload( *, lifecycle_id: str | None, agent_id: str | None, + recipient_role: AgentRole | None = None, ) -> dict[str, Any]: - entries = _store(config).list_pending(lifecycle_id=lifecycle_id, agent_id=agent_id) + entries = _store(config).list_pending( + lifecycle_id=lifecycle_id, + agent_id=agent_id, + recipient_role=recipient_role, + ) return _tool_payload( "operator_inbox_poll", { @@ -82,6 +125,7 @@ def operator_inbox_poll_payload( "operation": "operator_inbox_poll", "lifecycleId": lifecycle_id, "agentId": agent_id, + "recipientRole": recipient_role, "entryCount": len(entries), "entries": [_entry_payload(entry) for entry in entries], }, diff --git a/mcp/src/agents_remember/mcp/tools/orchestration.py b/mcp/src/agents_remember/mcp/tools/orchestration.py new file mode 100644 index 00000000..3f3af102 --- /dev/null +++ b/mcp/src/agents_remember/mcp/tools/orchestration.py @@ -0,0 +1,119 @@ +"""Payload builders for orchestration communication helpers.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from agents_remember.controlplane.orchestration_nudges import ( + NudgeReason, + OrchestrationNudgeRecord, + OrchestrationNudgeStore, + nudge_message, +) +from agents_remember.observer import observer_root +from agents_remember.observer.events import Event, now_iso +from agents_remember.observer.store import EventStore +from agents_remember.observer.ulid import new_ulid + +from .base import _tool_payload +from .operator_inbox import operator_inbox_post_payload + +if TYPE_CHECKING: + from agents_remember.mcp.config import McpRuntimeConfig + + +def orchestration_nudge_manager_payload( + config: McpRuntimeConfig, + *, + reason: NudgeReason, + subject: str, + manager_agent_id: str | None = None, + manager_lifecycle_id: str | None = None, + subject_agent_id: str | None = None, + subject_lifecycle_id: str | None = None, + artifact_path: str | None = None, + rate_limit_seconds: int = 900, +) -> dict[str, Any]: + """Record and push a manager nudge for inactivity or a missing turn report.""" + if manager_agent_id is None and manager_lifecycle_id is None: + raise ValueError("orchestration nudge requires manager_agent_id or manager_lifecycle_id") + now = now_iso() + message = nudge_message(reason, subject=subject, artifact_path=artifact_path) + store = OrchestrationNudgeStore(observer_root(config)) + record = store.record( + OrchestrationNudgeRecord( + id=new_ulid(), + ts=now, + state="sent", + reason=reason, + targetAgentId=manager_agent_id, + targetLifecycleId=manager_lifecycle_id, + subjectAgentId=subject_agent_id, + subjectLifecycleId=subject_lifecycle_id, + artifactPath=artifact_path, + message=message, + ), + rate_limit_seconds=rate_limit_seconds, + ) + _log_nudge_event(config, record) + if record.state == "rate-limited": + return _tool_payload( + "orchestration_nudge_manager", + { + "ok": True, + "operation": "orchestration_nudge_manager", + "status": record.state, + "reason": reason, + "nudgeId": record.id, + "message": message, + }, + ) + + posted = operator_inbox_post_payload( + config, + lifecycle_id=manager_lifecycle_id, + agent_id=manager_agent_id, + sender_role="system", + recipient_role="manager", + message_kind="nudge", + artifact_path=artifact_path, + ask=f"Nudge manager about {subject}", + response=message, + created_by="system", + created_via="cli", + ) + return _tool_payload( + "orchestration_nudge_manager", + { + "ok": True, + "operation": "orchestration_nudge_manager", + "status": record.state, + "reason": reason, + "nudgeId": record.id, + "entryId": posted["entryId"], + "deliveryState": posted.get("deliveryState"), + "deliveredToSession": posted.get("deliveredToSession"), + "message": message, + }, + ) + + +def _log_nudge_event(config: McpRuntimeConfig, record: OrchestrationNudgeRecord) -> None: + EventStore(observer_root(config)).append( + Event( + id=new_ulid(), + ts=record.ts, + kind="orchestration.nudge", + trust="observed", + actor="system", + data={ + "state": record.state, + "reason": record.reason, + "targetAgentId": record.targetAgentId, + "targetLifecycleId": record.targetLifecycleId, + "subjectAgentId": record.subjectAgentId, + "subjectLifecycleId": record.subjectLifecycleId, + "artifactPath": record.artifactPath, + }, + ) + ) diff --git a/mcp/src/agents_remember/mcp/tools/terminal.py b/mcp/src/agents_remember/mcp/tools/terminal.py index 316eb3bc..217a43f2 100644 --- a/mcp/src/agents_remember/mcp/tools/terminal.py +++ b/mcp/src/agents_remember/mcp/tools/terminal.py @@ -2,16 +2,51 @@ from __future__ import annotations +import os +from dataclasses import dataclass +from pathlib import Path from typing import TYPE_CHECKING, Any +from uuid import uuid4 -from agents_remember.serving.terminal_catalog import TerminalCatalog, terminal_catalog_path +from agents_remember.kernel.agentic_settings import ( + AgenticSettings, + RoleKnobs, + load_agentic_settings, +) +from agents_remember.observer.ambient import ambient +from agents_remember.serving.harnesses import ( + Harness, + Which, + effort_session_commands, + find_harness, + invalid_effort_detail, + invalid_model_detail, + is_detected, + unknown_harness_detail, +) +from agents_remember.serving.terminal import TerminalHost +from agents_remember.serving.terminal_catalog import ( + TerminalCatalog, + TerminalCatalogEntry, + terminal_catalog_path, +) from agents_remember.serving.terminal_leaf_assignment import assign_terminal_session_to_leaf +from agents_remember.serving.terminal_opener import open_terminal_session +from agents_remember.serving.terminal_paste import TerminalPaster from .base import _tool_payload if TYPE_CHECKING: from agents_remember.mcp.config import McpRuntimeConfig +_DEFAULT_SHELL = "/bin/bash" + +# The dispatch levels (260703-L16, ruling 2026-07-07T08:15) -- the same vocabulary as +# orchestration.loops.perLevel / orchestration.rolesPerLevel so the per-level families stay +# congruent. The dispatcher knows its level: a manager dispatching leaf seats = leaf, the seam +# reviewer = master, portfolio/end-to-end seats = portfolio. Omitted = leaf. +_SPAWN_LEVELS = ("leaf", "master", "portfolio") + def attach_terminal_session_to_leaf_payload( config: McpRuntimeConfig, @@ -40,3 +75,477 @@ def attach_terminal_session_to_leaf_payload( "role": result.role, }, ) + + +def _spawn_env( + model: str | None, + effort: str | None, + env: dict[str, str] | None, +) -> dict[str, str]: + """Fold the role knobs into the spawn env the terminal host seeds at ``tmux new-session``. + + Model/effort ride as namespaced env vars (``AR_SPAWN_MODEL`` / ``AR_SPAWN_EFFORT``) alongside any + caller-supplied ``env`` (explicit keys win). This is the injection SEAM the leaf owns; mapping these + to a given harness's concrete CLI flags / config is the role-knob resolution layer's job (job-file + defaults + settings overrides), deferred to that layer -- this tool just delivers the passthrough. + """ + resolved = dict(env or {}) + if model: + resolved.setdefault("AR_SPAWN_MODEL", model) + if effort: + resolved.setdefault("AR_SPAWN_EFFORT", effort) + return resolved + + +def _ambient_lifecycle_id() -> str | None: + """The active (spawning) lifecycle id, for default spawned-by provenance. Best-effort, never raises.""" + amb = ambient() + if amb is not None and amb.current is not None: + return amb.current.id + return None + + +def _spawn_repo_root(config: McpRuntimeConfig, leaf_key: str | None) -> Path | None: + """The code-repo root whose repo-local agentic settings apply to this spawn. + + Derived from the qualified leaf key (``//`` -- the + l-01 catalog-binding contract): a leaf-attached spawn works on that repo, so + its ``/system/settings.json`` layer participates. Leafless spawns (and + unconfigured repo segments) resolve against the global layer only. + """ + if not leaf_key: + return None + repo_id = leaf_key.split("/", 1)[0] + scope = config.repositories.get(repo_id) + return scope.path if scope is not None else None + + +def _resolve_spawn_harness( + settings: AgenticSettings, + harness: str | None, + which: Which | None, +) -> tuple[Harness | None, dict[str, Any] | None]: + """Resolve the harness for a spawn (260703-L13 seam; effective registry 260703-L16). + + Precedence: explicit argument > repo-local settings > global settings > + detection-gated default (the first EFFECTIVE-registry harness detected on + PATH). Every id resolves against ``settings.harnesses`` -- the builtin + registry merged with the ``orchestration.harnesses`` family, so users can + teach the system a new TUI or pre-customize a builtin's launch. An id known + nowhere refuses loudly pointing at the manual (never a crash); ``settings`` + comes from the per-use loader (a malformed file raises -- never a silent + fallback). Returns ``(harness, refusal_payload)`` with exactly one side set. + """ + registry = settings.harnesses + if harness is not None: + found = find_harness(harness, registry=registry) + if found is None: + return None, _spawn_refusal( + "harness-unknown", + harness, + "harness", + detail=unknown_harness_detail(harness, registry=registry), + ) + if not is_detected(found, which=which): + return None, _spawn_refusal( + "harness-not-detected", + harness, + "harness", + detail=f"harness not installed: {harness!r}", + ) + return found, None + + preferred = settings.spawn_harness + if preferred is not None: + found = find_harness(preferred, registry=registry) + assert found is not None # the loader validates against the effective ids + if not is_detected(found, which=which): + source = ", ".join(str(path) for path in settings.sources) + return None, _spawn_refusal( + "harness-not-detected", + preferred, + "harness", + detail=( + f"configured spawn harness not installed: {preferred!r} " + f"(orchestration.spawn.harness in {source})" + ), + ) + return found, None + + for candidate in registry: + if is_detected(candidate, which=which): + return candidate, None + ids = ", ".join(candidate.id for candidate in registry) + return None, _spawn_refusal( + "harness-not-detected", + None, + "harness", + detail=( + "no harness given, none preferred in settings, and none detected on " + f"PATH; install one of: {ids} (or pass harness explicitly)" + ), + ) + + +@dataclass(frozen=True) +class _HarnessDispatch: + """The pre-spawn knob bundle for one harness-kind dispatch (260703-L16). + + Everything the settings rungs resolved for this seat: the harness id (effective-registry + validated), the effective registry itself, the folded model/effort (explicit args over role + knobs), the free-form escape hatch, the RESOLVED session-command list (effort vehicle first), + and the level provenance. + """ + + harness_id: str + registry: tuple[Harness, ...] + model: str | None + effort: str | None + launch_args: list[str] | None + prompt_keywords: list[str] | None + session_commands: list[str] + spawn_level: str + spawn_level_source: str + + +def _resolve_harness_dispatch( + config: McpRuntimeConfig, + *, + harness: str | None, + leaf_key: str | None, + level: str | None, + model: str | None, + effort: str | None, + env: dict[str, str] | None, + launch_args: list[str] | None, + prompt_keywords: list[str] | None, + session_commands: list[str] | None, + which: Which | None, +) -> tuple[_HarnessDispatch | None, dict[str, Any] | None]: + """Resolve + validate every knob BEFORE anything spawns (260703-L16). + + Realizes the dispatch chain explicit args > repo-local level override > global level override > + repo-local role default > global role default > spawn preference > detection-gated default: the + settings rungs come from ``resolved_role_knobs(AR_SPAWN_ROLE, level)`` (per-use read; the + repo-local layer selected by the qualified leaf key), the harness resolves against the EFFECTIVE + registry, and model/effort are refused per-harness (``model-invalid``/``effort-invalid``) before + any tmux exists. A session-vocabulary effort (claude ``ultracode``) contributes the FIRST + session command. Returns ``(dispatch, refusal)`` with exactly one side set. + """ + spawn_level = level or "leaf" + spawn_level_source = "explicit" if level is not None else "default" + if spawn_level not in _SPAWN_LEVELS: + valid = ", ".join(_SPAWN_LEVELS) + return None, _spawn_refusal( + "level-invalid", + harness, + "harness", + detail=f"unknown dispatch level {spawn_level!r}; valid levels: [{valid}]", + ) + settings = load_agentic_settings( + config.coordination_root, repo_root=_spawn_repo_root(config, leaf_key) + ) + # The settings rungs, keyed by the AR_SPAWN_ROLE riding the caller's env (no role = no settings + # rung, today's behavior); unset explicit args fold in from the level-merged role knobs. + role = (env or {}).get("AR_SPAWN_ROLE") + knobs = settings.resolved_role_knobs(role, spawn_level) if role else RoleKnobs() + model = model or knobs.model + effort = effort or knobs.effort + if launch_args is None and knobs.launch_args: + launch_args = list(knobs.launch_args) + if prompt_keywords is None and knobs.prompt_keywords: + prompt_keywords = list(knobs.prompt_keywords) + resolved_session_commands = ( + list(session_commands) if session_commands is not None else list(knobs.session_commands) + ) + # Harness rung order: explicit argument > role knobs (level-merged) > spawn preference > + # detection-gated default (the last two inside _resolve_spawn_harness). + found, refusal = _resolve_spawn_harness(settings, harness or knobs.harness, which) + if refusal is not None: + return None, refusal + assert found is not None # no refusal => a resolved effective-registry harness + # Validate the EFFECTIVE values (env wins over arg wins over settings, mirroring _spawn_env). + effective_model = (env or {}).get("AR_SPAWN_MODEL") or model + effective_effort = (env or {}).get("AR_SPAWN_EFFORT") or effort + refusal = _knob_refusal(found, effective_model, effective_effort) + if refusal is not None: + return None, refusal + # A session-vocabulary effort is delivered as the FIRST post-launch session command, ahead of + # any caller/settings free-form ones, then the brief. + resolved_session_commands = ( + effort_session_commands(found, effective_effort) + resolved_session_commands + ) + return ( + _HarnessDispatch( + harness_id=found.id, + registry=settings.harnesses, + model=model, + effort=effort, + launch_args=launch_args, + prompt_keywords=prompt_keywords, + session_commands=resolved_session_commands, + spawn_level=spawn_level, + spawn_level_source=spawn_level_source, + ), + None, + ) + + +def _knob_refusal( + found: Harness, effective_model: str | None, effective_effort: str | None +) -> dict[str, Any] | None: + """The ``model-invalid``/``effort-invalid`` pre-spawn refusal, or ``None`` when the knobs apply.""" + checks = ( + ("model-invalid", invalid_model_detail(found, effective_model) if effective_model else None), + ( + "effort-invalid", + invalid_effort_detail(found, effective_effort) if effective_effort else None, + ), + ) + for status, detail in checks: + if detail is not None: + return _spawn_refusal(status, found.id, "harness", detail=detail) + return None + + +def _brief_packet(context: str | None, prompt_keywords: list[str] | None) -> str | None: + """The brief paste text: promptKeywords ride as its first line (delivered alone with no brief).""" + if not prompt_keywords: + return context + keyword_line = " ".join(prompt_keywords) + return f"{keyword_line}\n\n{context}" if context else keyword_line + + +def _deliver_spawn_pastes( + paster: TerminalPaster, + tmux_name: str, + session_commands: list[str], + packet: str | None, + submit: bool, +) -> tuple[bool | None, bool | None, bool | None]: + """Deliver the session layer: session commands FIRST (each its own echo-confirmed paste, always + submitted -- an unexecuted ``/effort ultracode`` would be a silent downgrade), THEN the brief. + + Returns ``(session_commands_delivered, context_delivered, submitted)`` (``None`` = not sent). + """ + session_commands_delivered: bool | None = None + context_delivered: bool | None = None + submitted: bool | None = None + if session_commands: + session_commands_delivered = True + for command_line in session_commands: + outcome = paster.paste(tmux_name, command_line, submit=True) + session_commands_delivered = ( + session_commands_delivered and outcome.delivered and outcome.submitted + ) + if packet: + # Workers auto-start (paste + submit); a human draft-only flow leaves submit=False so the + # draft stays editable. Echo-confirmed server-side (the frontend pasteAndConfirm mirror). + outcome = paster.paste(tmux_name, packet, submit=submit) + context_delivered = outcome.delivered + submitted = outcome.submitted if submit else None + return session_commands_delivered, context_delivered, submitted + + +def spawn_agent_session_payload( + config: McpRuntimeConfig, + *, + harness: str | None = None, + leaf_key: str | None = None, + context: str | None = None, + submit: bool = False, + label: str | None = None, + model: str | None = None, + effort: str | None = None, + env: dict[str, str] | None = None, + launch_args: list[str] | None = None, + prompt_keywords: list[str] | None = None, + session_commands: list[str] | None = None, + level: str | None = None, + spawned_by_session: str | None = None, + spawned_by_lifecycle: str | None = None, + kind: str = "harness", + session_id: str | None = None, + host: TerminalHost | None = None, + paster: TerminalPaster | None = None, + which: Which | None = None, +) -> dict[str, Any]: + """Spawn one role-configured, leaf-attached, context-primed hosted session (L2 dispatch). + + Composes the EXISTING session primitives -- the shared serving opener (create + leaf claim + + detached tmux ensure with env-seeded knobs), then an echo-confirmed context-packet paste with an + optional submit -- so orchestrators spawn managers and managers spawn workers without dashboard + clicks. ``harness`` is optional (260703-L13): omitted, it resolves per-use through the agentic + settings (repo-local over global ``orchestration.spawn.harness``), else the detection-gated + default. Leaf uniqueness stays server-arbitrated: a taken leaf returns ``leaf-taken`` (never + overridden). ``host``/``paster``/``which``/``session_id`` are injectable seams for tests. + + Per-level knob resolution (ruling 2026-07-07T08:15): the settings rungs come from + ``resolved_role_knobs(AR_SPAWN_ROLE, level)`` -- the ``orchestration.rolesPerLevel[level]`` + override deep-merged over the flat ``orchestration.roles`` default -- realizing the chain + explicit args > repo-local level override > global level override > repo-local role default > + global role default > detection-gated default. ``level`` is the dispatcher's declaration + (leaf|master|portfolio, default leaf); the RESOLVED level + its source (explicit/default) are + recorded in spawn provenance. + + Knob application (260703-L16): ``model``/``effort`` keep riding the spawn env AND are mapped onto + the harness argv per-harness via the EFFECTIVE registry -- the builtin table merged with the + ``orchestration.harnesses`` settings family (new ids add a harness, builtin ids can be + pre-customized; an id known nowhere refuses loudly pointing at ``docs/reference/harnesses.md``, + never a crash). Env-only builtins get no flags; a settings-defined harness with no declared + mapping refuses the knob with guidance (``model-invalid``/``effort-invalid``). ``effort`` is + validated against the resolved harness's known vocabulary BEFORE anything spawns -- an unknown + value returns the ``effort-invalid`` refusal naming the harness and its valid sets (the CLI + would warn-and-silently-degrade). A session-level effort value (claude ``ultracode``) rides a + post-launch session command instead of the flag. The free-form escape hatch is never validated, + only recorded in spawn provenance: ``launch_args`` (verbatim argv), ``session_commands`` (each + line pasted + submitted into the fresh session BEFORE the brief; the resolved list -- effort + vehicle first, then the caller's -- is what gets recorded), ``prompt_keywords`` (prepended as + the first line of the brief paste). + """ + dispatch: _HarnessDispatch | None = None + if kind == "harness": + dispatch, refusal = _resolve_harness_dispatch( + config, + harness=harness, + leaf_key=leaf_key, + level=level, + model=model, + effort=effort, + env=env, + launch_args=launch_args, + prompt_keywords=prompt_keywords, + session_commands=session_commands, + which=which, + ) + if refusal is not None: + return refusal + assert dispatch is not None # no refusal => a resolved dispatch bundle + harness = dispatch.harness_id + model = dispatch.model + effort = dispatch.effort + launch_args = dispatch.launch_args + prompt_keywords = dispatch.prompt_keywords + + resolved_session_commands = ( + dispatch.session_commands if dispatch is not None else list(session_commands or []) + ) + sid = session_id or uuid4().hex + spawn_env = _spawn_env(model, effort, env) + provenance_lifecycle = spawned_by_lifecycle or _ambient_lifecycle_id() + + catalog = TerminalCatalog(terminal_catalog_path(config.coordination_root)) + spawn_host = host if host is not None else TerminalHost() + shell = os.environ.get("SHELL") or _DEFAULT_SHELL + result = open_terminal_session( + catalog=catalog, + host=spawn_host, + session_id=sid, + kind=kind, + workspace_root=config.workspace_root, + shell=shell, + harness=harness if kind == "harness" else None, + label=label, + leaf_key=leaf_key, + env=spawn_env, + launch_args=launch_args, + prompt_keywords=prompt_keywords, + session_commands=resolved_session_commands or None, + spawn_level=dispatch.spawn_level if dispatch is not None else None, + spawn_level_source=dispatch.spawn_level_source if dispatch is not None else None, + spawned_by_session=spawned_by_session, + spawned_by_lifecycle=provenance_lifecycle, + which=which, + harnesses=dispatch.registry if dispatch is not None else None, + ) + + if result.status == "bad-kind": + return _spawn_refusal("bad-kind", harness, kind, detail=result.detail) + if result.status == "leaf-taken": + return _tool_payload( + "spawn_agent_session", + { + "ok": False, + "operation": "spawn_agent_session", + "status": "leaf-taken", + "session": sid, + "harness": harness if kind == "harness" else None, + "kind": result.kind, + "leafKey": leaf_key, + "ownerSession": result.owner_session_id, + }, + ) + + entry = result.entry + assert entry is not None # opened => an upserted row + + packet = _brief_packet(context, prompt_keywords) + session_commands_delivered: bool | None = None + context_delivered: bool | None = None + submitted: bool | None = None + if resolved_session_commands or packet: + spawn_paster = paster if paster is not None else TerminalPaster() + session_commands_delivered, context_delivered, submitted = _deliver_spawn_pastes( + spawn_paster, entry.tmux_name, resolved_session_commands, packet, submit + ) + + return _tool_payload( + "spawn_agent_session", + _spawned_payload(entry, session_commands_delivered, context_delivered, submitted), + ) + + +def _spawned_payload( + entry: TerminalCatalogEntry, + session_commands_delivered: bool | None, + context_delivered: bool | None, + submitted: bool | None, +) -> dict[str, Any]: + """The ``spawned`` payload: the upserted row (incl. the L16 provenance) + delivery outcomes.""" + return { + "ok": True, + "operation": "spawn_agent_session", + "status": "spawned", + "session": entry.id, + "harness": entry.harness, + "kind": entry.kind, + "leafKey": entry.leaf_key, + "label": entry.label, + "cwd": str(entry.cwd), + "tmuxName": entry.tmux_name, + "spawnedBySession": entry.spawned_by_session, + "spawnedByLifecycle": entry.spawned_by_lifecycle, + "spawnRole": entry.spawn_role, + # The resolved dispatch level + how it was supplied (rolesPerLevel resolution input). + "spawnLevel": entry.spawn_level, + "spawnLevelSource": entry.spawn_level_source, + # Free-form spawn provenance (260703-L16), echoed as recorded on the catalog row. + "launchArgs": list(entry.launch_args) if entry.launch_args else None, + "promptKeywords": list(entry.prompt_keywords) if entry.prompt_keywords else None, + "sessionCommands": list(entry.session_commands) if entry.session_commands else None, + "sessionCommandsDelivered": session_commands_delivered, + "contextDelivered": context_delivered, + "submitted": submitted, + } + + +def _spawn_refusal( + status: str, + harness: str | None, + kind: str, + *, + detail: str | None = None, +) -> dict[str, Any]: + """A pre-spawn refusal payload (unknown/undetected harness or bad kind) -- nothing was spawned.""" + return _tool_payload( + "spawn_agent_session", + { + "ok": False, + "operation": "spawn_agent_session", + "status": status, + "session": "", + "harness": harness, + "kind": kind if kind in ("harness", "terminal") else None, + "detail": detail, + }, + ) diff --git a/mcp/src/agents_remember/models/gates.py b/mcp/src/agents_remember/models/gates.py index d093b758..4dc9833b 100644 --- a/mcp/src/agents_remember/models/gates.py +++ b/mcp/src/agents_remember/models/gates.py @@ -9,6 +9,8 @@ from typing import Any +from pydantic import Field + from agents_remember.controlplane.records import GateKind, GateState from agents_remember.models.base import ToolResponse @@ -38,6 +40,8 @@ class GateDecideResponse(ToolResponse): state: GateState decidedBy: str decidedVia: str + decidingRole: str | None = None + evidenceRefs: list[dict[str, Any]] = Field(default_factory=list) class GateWaitResponse(ToolResponse): diff --git a/mcp/src/agents_remember/models/operator_inbox.py b/mcp/src/agents_remember/models/operator_inbox.py index 33b86408..4e61b6c5 100644 --- a/mcp/src/agents_remember/models/operator_inbox.py +++ b/mcp/src/agents_remember/models/operator_inbox.py @@ -4,7 +4,12 @@ from typing import Any -from agents_remember.controlplane.operator_inbox_records import OperatorInboxState +from agents_remember.controlplane.operator_inbox_records import ( + AgentRole, + InboxDeliveryState, + InboxMessageKind, + OperatorInboxState, +) from agents_remember.models.base import ToolResponse @@ -15,7 +20,16 @@ class OperatorInboxPostResponse(ToolResponse): state: OperatorInboxState lifecycleId: str | None = None agentId: str | None = None + senderAgentId: str | None = None + senderRole: AgentRole | None = None + recipientRole: AgentRole | None = None gateId: str | None = None + messageKind: InboxMessageKind + artifactPath: str | None = None + deliveryState: InboxDeliveryState + deliveredAt: str | None = None + deliveredToSession: str | None = None + deliveryDetail: str | None = None class OperatorInboxPollResponse(ToolResponse): @@ -23,6 +37,7 @@ class OperatorInboxPollResponse(ToolResponse): lifecycleId: str | None = None agentId: str | None = None + recipientRole: AgentRole | None = None entryCount: int entries: list[dict[str, Any]] diff --git a/mcp/src/agents_remember/models/orchestration.py b/mcp/src/agents_remember/models/orchestration.py new file mode 100644 index 00000000..83e95bc5 --- /dev/null +++ b/mcp/src/agents_remember/models/orchestration.py @@ -0,0 +1,22 @@ +"""Response models for orchestration helper tools.""" + +from __future__ import annotations + +from typing import Literal + +from agents_remember.controlplane.operator_inbox_records import InboxDeliveryState +from agents_remember.controlplane.orchestration_nudges import NudgeReason, NudgeState +from agents_remember.models.base import ToolResponse + + +class OrchestrationNudgeManagerResponse(ToolResponse): + """``orchestration_nudge_manager``: rate-limited manager stdin nudge.""" + + operation: Literal["orchestration_nudge_manager"] = "orchestration_nudge_manager" + status: NudgeState + reason: NudgeReason + nudgeId: str + entryId: str | None = None + deliveryState: InboxDeliveryState | None = None + deliveredToSession: str | None = None + message: str diff --git a/mcp/src/agents_remember/models/task_doc.py b/mcp/src/agents_remember/models/task_doc.py index ac914661..e88f3bae 100644 --- a/mcp/src/agents_remember/models/task_doc.py +++ b/mcp/src/agents_remember/models/task_doc.py @@ -48,6 +48,15 @@ class TaskDocResponse(ToolResponse): diff: str | None = None wouldLose: bool = False masterSync: TaskDocMasterSync | None = None + # remove_subtask outcome (260703-L18 finding 1, closes friction F-N): the op removes the master + # row and (unless keep_file) deletes the leaf doc, then echoes what it did. Without these fields + # the extra=forbid envelope REJECTED the real payload, surfacing a tool error after a destructive + # success -- a caller who believes the error could retry the (already-done) removal. Present only + # on remove_subtask (real op: removedSubtask + deletedFiles; dry-run: removedSubtask + + # wouldDeleteFiles); every other operation leaves them None (excluded by exclude_none). + removedSubtask: str | None = None + deletedFiles: list[str] | None = None + wouldDeleteFiles: list[str] | None = None class TaskReopenResponse(WorktreeCommandResponse): diff --git a/mcp/src/agents_remember/models/terminal.py b/mcp/src/agents_remember/models/terminal.py index 4bc75fda..02bf3dfe 100644 --- a/mcp/src/agents_remember/models/terminal.py +++ b/mcp/src/agents_remember/models/terminal.py @@ -19,3 +19,66 @@ class AttachTerminalSessionToLeafResponse(ToolResponse): previousLeafKey: str | None = None ownerSession: str | None = None role: Literal["chat", "terminal"] | None = None + + +SpawnAgentSessionStatus = Literal[ + "spawned", + "leaf-taken", + "harness-unknown", + "harness-not-detected", + # 260703-L16: the effort value is outside the resolved harness's known vocabulary (or a + # settings-defined harness declares no effort mapping) -- refused at dispatch (naming the + # harness + its valid sets) instead of letting the CLI warn-and-degrade. + "effort-invalid", + # 260703-L16: a settings-defined harness with no declared modelFlag got a model knob -- refused + # with guidance (declare the flag or use launchArgs); explicit over guessing. + "model-invalid", + # 260703-L16 (ruling 2026-07-07T08:15): the dispatch level is outside leaf|master|portfolio. + "level-invalid", + "bad-kind", +] + + +class SpawnAgentSessionResponse(ToolResponse): + """``spawn_agent_session``: spawn a role-configured, leaf-attached, context-primed hosted session. + + Composes the existing session primitives (opener + leaf claim + echo-confirmed paste + optional + submit). ``ok`` is true only for ``spawned``; ``leaf-taken`` surfaces the server-arbitrated + refusal (the tool never overrides it), and the harness/kind statuses report a validation refusal + before anything is spawned. + """ + + operation: Literal["spawn_agent_session"] = "spawn_agent_session" + status: SpawnAgentSessionStatus + session: str + harness: str | None = None + kind: Literal["harness", "terminal"] | None = None + leafKey: str | None = None + label: str | None = None + cwd: str | None = None + tmuxName: str | None = None + # Spawned-by provenance recorded on the catalog row (the dashboard orchestration-tree seam). + spawnedBySession: str | None = None + spawnedByLifecycle: str | None = None + # The AR_SPAWN_ROLE recorded on the catalog row (L14: the Chats command-tree grouping key). + spawnRole: str | None = None + # The RESOLVED dispatch level (leaf|master|portfolio) and whether the dispatcher supplied it + # ("explicit") or it defaulted ("default") -- the rolesPerLevel knob-resolution input + # (260703-L16, ruling 2026-07-07T08:15), recorded on the catalog row. + spawnLevel: str | None = None + spawnLevelSource: str | None = None + # Free-form spawn provenance (260703-L16), as recorded on the catalog row: launchArgs rode the + # argv verbatim, sessionCommands were pasted post-launch before the brief (the resolved list -- + # a session-vocabulary effort like claude's ultracode arrives here as "/effort ultracode"), + # promptKeywords were prepended to the brief paste. Never validated. + launchArgs: list[str] | None = None + promptKeywords: list[str] | None = None + sessionCommands: list[str] | None = None + # Whether every session command was echo-confirmed AND submitted (None = none were sent). + sessionCommandsDelivered: bool | None = None + # Set on ``leaf-taken``: the running same-role session that already owns the leaf. + ownerSession: str | None = None + # Context-packet delivery outcome (echo-confirmed paste; submit only when requested). + contextDelivered: bool | None = None + submitted: bool | None = None + detail: str | None = None diff --git a/mcp/src/agents_remember/models/tool_registry.py b/mcp/src/agents_remember/models/tool_registry.py index e9766b70..45ba3697 100644 --- a/mcp/src/agents_remember/models/tool_registry.py +++ b/mcp/src/agents_remember/models/tool_registry.py @@ -62,6 +62,7 @@ OperatorInboxPollResponse, OperatorInboxPostResponse, ) +from agents_remember.models.orchestration import OrchestrationNudgeManagerResponse from agents_remember.models.providers import ( CGCCalleesResponse, CGCCallersResponse, @@ -79,7 +80,10 @@ from agents_remember.models.runtime import ResolveContextResponse, RuntimeInstallResponse from agents_remember.models.skills import SkillsInstallResponse from agents_remember.models.task_doc import TaskDocResponse, TaskReopenResponse -from agents_remember.models.terminal import AttachTerminalSessionToLeafResponse +from agents_remember.models.terminal import ( + AttachTerminalSessionToLeafResponse, + SpawnAgentSessionResponse, +) from agents_remember.models.worktree import ( WorktreeAbandonResponse, WorktreeAttachResponse, @@ -108,6 +112,7 @@ "context_packet": ContextPacketV2, "read_ar_files": ReadArFilesResponse, "attach_terminal_session_to_leaf": AttachTerminalSessionToLeafResponse, + "spawn_agent_session": SpawnAgentSessionResponse, "runtime_install": RuntimeInstallResponse, "resolve_context": ResolveContextResponse, "drift_check": DriftCheckResponse, @@ -160,6 +165,7 @@ "operator_inbox_post": OperatorInboxPostResponse, "operator_inbox_poll": OperatorInboxPollResponse, "operator_inbox_consume": OperatorInboxConsumeResponse, + "orchestration_nudge_manager": OrchestrationNudgeManagerResponse, } PUBLIC_TOOL_RESPONSE_MODELS: dict[str, type[BaseModel]] = { diff --git a/mcp/src/agents_remember/observer/projection.py b/mcp/src/agents_remember/observer/projection.py index 591b918e..feacadb1 100644 --- a/mcp/src/agents_remember/observer/projection.py +++ b/mcp/src/agents_remember/observer/projection.py @@ -74,6 +74,7 @@ class GateNode(BaseModel): state: str decidedBy: str | None = None decidedVia: str | None = None + evidenceRefs: list[dict[str, Any]] = Field(default_factory=list) decisions: list[str] = Field(default_factory=list) packet: dict[str, Any] = Field(default_factory=dict) ts: str @@ -126,6 +127,13 @@ class EnclosureNode(BaseModel): ``lifecycleId`` cross-references the lifecycle this enclosure anchors (it is ``""`` for a legacy contract written before the lifecycle field existed). + + ``codeWorktreeExists`` / ``memoryWorktreeExists`` are the worktree-existence + TRUTH (L11): stat'ed at snapshot time in the I/O layer, exactly how the worktree + tools report existence (``contract.code_worktree.exists()`` in + ``worktree_status``). The tasks surface filters visibility on these, never on a + cleanup-state proxy — ``cleanup: reopened`` means contract-reset-awaiting-restart + (worktrees gone until the next ``worktree_start``), not live work. """ model_config = ConfigDict(extra="forbid") @@ -143,6 +151,8 @@ class EnclosureNode(BaseModel): closeoutStatus: str integrationStatus: str cleanup: str + codeWorktreeExists: bool = False + memoryWorktreeExists: bool = False actions: list[ActionAvailability] = Field(default_factory=list) @@ -276,7 +286,14 @@ class AgentPickupNode(BaseModel): entryId: str lifecycleId: str | None = None agentId: str | None = None + senderAgentId: str | None = None + senderRole: str | None = None + recipientRole: str | None = None gateId: str | None = None + messageKind: str = "message" + artifactPath: str | None = None + deliveryState: str = "queued" + deliveredToSession: str | None = None state: str ageSeconds: float | None = None ttlSeconds: float @@ -475,6 +492,10 @@ class TaskDocNode(BaseModel): # The lifecycle of the parent master this doc declares via its `master` ref, when that ref points to # a master in another series (a different lifecycle) -- drives a "↑ parent series" breadcrumb (6g). masterLifecycleId: str | None = None + # The orchestration-command relation (260703-L14): non-empty only on a ``master`` doc that IS an + # orchestration task -- the master task names it commands. The dashboard derives the + # orchestration > master > leaf hierarchy from it; docs without the field render as before. + orchestrates: list[str] = Field(default_factory=list) class SeriesSubTaskNode(BaseModel): diff --git a/mcp/src/agents_remember/observer/reducer.py b/mcp/src/agents_remember/observer/reducer.py index 6faf3fc5..33e260ba 100644 --- a/mcp/src/agents_remember/observer/reducer.py +++ b/mcp/src/agents_remember/observer/reducer.py @@ -281,7 +281,7 @@ def _persistent_lifecycles( def _persistent_from_enclosure(enclosure: EnclosureNode) -> LifecycleProjection: """Seed a paused persistent lifecycle from a worktree contract (no event log). - The l-01 phase is unknown without events, so it is inferred from the contract's git progress: + The lifecycle phase is unknown without events, so it is inferred from the contract's git progress: a completed closeout/integration reads ``close``, otherwise ``build`` (worktrees live in build). """ closed = "completed" in {enclosure.closeoutStatus, enclosure.integrationStatus} @@ -463,11 +463,36 @@ def _metrics( # --- analytical rollups (slice 3b) ------------------------------------------- +# The served fuel-gauge bound (260703-L15): one sample per token-bearing ``tool.completed`` +# event is UNBOUNDED over a long lifecycle (~60 wire bytes/sample), and the lifecycle node +# re-emits on every real change while its agent works -- an uncapped series multiplies into +# the serving hot path (10k tool calls ≈ 600 KB riding every lifecycle delta). The gauge is +# a chart, so the bound decimates: the newest TOKEN_SERIES_RECENT samples stay exact and the +# older history thins uniformly (first sample always kept) to TOKEN_SERIES_MAX total. The +# observer LOG keeps every event -- this bounds only the served projection. +TOKEN_SERIES_MAX = 512 +TOKEN_SERIES_RECENT = 256 + + +def _decimate_token_series(samples: list[TokenSample]) -> list[TokenSample]: + """Bound the series: uniform-thin the older history, keep the newest window exact.""" + if len(samples) <= TOKEN_SERIES_MAX: + return samples + history = samples[:-TOKEN_SERIES_RECENT] + budget = TOKEN_SERIES_MAX - TOKEN_SERIES_RECENT + step = len(history) / budget + thinned = [history[int(index * step)] for index in range(budget)] + return thinned + samples[-TOKEN_SERIES_RECENT:] + + def token_series(events: list[Event]) -> list[TokenSample]: """Cumulative token spend over time, from the log's ``tool.completed`` events (§2.4). The per-lifecycle fuel gauge: gap #2 ("no token-spend persistence") is closed by - the event substrate, so the running total is a pure fold of the log. + the event substrate, so the running total is a pure fold of the log. Served bounded + (260703-L15): past :data:`TOKEN_SERIES_MAX` points the older history is decimated + (shape- and total-preserving -- ``cumulative`` stays exact per retained sample) while + the newest :data:`TOKEN_SERIES_RECENT` samples stay complete. """ total = 0 samples: list[TokenSample] = [] @@ -478,7 +503,7 @@ def token_series(events: list[Event]) -> list[TokenSample]: if isinstance(tokens, int): total += tokens samples.append(TokenSample(ts=event.ts, cumulative=total)) - return samples + return _decimate_token_series(samples) # Upper bound (exclusive, seconds) per verification-age bucket; the final bucket is @@ -744,6 +769,9 @@ def _gate_node(gate: GateRecord) -> GateNode: state=gate.state, decidedBy=gate.decidedBy, decidedVia=gate.decidedVia, + evidenceRefs=[ + ref.model_dump(mode="json", exclude_none=True) for ref in gate.evidenceRefs + ], decisions=sorted(DECISION_STATES) if gate.state == "open" else [], packet=gate.packet, ts=gate.ts, diff --git a/mcp/src/agents_remember/observer/snapshots.py b/mcp/src/agents_remember/observer/snapshots.py index de83e7ea..cc5c2103 100644 --- a/mcp/src/agents_remember/observer/snapshots.py +++ b/mcp/src/agents_remember/observer/snapshots.py @@ -426,6 +426,13 @@ def _enclosure_from_contract(path: Path) -> EnclosureNode | None: closeoutStatus=contract.closeout_status, integrationStatus=contract.integration_status, cleanup=contract.cleanup, + # Worktree-existence truth (L11), stat'ed here at snapshot time exactly as + # worktree_status reports it: the tasks surface renders a leaf ONLY while a + # worktree physically exists, so this must never be inferred from cleanup state. + codeWorktreeExists=contract.code_worktree.exists(), + memoryWorktreeExists=( + contract.memory_worktree.exists() if contract.memory_worktree else False + ), ) @@ -484,7 +491,14 @@ def read_agent_pickups(coordination_root: Path, *, now: datetime) -> list[AgentP entryId=entry.id, lifecycleId=entry.lifecycleId, agentId=entry.agentId, + senderAgentId=entry.senderAgentId, + senderRole=entry.senderRole, + recipientRole=entry.recipientRole, gateId=entry.gateId, + messageKind=entry.messageKind, + artifactPath=entry.artifactPath, + deliveryState=entry.deliveryState, + deliveredToSession=entry.deliveredToSession, state=pickup_state(entry, now=now), ageSeconds=pickup_age_seconds(entry, now=now), ttlSeconds=AGENT_PICKUP_TTL_SECONDS, @@ -1147,6 +1161,7 @@ def _task_doc_node( for section in doc.sections ], masterLifecycleId=parent_lifecycle, + orchestrates=list(doc.orchestrates), ) diff --git a/mcp/src/agents_remember/package_data/dashboard.fingerprint b/mcp/src/agents_remember/package_data/dashboard.fingerprint index acdd559b..fc762ba9 100644 --- a/mcp/src/agents_remember/package_data/dashboard.fingerprint +++ b/mcp/src/agents_remember/package_data/dashboard.fingerprint @@ -1 +1 @@ -1ed41496595a626356f7cea57b44998801e5a1bcbce0a7c048e3d29546dc9e6e +9c7015119ad08d3419057365ad8281b8128d0782af309aa543e4755c05ea8146 diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/Terminal-ChlT6ruV.js b/mcp/src/agents_remember/package_data/dashboard/assets/Terminal-CyrgkVUD.js similarity index 99% rename from mcp/src/agents_remember/package_data/dashboard/assets/Terminal-ChlT6ruV.js rename to mcp/src/agents_remember/package_data/dashboard/assets/Terminal-CyrgkVUD.js index fd52128d..754f40d0 100644 --- a/mcp/src/agents_remember/package_data/dashboard/assets/Terminal-ChlT6ruV.js +++ b/mcp/src/agents_remember/package_data/dashboard/assets/Terminal-CyrgkVUD.js @@ -1,4 +1,4 @@ -import{J as e,Q as t,X as n,Y as r,Z as i,et as a,q as o}from"./index-BLlkJI-k.js";var s=t(((e,t)=>{(function(n,r){typeof e==`object`&&typeof t==`object`?t.exports=r():typeof define==`function`&&define.amd?define([],r):typeof e==`object`?e.FitAddon=r():n.FitAddon=r()})(self,(()=>(()=>{var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core,t=e._renderService.dimensions;if(t.css.cell.width===0||t.css.cell.height===0)return;let n=this._terminal.options.scrollback===0?0:e.viewport.scrollBarWidth,r=window.getComputedStyle(this._terminal.element.parentElement),i=parseInt(r.getPropertyValue(`height`)),a=Math.max(0,parseInt(r.getPropertyValue(`width`))),o=window.getComputedStyle(this._terminal.element),s=i-(parseInt(o.getPropertyValue(`padding-top`))+parseInt(o.getPropertyValue(`padding-bottom`))),c=a-(parseInt(o.getPropertyValue(`padding-right`))+parseInt(o.getPropertyValue(`padding-left`)))-n;return{cols:Math.max(2,Math.floor(c/t.css.cell.width)),rows:Math.max(1,Math.floor(s/t.css.cell.height))}}}})(),e})()))})),c=t(((e,t)=>{(function(n,r){if(typeof e==`object`&&typeof t==`object`)t.exports=r();else if(typeof define==`function`&&define.amd)define([],r);else{var i=r();for(var a in i)(typeof e==`object`?e:n)[a]=i[a]}})(globalThis,(()=>(()=>{var e={4567:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;let a=n(9042),o=n(9924),s=n(844),c=n(4725),l=n(2585),u=n(3656),d=t.AccessibilityManager=class extends s.Disposable{constructor(e,t,n,r){super(),this._terminal=e,this._coreBrowserService=n,this._renderService=r,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce=``,this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement(`div`),this._accessibilityContainer.classList.add(`xterm-accessibility`),this._rowContainer=this._coreBrowserService.mainDocument.createElement(`div`),this._rowContainer.setAttribute(`role`,`list`),this._rowContainer.classList.add(`xterm-accessibility-tree`),this._rowElements=[];for(let e=0;ethis._handleBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._handleBoundaryFocus(e,1),this._rowElements[0].addEventListener(`focus`,this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener(`focus`,this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement(`div`),this._liveRegion.classList.add(`live-region`),this._liveRegion.setAttribute(`aria-live`,`assertive`),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new o.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw Error(`Cannot enable accessibility before Terminal.open`);this._terminal.element.insertAdjacentElement(`afterbegin`,this._accessibilityContainer),this.register(this._terminal.onResize((e=>this._handleResize(e.rows)))),this.register(this._terminal.onRender((e=>this._refreshRows(e.start,e.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((e=>this._handleChar(e)))),this.register(this._terminal.onLineFeed((()=>this._handleChar(` +import{J as e,Q as t,X as n,Y as r,Z as i,et as a,q as o}from"./index-CLJ0aycO.js";var s=t(((e,t)=>{(function(n,r){typeof e==`object`&&typeof t==`object`?t.exports=r():typeof define==`function`&&define.amd?define([],r):typeof e==`object`?e.FitAddon=r():n.FitAddon=r()})(self,(()=>(()=>{var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core,t=e._renderService.dimensions;if(t.css.cell.width===0||t.css.cell.height===0)return;let n=this._terminal.options.scrollback===0?0:e.viewport.scrollBarWidth,r=window.getComputedStyle(this._terminal.element.parentElement),i=parseInt(r.getPropertyValue(`height`)),a=Math.max(0,parseInt(r.getPropertyValue(`width`))),o=window.getComputedStyle(this._terminal.element),s=i-(parseInt(o.getPropertyValue(`padding-top`))+parseInt(o.getPropertyValue(`padding-bottom`))),c=a-(parseInt(o.getPropertyValue(`padding-right`))+parseInt(o.getPropertyValue(`padding-left`)))-n;return{cols:Math.max(2,Math.floor(c/t.css.cell.width)),rows:Math.max(1,Math.floor(s/t.css.cell.height))}}}})(),e})()))})),c=t(((e,t)=>{(function(n,r){if(typeof e==`object`&&typeof t==`object`)t.exports=r();else if(typeof define==`function`&&define.amd)define([],r);else{var i=r();for(var a in i)(typeof e==`object`?e:n)[a]=i[a]}})(globalThis,(()=>(()=>{var e={4567:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;let a=n(9042),o=n(9924),s=n(844),c=n(4725),l=n(2585),u=n(3656),d=t.AccessibilityManager=class extends s.Disposable{constructor(e,t,n,r){super(),this._terminal=e,this._coreBrowserService=n,this._renderService=r,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce=``,this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement(`div`),this._accessibilityContainer.classList.add(`xterm-accessibility`),this._rowContainer=this._coreBrowserService.mainDocument.createElement(`div`),this._rowContainer.setAttribute(`role`,`list`),this._rowContainer.classList.add(`xterm-accessibility-tree`),this._rowElements=[];for(let e=0;ethis._handleBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._handleBoundaryFocus(e,1),this._rowElements[0].addEventListener(`focus`,this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener(`focus`,this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement(`div`),this._liveRegion.classList.add(`live-region`),this._liveRegion.setAttribute(`aria-live`,`assertive`),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new o.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw Error(`Cannot enable accessibility before Terminal.open`);this._terminal.element.insertAdjacentElement(`afterbegin`,this._accessibilityContainer),this.register(this._terminal.onResize((e=>this._handleResize(e.rows)))),this.register(this._terminal.onRender((e=>this._refreshRows(e.start,e.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((e=>this._handleChar(e)))),this.register(this._terminal.onLineFeed((()=>this._handleChar(` `)))),this.register(this._terminal.onA11yTab((e=>this._handleTab(e)))),this.register(this._terminal.onKey((e=>this._handleKey(e.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this.register((0,u.addDisposableDomListener)(document,`selectionchange`,(()=>this._handleSelectionChange()))),this.register(this._coreBrowserService.onDprChange((()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,s.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(e){for(let t=0;t0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,e===` `&&(this._liveRegionLineCount++,this._liveRegionLineCount===21&&(this._liveRegion.textContent+=a.tooMuchOutput)))}_clearLiveRegion(){this._liveRegion.textContent=``,this._liveRegionLineCount=0}_handleKey(e){this._clearLiveRegion(),/\p{Control}/u.test(e)||this._charsToConsume.push(e)}_refreshRows(e,t){this._liveRegionDebouncer.refresh(e,t,this._terminal.rows)}_renderRows(e,t){let n=this._terminal.buffer,r=n.lines.length.toString();for(let i=e;i<=t;i++){let e=n.lines.get(n.ydisp+i),t=[],a=e?.translateToString(!0,void 0,void 0,t)||``,o=(n.ydisp+i+1).toString(),s=this._rowElements[i];s&&(a.length===0?(s.innerText=`\xA0`,this._rowColumns.set(s,[0,1])):(s.textContent=a,this._rowColumns.set(s,t)),s.setAttribute(`aria-posinset`,o),s.setAttribute(`aria-setsize`,r))}this._announceCharacters()}_announceCharacters(){this._charsToAnnounce.length!==0&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce=``)}_handleBoundaryFocus(e,t){let n=e.target,r=this._rowElements[t===0?1:this._rowElements.length-2];if(n.getAttribute(`aria-posinset`)===(t===0?`1`:`${this._terminal.buffer.lines.length}`)||e.relatedTarget!==r)return;let i,a;if(t===0?(i=n,a=this._rowElements.pop(),this._rowContainer.removeChild(a)):(i=this._rowElements.shift(),a=n,this._rowContainer.removeChild(i)),i.removeEventListener(`focus`,this._topBoundaryFocusListener),a.removeEventListener(`focus`,this._bottomBoundaryFocusListener),t===0){let e=this._createAccessibilityTreeNode();this._rowElements.unshift(e),this._rowContainer.insertAdjacentElement(`afterbegin`,e)}else{let e=this._createAccessibilityTreeNode();this._rowElements.push(e),this._rowContainer.appendChild(e)}this._rowElements[0].addEventListener(`focus`,this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener(`focus`,this._bottomBoundaryFocusListener),this._terminal.scrollLines(t===0?-1:1),this._rowElements[t===0?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}_handleSelectionChange(){if(this._rowElements.length===0)return;let e=document.getSelection();if(!e)return;if(e.isCollapsed)return void(this._rowContainer.contains(e.anchorNode)&&this._terminal.clearSelection());if(!e.anchorNode||!e.focusNode)return void console.error(`anchorNode and/or focusNode are null`);let t={node:e.anchorNode,offset:e.anchorOffset},n={node:e.focusNode,offset:e.focusOffset};if((t.node.compareDocumentPosition(n.node)&Node.DOCUMENT_POSITION_PRECEDING||t.node===n.node&&t.offset>n.offset)&&([t,n]=[n,t]),t.node.compareDocumentPosition(this._rowElements[0])&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_FOLLOWING)&&(t={node:this._rowElements[0].childNodes[0],offset:0}),!this._rowContainer.contains(t.node))return;let r=this._rowElements.slice(-1)[0];if(n.node.compareDocumentPosition(r)&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_PRECEDING)&&(n={node:r,offset:r.textContent?.length??0}),!this._rowContainer.contains(n.node))return;let i=({node:e,offset:t})=>{let n=e instanceof Text?e.parentNode:e,r=parseInt(n?.getAttribute(`aria-posinset`),10)-1;if(isNaN(r))return console.warn(`row is invalid. Race condition?`),null;let i=this._rowColumns.get(n);if(!i)return console.warn(`columns is null. Race condition?`),null;let a=t=this._terminal.cols&&(++r,a=0),{row:r,column:a}},a=i(t),o=i(n);if(a&&o){if(a.row>o.row||a.row===o.row&&a.column>=o.column)throw Error(`invalid range`);this._terminal.select(a.column,a.row,(o.row-a.row)*this._terminal.cols-a.column+o.column)}}_handleResize(e){this._rowElements[this._rowElements.length-1].removeEventListener(`focus`,this._bottomBoundaryFocusListener);for(let e=this._rowContainer.children.length;ee;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener(`focus`,this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){let e=this._coreBrowserService.mainDocument.createElement(`div`);return e.setAttribute(`role`,`listitem`),e.tabIndex=-1,this._refreshRowDimensions(e),e}_refreshRowsDimensions(){if(this._renderService.dimensions.css.cell.height){this._accessibilityContainer.style.width=`${this._renderService.dimensions.css.canvas.width}px`,this._rowElements.length!==this._terminal.rows&&this._handleResize(this._terminal.rows);for(let e=0;e{function n(e){return e.replace(/\r?\n/g,`\r`)}function r(e,t){return t?`\x1B[200~`+e+`\x1B[201~`:e}function i(e,t,i,a){e=r(e=n(e),i.decPrivateModes.bracketedPasteMode&&!0!==a.rawOptions.ignoreBracketedPasteMode),i.triggerDataEvent(e,!0),t.value=``}function a(e,t,n){let r=n.getBoundingClientRect(),i=e.clientX-r.left-10,a=e.clientY-r.top-10;t.style.width=`20px`,t.style.height=`20px`,t.style.left=`${i}px`,t.style.top=`${a}px`,t.style.zIndex=`1000`,t.focus()}Object.defineProperty(t,"__esModule",{value:!0}),t.rightClickHandler=t.moveTextAreaUnderMouseCursor=t.paste=t.handlePasteEvent=t.copyHandler=t.bracketTextForPaste=t.prepareTextForTerminal=void 0,t.prepareTextForTerminal=n,t.bracketTextForPaste=r,t.copyHandler=function(e,t){e.clipboardData&&e.clipboardData.setData(`text/plain`,t.selectionText),e.preventDefault()},t.handlePasteEvent=function(e,t,n,r){e.stopPropagation(),e.clipboardData&&i(e.clipboardData.getData(`text/plain`),t,n,r)},t.paste=i,t.moveTextAreaUnderMouseCursor=a,t.rightClickHandler=function(e,t,n,r,i){a(e,t,n),i&&r.rightClickSelect(e),t.value=r.selectionText,t.select()}},7239:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorContrastCache=void 0;let r=n(1505);t.ColorContrastCache=class{constructor(){this._color=new r.TwoKeyMap,this._css=new r.TwoKeyMap}setCss(e,t,n){this._css.set(e,t,n)}getCss(e,t){return this._css.get(e,t)}setColor(e,t,n){this._color.set(e,t,n)}getColor(e,t){return this._color.get(e,t)}clear(){this._color.clear(),this._css.clear()}}},3656:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addDisposableDomListener=void 0,t.addDisposableDomListener=function(e,t,n,r){e.addEventListener(t,n,r);let i=!1;return{dispose:()=>{i||(i=!0,e.removeEventListener(t,n,r))}}}},3551:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Linkifier=void 0;let a=n(3656),o=n(8460),s=n(844),c=n(2585),l=n(4725),u=t.Linkifier=class extends s.Disposable{get currentLink(){return this._currentLink}constructor(e,t,n,r,i){super(),this._element=e,this._mouseService=t,this._renderService=n,this._bufferService=r,this._linkProviderService=i,this._linkCacheDisposables=[],this._isMouseOut=!0,this._wasResized=!1,this._activeLine=-1,this._onShowLinkUnderline=this.register(new o.EventEmitter),this.onShowLinkUnderline=this._onShowLinkUnderline.event,this._onHideLinkUnderline=this.register(new o.EventEmitter),this.onHideLinkUnderline=this._onHideLinkUnderline.event,this.register((0,s.getDisposeArrayDisposable)(this._linkCacheDisposables)),this.register((0,s.toDisposable)((()=>{this._lastMouseEvent=void 0,this._activeProviderReplies?.clear()}))),this.register(this._bufferService.onResize((()=>{this._clearCurrentLink(),this._wasResized=!0}))),this.register((0,a.addDisposableDomListener)(this._element,`mouseleave`,(()=>{this._isMouseOut=!0,this._clearCurrentLink()}))),this.register((0,a.addDisposableDomListener)(this._element,`mousemove`,this._handleMouseMove.bind(this))),this.register((0,a.addDisposableDomListener)(this._element,`mousedown`,this._handleMouseDown.bind(this))),this.register((0,a.addDisposableDomListener)(this._element,`mouseup`,this._handleMouseUp.bind(this)))}_handleMouseMove(e){this._lastMouseEvent=e;let t=this._positionFromMouseEvent(e,this._element,this._mouseService);if(!t)return;this._isMouseOut=!1;let n=e.composedPath();for(let e=0;e{e?.forEach((e=>{e.link.dispose&&e.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=e.y);let n=!1;for(let[r,i]of this._linkProviderService.linkProviders.entries())t?this._activeProviderReplies?.get(r)&&(n=this._checkLinkProviderResult(r,e,n)):i.provideLinks(e.y,(t=>{if(this._isMouseOut)return;let i=t?.map((e=>({link:e})));this._activeProviderReplies?.set(r,i),n=this._checkLinkProviderResult(r,e,n),this._activeProviderReplies?.size===this._linkProviderService.linkProviders.length&&this._removeIntersectingLinks(e.y,this._activeProviderReplies)}))}_removeIntersectingLinks(e,t){let n=new Set;for(let r=0;re?this._bufferService.cols:r.link.range.end.x;for(let e=a;e<=o;e++){if(n.has(e)){i.splice(t--,1);break}n.add(e)}}}}_checkLinkProviderResult(e,t,n){if(!this._activeProviderReplies)return n;let r=this._activeProviderReplies.get(e),i=!1;for(let t=0;tthis._linkAtPosition(e.link,t)));e&&(n=!0,this._handleNewLink(e))}if(this._activeProviderReplies.size===this._linkProviderService.linkProviders.length&&!n)for(let e=0;ethis._linkAtPosition(e.link,t)));if(r){n=!0,this._handleNewLink(r);break}}return n}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(e){if(!this._currentLink)return;let t=this._positionFromMouseEvent(e,this._element,this._mouseService);t&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,t)&&this._currentLink.link.activate(e,this._currentLink.link.text)}_clearCurrentLink(e,t){this._currentLink&&this._lastMouseEvent&&(!e||!t||this._currentLink.link.range.start.y>=e&&this._currentLink.link.range.end.y<=t)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,s.disposeArray)(this._linkCacheDisposables))}_handleNewLink(e){if(!this._lastMouseEvent)return;let t=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);t&&this._linkAtPosition(e.link,t)&&(this._currentLink=e,this._currentLink.state={decorations:{underline:e.link.decorations===void 0||e.link.decorations.underline,pointerCursor:e.link.decorations===void 0||e.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,e.link,this._lastMouseEvent),e.link.decorations={},Object.defineProperties(e.link.decorations,{pointerCursor:{get:()=>this._currentLink?.state?.decorations.pointerCursor,set:e=>{this._currentLink?.state&&this._currentLink.state.decorations.pointerCursor!==e&&(this._currentLink.state.decorations.pointerCursor=e,this._currentLink.state.isHovered&&this._element.classList.toggle(`xterm-cursor-pointer`,e))}},underline:{get:()=>this._currentLink?.state?.decorations.underline,set:t=>{this._currentLink?.state&&this._currentLink?.state?.decorations.underline!==t&&(this._currentLink.state.decorations.underline=t,this._currentLink.state.isHovered&&this._fireUnderlineEvent(e.link,t))}}}),this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange((e=>{if(!this._currentLink)return;let t=e.start===0?0:e.start+1+this._bufferService.buffer.ydisp,n=this._bufferService.buffer.ydisp+1+e.end;if(this._currentLink.link.range.start.y>=t&&this._currentLink.link.range.end.y<=n&&(this._clearCurrentLink(t,n),this._lastMouseEvent)){let e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);e&&this._askForLink(e,!1)}}))))}_linkHover(e,t,n){this._currentLink?.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!0),this._currentLink.state.decorations.pointerCursor&&e.classList.add(`xterm-cursor-pointer`)),t.hover&&t.hover(n,t.text)}_fireUnderlineEvent(e,t){let n=e.range,r=this._bufferService.buffer.ydisp,i=this._createLinkUnderlineEvent(n.start.x-1,n.start.y-r-1,n.end.x,n.end.y-r-1,void 0);(t?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(i)}_linkLeave(e,t,n){this._currentLink?.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!1),this._currentLink.state.decorations.pointerCursor&&e.classList.remove(`xterm-cursor-pointer`)),t.leave&&t.leave(n,t.text)}_linkAtPosition(e,t){let n=e.range.start.y*this._bufferService.cols+e.range.start.x,r=e.range.end.y*this._bufferService.cols+e.range.end.x,i=t.y*this._bufferService.cols+t.x;return n<=i&&i<=r}_positionFromMouseEvent(e,t,n){let r=n.getCoords(e,t,this._bufferService.cols,this._bufferService.rows);if(r)return{x:r[0],y:r[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(e,t,n,r,i){return{x1:e,y1:t,x2:n,y2:r,cols:this._bufferService.cols,fg:i}}};t.Linkifier=u=r([i(1,l.IMouseService),i(2,l.IRenderService),i(3,c.IBufferService),i(4,l.ILinkProviderService)],u)},9042:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.tooMuchOutput=t.promptLabel=void 0,t.promptLabel=`Terminal input`,t.tooMuchOutput=`Too much output to announce, navigate to rows manually to read`},3730:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkProvider=void 0;let a=n(511),o=n(2585),s=t.OscLinkProvider=class{constructor(e,t,n){this._bufferService=e,this._optionsService=t,this._oscLinkService=n}provideLinks(e,t){let n=this._bufferService.buffer.lines.get(e-1);if(!n)return void t(void 0);let r=[],i=this._optionsService.rawOptions.linkHandler,o=new a.CellData,s=n.getTrimmedLength(),l=-1,u=-1,d=!1;for(let t=0;ti?i.activate(e,t,a):c(0,t),hover:(e,t)=>i?.hover?.(e,t,a),leave:(e,t)=>i?.leave?.(e,t,a)})}d=!1,o.hasExtendedAttrs()&&o.extended.urlId?(u=t,l=o.extended.urlId):(u=-1,l=-1)}}t(r)}};function c(e,t){if(confirm(`Do you want to navigate to ${t}?\n\nWARNING: This link could potentially be dangerous`)){let e=window.open();if(e){try{e.opener=null}catch{}e.location.href=t}else console.warn(`Opening link blocked as opener could not be cleared`)}}t.OscLinkProvider=s=r([i(0,o.IBufferService),i(1,o.IOptionsService),i(2,o.IOscLinkService)],s)},6193:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.RenderDebouncer=void 0,t.RenderDebouncer=class{constructor(e,t){this._renderCallback=e,this._coreBrowserService=t,this._refreshCallbacks=[]}dispose(){this._animationFrame&&=(this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame),void 0)}addRefreshCallback(e){return this._refreshCallbacks.push(e),this._animationFrame||=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())),this._animationFrame}refresh(e,t,n){this._rowCount=n,e=e===void 0?0:e,t=t===void 0?this._rowCount-1:t,this._rowStart=this._rowStart===void 0?e:Math.min(this._rowStart,e),this._rowEnd=this._rowEnd===void 0?t:Math.max(this._rowEnd,t),this._animationFrame||=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh()))}_innerRefresh(){if(this._animationFrame=void 0,this._rowStart===void 0||this._rowEnd===void 0||this._rowCount===void 0)return void this._runRefreshCallbacks();let e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t),this._runRefreshCallbacks()}_runRefreshCallbacks(){for(let e of this._refreshCallbacks)e(0);this._refreshCallbacks=[]}}},3236:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;let r=n(3614),i=n(3656),a=n(3551),o=n(9042),s=n(3730),c=n(1680),l=n(3107),u=n(5744),d=n(2950),f=n(1296),p=n(428),m=n(4269),h=n(5114),g=n(8934),_=n(3230),v=n(9312),y=n(4725),b=n(6731),x=n(8055),S=n(8969),C=n(8460),w=n(844),T=n(6114),E=n(8437),D=n(2584),O=n(7399),k=n(5941),A=n(9074),j=n(2585),M=n(5435),N=n(4567),P=n(779);class F extends S.CoreTerminal{get onFocus(){return this._onFocus.event}get onBlur(){return this._onBlur.event}get onA11yChar(){return this._onA11yCharEmitter.event}get onA11yTab(){return this._onA11yTabEmitter.event}get onWillOpen(){return this._onWillOpen.event}constructor(e={}){super(e),this.browser=T,this._keyDownHandled=!1,this._keyDownSeen=!1,this._keyPressHandled=!1,this._unprocessedDeadKey=!1,this._accessibilityManager=this.register(new w.MutableDisposable),this._onCursorMove=this.register(new C.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onKey=this.register(new C.EventEmitter),this.onKey=this._onKey.event,this._onRender=this.register(new C.EventEmitter),this.onRender=this._onRender.event,this._onSelectionChange=this.register(new C.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onTitleChange=this.register(new C.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onBell=this.register(new C.EventEmitter),this.onBell=this._onBell.event,this._onFocus=this.register(new C.EventEmitter),this._onBlur=this.register(new C.EventEmitter),this._onA11yCharEmitter=this.register(new C.EventEmitter),this._onA11yTabEmitter=this.register(new C.EventEmitter),this._onWillOpen=this.register(new C.EventEmitter),this._setup(),this._decorationService=this._instantiationService.createInstance(A.DecorationService),this._instantiationService.setService(j.IDecorationService,this._decorationService),this._linkProviderService=this._instantiationService.createInstance(P.LinkProviderService),this._instantiationService.setService(y.ILinkProviderService,this._linkProviderService),this._linkProviderService.registerLinkProvider(this._instantiationService.createInstance(s.OscLinkProvider)),this.register(this._inputHandler.onRequestBell((()=>this._onBell.fire()))),this.register(this._inputHandler.onRequestRefreshRows(((e,t)=>this.refresh(e,t)))),this.register(this._inputHandler.onRequestSendFocus((()=>this._reportFocus()))),this.register(this._inputHandler.onRequestReset((()=>this.reset()))),this.register(this._inputHandler.onRequestWindowsOptionsReport((e=>this._reportWindowsOptions(e)))),this.register(this._inputHandler.onColor((e=>this._handleColorEvent(e)))),this.register((0,C.forwardEvent)(this._inputHandler.onCursorMove,this._onCursorMove)),this.register((0,C.forwardEvent)(this._inputHandler.onTitleChange,this._onTitleChange)),this.register((0,C.forwardEvent)(this._inputHandler.onA11yChar,this._onA11yCharEmitter)),this.register((0,C.forwardEvent)(this._inputHandler.onA11yTab,this._onA11yTabEmitter)),this.register(this._bufferService.onResize((e=>this._afterResize(e.cols,e.rows)))),this.register((0,w.toDisposable)((()=>{this._customKeyEventHandler=void 0,this.element?.parentNode?.removeChild(this.element)})))}_handleColorEvent(e){if(this._themeService)for(let t of e){let e,n=``;switch(t.index){case 256:e=`foreground`,n=`10`;break;case 257:e=`background`,n=`11`;break;case 258:e=`cursor`,n=`12`;break;default:e=`ansi`,n=`4;`+t.index}switch(t.type){case 0:let r=x.color.toColorRGB(e===`ansi`?this._themeService.colors.ansi[t.index]:this._themeService.colors[e]);this.coreService.triggerDataEvent(`${D.C0.ESC}]${n};${(0,k.toRgbString)(r)}${D.C1_ESCAPED.ST}`);break;case 1:if(e===`ansi`)this._themeService.modifyColors((e=>e.ansi[t.index]=x.channels.toColor(...t.color)));else{let n=e;this._themeService.modifyColors((e=>e[n]=x.channels.toColor(...t.color)))}break;case 2:this._themeService.restoreColor(t.index)}}}_setup(){super._setup(),this._customKeyEventHandler=void 0}get buffer(){return this.buffers.active}focus(){this.textarea&&this.textarea.focus({preventScroll:!0})}_handleScreenReaderModeOptionChange(e){e?!this._accessibilityManager.value&&this._renderService&&(this._accessibilityManager.value=this._instantiationService.createInstance(N.AccessibilityManager,this)):this._accessibilityManager.clear()}_handleTextAreaFocus(e){this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+`[I`),this.element.classList.add(`focus`),this._showCursor(),this._onFocus.fire()}blur(){return this.textarea?.blur()}_handleTextAreaBlur(){this.textarea.value=``,this.refresh(this.buffer.y,this.buffer.y),this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+`[O`),this.element.classList.remove(`focus`),this._onBlur.fire()}_syncTextArea(){if(!this.textarea||!this.buffer.isCursorInViewport||this._compositionHelper.isComposing||!this._renderService)return;let e=this.buffer.ybase+this.buffer.y,t=this.buffer.lines.get(e);if(!t)return;let n=Math.min(this.buffer.x,this.cols-1),r=this._renderService.dimensions.css.cell.height,i=t.getWidth(n),a=this._renderService.dimensions.css.cell.width*i,o=this.buffer.y*this._renderService.dimensions.css.cell.height,s=n*this._renderService.dimensions.css.cell.width;this.textarea.style.left=s+`px`,this.textarea.style.top=o+`px`,this.textarea.style.width=a+`px`,this.textarea.style.height=r+`px`,this.textarea.style.lineHeight=r+`px`,this.textarea.style.zIndex=`-5`}_initGlobal(){this._bindKeys(),this.register((0,i.addDisposableDomListener)(this.element,`copy`,(e=>{this.hasSelection()&&(0,r.copyHandler)(e,this._selectionService)})));let e=e=>(0,r.handlePasteEvent)(e,this.textarea,this.coreService,this.optionsService);this.register((0,i.addDisposableDomListener)(this.textarea,`paste`,e)),this.register((0,i.addDisposableDomListener)(this.element,`paste`,e)),T.isFirefox?this.register((0,i.addDisposableDomListener)(this.element,`mousedown`,(e=>{e.button===2&&(0,r.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))):this.register((0,i.addDisposableDomListener)(this.element,`contextmenu`,(e=>{(0,r.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))),T.isLinux&&this.register((0,i.addDisposableDomListener)(this.element,`auxclick`,(e=>{e.button===1&&(0,r.moveTextAreaUnderMouseCursor)(e,this.textarea,this.screenElement)})))}_bindKeys(){this.register((0,i.addDisposableDomListener)(this.textarea,`keyup`,(e=>this._keyUp(e)),!0)),this.register((0,i.addDisposableDomListener)(this.textarea,`keydown`,(e=>this._keyDown(e)),!0)),this.register((0,i.addDisposableDomListener)(this.textarea,`keypress`,(e=>this._keyPress(e)),!0)),this.register((0,i.addDisposableDomListener)(this.textarea,`compositionstart`,(()=>this._compositionHelper.compositionstart()))),this.register((0,i.addDisposableDomListener)(this.textarea,`compositionupdate`,(e=>this._compositionHelper.compositionupdate(e)))),this.register((0,i.addDisposableDomListener)(this.textarea,`compositionend`,(()=>this._compositionHelper.compositionend()))),this.register((0,i.addDisposableDomListener)(this.textarea,`input`,(e=>this._inputEvent(e)),!0)),this.register(this.onRender((()=>this._compositionHelper.updateCompositionElements())))}open(e){if(!e)throw Error(`Terminal requires a parent element.`);if(e.isConnected||this._logService.debug(`Terminal.open was called on an element that was not attached to the DOM`),this.element?.ownerDocument.defaultView&&this._coreBrowserService)return void(this.element.ownerDocument.defaultView!==this._coreBrowserService.window&&(this._coreBrowserService.window=this.element.ownerDocument.defaultView));this._document=e.ownerDocument,this.options.documentOverride&&this.options.documentOverride instanceof Document&&(this._document=this.optionsService.rawOptions.documentOverride),this.element=this._document.createElement(`div`),this.element.dir=`ltr`,this.element.classList.add(`terminal`),this.element.classList.add(`xterm`),e.appendChild(this.element);let t=this._document.createDocumentFragment();this._viewportElement=this._document.createElement(`div`),this._viewportElement.classList.add(`xterm-viewport`),t.appendChild(this._viewportElement),this._viewportScrollArea=this._document.createElement(`div`),this._viewportScrollArea.classList.add(`xterm-scroll-area`),this._viewportElement.appendChild(this._viewportScrollArea),this.screenElement=this._document.createElement(`div`),this.screenElement.classList.add(`xterm-screen`),this.register((0,i.addDisposableDomListener)(this.screenElement,`mousemove`,(e=>this.updateCursorStyle(e)))),this._helperContainer=this._document.createElement(`div`),this._helperContainer.classList.add(`xterm-helpers`),this.screenElement.appendChild(this._helperContainer),t.appendChild(this.screenElement),this.textarea=this._document.createElement(`textarea`),this.textarea.classList.add(`xterm-helper-textarea`),this.textarea.setAttribute(`aria-label`,o.promptLabel),T.isChromeOS||this.textarea.setAttribute(`aria-multiline`,`false`),this.textarea.setAttribute(`autocorrect`,`off`),this.textarea.setAttribute(`autocapitalize`,`off`),this.textarea.setAttribute(`spellcheck`,`false`),this.textarea.tabIndex=0,this._coreBrowserService=this.register(this._instantiationService.createInstance(h.CoreBrowserService,this.textarea,e.ownerDocument.defaultView??window,this._document??typeof window<`u`?window.document:null)),this._instantiationService.setService(y.ICoreBrowserService,this._coreBrowserService),this.register((0,i.addDisposableDomListener)(this.textarea,`focus`,(e=>this._handleTextAreaFocus(e)))),this.register((0,i.addDisposableDomListener)(this.textarea,`blur`,(()=>this._handleTextAreaBlur()))),this._helperContainer.appendChild(this.textarea),this._charSizeService=this._instantiationService.createInstance(p.CharSizeService,this._document,this._helperContainer),this._instantiationService.setService(y.ICharSizeService,this._charSizeService),this._themeService=this._instantiationService.createInstance(b.ThemeService),this._instantiationService.setService(y.IThemeService,this._themeService),this._characterJoinerService=this._instantiationService.createInstance(m.CharacterJoinerService),this._instantiationService.setService(y.ICharacterJoinerService,this._characterJoinerService),this._renderService=this.register(this._instantiationService.createInstance(_.RenderService,this.rows,this.screenElement)),this._instantiationService.setService(y.IRenderService,this._renderService),this.register(this._renderService.onRenderedViewportChange((e=>this._onRender.fire(e)))),this.onResize((e=>this._renderService.resize(e.cols,e.rows))),this._compositionView=this._document.createElement(`div`),this._compositionView.classList.add(`composition-view`),this._compositionHelper=this._instantiationService.createInstance(d.CompositionHelper,this.textarea,this._compositionView),this._helperContainer.appendChild(this._compositionView),this._mouseService=this._instantiationService.createInstance(g.MouseService),this._instantiationService.setService(y.IMouseService,this._mouseService),this.linkifier=this.register(this._instantiationService.createInstance(a.Linkifier,this.screenElement)),this.element.appendChild(t);try{this._onWillOpen.fire(this.element)}catch{}this._renderService.hasRenderer()||this._renderService.setRenderer(this._createRenderer()),this.viewport=this._instantiationService.createInstance(c.Viewport,this._viewportElement,this._viewportScrollArea),this.viewport.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent,1))),this.register(this._inputHandler.onRequestSyncScrollBar((()=>this.viewport.syncScrollArea()))),this.register(this.viewport),this.register(this.onCursorMove((()=>{this._renderService.handleCursorMove(),this._syncTextArea()}))),this.register(this.onResize((()=>this._renderService.handleResize(this.cols,this.rows)))),this.register(this.onBlur((()=>this._renderService.handleBlur()))),this.register(this.onFocus((()=>this._renderService.handleFocus()))),this.register(this._renderService.onDimensionsChange((()=>this.viewport.syncScrollArea()))),this._selectionService=this.register(this._instantiationService.createInstance(v.SelectionService,this.element,this.screenElement,this.linkifier)),this._instantiationService.setService(y.ISelectionService,this._selectionService),this.register(this._selectionService.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent)))),this.register(this._selectionService.onSelectionChange((()=>this._onSelectionChange.fire()))),this.register(this._selectionService.onRequestRedraw((e=>this._renderService.handleSelectionChanged(e.start,e.end,e.columnSelectMode)))),this.register(this._selectionService.onLinuxMouseSelection((e=>{this.textarea.value=e,this.textarea.focus(),this.textarea.select()}))),this.register(this._onScroll.event((e=>{this.viewport.syncScrollArea(),this._selectionService.refresh()}))),this.register((0,i.addDisposableDomListener)(this._viewportElement,`scroll`,(()=>this._selectionService.refresh()))),this.register(this._instantiationService.createInstance(l.BufferDecorationRenderer,this.screenElement)),this.register((0,i.addDisposableDomListener)(this.element,`mousedown`,(e=>this._selectionService.handleMouseDown(e)))),this.coreMouseService.areMouseEventsActive?(this._selectionService.disable(),this.element.classList.add(`enable-mouse-events`)):this._selectionService.enable(),this.options.screenReaderMode&&(this._accessibilityManager.value=this._instantiationService.createInstance(N.AccessibilityManager,this)),this.register(this.optionsService.onSpecificOptionChange(`screenReaderMode`,(e=>this._handleScreenReaderModeOptionChange(e)))),this.options.overviewRulerWidth&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(u.OverviewRulerRenderer,this._viewportElement,this.screenElement))),this.optionsService.onSpecificOptionChange(`overviewRulerWidth`,(e=>{!this._overviewRulerRenderer&&e&&this._viewportElement&&this.screenElement&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(u.OverviewRulerRenderer,this._viewportElement,this.screenElement)))})),this._charSizeService.measure(),this.refresh(0,this.rows-1),this._initGlobal(),this.bindMouse()}_createRenderer(){return this._instantiationService.createInstance(f.DomRenderer,this,this._document,this.element,this.screenElement,this._viewportElement,this._helperContainer,this.linkifier)}bindMouse(){let e=this,t=this.element;function n(t){let n=e._mouseService.getMouseReportCoords(t,e.screenElement);if(!n)return!1;let r,i;switch(t.overrideType||t.type){case`mousemove`:i=32,t.buttons===void 0?(r=3,t.button!==void 0&&(r=t.button<3?t.button:3)):r=1&t.buttons?0:4&t.buttons?1:2&t.buttons?2:3;break;case`mouseup`:i=0,r=t.button<3?t.button:3;break;case`mousedown`:i=1,r=t.button<3?t.button:3;break;case`wheel`:if(e._customWheelEventHandler&&!1===e._customWheelEventHandler(t)||e.viewport.getLinesScrolled(t)===0)return!1;i=t.deltaY<0?0:1,r=4;break;default:return!1}return!(i===void 0||r===void 0||r>4)&&e.coreMouseService.triggerMouseEvent({col:n.col,row:n.row,x:n.x,y:n.y,button:r,action:i,ctrl:t.ctrlKey,alt:t.altKey,shift:t.shiftKey})}let r={mouseup:null,wheel:null,mousedrag:null,mousemove:null},a={mouseup:e=>(n(e),e.buttons||(this._document.removeEventListener(`mouseup`,r.mouseup),r.mousedrag&&this._document.removeEventListener(`mousemove`,r.mousedrag)),this.cancel(e)),wheel:e=>(n(e),this.cancel(e,!0)),mousedrag:e=>{e.buttons&&n(e)},mousemove:e=>{e.buttons||n(e)}};this.register(this.coreMouseService.onProtocolChange((e=>{e?(this.optionsService.rawOptions.logLevel===`debug`&&this._logService.debug(`Binding to mouse events:`,this.coreMouseService.explainEvents(e)),this.element.classList.add(`enable-mouse-events`),this._selectionService.disable()):(this._logService.debug(`Unbinding from mouse events.`),this.element.classList.remove(`enable-mouse-events`),this._selectionService.enable()),8&e?r.mousemove||=(t.addEventListener(`mousemove`,a.mousemove),a.mousemove):(t.removeEventListener(`mousemove`,r.mousemove),r.mousemove=null),16&e?r.wheel||=(t.addEventListener(`wheel`,a.wheel,{passive:!1}),a.wheel):(t.removeEventListener(`wheel`,r.wheel),r.wheel=null),2&e?r.mouseup||=a.mouseup:(this._document.removeEventListener(`mouseup`,r.mouseup),r.mouseup=null),4&e?r.mousedrag||=a.mousedrag:(this._document.removeEventListener(`mousemove`,r.mousedrag),r.mousedrag=null)}))),this.coreMouseService.activeProtocol=this.coreMouseService.activeProtocol,this.register((0,i.addDisposableDomListener)(t,`mousedown`,(e=>{if(e.preventDefault(),this.focus(),this.coreMouseService.areMouseEventsActive&&!this._selectionService.shouldForceSelection(e))return n(e),r.mouseup&&this._document.addEventListener(`mouseup`,r.mouseup),r.mousedrag&&this._document.addEventListener(`mousemove`,r.mousedrag),this.cancel(e)}))),this.register((0,i.addDisposableDomListener)(t,`wheel`,(e=>{if(!r.wheel){if(this._customWheelEventHandler&&!1===this._customWheelEventHandler(e))return!1;if(!this.buffer.hasScrollback){let t=this.viewport.getLinesScrolled(e);if(t===0)return;let n=D.C0.ESC+(this.coreService.decPrivateModes.applicationCursorKeys?`O`:`[`)+(e.deltaY<0?`A`:`B`),r=``;for(let e=0;e{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchStart(e),this.cancel(e)}),{passive:!0})),this.register((0,i.addDisposableDomListener)(t,`touchmove`,(e=>{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchMove(e)?void 0:this.cancel(e)}),{passive:!1}))}refresh(e,t){this._renderService?.refreshRows(e,t)}updateCursorStyle(e){this._selectionService?.shouldColumnSelect(e)?this.element.classList.add(`column-select`):this.element.classList.remove(`column-select`)}_showCursor(){this.coreService.isCursorInitialized||(this.coreService.isCursorInitialized=!0,this.refresh(this.buffer.y,this.buffer.y))}scrollLines(e,t,n=0){n===1?(super.scrollLines(e,t,n),this.refresh(0,this.rows-1)):this.viewport?.scrollLines(e)}paste(e){(0,r.paste)(e,this.textarea,this.coreService,this.optionsService)}attachCustomKeyEventHandler(e){this._customKeyEventHandler=e}attachCustomWheelEventHandler(e){this._customWheelEventHandler=e}registerLinkProvider(e){return this._linkProviderService.registerLinkProvider(e)}registerCharacterJoiner(e){if(!this._characterJoinerService)throw Error(`Terminal must be opened first`);let t=this._characterJoinerService.register(e);return this.refresh(0,this.rows-1),t}deregisterCharacterJoiner(e){if(!this._characterJoinerService)throw Error(`Terminal must be opened first`);this._characterJoinerService.deregister(e)&&this.refresh(0,this.rows-1)}get markers(){return this.buffer.markers}registerMarker(e){return this.buffer.addMarker(this.buffer.ybase+this.buffer.y+e)}registerDecoration(e){return this._decorationService.registerDecoration(e)}hasSelection(){return!!this._selectionService&&this._selectionService.hasSelection}select(e,t,n){this._selectionService.setSelection(e,t,n)}getSelection(){return this._selectionService?this._selectionService.selectionText:``}getSelectionPosition(){if(this._selectionService&&this._selectionService.hasSelection)return{start:{x:this._selectionService.selectionStart[0],y:this._selectionService.selectionStart[1]},end:{x:this._selectionService.selectionEnd[0],y:this._selectionService.selectionEnd[1]}}}clearSelection(){this._selectionService?.clearSelection()}selectAll(){this._selectionService?.selectAll()}selectLines(e,t){this._selectionService?.selectLines(e,t)}_keyDown(e){if(this._keyDownHandled=!1,this._keyDownSeen=!0,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;let t=this.browser.isMac&&this.options.macOptionIsMeta&&e.altKey;if(!t&&!this._compositionHelper.keydown(e))return this.options.scrollOnUserInput&&this.buffer.ybase!==this.buffer.ydisp&&this.scrollToBottom(),!1;t||e.key!==`Dead`&&e.key!==`AltGraph`||(this._unprocessedDeadKey=!0);let n=(0,O.evaluateKeyboardEvent)(e,this.coreService.decPrivateModes.applicationCursorKeys,this.browser.isMac,this.options.macOptionIsMeta);if(this.updateCursorStyle(e),n.type===3||n.type===2){let t=this.rows-1;return this.scrollLines(n.type===2?-t:t),this.cancel(e,!0)}return n.type===1&&this.selectAll(),!!this._isThirdLevelShift(this.browser,e)||(n.cancel&&this.cancel(e,!0),!n.key||!!(e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&e.key.length===1&&e.key.charCodeAt(0)>=65&&e.key.charCodeAt(0)<=90)||(this._unprocessedDeadKey?(this._unprocessedDeadKey=!1,!0):(n.key!==D.C0.ETX&&n.key!==D.C0.CR||(this.textarea.value=``),this._onKey.fire({key:n.key,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(n.key,!0),!this.optionsService.rawOptions.screenReaderMode||e.altKey||e.ctrlKey?this.cancel(e,!0):void(this._keyDownHandled=!0))))}_isThirdLevelShift(e,t){let n=e.isMac&&!this.options.macOptionIsMeta&&t.altKey&&!t.ctrlKey&&!t.metaKey||e.isWindows&&t.altKey&&t.ctrlKey&&!t.metaKey||e.isWindows&&t.getModifierState(`AltGraph`);return t.type===`keypress`?n:n&&(!t.keyCode||t.keyCode>47)}_keyUp(e){this._keyDownSeen=!1,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e)||(function(e){return e.keyCode===16||e.keyCode===17||e.keyCode===18}(e)||this.focus(),this.updateCursorStyle(e),this._keyPressHandled=!1)}_keyPress(e){let t;if(this._keyPressHandled=!1,this._keyDownHandled||this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;if(this.cancel(e),e.charCode)t=e.charCode;else if(e.which===null||e.which===void 0)t=e.keyCode;else{if(e.which===0||e.charCode===0)return!1;t=e.which}return!(!t||(e.altKey||e.ctrlKey||e.metaKey)&&!this._isThirdLevelShift(this.browser,e)||(t=String.fromCharCode(t),this._onKey.fire({key:t,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(t,!0),this._keyPressHandled=!0,this._unprocessedDeadKey=!1,0))}_inputEvent(e){if(e.data&&e.inputType===`insertText`&&(!e.composed||!this._keyDownSeen)&&!this.optionsService.rawOptions.screenReaderMode){if(this._keyPressHandled)return!1;this._unprocessedDeadKey=!1;let t=e.data;return this.coreService.triggerDataEvent(t,!0),this.cancel(e),!0}return!1}resize(e,t){e!==this.cols||t!==this.rows?super.resize(e,t):this._charSizeService&&!this._charSizeService.hasValidSize&&this._charSizeService.measure()}_afterResize(e,t){this._charSizeService?.measure(),this.viewport?.syncScrollArea(!0)}clear(){if(this.buffer.ybase!==0||this.buffer.y!==0){this.buffer.clearAllMarkers(),this.buffer.lines.set(0,this.buffer.lines.get(this.buffer.ybase+this.buffer.y)),this.buffer.lines.length=1,this.buffer.ydisp=0,this.buffer.ybase=0,this.buffer.y=0;for(let e=1;e{Object.defineProperty(t,"__esModule",{value:!0}),t.TimeBasedDebouncer=void 0,t.TimeBasedDebouncer=class{constructor(e,t=1e3){this._renderCallback=e,this._debounceThresholdMS=t,this._lastRefreshMs=0,this._additionalRefreshRequested=!1}dispose(){this._refreshTimeoutID&&clearTimeout(this._refreshTimeoutID)}refresh(e,t,n){this._rowCount=n,e=e===void 0?0:e,t=t===void 0?this._rowCount-1:t,this._rowStart=this._rowStart===void 0?e:Math.min(this._rowStart,e),this._rowEnd=this._rowEnd===void 0?t:Math.max(this._rowEnd,t);let r=Date.now();if(r-this._lastRefreshMs>=this._debounceThresholdMS)this._lastRefreshMs=r,this._innerRefresh();else if(!this._additionalRefreshRequested){let e=r-this._lastRefreshMs,t=this._debounceThresholdMS-e;this._additionalRefreshRequested=!0,this._refreshTimeoutID=window.setTimeout((()=>{this._lastRefreshMs=Date.now(),this._innerRefresh(),this._additionalRefreshRequested=!1,this._refreshTimeoutID=void 0}),t)}}_innerRefresh(){if(this._rowStart===void 0||this._rowEnd===void 0||this._rowCount===void 0)return;let e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t)}}},1680:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Viewport=void 0;let a=n(3656),o=n(4725),s=n(8460),c=n(844),l=n(2585),u=t.Viewport=class extends c.Disposable{constructor(e,t,n,r,i,o,c,l){super(),this._viewportElement=e,this._scrollArea=t,this._bufferService=n,this._optionsService=r,this._charSizeService=i,this._renderService=o,this._coreBrowserService=c,this.scrollBarWidth=0,this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._wheelPartialScroll=0,this._refreshAnimationFrame=null,this._ignoreNextScrollEvent=!1,this._smoothScrollState={startTime:0,origin:-1,target:-1},this._onRequestScrollLines=this.register(new s.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this.scrollBarWidth=this._viewportElement.offsetWidth-this._scrollArea.offsetWidth||15,this.register((0,a.addDisposableDomListener)(this._viewportElement,`scroll`,this._handleScroll.bind(this))),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._renderDimensions=this._renderService.dimensions,this.register(this._renderService.onDimensionsChange((e=>this._renderDimensions=e))),this._handleThemeChange(l.colors),this.register(l.onChangeColors((e=>this._handleThemeChange(e)))),this.register(this._optionsService.onSpecificOptionChange(`scrollback`,(()=>this.syncScrollArea()))),setTimeout((()=>this.syncScrollArea()))}_handleThemeChange(e){this._viewportElement.style.backgroundColor=e.background.css}reset(){this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._coreBrowserService.window.requestAnimationFrame((()=>this.syncScrollArea()))}_refresh(e){if(e)return this._innerRefresh(),void(this._refreshAnimationFrame!==null&&this._coreBrowserService.window.cancelAnimationFrame(this._refreshAnimationFrame));this._refreshAnimationFrame===null&&(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._charSizeService.height>0){this._currentRowHeight=this._renderDimensions.device.cell.height/this._coreBrowserService.dpr,this._currentDeviceCellHeight=this._renderDimensions.device.cell.height,this._lastRecordedViewportHeight=this._viewportElement.offsetHeight;let e=Math.round(this._currentRowHeight*this._lastRecordedBufferLength)+(this._lastRecordedViewportHeight-this._renderDimensions.css.canvas.height);this._lastRecordedBufferHeight!==e&&(this._lastRecordedBufferHeight=e,this._scrollArea.style.height=this._lastRecordedBufferHeight+`px`)}let e=this._bufferService.buffer.ydisp*this._currentRowHeight;this._viewportElement.scrollTop!==e&&(this._ignoreNextScrollEvent=!0,this._viewportElement.scrollTop=e),this._refreshAnimationFrame=null}syncScrollArea(e=!1){if(this._lastRecordedBufferLength!==this._bufferService.buffer.lines.length)return this._lastRecordedBufferLength=this._bufferService.buffer.lines.length,void this._refresh(e);this._lastRecordedViewportHeight===this._renderService.dimensions.css.canvas.height&&this._lastScrollTop===this._activeBuffer.ydisp*this._currentRowHeight&&this._renderDimensions.device.cell.height===this._currentDeviceCellHeight||this._refresh(e)}_handleScroll(e){if(this._lastScrollTop=this._viewportElement.scrollTop,!this._viewportElement.offsetParent)return;if(this._ignoreNextScrollEvent)return this._ignoreNextScrollEvent=!1,void this._onRequestScrollLines.fire({amount:0,suppressScrollEvent:!0});let t=Math.round(this._lastScrollTop/this._currentRowHeight)-this._bufferService.buffer.ydisp;this._onRequestScrollLines.fire({amount:t,suppressScrollEvent:!0})}_smoothScroll(){if(this._isDisposed||this._smoothScrollState.origin===-1||this._smoothScrollState.target===-1)return;let e=this._smoothScrollPercent();this._viewportElement.scrollTop=this._smoothScrollState.origin+Math.round(e*(this._smoothScrollState.target-this._smoothScrollState.origin)),e<1?this._coreBrowserService.window.requestAnimationFrame((()=>this._smoothScroll())):this._clearSmoothScrollState()}_smoothScrollPercent(){return this._optionsService.rawOptions.smoothScrollDuration&&this._smoothScrollState.startTime?Math.max(Math.min((Date.now()-this._smoothScrollState.startTime)/this._optionsService.rawOptions.smoothScrollDuration,1),0):1}_clearSmoothScrollState(){this._smoothScrollState.startTime=0,this._smoothScrollState.origin=-1,this._smoothScrollState.target=-1}_bubbleScroll(e,t){let n=this._viewportElement.scrollTop+this._lastRecordedViewportHeight;return!(t<0&&this._viewportElement.scrollTop!==0||t>0&&n0&&(n=e),r=``}}return{bufferElements:i,cursorElement:n}}getLinesScrolled(e){if(e.deltaY===0||e.shiftKey)return 0;let t=this._applyScrollModifier(e.deltaY,e);return e.deltaMode===WheelEvent.DOM_DELTA_PIXEL?(t/=this._currentRowHeight+0,this._wheelPartialScroll+=t,t=Math.floor(Math.abs(this._wheelPartialScroll))*(this._wheelPartialScroll>0?1:-1),this._wheelPartialScroll%=1):e.deltaMode===WheelEvent.DOM_DELTA_PAGE&&(t*=this._bufferService.rows),t}_applyScrollModifier(e,t){let n=this._optionsService.rawOptions.fastScrollModifier;return n===`alt`&&t.altKey||n===`ctrl`&&t.ctrlKey||n===`shift`&&t.shiftKey?e*this._optionsService.rawOptions.fastScrollSensitivity*this._optionsService.rawOptions.scrollSensitivity:e*this._optionsService.rawOptions.scrollSensitivity}handleTouchStart(e){this._lastTouchY=e.touches[0].pageY}handleTouchMove(e){let t=this._lastTouchY-e.touches[0].pageY;return this._lastTouchY=e.touches[0].pageY,t!==0&&(this._viewportElement.scrollTop+=t,this._bubbleScroll(e,t))}};t.Viewport=u=r([i(2,l.IBufferService),i(3,l.IOptionsService),i(4,o.ICharSizeService),i(5,o.IRenderService),i(6,o.ICoreBrowserService),i(7,o.IThemeService)],u)},3107:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferDecorationRenderer=void 0;let a=n(4725),o=n(844),s=n(2585),c=t.BufferDecorationRenderer=class extends o.Disposable{constructor(e,t,n,r,i){super(),this._screenElement=e,this._bufferService=t,this._coreBrowserService=n,this._decorationService=r,this._renderService=i,this._decorationElements=new Map,this._altBufferIsActive=!1,this._dimensionsChanged=!1,this._container=document.createElement(`div`),this._container.classList.add(`xterm-decoration-container`),this._screenElement.appendChild(this._container),this.register(this._renderService.onRenderedViewportChange((()=>this._doRefreshDecorations()))),this.register(this._renderService.onDimensionsChange((()=>{this._dimensionsChanged=!0,this._queueRefresh()}))),this.register(this._coreBrowserService.onDprChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._altBufferIsActive=this._bufferService.buffer===this._bufferService.buffers.alt}))),this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh()))),this.register(this._decorationService.onDecorationRemoved((e=>this._removeDecoration(e)))),this.register((0,o.toDisposable)((()=>{this._container.remove(),this._decorationElements.clear()})))}_queueRefresh(){this._animationFrame===void 0&&(this._animationFrame=this._renderService.addRefreshCallback((()=>{this._doRefreshDecorations(),this._animationFrame=void 0})))}_doRefreshDecorations(){for(let e of this._decorationService.decorations)this._renderDecoration(e);this._dimensionsChanged=!1}_renderDecoration(e){this._refreshStyle(e),this._dimensionsChanged&&this._refreshXPosition(e)}_createElement(e){let t=this._coreBrowserService.mainDocument.createElement(`div`);t.classList.add(`xterm-decoration`),t.classList.toggle(`xterm-decoration-top-layer`,e?.options?.layer===`top`),t.style.width=`${Math.round((e.options.width||1)*this._renderService.dimensions.css.cell.width)}px`,t.style.height=(e.options.height||1)*this._renderService.dimensions.css.cell.height+`px`,t.style.top=(e.marker.line-this._bufferService.buffers.active.ydisp)*this._renderService.dimensions.css.cell.height+`px`,t.style.lineHeight=`${this._renderService.dimensions.css.cell.height}px`;let n=e.options.x??0;return n&&n>this._bufferService.cols&&(t.style.display=`none`),this._refreshXPosition(e,t),t}_refreshStyle(e){let t=e.marker.line-this._bufferService.buffers.active.ydisp;if(t<0||t>=this._bufferService.rows)e.element&&(e.element.style.display=`none`,e.onRenderEmitter.fire(e.element));else{let n=this._decorationElements.get(e);n||(n=this._createElement(e),e.element=n,this._decorationElements.set(e,n),this._container.appendChild(n),e.onDispose((()=>{this._decorationElements.delete(e),n.remove()}))),n.style.top=t*this._renderService.dimensions.css.cell.height+`px`,n.style.display=this._altBufferIsActive?`none`:`block`,e.onRenderEmitter.fire(n)}}_refreshXPosition(e,t=e.element){if(!t)return;let n=e.options.x??0;(e.options.anchor||`left`)===`right`?t.style.right=n?n*this._renderService.dimensions.css.cell.width+`px`:``:t.style.left=n?n*this._renderService.dimensions.css.cell.width+`px`:``}_removeDecoration(e){this._decorationElements.get(e)?.remove(),this._decorationElements.delete(e),e.dispose()}};t.BufferDecorationRenderer=c=r([i(1,s.IBufferService),i(2,a.ICoreBrowserService),i(3,s.IDecorationService),i(4,a.IRenderService)],c)},5871:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorZoneStore=void 0,t.ColorZoneStore=class{constructor(){this._zones=[],this._zonePool=[],this._zonePoolIndex=0,this._linePadding={full:0,left:0,center:0,right:0}}get zones(){return this._zonePool.length=Math.min(this._zonePool.length,this._zones.length),this._zones}clear(){this._zones.length=0,this._zonePoolIndex=0}addDecoration(e){if(e.options.overviewRulerOptions){for(let t of this._zones)if(t.color===e.options.overviewRulerOptions.color&&t.position===e.options.overviewRulerOptions.position){if(this._lineIntersectsZone(t,e.marker.line))return;if(this._lineAdjacentToZone(t,e.marker.line,e.options.overviewRulerOptions.position))return void this._addLineToZone(t,e.marker.line)}if(this._zonePoolIndex=e.startBufferLine&&t<=e.endBufferLine}_lineAdjacentToZone(e,t,n){return t>=e.startBufferLine-this._linePadding[n||`full`]&&t<=e.endBufferLine+this._linePadding[n||`full`]}_addLineToZone(e,t){e.startBufferLine=Math.min(e.startBufferLine,t),e.endBufferLine=Math.max(e.endBufferLine,t)}}},5744:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OverviewRulerRenderer=void 0;let a=n(5871),o=n(4725),s=n(844),c=n(2585),l={full:0,left:0,center:0,right:0},u={full:0,left:0,center:0,right:0},d={full:0,left:0,center:0,right:0},f=t.OverviewRulerRenderer=class extends s.Disposable{get _width(){return this._optionsService.options.overviewRulerWidth||0}constructor(e,t,n,r,i,o,c){super(),this._viewportElement=e,this._screenElement=t,this._bufferService=n,this._decorationService=r,this._renderService=i,this._optionsService=o,this._coreBrowserService=c,this._colorZoneStore=new a.ColorZoneStore,this._shouldUpdateDimensions=!0,this._shouldUpdateAnchor=!0,this._lastKnownBufferLength=0,this._canvas=this._coreBrowserService.mainDocument.createElement(`canvas`),this._canvas.classList.add(`xterm-decoration-overview-ruler`),this._refreshCanvasDimensions(),this._viewportElement.parentElement?.insertBefore(this._canvas,this._viewportElement);let l=this._canvas.getContext(`2d`);if(!l)throw Error(`Ctx cannot be null`);this._ctx=l,this._registerDecorationListeners(),this._registerBufferChangeListeners(),this._registerDimensionChangeListeners(),this.register((0,s.toDisposable)((()=>{this._canvas?.remove()})))}_registerDecorationListeners(){this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh(void 0,!0)))),this.register(this._decorationService.onDecorationRemoved((()=>this._queueRefresh(void 0,!0))))}_registerBufferChangeListeners(){this.register(this._renderService.onRenderedViewportChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._canvas.style.display=this._bufferService.buffer===this._bufferService.buffers.alt?`none`:`block`}))),this.register(this._bufferService.onScroll((()=>{this._lastKnownBufferLength!==this._bufferService.buffers.normal.lines.length&&(this._refreshDrawHeightConstants(),this._refreshColorZonePadding())})))}_registerDimensionChangeListeners(){this.register(this._renderService.onRender((()=>{this._containerHeight&&this._containerHeight===this._screenElement.clientHeight||(this._queueRefresh(!0),this._containerHeight=this._screenElement.clientHeight)}))),this.register(this._optionsService.onSpecificOptionChange(`overviewRulerWidth`,(()=>this._queueRefresh(!0)))),this.register(this._coreBrowserService.onDprChange((()=>this._queueRefresh(!0)))),this._queueRefresh(!0)}_refreshDrawConstants(){let e=Math.floor(this._canvas.width/3),t=Math.ceil(this._canvas.width/3);u.full=this._canvas.width,u.left=e,u.center=t,u.right=e,this._refreshDrawHeightConstants(),d.full=0,d.left=0,d.center=u.left,d.right=u.left+u.center}_refreshDrawHeightConstants(){l.full=Math.round(2*this._coreBrowserService.dpr);let e=this._canvas.height/this._bufferService.buffer.lines.length,t=Math.round(Math.max(Math.min(e,12),6)*this._coreBrowserService.dpr);l.left=t,l.center=t,l.right=t}_refreshColorZonePadding(){this._colorZoneStore.setPadding({full:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*l.full),left:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*l.left),center:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*l.center),right:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*l.right)}),this._lastKnownBufferLength=this._bufferService.buffers.normal.lines.length}_refreshCanvasDimensions(){this._canvas.style.width=`${this._width}px`,this._canvas.width=Math.round(this._width*this._coreBrowserService.dpr),this._canvas.style.height=`${this._screenElement.clientHeight}px`,this._canvas.height=Math.round(this._screenElement.clientHeight*this._coreBrowserService.dpr),this._refreshDrawConstants(),this._refreshColorZonePadding()}_refreshDecorations(){this._shouldUpdateDimensions&&this._refreshCanvasDimensions(),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._colorZoneStore.clear();for(let e of this._decorationService.decorations)this._colorZoneStore.addDecoration(e);this._ctx.lineWidth=1;let e=this._colorZoneStore.zones;for(let t of e)t.position!==`full`&&this._renderColorZone(t);for(let t of e)t.position===`full`&&this._renderColorZone(t);this._shouldUpdateDimensions=!1,this._shouldUpdateAnchor=!1}_renderColorZone(e){this._ctx.fillStyle=e.color,this._ctx.fillRect(d[e.position||`full`],Math.round((this._canvas.height-1)*(e.startBufferLine/this._bufferService.buffers.active.lines.length)-l[e.position||`full`]/2),u[e.position||`full`],Math.round((this._canvas.height-1)*((e.endBufferLine-e.startBufferLine)/this._bufferService.buffers.active.lines.length)+l[e.position||`full`]))}_queueRefresh(e,t){this._shouldUpdateDimensions=e||this._shouldUpdateDimensions,this._shouldUpdateAnchor=t||this._shouldUpdateAnchor,this._animationFrame===void 0&&(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>{this._refreshDecorations(),this._animationFrame=void 0})))}};t.OverviewRulerRenderer=f=r([i(2,c.IBufferService),i(3,c.IDecorationService),i(4,o.IRenderService),i(5,c.IOptionsService),i(6,o.ICoreBrowserService)],f)},2950:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CompositionHelper=void 0;let a=n(4725),o=n(2585),s=n(2584),c=t.CompositionHelper=class{get isComposing(){return this._isComposing}constructor(e,t,n,r,i,a){this._textarea=e,this._compositionView=t,this._bufferService=n,this._optionsService=r,this._coreService=i,this._renderService=a,this._isComposing=!1,this._isSendingComposition=!1,this._compositionPosition={start:0,end:0},this._dataAlreadySent=``}compositionstart(){this._isComposing=!0,this._compositionPosition.start=this._textarea.value.length,this._compositionView.textContent=``,this._dataAlreadySent=``,this._compositionView.classList.add(`active`)}compositionupdate(e){this._compositionView.textContent=e.data,this.updateCompositionElements(),setTimeout((()=>{this._compositionPosition.end=this._textarea.value.length}),0)}compositionend(){this._finalizeComposition(!0)}keydown(e){if(this._isComposing||this._isSendingComposition){if(e.keyCode===229||e.keyCode===16||e.keyCode===17||e.keyCode===18)return!1;this._finalizeComposition(!1)}return e.keyCode!==229||(this._handleAnyTextareaChanges(),!1)}_finalizeComposition(e){if(this._compositionView.classList.remove(`active`),this._isComposing=!1,e){let e={start:this._compositionPosition.start,end:this._compositionPosition.end};this._isSendingComposition=!0,setTimeout((()=>{if(this._isSendingComposition){let t;this._isSendingComposition=!1,e.start+=this._dataAlreadySent.length,t=this._isComposing?this._textarea.value.substring(e.start,e.end):this._textarea.value.substring(e.start),t.length>0&&this._coreService.triggerDataEvent(t,!0)}}),0)}else{this._isSendingComposition=!1;let e=this._textarea.value.substring(this._compositionPosition.start,this._compositionPosition.end);this._coreService.triggerDataEvent(e,!0)}}_handleAnyTextareaChanges(){let e=this._textarea.value;setTimeout((()=>{if(!this._isComposing){let t=this._textarea.value,n=t.replace(e,``);this._dataAlreadySent=n,t.length>e.length?this._coreService.triggerDataEvent(n,!0):t.lengththis.updateCompositionElements(!0)),0)}}};t.CompositionHelper=c=r([i(2,o.IBufferService),i(3,o.IOptionsService),i(4,o.ICoreService),i(5,a.IRenderService)],c)},9806:(e,t)=>{function n(e,t,n){let r=n.getBoundingClientRect(),i=e.getComputedStyle(n),a=parseInt(i.getPropertyValue(`padding-left`)),o=parseInt(i.getPropertyValue(`padding-top`));return[t.clientX-r.left-a,t.clientY-r.top-o]}Object.defineProperty(t,"__esModule",{value:!0}),t.getCoords=t.getCoordsRelativeToElement=void 0,t.getCoordsRelativeToElement=n,t.getCoords=function(e,t,r,i,a,o,s,c,l){if(!o)return;let u=n(e,t,r);return u?(u[0]=Math.ceil((u[0]+(l?s/2:0))/s),u[1]=Math.ceil(u[1]/c),u[0]=Math.min(Math.max(u[0],1),i+ +!!l),u[1]=Math.min(Math.max(u[1],1),a),u):void 0}},9504:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.moveToCellSequence=void 0;let r=n(2584);function i(e,t,n,r){let i=e-a(e,n),s=t-a(t,n);return l(Math.abs(i-s)-function(e,t,n){let r=0,i=e-a(e,n),s=t-a(t,n);for(let a=0;a=0&&et?`A`:`B`}function s(e,t,n,r,i,a){let o=e,s=t,c=``;for(;o!==n||s!==r;)o+=i?1:-1,i&&o>a.cols-1?(c+=a.buffer.translateBufferLineToString(s,!1,e,o),o=0,e=0,s++):!i&&o<0&&(c+=a.buffer.translateBufferLineToString(s,!1,0,e+1),o=a.cols-1,e=o,s--);return c+a.buffer.translateBufferLineToString(s,!1,e,o)}function c(e,t){let n=t?`O`:`[`;return r.C0.ESC+n+e}function l(e,t){e=Math.floor(e);let n=``;for(let r=0;r0?r-a(r,o):t;let f=r,p=function(e,t,n,r,o,s){let c;return c=i(n,r,o,s).length>0?r-a(r,o):t,e=n&&ce?`D`:`C`,l(Math.abs(o-e),c(d,r));d=u>t?`D`:`C`;let f=Math.abs(u-t);return l(function(e,t){return t.cols-e}(u>t?e:o,n)+(f-1)*n.cols+1+((u>t?o:e)-1),c(d,r))}},1296:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRenderer=void 0;let a=n(3787),o=n(2550),s=n(2223),c=n(6171),l=n(6052),u=n(4725),d=n(8055),f=n(8460),p=n(844),m=n(2585),h=`xterm-dom-renderer-owner-`,g=`xterm-rows`,_=`xterm-fg-`,v=`xterm-bg-`,y=`xterm-focus`,b=`xterm-selection`,x=1,S=t.DomRenderer=class extends p.Disposable{constructor(e,t,n,r,i,s,u,d,m,_,v,y,S){super(),this._terminal=e,this._document=t,this._element=n,this._screenElement=r,this._viewportElement=i,this._helperContainer=s,this._linkifier2=u,this._charSizeService=m,this._optionsService=_,this._bufferService=v,this._coreBrowserService=y,this._themeService=S,this._terminalClass=x++,this._rowElements=[],this._selectionRenderModel=(0,l.createSelectionRenderModel)(),this.onRequestRedraw=this.register(new f.EventEmitter).event,this._rowContainer=this._document.createElement(`div`),this._rowContainer.classList.add(g),this._rowContainer.style.lineHeight=`normal`,this._rowContainer.setAttribute(`aria-hidden`,`true`),this._refreshRowElements(this._bufferService.cols,this._bufferService.rows),this._selectionContainer=this._document.createElement(`div`),this._selectionContainer.classList.add(b),this._selectionContainer.setAttribute(`aria-hidden`,`true`),this.dimensions=(0,c.createRenderDimensions)(),this._updateDimensions(),this.register(this._optionsService.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._themeService.onChangeColors((e=>this._injectCss(e)))),this._injectCss(this._themeService.colors),this._rowFactory=d.createInstance(a.DomRendererRowFactory,document),this._element.classList.add(h+this._terminalClass),this._screenElement.appendChild(this._rowContainer),this._screenElement.appendChild(this._selectionContainer),this.register(this._linkifier2.onShowLinkUnderline((e=>this._handleLinkHover(e)))),this.register(this._linkifier2.onHideLinkUnderline((e=>this._handleLinkLeave(e)))),this.register((0,p.toDisposable)((()=>{this._element.classList.remove(h+this._terminalClass),this._rowContainer.remove(),this._selectionContainer.remove(),this._widthCache.dispose(),this._themeStyleElement.remove(),this._dimensionsStyleElement.remove()}))),this._widthCache=new o.WidthCache(this._document,this._helperContainer),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}_updateDimensions(){let e=this._coreBrowserService.dpr;this.dimensions.device.char.width=this._charSizeService.width*e,this.dimensions.device.char.height=Math.ceil(this._charSizeService.height*e),this.dimensions.device.cell.width=this.dimensions.device.char.width+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.device.cell.height=Math.floor(this.dimensions.device.char.height*this._optionsService.rawOptions.lineHeight),this.dimensions.device.char.left=0,this.dimensions.device.char.top=0,this.dimensions.device.canvas.width=this.dimensions.device.cell.width*this._bufferService.cols,this.dimensions.device.canvas.height=this.dimensions.device.cell.height*this._bufferService.rows,this.dimensions.css.canvas.width=Math.round(this.dimensions.device.canvas.width/e),this.dimensions.css.canvas.height=Math.round(this.dimensions.device.canvas.height/e),this.dimensions.css.cell.width=this.dimensions.css.canvas.width/this._bufferService.cols,this.dimensions.css.cell.height=this.dimensions.css.canvas.height/this._bufferService.rows;for(let e of this._rowElements)e.style.width=`${this.dimensions.css.canvas.width}px`,e.style.height=`${this.dimensions.css.cell.height}px`,e.style.lineHeight=`${this.dimensions.css.cell.height}px`,e.style.overflow=`hidden`;this._dimensionsStyleElement||(this._dimensionsStyleElement=this._document.createElement(`style`),this._screenElement.appendChild(this._dimensionsStyleElement));let t=`${this._terminalSelector} .${g} span { display: inline-block; height: 100%; vertical-align: top;}`;this._dimensionsStyleElement.textContent=t,this._selectionContainer.style.height=this._viewportElement.style.height,this._screenElement.style.width=`${this.dimensions.css.canvas.width}px`,this._screenElement.style.height=`${this.dimensions.css.canvas.height}px`}_injectCss(e){this._themeStyleElement||(this._themeStyleElement=this._document.createElement(`style`),this._screenElement.appendChild(this._themeStyleElement));let t=`${this._terminalSelector} .${g} { color: ${e.foreground.css}; font-family: ${this._optionsService.rawOptions.fontFamily}; font-size: ${this._optionsService.rawOptions.fontSize}px; font-kerning: none; white-space: pre}`;t+=`${this._terminalSelector} .${g} .xterm-dim { color: ${d.color.multiplyOpacity(e.foreground,.5).css};}`,t+=`${this._terminalSelector} span:not(.xterm-bold) { font-weight: ${this._optionsService.rawOptions.fontWeight};}${this._terminalSelector} span.xterm-bold { font-weight: ${this._optionsService.rawOptions.fontWeightBold};}${this._terminalSelector} span.xterm-italic { font-style: italic;}`;let n=`blink_underline_${this._terminalClass}`,r=`blink_bar_${this._terminalClass}`,i=`blink_block_${this._terminalClass}`;t+=`@keyframes ${n} { 50% { border-bottom-style: hidden; }}`,t+=`@keyframes ${r} { 50% { box-shadow: none; }}`,t+=`@keyframes ${i} { 0% { background-color: ${e.cursor.css}; color: ${e.cursorAccent.css}; } 50% { background-color: inherit; color: ${e.cursor.css}; }}`,t+=`${this._terminalSelector} .${g}.${y} .xterm-cursor.xterm-cursor-blink.xterm-cursor-underline { animation: ${n} 1s step-end infinite;}${this._terminalSelector} .${g}.${y} .xterm-cursor.xterm-cursor-blink.xterm-cursor-bar { animation: ${r} 1s step-end infinite;}${this._terminalSelector} .${g}.${y} .xterm-cursor.xterm-cursor-blink.xterm-cursor-block { animation: ${i} 1s step-end infinite;}${this._terminalSelector} .${g} .xterm-cursor.xterm-cursor-block { background-color: ${e.cursor.css}; color: ${e.cursorAccent.css};}${this._terminalSelector} .${g} .xterm-cursor.xterm-cursor-block:not(.xterm-cursor-blink) { background-color: ${e.cursor.css} !important; color: ${e.cursorAccent.css} !important;}${this._terminalSelector} .${g} .xterm-cursor.xterm-cursor-outline { outline: 1px solid ${e.cursor.css}; outline-offset: -1px;}${this._terminalSelector} .${g} .xterm-cursor.xterm-cursor-bar { box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${e.cursor.css} inset;}${this._terminalSelector} .${g} .xterm-cursor.xterm-cursor-underline { border-bottom: 1px ${e.cursor.css}; border-bottom-style: solid; height: calc(100% - 1px);}`,t+=`${this._terminalSelector} .${b} { position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;}${this._terminalSelector}.focus .${b} div { position: absolute; background-color: ${e.selectionBackgroundOpaque.css};}${this._terminalSelector} .${b} div { position: absolute; background-color: ${e.selectionInactiveBackgroundOpaque.css};}`;for(let[n,r]of e.ansi.entries())t+=`${this._terminalSelector} .${_}${n} { color: ${r.css}; }${this._terminalSelector} .${_}${n}.xterm-dim { color: ${d.color.multiplyOpacity(r,.5).css}; }${this._terminalSelector} .${v}${n} { background-color: ${r.css}; }`;t+=`${this._terminalSelector} .${_}${s.INVERTED_DEFAULT_COLOR} { color: ${d.color.opaque(e.background).css}; }${this._terminalSelector} .${_}${s.INVERTED_DEFAULT_COLOR}.xterm-dim { color: ${d.color.multiplyOpacity(d.color.opaque(e.background),.5).css}; }${this._terminalSelector} .${v}${s.INVERTED_DEFAULT_COLOR} { background-color: ${e.foreground.css}; }`,this._themeStyleElement.textContent=t}_setDefaultSpacing(){let e=this.dimensions.css.cell.width-this._widthCache.get(`W`,!1,!1);this._rowContainer.style.letterSpacing=`${e}px`,this._rowFactory.defaultSpacing=e}handleDevicePixelRatioChange(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}_refreshRowElements(e,t){for(let e=this._rowElements.length;e<=t;e++){let e=this._document.createElement(`div`);this._rowContainer.appendChild(e),this._rowElements.push(e)}for(;this._rowElements.length>t;)this._rowContainer.removeChild(this._rowElements.pop())}handleResize(e,t){this._refreshRowElements(e,t),this._updateDimensions(),this.handleSelectionChanged(this._selectionRenderModel.selectionStart,this._selectionRenderModel.selectionEnd,this._selectionRenderModel.columnSelectMode)}handleCharSizeChanged(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}handleBlur(){this._rowContainer.classList.remove(y),this.renderRows(0,this._bufferService.rows-1)}handleFocus(){this._rowContainer.classList.add(y),this.renderRows(this._bufferService.buffer.y,this._bufferService.buffer.y)}handleSelectionChanged(e,t,n){if(this._selectionContainer.replaceChildren(),this._rowFactory.handleSelectionChanged(e,t,n),this.renderRows(0,this._bufferService.rows-1),!e||!t)return;this._selectionRenderModel.update(this._terminal,e,t,n);let r=this._selectionRenderModel.viewportStartRow,i=this._selectionRenderModel.viewportEndRow,a=this._selectionRenderModel.viewportCappedStartRow,o=this._selectionRenderModel.viewportCappedEndRow;if(a>=this._bufferService.rows||o<0)return;let s=this._document.createDocumentFragment();if(n){let n=e[0]>t[0];s.appendChild(this._createSelectionElement(a,n?t[0]:e[0],n?e[0]:t[0],o-a+1))}else{let n=r===a?e[0]:0,c=a===i?t[0]:this._bufferService.cols;s.appendChild(this._createSelectionElement(a,n,c));let l=o-a-1;if(s.appendChild(this._createSelectionElement(a+1,0,this._bufferService.cols,l)),a!==o){let e=i===o?t[0]:this._bufferService.cols;s.appendChild(this._createSelectionElement(o,0,e))}}this._selectionContainer.appendChild(s)}_createSelectionElement(e,t,n,r=1){let i=this._document.createElement(`div`),a=t*this.dimensions.css.cell.width,o=this.dimensions.css.cell.width*(n-t);return a+o>this.dimensions.css.canvas.width&&(o=this.dimensions.css.canvas.width-a),i.style.height=r*this.dimensions.css.cell.height+`px`,i.style.top=e*this.dimensions.css.cell.height+`px`,i.style.left=`${a}px`,i.style.width=`${o}px`,i}handleCursorMove(){}_handleOptionsChanged(){this._updateDimensions(),this._injectCss(this._themeService.colors),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}clear(){for(let e of this._rowElements)e.replaceChildren()}renderRows(e,t){let n=this._bufferService.buffer,r=n.ybase+n.y,i=Math.min(n.x,this._bufferService.cols-1),a=this._optionsService.rawOptions.cursorBlink,o=this._optionsService.rawOptions.cursorStyle,s=this._optionsService.rawOptions.cursorInactiveStyle;for(let c=e;c<=t;c++){let e=c+n.ydisp,t=this._rowElements[c],l=n.lines.get(e);if(!t||!l)break;t.replaceChildren(...this._rowFactory.createRow(l,e,e===r,o,s,i,a,this.dimensions.css.cell.width,this._widthCache,-1,-1))}}get _terminalSelector(){return`.${h}${this._terminalClass}`}_handleLinkHover(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!0)}_handleLinkLeave(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!1)}_setCellUnderline(e,t,n,r,i,a){n<0&&(e=0),r<0&&(t=0);let o=this._bufferService.rows-1;n=Math.max(Math.min(n,o),0),r=Math.max(Math.min(r,o),0),i=Math.min(i,this._bufferService.cols);let s=this._bufferService.buffer,c=s.ybase+s.y,l=Math.min(s.x,i-1),u=this._optionsService.rawOptions.cursorBlink,d=this._optionsService.rawOptions.cursorStyle,f=this._optionsService.rawOptions.cursorInactiveStyle;for(let o=n;o<=r;++o){let p=o+s.ydisp,m=this._rowElements[o],h=s.lines.get(p);if(!m||!h)break;m.replaceChildren(...this._rowFactory.createRow(h,p,p===c,d,f,l,u,this.dimensions.css.cell.width,this._widthCache,a?o===n?e:0:-1,a?(o===r?t:i)-1:-1))}}};t.DomRenderer=S=r([i(7,m.IInstantiationService),i(8,u.ICharSizeService),i(9,m.IOptionsService),i(10,m.IBufferService),i(11,u.ICoreBrowserService),i(12,u.IThemeService)],S)},3787:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRendererRowFactory=void 0;let a=n(2223),o=n(643),s=n(511),c=n(2585),l=n(8055),u=n(4725),d=n(4269),f=n(6171),p=n(3734),m=t.DomRendererRowFactory=class{constructor(e,t,n,r,i,a,o){this._document=e,this._characterJoinerService=t,this._optionsService=n,this._coreBrowserService=r,this._coreService=i,this._decorationService=a,this._themeService=o,this._workCell=new s.CellData,this._columnSelectMode=!1,this.defaultSpacing=0}handleSelectionChanged(e,t,n){this._selectionStart=e,this._selectionEnd=t,this._columnSelectMode=n}createRow(e,t,n,r,i,s,c,u,f,m,g){let _=[],v=this._characterJoinerService.getJoinedCharacters(t),y=this._themeService.colors,b,x=e.getNoBgTrimmedLength();n&&x0&&N===v[0][0]){P=!0;let t=v.shift();I=new d.JoinedCellData(this._workCell,e.translateToString(!0,t[0],t[1]),t[1]-t[0]),F=t[1]-1,x=I.getWidth()}let L=this._isCellInSelection(N,t),R=n&&N===s,z=M&&N>=m&&N<=g,B=!1;this._decorationService.forEachDecorationAtCell(N,t,void 0,(e=>{B=!0}));let V=I.getChars()||o.WHITESPACE_CELL_CHAR;if(V===` `&&(I.isUnderline()||I.isOverline())&&(V=`\xA0`),A=x*u-f.get(V,I.isBold(),I.isItalic()),b){if(S&&(L&&k||!L&&!k&&I.bg===w)&&(L&&k&&y.selectionForeground||I.fg===T)&&I.extended.ext===E&&z===D&&A===O&&!R&&!P&&!B){I.isInvisible()?C+=o.WHITESPACE_CELL_CHAR:C+=V,S++;continue}S&&(b.textContent=C),b=this._document.createElement(`span`),S=0,C=``}else b=this._document.createElement(`span`);if(w=I.bg,T=I.fg,E=I.extended.ext,D=z,O=A,k=L,P&&s>=N&&s<=F&&(s=N),!this._coreService.isCursorHidden&&R&&this._coreService.isCursorInitialized){if(j.push(`xterm-cursor`),this._coreBrowserService.isFocused)c&&j.push(`xterm-cursor-blink`),j.push(r===`bar`?`xterm-cursor-bar`:r===`underline`?`xterm-cursor-underline`:`xterm-cursor-block`);else if(i)switch(i){case`outline`:j.push(`xterm-cursor-outline`);break;case`block`:j.push(`xterm-cursor-block`);break;case`bar`:j.push(`xterm-cursor-bar`);break;case`underline`:j.push(`xterm-cursor-underline`)}}if(I.isBold()&&j.push(`xterm-bold`),I.isItalic()&&j.push(`xterm-italic`),I.isDim()&&j.push(`xterm-dim`),C=I.isInvisible()?o.WHITESPACE_CELL_CHAR:I.getChars()||o.WHITESPACE_CELL_CHAR,I.isUnderline()&&(j.push(`xterm-underline-${I.extended.underlineStyle}`),C===` `&&(C=`\xA0`),!I.isUnderlineColorDefault()))if(I.isUnderlineColorRGB())b.style.textDecorationColor=`rgb(${p.AttributeData.toColorRGB(I.getUnderlineColor()).join(`,`)})`;else{let e=I.getUnderlineColor();this._optionsService.rawOptions.drawBoldTextInBrightColors&&I.isBold()&&e<8&&(e+=8),b.style.textDecorationColor=y.ansi[e].css}I.isOverline()&&(j.push(`xterm-overline`),C===` `&&(C=`\xA0`)),I.isStrikethrough()&&j.push(`xterm-strikethrough`),z&&(b.style.textDecoration=`underline`);let H=I.getFgColor(),U=I.getFgColorMode(),W=I.getBgColor(),G=I.getBgColorMode(),K=!!I.isInverse();if(K){let e=H;H=W,W=e;let t=U;U=G,G=t}let q,J,Y,X=!1;switch(this._decorationService.forEachDecorationAtCell(N,t,void 0,(e=>{e.options.layer!==`top`&&X||(e.backgroundColorRGB&&(G=50331648,W=e.backgroundColorRGB.rgba>>8&16777215,q=e.backgroundColorRGB),e.foregroundColorRGB&&(U=50331648,H=e.foregroundColorRGB.rgba>>8&16777215,J=e.foregroundColorRGB),X=e.options.layer===`top`)})),!X&&L&&(q=this._coreBrowserService.isFocused?y.selectionBackgroundOpaque:y.selectionInactiveBackgroundOpaque,W=q.rgba>>8&16777215,G=50331648,X=!0,y.selectionForeground&&(U=50331648,H=y.selectionForeground.rgba>>8&16777215,J=y.selectionForeground)),X&&j.push(`xterm-decoration-top`),G){case 16777216:case 33554432:Y=y.ansi[W],j.push(`xterm-bg-${W}`);break;case 50331648:Y=l.channels.toColor(W>>16,W>>8&255,255&W),this._addStyle(b,`background-color:#${h((W>>>0).toString(16),`0`,6)}`);break;default:K?(Y=y.foreground,j.push(`xterm-bg-${a.INVERTED_DEFAULT_COLOR}`)):Y=y.background}switch(q||I.isDim()&&(q=l.color.multiplyOpacity(Y,.5)),U){case 16777216:case 33554432:I.isBold()&&H<8&&this._optionsService.rawOptions.drawBoldTextInBrightColors&&(H+=8),this._applyMinimumContrast(b,Y,y.ansi[H],I,q,void 0)||j.push(`xterm-fg-${H}`);break;case 50331648:let e=l.channels.toColor(H>>16&255,H>>8&255,255&H);this._applyMinimumContrast(b,Y,e,I,q,J)||this._addStyle(b,`color:#${h(H.toString(16),`0`,6)}`);break;default:this._applyMinimumContrast(b,Y,y.foreground,I,q,J)||K&&j.push(`xterm-fg-${a.INVERTED_DEFAULT_COLOR}`)}j.length&&=(b.className=j.join(` `),0),R||P||B?b.textContent=C:S++,A!==this.defaultSpacing&&(b.style.letterSpacing=`${A}px`),_.push(b),N=F}return b&&S&&(b.textContent=C),_}_applyMinimumContrast(e,t,n,r,i,a){if(this._optionsService.rawOptions.minimumContrastRatio===1||(0,f.treatGlyphAsBackgroundColor)(r.getCode()))return!1;let o=this._getContrastCache(r),s;if(i||a||(s=o.getColor(t.rgba,n.rgba)),s===void 0){let e=this._optionsService.rawOptions.minimumContrastRatio/(r.isDim()?2:1);s=l.color.ensureContrastRatio(i||t,a||n,e),o.setColor((i||t).rgba,(a||n).rgba,s??null)}return!!s&&(this._addStyle(e,`color:${s.css}`),!0)}_getContrastCache(e){return e.isDim()?this._themeService.colors.halfContrastCache:this._themeService.colors.contrastCache}_addStyle(e,t){e.setAttribute(`style`,`${e.getAttribute(`style`)||``}${t};`)}_isCellInSelection(e,t){let n=this._selectionStart,r=this._selectionEnd;return!(!n||!r)&&(this._columnSelectMode?n[0]<=r[0]?e>=n[0]&&t>=n[1]&&e=n[1]&&e>=r[0]&&t<=r[1]:t>n[1]&&t=n[0]&&e=n[0])}};function h(e,t,n){for(;e.length{Object.defineProperty(t,"__esModule",{value:!0}),t.WidthCache=void 0,t.WidthCache=class{constructor(e,t){this._flat=new Float32Array(256),this._font=``,this._fontSize=0,this._weight=`normal`,this._weightBold=`bold`,this._measureElements=[],this._container=e.createElement(`div`),this._container.classList.add(`xterm-width-cache-measure-container`),this._container.setAttribute(`aria-hidden`,`true`),this._container.style.whiteSpace=`pre`,this._container.style.fontKerning=`none`;let n=e.createElement(`span`);n.classList.add(`xterm-char-measure-element`);let r=e.createElement(`span`);r.classList.add(`xterm-char-measure-element`),r.style.fontWeight=`bold`;let i=e.createElement(`span`);i.classList.add(`xterm-char-measure-element`),i.style.fontStyle=`italic`;let a=e.createElement(`span`);a.classList.add(`xterm-char-measure-element`),a.style.fontWeight=`bold`,a.style.fontStyle=`italic`,this._measureElements=[n,r,i,a],this._container.appendChild(n),this._container.appendChild(r),this._container.appendChild(i),this._container.appendChild(a),t.appendChild(this._container),this.clear()}dispose(){this._container.remove(),this._measureElements.length=0,this._holey=void 0}clear(){this._flat.fill(-9999),this._holey=new Map}setFont(e,t,n,r){e===this._font&&t===this._fontSize&&n===this._weight&&r===this._weightBold||(this._font=e,this._fontSize=t,this._weight=n,this._weightBold=r,this._container.style.fontFamily=this._font,this._container.style.fontSize=`${this._fontSize}px`,this._measureElements[0].style.fontWeight=`${n}`,this._measureElements[1].style.fontWeight=`${r}`,this._measureElements[2].style.fontWeight=`${n}`,this._measureElements[3].style.fontWeight=`${r}`,this.clear())}get(e,t,n){let r=0;if(!t&&!n&&e.length===1&&(r=e.charCodeAt(0))<256){if(this._flat[r]!==-9999)return this._flat[r];let t=this._measure(e,0);return t>0&&(this._flat[r]=t),t}let i=e;t&&(i+=`B`),n&&(i+=`I`);let a=this._holey.get(i);if(a===void 0){let r=0;t&&(r|=1),n&&(r|=2),a=this._measure(e,r),a>0&&this._holey.set(i,a)}return a}_measure(e,t){let n=this._measureElements[t];return n.textContent=e.repeat(32),n.offsetWidth/32}}},2223:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.TEXT_BASELINE=t.DIM_OPACITY=t.INVERTED_DEFAULT_COLOR=void 0;let r=n(6114);t.INVERTED_DEFAULT_COLOR=257,t.DIM_OPACITY=.5,t.TEXT_BASELINE=r.isFirefox||r.isLegacyEdge?`bottom`:`ideographic`},6171:(e,t)=>{function n(e){return 57508<=e&&e<=57558}function r(e){return e>=128512&&e<=128591||e>=127744&&e<=128511||e>=128640&&e<=128767||e>=9728&&e<=9983||e>=9984&&e<=10175||e>=65024&&e<=65039||e>=129280&&e<=129535||e>=127462&&e<=127487}Object.defineProperty(t,"__esModule",{value:!0}),t.computeNextVariantOffset=t.createRenderDimensions=t.treatGlyphAsBackgroundColor=t.allowRescaling=t.isEmoji=t.isRestrictedPowerlineGlyph=t.isPowerlineGlyph=t.throwIfFalsy=void 0,t.throwIfFalsy=function(e){if(!e)throw Error(`value must not be falsy`);return e},t.isPowerlineGlyph=n,t.isRestrictedPowerlineGlyph=function(e){return 57520<=e&&e<=57527},t.isEmoji=r,t.allowRescaling=function(e,t,i,a){return t===1&&i>Math.ceil(1.5*a)&&e!==void 0&&e>255&&!r(e)&&!n(e)&&!function(e){return 57344<=e&&e<=63743}(e)},t.treatGlyphAsBackgroundColor=function(e){return n(e)||function(e){return 9472<=e&&e<=9631}(e)},t.createRenderDimensions=function(){return{css:{canvas:{width:0,height:0},cell:{width:0,height:0}},device:{canvas:{width:0,height:0},cell:{width:0,height:0},char:{width:0,height:0,left:0,top:0}}}},t.computeNextVariantOffset=function(e,t,n=0){return(e-(2*Math.round(t)-n))%(2*Math.round(t))}},6052:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createSelectionRenderModel=void 0;class n{constructor(){this.clear()}clear(){this.hasSelection=!1,this.columnSelectMode=!1,this.viewportStartRow=0,this.viewportEndRow=0,this.viewportCappedStartRow=0,this.viewportCappedEndRow=0,this.startCol=0,this.endCol=0,this.selectionStart=void 0,this.selectionEnd=void 0}update(e,t,n,r=!1){if(this.selectionStart=t,this.selectionEnd=n,!t||!n||t[0]===n[0]&&t[1]===n[1])return void this.clear();let i=e.buffers.active.ydisp,a=t[1]-i,o=n[1]-i,s=Math.max(a,0),c=Math.min(o,e.rows-1);s>=e.rows||c<0?this.clear():(this.hasSelection=!0,this.columnSelectMode=r,this.viewportStartRow=a,this.viewportEndRow=o,this.viewportCappedStartRow=s,this.viewportCappedEndRow=c,this.startCol=t[0],this.endCol=n[0])}isCellSelected(e,t,n){return!!this.hasSelection&&(n-=e.buffer.active.viewportY,this.columnSelectMode?this.startCol<=this.endCol?t>=this.startCol&&n>=this.viewportCappedStartRow&&t=this.viewportCappedStartRow&&t>=this.endCol&&n<=this.viewportCappedEndRow:n>this.viewportStartRow&&n=this.startCol&&t=this.startCol)}}t.createSelectionRenderModel=function(){return new n}},456:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionModel=void 0,t.SelectionModel=class{constructor(e){this._bufferService=e,this.isSelectAllActive=!1,this.selectionStartLength=0}clearSelection(){this.selectionStart=void 0,this.selectionEnd=void 0,this.isSelectAllActive=!1,this.selectionStartLength=0}get finalSelectionStart(){return this.isSelectAllActive?[0,0]:this.selectionEnd&&this.selectionStart&&this.areSelectionValuesReversed()?this.selectionEnd:this.selectionStart}get finalSelectionEnd(){if(this.isSelectAllActive)return[this._bufferService.cols,this._bufferService.buffer.ybase+this._bufferService.rows-1];if(this.selectionStart){if(!this.selectionEnd||this.areSelectionValuesReversed()){let e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?e%this._bufferService.cols==0?[this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)-1]:[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[e,this.selectionStart[1]]}if(this.selectionStartLength&&this.selectionEnd[1]===this.selectionStart[1]){let e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[Math.max(e,this.selectionEnd[0]),this.selectionEnd[1]]}return this.selectionEnd}}areSelectionValuesReversed(){let e=this.selectionStart,t=this.selectionEnd;return!(!e||!t)&&(e[1]>t[1]||e[1]===t[1]&&e[0]>t[0])}handleTrim(e){return this.selectionStart&&(this.selectionStart[1]-=e),this.selectionEnd&&(this.selectionEnd[1]-=e),this.selectionEnd&&this.selectionEnd[1]<0?(this.clearSelection(),!0):(this.selectionStart&&this.selectionStart[1]<0&&(this.selectionStart[1]=0),!1)}}},428:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharSizeService=void 0;let a=n(2585),o=n(8460),s=n(844),c=t.CharSizeService=class extends s.Disposable{get hasValidSize(){return this.width>0&&this.height>0}constructor(e,t,n){super(),this._optionsService=n,this.width=0,this.height=0,this._onCharSizeChange=this.register(new o.EventEmitter),this.onCharSizeChange=this._onCharSizeChange.event;try{this._measureStrategy=this.register(new d(this._optionsService))}catch{this._measureStrategy=this.register(new u(e,t,this._optionsService))}this.register(this._optionsService.onMultipleOptionChange([`fontFamily`,`fontSize`],(()=>this.measure())))}measure(){let e=this._measureStrategy.measure();e.width===this.width&&e.height===this.height||(this.width=e.width,this.height=e.height,this._onCharSizeChange.fire())}};t.CharSizeService=c=r([i(2,a.IOptionsService)],c);class l extends s.Disposable{constructor(){super(...arguments),this._result={width:0,height:0}}_validateAndSet(e,t){e!==void 0&&e>0&&t!==void 0&&t>0&&(this._result.width=e,this._result.height=t)}}class u extends l{constructor(e,t,n){super(),this._document=e,this._parentElement=t,this._optionsService=n,this._measureElement=this._document.createElement(`span`),this._measureElement.classList.add(`xterm-char-measure-element`),this._measureElement.textContent=`W`.repeat(32),this._measureElement.setAttribute(`aria-hidden`,`true`),this._measureElement.style.whiteSpace=`pre`,this._measureElement.style.fontKerning=`none`,this._parentElement.appendChild(this._measureElement)}measure(){return this._measureElement.style.fontFamily=this._optionsService.rawOptions.fontFamily,this._measureElement.style.fontSize=`${this._optionsService.rawOptions.fontSize}px`,this._validateAndSet(Number(this._measureElement.offsetWidth)/32,Number(this._measureElement.offsetHeight)),this._result}}class d extends l{constructor(e){super(),this._optionsService=e,this._canvas=new OffscreenCanvas(100,100),this._ctx=this._canvas.getContext(`2d`);let t=this._ctx.measureText(`W`);if(!(`width`in t&&`fontBoundingBoxAscent`in t&&`fontBoundingBoxDescent`in t))throw Error(`Required font metrics not supported`)}measure(){this._ctx.font=`${this._optionsService.rawOptions.fontSize}px ${this._optionsService.rawOptions.fontFamily}`;let e=this._ctx.measureText(`W`);return this._validateAndSet(e.width,e.fontBoundingBoxAscent+e.fontBoundingBoxDescent),this._result}}},4269:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharacterJoinerService=t.JoinedCellData=void 0;let a=n(3734),o=n(643),s=n(511),c=n(2585);class l extends a.AttributeData{constructor(e,t,n){super(),this.content=0,this.combinedData=``,this.fg=e.fg,this.bg=e.bg,this.combinedData=t,this._width=n}isCombined(){return 2097152}getWidth(){return this._width}getChars(){return this.combinedData}getCode(){return 2097151}setFromCharData(e){throw Error(`not implemented`)}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.JoinedCellData=l;let u=t.CharacterJoinerService=class e{constructor(e){this._bufferService=e,this._characterJoiners=[],this._nextCharacterJoinerId=0,this._workCell=new s.CellData}register(e){let t={id:this._nextCharacterJoinerId++,handler:e};return this._characterJoiners.push(t),t.id}deregister(e){for(let t=0;t1){let e=this._getJoinedRanges(r,s,a,t,i);for(let t=0;t1){let e=this._getJoinedRanges(r,s,a,t,i);for(let t=0;t{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreBrowserService=void 0;let r=n(844),i=n(8460),a=n(3656);class o extends r.Disposable{constructor(e,t,n){super(),this._textarea=e,this._window=t,this.mainDocument=n,this._isFocused=!1,this._cachedIsFocused=void 0,this._screenDprMonitor=new s(this._window),this._onDprChange=this.register(new i.EventEmitter),this.onDprChange=this._onDprChange.event,this._onWindowChange=this.register(new i.EventEmitter),this.onWindowChange=this._onWindowChange.event,this.register(this.onWindowChange((e=>this._screenDprMonitor.setWindow(e)))),this.register((0,i.forwardEvent)(this._screenDprMonitor.onDprChange,this._onDprChange)),this._textarea.addEventListener(`focus`,(()=>this._isFocused=!0)),this._textarea.addEventListener(`blur`,(()=>this._isFocused=!1))}get window(){return this._window}set window(e){this._window!==e&&(this._window=e,this._onWindowChange.fire(this._window))}get dpr(){return this.window.devicePixelRatio}get isFocused(){return this._cachedIsFocused===void 0&&(this._cachedIsFocused=this._isFocused&&this._textarea.ownerDocument.hasFocus(),queueMicrotask((()=>this._cachedIsFocused=void 0))),this._cachedIsFocused}}t.CoreBrowserService=o;class s extends r.Disposable{constructor(e){super(),this._parentWindow=e,this._windowResizeListener=this.register(new r.MutableDisposable),this._onDprChange=this.register(new i.EventEmitter),this.onDprChange=this._onDprChange.event,this._outerListener=()=>this._setDprAndFireIfDiffers(),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._updateDpr(),this._setWindowResizeListener(),this.register((0,r.toDisposable)((()=>this.clearListener())))}setWindow(e){this._parentWindow=e,this._setWindowResizeListener(),this._setDprAndFireIfDiffers()}_setWindowResizeListener(){this._windowResizeListener.value=(0,a.addDisposableDomListener)(this._parentWindow,`resize`,(()=>this._setDprAndFireIfDiffers()))}_setDprAndFireIfDiffers(){this._parentWindow.devicePixelRatio!==this._currentDevicePixelRatio&&this._onDprChange.fire(this._parentWindow.devicePixelRatio),this._updateDpr()}_updateDpr(){this._outerListener&&(this._resolutionMediaMatchList?.removeListener(this._outerListener),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._resolutionMediaMatchList=this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`),this._resolutionMediaMatchList.addListener(this._outerListener))}clearListener(){this._resolutionMediaMatchList&&this._outerListener&&(this._resolutionMediaMatchList.removeListener(this._outerListener),this._resolutionMediaMatchList=void 0,this._outerListener=void 0)}}},779:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.LinkProviderService=void 0;let r=n(844);class i extends r.Disposable{constructor(){super(),this.linkProviders=[],this.register((0,r.toDisposable)((()=>this.linkProviders.length=0)))}registerLinkProvider(e){return this.linkProviders.push(e),{dispose:()=>{let t=this.linkProviders.indexOf(e);t!==-1&&this.linkProviders.splice(t,1)}}}}t.LinkProviderService=i},8934:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.MouseService=void 0;let a=n(4725),o=n(9806),s=t.MouseService=class{constructor(e,t){this._renderService=e,this._charSizeService=t}getCoords(e,t,n,r,i){return(0,o.getCoords)(window,e,t,n,r,this._charSizeService.hasValidSize,this._renderService.dimensions.css.cell.width,this._renderService.dimensions.css.cell.height,i)}getMouseReportCoords(e,t){let n=(0,o.getCoordsRelativeToElement)(window,e,t);if(this._charSizeService.hasValidSize)return n[0]=Math.min(Math.max(n[0],0),this._renderService.dimensions.css.canvas.width-1),n[1]=Math.min(Math.max(n[1],0),this._renderService.dimensions.css.canvas.height-1),{col:Math.floor(n[0]/this._renderService.dimensions.css.cell.width),row:Math.floor(n[1]/this._renderService.dimensions.css.cell.height),x:Math.floor(n[0]),y:Math.floor(n[1])}}};t.MouseService=s=r([i(0,a.IRenderService),i(1,a.ICharSizeService)],s)},3230:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.RenderService=void 0;let a=n(6193),o=n(4725),s=n(8460),c=n(844),l=n(7226),u=n(2585),d=t.RenderService=class extends c.Disposable{get dimensions(){return this._renderer.value.dimensions}constructor(e,t,n,r,i,o,u,d){super(),this._rowCount=e,this._charSizeService=r,this._renderer=this.register(new c.MutableDisposable),this._pausedResizeTask=new l.DebouncedIdleTask,this._observerDisposable=this.register(new c.MutableDisposable),this._isPaused=!1,this._needsFullRefresh=!1,this._isNextRenderRedrawOnly=!0,this._needsSelectionRefresh=!1,this._canvasWidth=0,this._canvasHeight=0,this._selectionState={start:void 0,end:void 0,columnSelectMode:!1},this._onDimensionsChange=this.register(new s.EventEmitter),this.onDimensionsChange=this._onDimensionsChange.event,this._onRenderedViewportChange=this.register(new s.EventEmitter),this.onRenderedViewportChange=this._onRenderedViewportChange.event,this._onRender=this.register(new s.EventEmitter),this.onRender=this._onRender.event,this._onRefreshRequest=this.register(new s.EventEmitter),this.onRefreshRequest=this._onRefreshRequest.event,this._renderDebouncer=new a.RenderDebouncer(((e,t)=>this._renderRows(e,t)),u),this.register(this._renderDebouncer),this.register(u.onDprChange((()=>this.handleDevicePixelRatioChange()))),this.register(o.onResize((()=>this._fullRefresh()))),this.register(o.buffers.onBufferActivate((()=>this._renderer.value?.clear()))),this.register(n.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._charSizeService.onCharSizeChange((()=>this.handleCharSizeChanged()))),this.register(i.onDecorationRegistered((()=>this._fullRefresh()))),this.register(i.onDecorationRemoved((()=>this._fullRefresh()))),this.register(n.onMultipleOptionChange([`customGlyphs`,`drawBoldTextInBrightColors`,`letterSpacing`,`lineHeight`,`fontFamily`,`fontSize`,`fontWeight`,`fontWeightBold`,`minimumContrastRatio`,`rescaleOverlappingGlyphs`],(()=>{this.clear(),this.handleResize(o.cols,o.rows),this._fullRefresh()}))),this.register(n.onMultipleOptionChange([`cursorBlink`,`cursorStyle`],(()=>this.refreshRows(o.buffer.y,o.buffer.y,!0)))),this.register(d.onChangeColors((()=>this._fullRefresh()))),this._registerIntersectionObserver(u.window,t),this.register(u.onWindowChange((e=>this._registerIntersectionObserver(e,t))))}_registerIntersectionObserver(e,t){if(`IntersectionObserver`in e){let n=new e.IntersectionObserver((e=>this._handleIntersectionChange(e[e.length-1])),{threshold:0});n.observe(t),this._observerDisposable.value=(0,c.toDisposable)((()=>n.disconnect()))}}_handleIntersectionChange(e){this._isPaused=e.isIntersecting===void 0?e.intersectionRatio===0:!e.isIntersecting,this._isPaused||this._charSizeService.hasValidSize||this._charSizeService.measure(),!this._isPaused&&this._needsFullRefresh&&(this._pausedResizeTask.flush(),this.refreshRows(0,this._rowCount-1),this._needsFullRefresh=!1)}refreshRows(e,t,n=!1){this._isPaused?this._needsFullRefresh=!0:(n||(this._isNextRenderRedrawOnly=!1),this._renderDebouncer.refresh(e,t,this._rowCount))}_renderRows(e,t){this._renderer.value&&(e=Math.min(e,this._rowCount-1),t=Math.min(t,this._rowCount-1),this._renderer.value.renderRows(e,t),this._needsSelectionRefresh&&=(this._renderer.value.handleSelectionChanged(this._selectionState.start,this._selectionState.end,this._selectionState.columnSelectMode),!1),this._isNextRenderRedrawOnly||this._onRenderedViewportChange.fire({start:e,end:t}),this._onRender.fire({start:e,end:t}),this._isNextRenderRedrawOnly=!0)}resize(e,t){this._rowCount=t,this._fireOnCanvasResize()}_handleOptionsChanged(){this._renderer.value&&(this.refreshRows(0,this._rowCount-1),this._fireOnCanvasResize())}_fireOnCanvasResize(){this._renderer.value&&(this._renderer.value.dimensions.css.canvas.width===this._canvasWidth&&this._renderer.value.dimensions.css.canvas.height===this._canvasHeight||this._onDimensionsChange.fire(this._renderer.value.dimensions))}hasRenderer(){return!!this._renderer.value}setRenderer(e){this._renderer.value=e,this._renderer.value&&(this._renderer.value.onRequestRedraw((e=>this.refreshRows(e.start,e.end,!0))),this._needsSelectionRefresh=!0,this._fullRefresh())}addRefreshCallback(e){return this._renderDebouncer.addRefreshCallback(e)}_fullRefresh(){this._isPaused?this._needsFullRefresh=!0:this.refreshRows(0,this._rowCount-1)}clearTextureAtlas(){this._renderer.value&&(this._renderer.value.clearTextureAtlas?.(),this._fullRefresh())}handleDevicePixelRatioChange(){this._charSizeService.measure(),this._renderer.value&&(this._renderer.value.handleDevicePixelRatioChange(),this.refreshRows(0,this._rowCount-1))}handleResize(e,t){this._renderer.value&&(this._isPaused?this._pausedResizeTask.set((()=>this._renderer.value?.handleResize(e,t))):this._renderer.value.handleResize(e,t),this._fullRefresh())}handleCharSizeChanged(){this._renderer.value?.handleCharSizeChanged()}handleBlur(){this._renderer.value?.handleBlur()}handleFocus(){this._renderer.value?.handleFocus()}handleSelectionChanged(e,t,n){this._selectionState.start=e,this._selectionState.end=t,this._selectionState.columnSelectMode=n,this._renderer.value?.handleSelectionChanged(e,t,n)}handleCursorMove(){this._renderer.value?.handleCursorMove()}clear(){this._renderer.value?.clear()}};t.RenderService=d=r([i(2,u.IOptionsService),i(3,o.ICharSizeService),i(4,u.IDecorationService),i(5,u.IBufferService),i(6,o.ICoreBrowserService),i(7,o.IThemeService)],d)},9312:function(e,t,n){var r=this&&this.__decorate||function(e,t,n,r){var i,a=arguments.length,o=a<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)o=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(o=(a<3?i(o):a>3?i(t,n,o):i(t,n))||o);return a>3&&o&&Object.defineProperty(t,n,o),o},i=this&&this.__param||function(e,t){return function(n,r){t(n,r,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionService=void 0;let a=n(9806),o=n(9504),s=n(456),c=n(4725),l=n(8460),u=n(844),d=n(6114),f=n(4841),p=n(511),m=n(2585),h=RegExp(`\xA0`,`g`),g=t.SelectionService=class extends u.Disposable{constructor(e,t,n,r,i,a,o,c,d){super(),this._element=e,this._screenElement=t,this._linkifier=n,this._bufferService=r,this._coreService=i,this._mouseService=a,this._optionsService=o,this._renderService=c,this._coreBrowserService=d,this._dragScrollAmount=0,this._enabled=!0,this._workCell=new p.CellData,this._mouseDownTimeStamp=0,this._oldHasSelection=!1,this._oldSelectionStart=void 0,this._oldSelectionEnd=void 0,this._onLinuxMouseSelection=this.register(new l.EventEmitter),this.onLinuxMouseSelection=this._onLinuxMouseSelection.event,this._onRedrawRequest=this.register(new l.EventEmitter),this.onRequestRedraw=this._onRedrawRequest.event,this._onSelectionChange=this.register(new l.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onRequestScrollLines=this.register(new l.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this._mouseMoveListener=e=>this._handleMouseMove(e),this._mouseUpListener=e=>this._handleMouseUp(e),this._coreService.onUserInput((()=>{this.hasSelection&&this.clearSelection()})),this._trimListener=this._bufferService.buffer.lines.onTrim((e=>this._handleTrim(e))),this.register(this._bufferService.buffers.onBufferActivate((e=>this._handleBufferActivate(e)))),this.enable(),this._model=new s.SelectionModel(this._bufferService),this._activeSelectionMode=0,this.register((0,u.toDisposable)((()=>{this._removeMouseDownListeners()})))}reset(){this.clearSelection()}disable(){this.clearSelection(),this._enabled=!1}enable(){this._enabled=!0}get selectionStart(){return this._model.finalSelectionStart}get selectionEnd(){return this._model.finalSelectionEnd}get hasSelection(){let e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;return!(!e||!t||e[0]===t[0]&&e[1]===t[1])}get selectionText(){let e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;if(!e||!t)return``;let n=this._bufferService.buffer,r=[];if(this._activeSelectionMode===3){if(e[0]===t[0])return``;let i=e[0]e.replace(h,` `))).join(d.isWindows?`\r `:` diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/dist-Brormx16.js b/mcp/src/agents_remember/package_data/dashboard/assets/dist-17r-i6rR.js similarity index 99% rename from mcp/src/agents_remember/package_data/dashboard/assets/dist-Brormx16.js rename to mcp/src/agents_remember/package_data/dashboard/assets/dist-17r-i6rR.js index 0d6b00fc..161484ee 100644 --- a/mcp/src/agents_remember/package_data/dashboard/assets/dist-Brormx16.js +++ b/mcp/src/agents_remember/package_data/dashboard/assets/dist-17r-i6rR.js @@ -1,4 +1,4 @@ -import{$ as e,C as t,D as n,I as r,M as i,_ as a,b as o,c as s,d as c,f as ee,i as te,l as ne,m as re,s as l,t as ie,u,v as d,x as f}from"./index-BLlkJI-k.js";import{i as p,n as m,r as ae,t as oe}from"./dist-CuvUDais.js";import{i as h,n as g,r as se}from"./dist-DeLSDQE4.js";var ce=316,le=317,_=1,ue=2,de=3,fe=4,pe=318,me=320,he=321,ge=5,_e=6,ve=0,v=[9,10,11,12,13,32,133,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288],y=125,ye=59,b=47,x=42,S=43,C=45,w=60,T=44,E=63,D=46,O=91,k=new oe({start:!1,shift(e,t){return t==ge||t==_e||t==me?e:t==he},strict:!1}),A=new m((e,t)=>{let{next:n}=e;(n==y||n==-1||t.context)&&e.acceptToken(pe)},{contextual:!0,fallback:!0}),j=new m((e,t)=>{let{next:n}=e,r;v.indexOf(n)>-1||n==b&&((r=e.peek(1))==b||r==x)||n!=y&&n!=ye&&n!=-1&&!t.context&&e.acceptToken(ce)},{contextual:!0}),M=new m((e,t)=>{e.next==O&&!t.context&&e.acceptToken(le)},{contextual:!0}),N=new m((e,t)=>{let{next:n}=e;if(n==S||n==C){if(e.advance(),n==e.next){e.advance();let n=!t.context&&t.canShift(_);e.acceptToken(n?_:ue)}}else n==E&&e.peek(1)==D&&(e.advance(),e.advance(),(e.next<48||e.next>57)&&e.acceptToken(de))},{contextual:!0});function P(e,t){return e>=65&&e<=90||e>=97&&e<=122||e==95||e>=192||!t&&e>=48&&e<=57}var be=new m((e,t)=>{if(e.next!=w||!t.dialectEnabled(ve)||(e.advance(),e.next==b))return;let n=0;for(;v.indexOf(e.next)>-1;)e.advance(),n++;if(P(e.next,!0)){for(e.advance(),n++;P(e.next,!1);)e.advance(),n++;for(;v.indexOf(e.next)>-1;)e.advance(),n++;if(e.next==T)return;for(let t=0;;t++){if(t==7){if(!P(e.next,!0))return;break}if(e.next!=`extends`.charCodeAt(t))break;e.advance(),n++}}e.acceptToken(fe,-n)}),xe=o({"get set async static":f.modifier,"for while do if else switch try catch finally return throw break continue default case defer":f.controlKeyword,"in of await yield void typeof delete instanceof as satisfies":f.operatorKeyword,"let var const using function class extends":f.definitionKeyword,"import export from":f.moduleKeyword,"with debugger new":f.keyword,TemplateString:f.special(f.string),super:f.atom,BooleanLiteral:f.bool,this:f.self,null:f.null,Star:f.modifier,VariableName:f.variableName,"CallExpression/VariableName TaggedTemplateExpression/VariableName":f.function(f.variableName),VariableDefinition:f.definition(f.variableName),Label:f.labelName,PropertyName:f.propertyName,PrivatePropertyName:f.special(f.propertyName),"CallExpression/MemberExpression/PropertyName":f.function(f.propertyName),"FunctionDeclaration/VariableDefinition":f.function(f.definition(f.variableName)),"ClassDeclaration/VariableDefinition":f.definition(f.className),"NewExpression/VariableName":f.className,PropertyDefinition:f.definition(f.propertyName),PrivatePropertyDefinition:f.definition(f.special(f.propertyName)),UpdateOp:f.updateOperator,"LineComment Hashbang":f.lineComment,BlockComment:f.blockComment,Number:f.number,String:f.string,Escape:f.escape,ArithOp:f.arithmeticOperator,LogicOp:f.logicOperator,BitOp:f.bitwiseOperator,CompareOp:f.compareOperator,RegExp:f.regexp,Equals:f.definitionOperator,Arrow:f.function(f.punctuation),": Spread":f.punctuation,"( )":f.paren,"[ ]":f.squareBracket,"{ }":f.brace,"InterpolationStart InterpolationEnd":f.special(f.brace),".":f.derefOperator,", ;":f.separator,"@":f.meta,TypeName:f.typeName,TypeDefinition:f.definition(f.typeName),"type enum interface implements namespace module declare":f.definitionKeyword,"abstract global Privacy readonly override":f.modifier,"is keyof unique infer asserts":f.operatorKeyword,JSXAttributeValue:f.attributeValue,JSXText:f.content,"JSXStartTag JSXStartCloseTag JSXSelfCloseEndTag JSXEndTag":f.angleBracket,"JSXIdentifier JSXNameSpacedName":f.tagName,"JSXAttribute/JSXIdentifier JSXAttribute/JSXNameSpacedName":f.attributeName,"JSXBuiltin/JSXIdentifier":f.standard(f.tagName)}),Se={__proto__:null,export:20,as:25,from:33,default:36,async:41,function:42,in:52,out:55,const:56,extends:60,this:64,true:72,false:72,null:84,void:88,typeof:92,super:108,new:142,delete:154,yield:163,await:167,class:172,public:235,private:235,protected:235,readonly:237,instanceof:256,satisfies:259,import:292,keyof:349,unique:353,infer:359,asserts:395,is:397,abstract:417,implements:419,type:421,let:424,var:426,using:429,interface:435,enum:439,namespace:445,module:447,declare:451,global:455,defer:471,for:476,of:485,while:488,with:492,do:496,if:500,else:502,switch:506,case:512,try:518,catch:522,finally:526,return:530,throw:534,break:538,continue:542,debugger:546},Ce={__proto__:null,async:129,get:131,set:133,declare:195,public:197,private:197,protected:197,static:199,abstract:201,override:203,readonly:209,accessor:211,new:401},we={__proto__:null,"<":193},Te=ae.deserialize({version:14,states:"$F|Q%TQlOOO%[QlOOO'_QpOOP(lO`OOO*zQ!0MxO'#CiO+RO#tO'#CjO+aO&jO'#CjO+oO#@ItO'#DaO.QQlO'#DgO.bQlO'#DrO%[QlO'#DzO0fQlO'#ESOOQ!0Lf'#E['#E[O1PQ`O'#EXOOQO'#Ep'#EpOOQO'#Il'#IlO1XQ`O'#GsO1dQ`O'#EoO1iQ`O'#EoO3hQ!0MxO'#JrO6[Q!0MxO'#JsO6uQ`O'#F]O6zQ,UO'#FtOOQ!0Lf'#Ff'#FfO7VO7dO'#FfO9XQMhO'#F|O9`Q`O'#F{OOQ!0Lf'#Js'#JsOOQ!0Lb'#Jr'#JrO9eQ`O'#GwOOQ['#K_'#K_O9pQ`O'#IYO9uQ!0LrO'#IZOOQ['#J`'#J`OOQ['#I_'#I_Q`QlOOQ`QlOOO9}Q!L^O'#DvO:UQlO'#EOO:]QlO'#EQO9kQ`O'#GsO:dQMhO'#CoO:rQ`O'#EnO:}Q`O'#EyO;hQMhO'#FeO;xQ`O'#GsOOQO'#K`'#K`O;}Q`O'#K`O<]Q`O'#G{O<]Q`O'#G|O<]Q`O'#HOO9kQ`O'#HRO=SQ`O'#HUO>kQ`O'#CeO>{Q`O'#HcO?TQ`O'#HiO?TQ`O'#HkO`QlO'#HmO?TQ`O'#HoO?TQ`O'#HrO?YQ`O'#HxO?_Q!0LsO'#IOO%[QlO'#IQO?jQ!0LsO'#ISO?uQ!0LsO'#IUO9uQ!0LrO'#IWO@QQ!0MxO'#CiOASQpO'#DlQOQ`OOO%[QlO'#EQOAjQ`O'#ETO:dQMhO'#EnOAuQ`O'#EnOBQQ!bO'#FeOOQ['#Cg'#CgOOQ!0Lb'#Dq'#DqOOQ!0Lb'#Jv'#JvO%[QlO'#JvOOQO'#Jy'#JyOOQO'#Ih'#IhOCQQpO'#EgOOQ!0Lb'#Ef'#EfOOQ!0Lb'#J}'#J}OC|Q!0MSO'#EgODWQpO'#EWOOQO'#Jx'#JxODlQpO'#JyOEyQpO'#EWODWQpO'#EgPFWO&2DjO'#CbPOOO)CD})CD}OOOO'#I`'#I`OFcO#tO,59UOOQ!0Lh,59U,59UOOOO'#Ia'#IaOFqO&jO,59UOGPQ!L^O'#DcOOOO'#Ic'#IcOGWO#@ItO,59{OOQ!0Lf,59{,59{OGfQlO'#IdOGyQ`O'#JtOIxQ!fO'#JtO+}QlO'#JtOJPQ`O,5:ROJgQ`O'#EpOJtQ`O'#KTOKPQ`O'#KSOKPQ`O'#KSOKXQ`O,5;^OK^Q`O'#KROOQ!0Ln,5:^,5:^OKeQlO,5:^OMcQ!0MxO,5:fONSQ`O,5:nONmQ!0LrO'#KQONtQ`O'#KPO9eQ`O'#KPO! YQ`O'#KPO! bQ`O,5;]O! gQ`O'#KPO!#lQ!fO'#JsOOQ!0Lh'#Ci'#CiO%[QlO'#ESO!$[Q!fO,5:sOOQS'#Jz'#JzOOQO-EtOOQ['#Jh'#JhOOQ[,5>u,5>uOOQ[-E<]-E<]O!TO`QlO,5>VO!LOQ`O,5>XO`QlO,5>ZO!LTQ`O,5>^O!LYQlO,5>dOOQ[,5>j,5>jO%[QlO,5>jO9uQ!0LrO,5>lOOQ[,5>n,5>nO#!dQ`O,5>nOOQ[,5>p,5>pO#!dQ`O,5>pOOQ[,5>r,5>rO##QQpO'#D_O%[QlO'#JvO##sQpO'#JvO##}QpO'#DmO#$`QpO'#DmO#&qQlO'#DmO#&xQ`O'#JuO#'QQ`O,5:WO#'VQ`O'#EtO#'eQ`O'#KUO#'mQ`O,5;_O#'rQpO'#DmO#(PQpO'#EVOOQ!0Lf,5:o,5:oO%[QlO,5:oO#(WQ`O,5:oO?YQ`O,5;YO!CUQpO,5;YO!C^QMhO,5;YO:dQMhO,5;YO#(`Q`O,5@bO#(eQ07dO,5:sOOQO-EPO$6^Q`O,5>POOQ[1G3i1G3iO`QlO1G3iOOQ[1G3o1G3oOOQ[1G3q1G3qO?TQ`O1G3sO$6cQlO1G3uO$:gQlO'#HtOOQ[1G3x1G3xO$:tQ`O'#HzO?YQ`O'#H|OOQ[1G4O1G4OO$:|QlO1G4OO9uQ!0LrO1G4UOOQ[1G4W1G4WOOQ!0Lb'#G_'#G_O9uQ!0LrO1G4YO9uQ!0LrO1G4[O$?TQ`O,5@bO!)[QlO,5;`O9eQ`O,5;`O?YQ`O,5:XO!)[QlO,5:XO!CUQpO,5:XO$?YQ?MtO,5:XOOQO,5;`,5;`O$?dQpO'#IeO$?zQ`O,5@aOOQ!0Lf1G/r1G/rO$@SQpO'#IkO$@^Q`O,5@pOOQ!0Lb1G0y1G0yO#$`QpO,5:XOOQO'#Ig'#IgO$@fQpO,5:qOOQ!0Ln,5:q,5:qO#(ZQ`O1G0ZOOQ!0Lf1G0Z1G0ZO%[QlO1G0ZOOQ!0Lf1G0t1G0tO?YQ`O1G0tO!CUQpO1G0tO!C^QMhO1G0tOOQ!0Lb1G5|1G5|O!ByQ!0LrO1G0^OOQO1G0m1G0mO%[QlO1G0mO$@mQ!0LrO1G0mO$@xQ!0LrO1G0mO!CUQpO1G0^ODWQpO1G0^O$AWQ!0LrO1G0mOOQO1G0^1G0^O$AlQ!0MxO1G0mPOOO-E<[-E<[POOO1G.h1G.hOOOO1G/i1G/iO$AvQ!bO,5QQpO,5@}OOQ!0Lb1G3c1G3cOOQ[7+$V7+$VO@zQ`O7+$VO9uQ!0LrO7+$VO%>]Q`O7+$VO%[QlO1G6lO%[QlO1G6mO%>bQ!0LrO1G6lO%>lQlO1G3kO%>sQ`O1G3kO%>xQlO1G3kOOQ[7+)T7+)TO9uQ!0LrO7+)_O`QlO7+)aOOQ['#Kh'#KhOOQ['#JS'#JSO%?PQlO,5>`OOQ[,5>`,5>`O%[QlO'#HuO%?^Q`O'#HwOOQ[,5>f,5>fO9eQ`O,5>fOOQ[,5>h,5>hOOQ[7+)j7+)jOOQ[7+)p7+)pOOQ[7+)t7+)tOOQ[7+)v7+)vO%?cQpO1G5|O%?}Q?MtO1G0zO%@XQ`O1G0zOOQO1G/s1G/sO%@dQ?MtO1G/sO?YQ`O1G/sO!)[QlO'#DmOOQO,5?P,5?POOQO-ERQ`O7+,WO&>WQ`O7+,XO%[QlO7+,WO%[QlO7+,XOOQ[7+)V7+)VO&>]Q`O7+)VO&>bQlO7+)VO&>iQ`O7+)VOOQ[<nQ`O,5>aOOQ[,5>c,5>cO&>sQ`O1G4QO9eQ`O7+&fO!)[QlO7+&fOOQO7+%_7+%_O&>xQ?MtO1G6ZO?YQ`O7+%_OOQ!0Lf<yQ?MvO,5?aO'@|Q?MvO,5?cO'CPQ?MvO7+'|O'DuQMjOG27TOOQO<VO!l$xO#jROe!iOpkOrPO(T)]O(VTO(YUO(aVO(o[O~O!]$_Oa$qa'z$qa'w$qa!k$qa!Y$qa!_$qa%i$qa!g$qa~Ol)dO~P!&zOh%VOp%WOr%XOs$tOt$tOz%YO|%ZO!O%]O!S${O!_$|O!i%bO!l$xO#j%cO$W%`O$t%^O$v%_O$y%aO(T(vO(VTO(YUO(a$uO(y$}O(z%PO~Og(pP~P!,TO!Q)iO!g)hO!_$^X$Z$^X$]$^X$_$^X$f$^X~O!g)hO!_({X$Z({X$]({X$_({X$f({X~O!Q)iO~P!.^O!Q)iO!_({X$Z({X$]({X$_({X$f({X~O!_)kO$Z)oO$])jO$_)jO$f)pO~O![)sO~P!)[O$]$hO$_$gO$f)wO~On$zX!Q$zX#S$zX'y$zX(y$zX(z$zX~OgmXg$zXnmX!]mX#`mX~P!0SOx)yO(b)zO(c)|O~On*VO!Q*OO'y*PO(y$}O(z%PO~Og)}O~P!1WOg*WO~Oh%VOr%XOs$tOt$tOz%YO|%ZO!OVO!l$xO#jVO!l$xO#jROe!iOpkOrPO(VTO(YUO(aVO(o[O~O(T=QO~P#$qO!]-]O!^(iX~O!^-_O~O!g-VO#`-UO!]#hX!^#hX~O!]-`O!^(xX~O!^-bO~O!c-cO!d-cO(U!lO~P#$`O!^-fO~P'_On-iO!_'`O~O!Y-nO~Os!{a!b!{a!c!{a!d!{a#T!{a#U!{a#V!{a#W!{a#X!{a#[!{a#]!{a(U!{a(V!{a(Y!{a(e!{a(o!{a~P!#vO!p-sO#`-qO~PChO!c-uO!d-uO(U!lO~PDWOa%nO#`-qO'z%nO~Oa%nO!g#vO#`-qO'z%nO~Oa%nO!g#vO!p-sO#`-qO'z%nO(r'pO~O(P'xO(Q'xO(R-zO~Ov-{O~O!Y'Wa!]'Wa~P!:tO![.PO!Y'WX!]'WX~P%[O!](VO!Y(ha~O!Y(ha~PHRO!](^O!Y(va~O!S%hO![.TO!_%iO(T%gO!Y'^X!]'^X~O#`.VO!](ta!k(taa(ta'z(ta~O!g#vO~P#,wO!](jO!k(sa~O!S%hO!_%iO#j.ZO(T%gO~Op.`O!S%hO![.]O!_%iO!|]O#i._O#j.]O(T%gO!]'aX!k'aX~OR.dO!l#xO~Oh%VOn.gO!_'`O%i.fO~Oa#ci!]#ci'z#ci'w#ci!Y#ci!k#civ#ci!_#ci%i#ci!g#ci~P!:tOn>]O!Q*OO'y*PO(y$}O(z%PO~O#k#_aa#_a#`#_a'z#_a!]#_a!k#_a!_#_a!Y#_a~P#/sO#k(`XP(`XR(`X[(`Xa(`Xj(`Xr(`X!S(`X!l(`X!p(`X#R(`X#n(`X#o(`X#p(`X#q(`X#r(`X#s(`X#t(`X#u(`X#v(`X#x(`X#z(`X#{(`X'z(`X(a(`X(r(`X!k(`X!Y(`X'w(`Xv(`X!_(`X%i(`X!g(`X~P!6kO!].tO!k(kX~P!:tO!k.wO~O!Y.yO~OP$[OR#zO!Q#yO!S#{O!l#xO!p$[O(aVO[#mia#mij#mir#mi!]#mi#R#mi#o#mi#p#mi#q#mi#r#mi#s#mi#t#mi#u#mi#v#mi#x#mi#z#mi#{#mi'z#mi(r#mi(y#mi(z#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#n#mi~P#3cO#n$OO~P#3cOP$[OR#zOr$aO!Q#yO!S#{O!l#xO!p$[O#n$OO#o$PO#p$PO#q$PO(aVO[#mia#mij#mi!]#mi#R#mi#s#mi#t#mi#u#mi#v#mi#x#mi#z#mi#{#mi'z#mi(r#mi(y#mi(z#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#r#mi~P#6QO#r$QO~P#6QOP$[OR#zO[$cOj$ROr$aO!Q#yO!S#{O!l#xO!p$[O#R$RO#n$OO#o$PO#p$PO#q$PO#r$QO#s$RO#t$RO#u$bO(aVOa#mi!]#mi#x#mi#z#mi#{#mi'z#mi(r#mi(y#mi(z#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#v#mi~P#8oOP$[OR#zO[$cOj$ROr$aO!Q#yO!S#{O!l#xO!p$[O#R$RO#n$OO#o$PO#p$PO#q$PO#r$QO#s$RO#t$RO#u$bO#v$SO(aVO(z#}Oa#mi!]#mi#z#mi#{#mi'z#mi(r#mi(y#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#x$UO~P#;VO#x#mi~P#;VO#v$SO~P#8oOP$[OR#zO[$cOj$ROr$aO!Q#yO!S#{O!l#xO!p$[O#R$RO#n$OO#o$PO#p$PO#q$PO#r$QO#s$RO#t$RO#u$bO#v$SO#x$UO(aVO(y#|O(z#}Oa#mi!]#mi#{#mi'z#mi(r#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#z#mi~P#={O#z$WO~P#={OP]XR]X[]Xj]Xr]X!Q]X!S]X!l]X!p]X#R]X#S]X#`]X#kfX#n]X#o]X#p]X#q]X#r]X#s]X#t]X#u]X#v]X#x]X#z]X#{]X$Q]X(a]X(r]X(y]X(z]X!]]X!^]X~O$O]X~P#@jOP$[OR#zO[]O!Q*OO'y*PO(y$}O(z%POP#miR#mi!S#mi!l#mi!p#mi#n#mi#o#mi#p#mi#q#mi(a#mi~P#EyO!]/POg(pX~P!1WOg/RO~Oa$Pi!]$Pi'z$Pi'w$Pi!Y$Pi!k$Piv$Pi!_$Pi%i$Pi!g$Pi~P!:tO$]/SO$_/SO~O$]/TO$_/TO~O!g)hO#`/UO!_$cX$Z$cX$]$cX$_$cX$f$cX~O![/VO~O!_)kO$Z/XO$])jO$_)jO$f/YO~O!]VO!l$xO#j^O!Q*OO'y*PO(y$}O(z%POP#miR#mi!S#mi!l#mi!p#mi#n#mi#o#mi#p#mi#q#mi(a#mi~P&,QO#S$dOP(`XR(`X[(`Xj(`Xn(`Xr(`X!Q(`X!S(`X!l(`X!p(`X#R(`X#n(`X#o(`X#p(`X#q(`X#r(`X#s(`X#t(`X#u(`X#v(`X#x(`X#z(`X#{(`X$O(`X'y(`X(a(`X(r(`X(y(`X(z(`X!](`X!^(`X~O$O$Pi!]$Pi!^$Pi~P#BwO$O!ri!^!ri~P$+oOg']a!]']a~P!1WO!^7nO~O!]'da!^'da~P#BwO!Y7oO~P#/sO!g#vO(r'pO!]'ea!k'ea~O!]/pO!k)Oi~O!]/pO!g#vO!k)Oi~Og$|q!]$|q#`$|q$O$|q~P!1WO!Y'ga!]'ga~P#/sO!g7vO~O!]/yO!Y)Pi~P#/sO!]/yO!Y)Pi~O!Y7yO~Oh%VOr8OO!l%eO(r'pO~Oj8QO!g#vO~Or8TO!g#vO(r'pO~O!Q*OO'y*PO(z%POn'ja(y'ja!]'ja#`'ja~Og'ja$O'ja~P&5RO!Q*OO'y*POn'la(y'la(z'la!]'la#`'la~Og'la$O'la~P&5tOg(_q!](_q~P!1WO#`8VOg(_q!](_q~P!1WO!Y8WO~Og%Oq!]%Oq#`%Oq$O%Oq~P!1WOa$oy!]$oy'z$oy'w$oy!Y$oy!k$oyv$oy!_$oy%i$oy!g$oy~P!:tO!g6rO~O!]5[O!_)Qa~O!_'`OP$TaR$Ta[$Taj$Tar$Ta!Q$Ta!S$Ta!]$Ta!l$Ta!p$Ta#R$Ta#n$Ta#o$Ta#p$Ta#q$Ta#r$Ta#s$Ta#t$Ta#u$Ta#v$Ta#x$Ta#z$Ta#{$Ta(a$Ta(r$Ta(y$Ta(z$Ta~O%i7WO~P&8fO%^8[Oa%[i!_%[i'z%[i!]%[i~Oa#cy!]#cy'z#cy'w#cy!Y#cy!k#cyv#cy!_#cy%i#cy!g#cy~P!:tO[8^O~Ob8`O(T+qO(VTO(YUO~O!]1TO!^)Xi~O`8dO~O(e(|O!]'pX!^'pX~O!]5uO!^)Ua~O!^8nO~P%;eO(o!sO~P$&YO#[8oO~O!_1oO~O!_1oO%i8qO~On8tO!_1oO%i8qO~O[8yO!]'sa!^'sa~O!]1zO!^)Vi~O!k8}O~O!k9OO~O!k9RO~O!k9RO~P%[Oa9TO~O!g9UO~O!k9VO~O!](wi!^(wi~P#BwOa%nO#`9_O'z%nO~O!](ty!k(tya(ty'z(ty~P!:tO!](jO!k(sy~O%i9bO~P&8fO!_'`O%i9bO~O#k$|qP$|qR$|q[$|qa$|qj$|qr$|q!S$|q!]$|q!l$|q!p$|q#R$|q#n$|q#o$|q#p$|q#q$|q#r$|q#s$|q#t$|q#u$|q#v$|q#x$|q#z$|q#{$|q'z$|q(a$|q(r$|q!k$|q!Y$|q'w$|q#`$|qv$|q!_$|q%i$|q!g$|q~P#/sO#k'jaP'jaR'ja['jaa'jaj'jar'ja!S'ja!l'ja!p'ja#R'ja#n'ja#o'ja#p'ja#q'ja#r'ja#s'ja#t'ja#u'ja#v'ja#x'ja#z'ja#{'ja'z'ja(a'ja(r'ja!k'ja!Y'ja'w'jav'ja!_'ja%i'ja!g'ja~P&5RO#k'laP'laR'la['laa'laj'lar'la!S'la!l'la!p'la#R'la#n'la#o'la#p'la#q'la#r'la#s'la#t'la#u'la#v'la#x'la#z'la#{'la'z'la(a'la(r'la!k'la!Y'la'w'lav'la!_'la%i'la!g'la~P&5tO#k%OqP%OqR%Oq[%Oqa%Oqj%Oqr%Oq!S%Oq!]%Oq!l%Oq!p%Oq#R%Oq#n%Oq#o%Oq#p%Oq#q%Oq#r%Oq#s%Oq#t%Oq#u%Oq#v%Oq#x%Oq#z%Oq#{%Oq'z%Oq(a%Oq(r%Oq!k%Oq!Y%Oq'w%Oq#`%Oqv%Oq!_%Oq%i%Oq!g%Oq~P#/sO!]'Yi!k'Yi~P!:tO$O#cq!]#cq!^#cq~P#BwO(y$}OP%aaR%aa[%aaj%aar%aa!S%aa!l%aa!p%aa#R%aa#n%aa#o%aa#p%aa#q%aa#r%aa#s%aa#t%aa#u%aa#v%aa#x%aa#z%aa#{%aa$O%aa(a%aa(r%aa!]%aa!^%aa~On%aa!Q%aa'y%aa(z%aa~P&IyO(z%POP%caR%ca[%caj%car%ca!S%ca!l%ca!p%ca#R%ca#n%ca#o%ca#p%ca#q%ca#r%ca#s%ca#t%ca#u%ca#v%ca#x%ca#z%ca#{%ca$O%ca(a%ca(r%ca!]%ca!^%ca~On%ca!Q%ca'y%ca(y%ca~P&LQOn>^O!Q*OO'y*PO(z%PO~P&IyOn>^O!Q*OO'y*PO(y$}O~P&LQOR0kO!Q0kO!S0lO#S$dOP}a[}aj}an}ar}a!l}a!p}a#R}a#n}a#o}a#p}a#q}a#r}a#s}a#t}a#u}a#v}a#x}a#z}a#{}a$O}a'y}a(a}a(r}a(y}a(z}a!]}a!^}a~O!Q*OO'y*POP$saR$sa[$saj$san$sar$sa!S$sa!l$sa!p$sa#R$sa#n$sa#o$sa#p$sa#q$sa#r$sa#s$sa#t$sa#u$sa#v$sa#x$sa#z$sa#{$sa$O$sa(a$sa(r$sa(y$sa(z$sa!]$sa!^$sa~O!Q*OO'y*POP$uaR$ua[$uaj$uan$uar$ua!S$ua!l$ua!p$ua#R$ua#n$ua#o$ua#p$ua#q$ua#r$ua#s$ua#t$ua#u$ua#v$ua#x$ua#z$ua#{$ua$O$ua(a$ua(r$ua(y$ua(z$ua!]$ua!^$ua~On>^O!Q*OO'y*PO(y$}O(z%PO~OP%TaR%Ta[%Taj%Tar%Ta!S%Ta!l%Ta!p%Ta#R%Ta#n%Ta#o%Ta#p%Ta#q%Ta#r%Ta#s%Ta#t%Ta#u%Ta#v%Ta#x%Ta#z%Ta#{%Ta$O%Ta(a%Ta(r%Ta!]%Ta!^%Ta~P''VO$O$mq!]$mq!^$mq~P#BwO$O$oq!]$oq!^$oq~P#BwO!^9oO~O$O9pO~P!1WO!g#vO!]'ei!k'ei~O!g#vO(r'pO!]'ei!k'ei~O!]/pO!k)Oq~O!Y'gi!]'gi~P#/sO!]/yO!Y)Pq~Or9wO!g#vO(r'pO~O[9yO!Y9xO~P#/sO!Y9xO~Oj:PO!g#vO~Og(_y!](_y~P!1WO!]'na!_'na~P#/sOa%[q!_%[q'z%[q!]%[q~P#/sO[:UO~O!]1TO!^)Xq~O`:YO~O#`:ZO!]'pa!^'pa~O!]5uO!^)Ui~P#BwO!S:]O~O!_1oO%i:`O~O(VTO(YUO(e:eO~O!]1zO!^)Vq~O!k:hO~O!k:iO~O!k:jO~O!k:jO~P%[O#`:mO!]#hy!^#hy~O!]#hy!^#hy~P#BwO%i:rO~P&8fO!_'`O%i:rO~O$O#|y!]#|y!^#|y~P#BwOP$|iR$|i[$|ij$|ir$|i!S$|i!l$|i!p$|i#R$|i#n$|i#o$|i#p$|i#q$|i#r$|i#s$|i#t$|i#u$|i#v$|i#x$|i#z$|i#{$|i$O$|i(a$|i(r$|i!]$|i!^$|i~P''VO!Q*OO'y*PO(z%POP'iaR'ia['iaj'ian'iar'ia!S'ia!l'ia!p'ia#R'ia#n'ia#o'ia#p'ia#q'ia#r'ia#s'ia#t'ia#u'ia#v'ia#x'ia#z'ia#{'ia$O'ia(a'ia(r'ia(y'ia!]'ia!^'ia~O!Q*OO'y*POP'kaR'ka['kaj'kan'kar'ka!S'ka!l'ka!p'ka#R'ka#n'ka#o'ka#p'ka#q'ka#r'ka#s'ka#t'ka#u'ka#v'ka#x'ka#z'ka#{'ka$O'ka(a'ka(r'ka(y'ka(z'ka!]'ka!^'ka~O(y$}OP%aiR%ai[%aij%ain%air%ai!Q%ai!S%ai!l%ai!p%ai#R%ai#n%ai#o%ai#p%ai#q%ai#r%ai#s%ai#t%ai#u%ai#v%ai#x%ai#z%ai#{%ai$O%ai'y%ai(a%ai(r%ai(z%ai!]%ai!^%ai~O(z%POP%ciR%ci[%cij%cin%cir%ci!Q%ci!S%ci!l%ci!p%ci#R%ci#n%ci#o%ci#p%ci#q%ci#r%ci#s%ci#t%ci#u%ci#v%ci#x%ci#z%ci#{%ci$O%ci'y%ci(a%ci(r%ci(y%ci!]%ci!^%ci~O$O$oy!]$oy!^$oy~P#BwO$O#cy!]#cy!^#cy~P#BwO!g#vO!]'eq!k'eq~O!]/pO!k)Oy~O!Y'gq!]'gq~P#/sOr:|O!g#vO(r'pO~O[;QO!Y;PO~P#/sO!Y;PO~Og(_!R!](_!R~P!1WOa%[y!_%[y'z%[y!]%[y~P#/sO!]1TO!^)Xy~O!]5uO!^)Uq~O(T;XO~O!_1oO%i;[O~O!k;_O~O%i;dO~P&8fOP$|qR$|q[$|qj$|qr$|q!S$|q!l$|q!p$|q#R$|q#n$|q#o$|q#p$|q#q$|q#r$|q#s$|q#t$|q#u$|q#v$|q#x$|q#z$|q#{$|q$O$|q(a$|q(r$|q!]$|q!^$|q~P''VO!Q*OO'y*PO(z%POP'jaR'ja['jaj'jan'jar'ja!S'ja!l'ja!p'ja#R'ja#n'ja#o'ja#p'ja#q'ja#r'ja#s'ja#t'ja#u'ja#v'ja#x'ja#z'ja#{'ja$O'ja(a'ja(r'ja(y'ja!]'ja!^'ja~O!Q*OO'y*POP'laR'la['laj'lan'lar'la!S'la!l'la!p'la#R'la#n'la#o'la#p'la#q'la#r'la#s'la#t'la#u'la#v'la#x'la#z'la#{'la$O'la(a'la(r'la(y'la(z'la!]'la!^'la~OP%OqR%Oq[%Oqj%Oqr%Oq!S%Oq!l%Oq!p%Oq#R%Oq#n%Oq#o%Oq#p%Oq#q%Oq#r%Oq#s%Oq#t%Oq#u%Oq#v%Oq#x%Oq#z%Oq#{%Oq$O%Oq(a%Oq(r%Oq!]%Oq!^%Oq~P''VOg%e!Z!]%e!Z#`%e!Z$O%e!Z~P!1WO!Y;hO~P#/sOr;iO!g#vO(r'pO~O[;kO!Y;hO~P#/sO!]'pq!^'pq~P#BwO!]#h!Z!^#h!Z~P#BwO#k%e!ZP%e!ZR%e!Z[%e!Za%e!Zj%e!Zr%e!Z!S%e!Z!]%e!Z!l%e!Z!p%e!Z#R%e!Z#n%e!Z#o%e!Z#p%e!Z#q%e!Z#r%e!Z#s%e!Z#t%e!Z#u%e!Z#v%e!Z#x%e!Z#z%e!Z#{%e!Z'z%e!Z(a%e!Z(r%e!Z!k%e!Z!Y%e!Z'w%e!Z#`%e!Zv%e!Z!_%e!Z%i%e!Z!g%e!Z~P#/sOr;tO!g#vO(r'pO~O!Y;uO~P#/sOr;|O!g#vO(r'pO~O!Y;}O~P#/sOP%e!ZR%e!Z[%e!Zj%e!Zr%e!Z!S%e!Z!l%e!Z!p%e!Z#R%e!Z#n%e!Z#o%e!Z#p%e!Z#q%e!Z#r%e!Z#s%e!Z#t%e!Z#u%e!Z#v%e!Z#x%e!Z#z%e!Z#{%e!Z$O%e!Z(a%e!Z(r%e!Z!]%e!Z!^%e!Z~P''VOrROe!iOpkOrPO(T)]O(VTO(YUO(aVO(o[O~O!]WO!l$xO#jgPPP!>oI[PPPPPPPPP!BOP!C]PPI[!DnPI[PI[I[I[I[I[PI[!FQP!I[P!LbP!Lf!Lp!Lt!LtP!IXP!Lx!LxP#!OP#!SI[PI[#!Y#%_CjA^PA^PA^A^P#&lA^A^#)OA^#+vA^#.SA^A^#.r#1W#1W#1]#1f#1W#1qPP#1WPA^#2ZA^#6YA^A^6mPPP#:_PPP#:x#:xP#:xP#;`#:xPP#;fP#;]P#;]#;y#;]#P#>V#>]#>k#>q#>{#?R#?]#?c#?s#?y#@k#@}#AT#AZ#Ai#BO#Cs#DR#DY#Et#FS#Gt#HS#HY#H`#Hf#Hp#Hv#H|#IW#Ij#IpPPPPPPPPPPP#IvPPPPPPP#Jk#Mx$ b$ i$ qPPP$']P$'f$*_$0x$0{$1O$1}$2Q$2X$2aP$2g$2jP$3W$3[$4S$5b$5g$5}PP$6S$6Y$6^$6a$6e$6i$7e$7|$8e$8i$8l$8o$8y$8|$9Q$9UR!|RoqOXst!Z#d%m&r&t&u&w,s,x2[2_Y!vQ'`-e1o5{Q%tvQ%|yQ&T|Q&j!VS'W!e-]Q'f!iS'l!r!yU*k$|*Z*oQ+o%}S+|&V&WQ,d&dQ-c'_Q-m'gQ-u'mQ0[*qQ1b,OQ1y,eR<{SU+P%]S!S!nQ!r!v!y!z$|'W'_'`'l'm'n*k*o*q*r-]-c-e-u0[0_1o5{5}%[$ti#v$b$c$d$x${%O%Q%^%_%c)y*R*T*V*Y*a*g*w*x+f+i,S,V.f/P/d/m/x/y/{0`0b0i0j0o1f1i1q3c4^4_4j4o5Q5[5_6S7W7v8Q8V8[8q9b9p9y:P:`:r;Q;[;d;kP>X>Y>]>^Q&X|Q'U!eS'[%i-`Q+t&PQ,P&WQ,f&gQ0n+SQ1Y+uQ1_+{Q2Q,jQ2R,kQ5f1TQ5o1aQ6[1zQ6_1|Q6`2PQ8`5gQ8c5lQ8|6bQ:X8dQ:f8yQ;V:YR<}*ZrnOXst!V!Z#d%m&i&r&t&u&w,s,x2[2_R,h&k&z^OPXYstuvwz!Z!`!g!j!o#S#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%m%t&R&k&n&o&r&t&u&w&{'T'b'r(V(](d(x(z)O)s)}*i+X+]+g,p,s,x-U-X-i-q.P.V.g.t.{/V/n0]0l0r1S1r2S2T2V2X2[2_2a2p3Q3W3d3l4T4z5w6T6e6f6i6s6|7[8t9T9_:Z:mR>S[#]WZ#W#Z'X(T!b%jm#h#i#l$x%e%h(^(h(i(j*Y*^*b+Z+[+^,o-V.T.Z.[.]._/m/p2d3[3]4a6r7TQ%wxQ%{yW&Q|&V&W,OQ&_!TQ'c!hQ'e!iQ(q#sS+n%|%}Q+r&PQ,_&bQ,c&dS-l'f'gQ.i(rQ1R+oQ1X+uQ1Z+vQ1^+zQ1t,`S1x,d,eQ2|-mQ5e1TQ5i1WQ5n1`Q6Z1yQ8_5gQ8b5kQ8f5pQ:T8^R;T:U!U$zi$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Y!^%yy!i!u%{%|%}'V'e'f'g'k'u*j+n+o-Y-l-m-t0R0U1R2u2|3T4r4s4v7}9{Q+h%wQ,T&[Q,W&]Q,b&dQ.h(qQ1s,_U1w,c,d,eQ3e.iQ6U1tS6Y1x1yQ8x6Z#f>T#v$b$c$x${)y*V*Y*g+f+i,S,V.f/d/m/y/{1f1i1q3c4^4j4o5[5_6S7W7v8Q8[8q9b9y:P:`:r;Q;[;d;k]>^o>UPS&[!Q&iQ&]!RQ&^!SU*}%[%d=sR,R&Y%]%Si#v$b$c$d$x${%O%Q%^%_%c)y*R*T*V*Y*a*g*w*x+f+i,S,V.f/P/d/m/x/y/{0`0b0i0j0o1f1i1q3c4^4_4j4o5Q5[5_6S7W7v8Q8V8[8q9b9p9y:P:`:r;Q;[;d;kP>X>Y>]>^T)z$u){V+P%]S$i$^c#Y#e%q%s%u(S(Y(t(y)R)S)T)U)V)W)X)Y)Z)[)^)`)b)g)q+d+x-Z-x-}.S.U.s.v.z.|.}/O/b0p2k2n3O3V3k3p3q3r3s3t3u3v3w3x3y3z3{3|4P4Q4X5X5c6u6{7Q7a7b7k7l8k9X9]9g9m9n:o;W;`SQ'Y!eR2q-]!W!nQ!e!r!v!y!z$|'W'_'`'l'm'n*Z*k*o*q*r-]-c-e-u0[0_1o5{5}R1l,ZnqOXst!Z#d%m&r&t&u&w,s,x2[2_Q&y!^Q'v!xS(s#u<^Q+l%zQ,]&_Q,^&aQ-j'dQ-w'oS.r(x=PS0q+X=ZQ1P+mQ1n,[Q2c,zQ2e,{Q2m-WQ2z-kQ2}-oS5Y0r=eQ5a1QS5d1S=fQ6t2oQ6x2{Q6}3SQ8]5bQ9Y6vQ9Z6yQ9^7OR:l9V$d$]c#Y#e%s%u(S(Y(t(y)R)S)T)U)V)W)X)Y)Z)[)^)`)b)g)q+d+x-Z-x-}.S.U.s.v.z.}/O/b0p2k2n3O3V3k3p3q3r3s3t3u3v3w3x3y3z3{3|4P4Q4X5X5c6u6{7Q7a7b7k7l8k9X9]9g9m9n:o;W;`SS#q]SU$fd)_,mS(p#p'iU*v%R(w4OU0m+O.n7gQ5^0xQ7V3`Q9d7YR:s9em!tQ!r!v!y!z'`'l'm'n-e-u1o5{5}Q't!uS(f#g2US-s'k'wQ/s*]Q0R*jQ3U-vQ4f/tQ4r0TQ4s0UQ4x0^Q7r4`S7}4t4vS8R4y4{Q9r7sQ9v7yQ9{8OQ:Q8TS:{9w9xS;g:|;PS;s;h;iS;{;t;uSSR=o>R%^bOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%m%t&R&k&n&o&r&t&u&w&{'T'b'r(T(V(](d(x(z)O)}*i+X+]+g,p,s,x-i-q.P.V.g.t.{/n0]0l0r1S1r2S2T2V2X2[2_2a3Q3W3d3l4z6T6e6f6i6|7[8t9T9_Q%fj!^%xy!i!u%{%|%}'V'e'f'g'k'u*j+n+o-Y-l-m-t0R0U1R2u2|3T4r4s4v7}9{S&Oz!jQ+k%yQ,a&dW1v,b,c,d,eU6X1w1x1yS8w6Y6ZQ:d8x!r=j$Z$n'X)s-U-X/V2p4T5w6s:Z:mSQ=t>QR=u>R%QeOPXYstuvw!Z!`!g!o#S#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%m%t&R&k&n&r&t&u&w&{'T'b'r(V(](d(x(z)O)}*i+X+]+g,p,s,x-i-q.P.V.g.t.{/n0]0l0r1S1r2S2T2V2X2[2_2a3Q3W3d3l4z6T6e6f6i6|7[8t9T9_Y#bWZ#W#Z(T!b%jm#h#i#l$x%e%h(^(h(i(j*Y*^*b+Z+[+^,o-V.T.Z.[.]._/m/p2d3[3]4a6r7TQ,n&o!p=k$Z$n)s-U-X/V2p4T5w6s:Z:mSR=n'XU']!e%i*ZR2s-`%SdOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%m%t&R&k&n&r&t&u&w&{'T'b'r(T(V(](d(x(z)O)}*i+X+],p,s,x-i-q.P.V.t.{/n0]0l0r1S1r2S2T2V2X2[2_2a3Q3W3l4z6T6e6f6i6|8t9T9_!r)_$Z$n'X)s-U-X/V2p4T5w6s:Z:mSQ,m&oQ0x+gQ3`.gQ7Y3dR9e7[!b$Tc#Y%q(S(Y(t(y)Z)[)`)g+x-x-}.S.U.s.v/b0p3O3V3k3{5X5c6{7Q7a9]:oS)^)q-Z.|2k2n3p4P4X6u7b7k7l8k9X9g9m9n;W;`=vQ>X>ZR>Y>['QkOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%m%t&R&k&n&o&r&t&u&w&{'T'X'b'r(T(V(](d(x(z)O)s)}*i+X+]+g,p,s,x-U-X-i-q.P.V.g.t.{/V/n0]0l0r1S1r2S2T2V2X2[2_2a2p3Q3W3d3l4T4z5w6T6e6f6i6s6|7[8t9T9_:Z:mSS$oh$pR4U/U'XgOPWXYZhstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n$p%m%t&R&k&n&o&r&t&u&w&{'T'X'b'r(T(V(](d(x(z)O)s)}*i+X+]+g,p,s,x-U-X-i-q.P.V.g.t.{/U/V/n0]0l0r1S1r2S2T2V2X2[2_2a2p3Q3W3d3l4T4z5w6T6e6f6i6s6|7[8t9T9_:Z:mST$kf$qQ$ifS)j$l)nR)v$qT$jf$qT)l$l)n'XhOPWXYZhstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n$p%m%t&R&k&n&o&r&t&u&w&{'T'X'b'r(T(V(](d(x(z)O)s)}*i+X+]+g,p,s,x-U-X-i-q.P.V.g.t.{/U/V/n0]0l0r1S1r2S2T2V2X2[2_2a2p3Q3W3d3l4T4z5w6T6e6f6i6s6|7[8t9T9_:Z:mST$oh$pQ$rhR)u$p%^jOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%m%t&R&k&n&o&r&t&u&w&{'T'b'r(T(V(](d(x(z)O)}*i+X+]+g,p,s,x-i-q.P.V.g.t.{/n0]0l0r1S1r2S2T2V2X2[2_2a3Q3W3d3l4z6T6e6f6i6|7[8t9T9_!s>Q$Z$n'X)s-U-X/V2p4T5w6s:Z:mS#glOPXZst!Z!`!o#S#d#o#{$n%m&k&n&o&r&t&u&w&{'T'b)O)s*i+]+g,p,s,x-i.g/V/n0]0l1r2S2T2V2X2[2_2a3d4T4z6T6e6f6i7[8t9T!U%Ri$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Y#f(w#v$b$c$x${)y*V*Y*g+f+i,S,V.f/d/m/y/{1f1i1q3c4^4j4o5[5_6S7W7v8Q8[8q9b9y:P:`:r;Q;[;d;k]>^Q+T%aQ/c*Oo4OP>X>YQ*c$zU*l$|*Z*oQ+U%bQ0W*m#f=q#v$b$c$x${)y*V*Y*g+f+i,S,V.f/d/m/y/{1f1i1q3c4^4j4o5[5_6S7W7v8Q8[8q9b9y:P:`:r;Q;[;d;k]>^n=rTQ=x>UQ=y>VR=z>W!U%Ri$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Y#f(w#v$b$c$x${)y*V*Y*g+f+i,S,V.f/d/m/y/{1f1i1q3c4^4j4o5[5_6S7W7v8Q8[8q9b9y:P:`:r;Q;[;d;k]>^o4OP>X>Y>]>^Q,U&]Q1h,WQ5s1gR8h5tV*n$|*Z*oU*n$|*Z*oT5z1o5{S0P*i/nQ4w0]T8S4z:]Q+j%xQ0V*lQ1O+kQ1u,aQ6W1vQ8v6XQ:c8wR;^:d!U%Oi$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Yx*R$v)e*S*u+V/v0d0e4R4g5R5S5W7p8U:R:x=p=}>OS0`*t0a#f]>^nZ>[`=T3}7c7f7j9h:t:w;yS=_.l3iT=`7e9k!U%Qi$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Y|*T$v)e*U*t+V/g/v0d0e4R4g4|5R5S5W7p8U:R:x=p=}>OS0b*u0c#f]>^nZ>[d=V3}7d7e7j9h9i:t:u:w;yS=a.m3jT=b7f9lrnOXst!V!Z#d%m&i&r&t&u&w,s,x2[2_Q&f!UR,p&ornOXst!V!Z#d%m&i&r&t&u&w,s,x2[2_R&f!UQ,Y&^R1d,RsnOXst!V!Z#d%m&i&r&t&u&w,s,x2[2_Q1p,_S6R1s1tU8p6P6Q6US:_8r8sS;Y:^:aQ;m;ZR;w;nQ&m!VR,i&iR6_1|R:f8yW&Q|&V&W,OR1Z+vQ&r!WR,s&sR,y&xT2],x2_R,}&yQ,|&yR2f,}Q'y!{R-y'ySsOtQ#dXT%ps#dQ#OTR'{#OQ#RUR'}#RQ){$uR/`){Q#UVR(Q#UQ#XWU(W#X(X.QQ(X#YR.Q(YQ-^'YR2r-^Q.u(yS3m.u3nR3n.vQ-e'`R2v-eY!rQ'`-e1o5{R'j!rQ/Q)eR4S/QU#_W%h*YU(_#_(`.RQ(`#`R.R(ZQ-a']R2t-at`OXst!V!Z#d%m&i&k&r&t&u&w,s,x2[2_S#hZ%eU#r`#h.[R.[(jQ(k#jQ.X(gW.a(k.X3X7RQ3X.YR7R3YQ)n$lR/W)nQ$phR)t$pQ$`cU)a$`-|O>Z>[Q/z*eU4k/z4m7xQ4m/|R7x4lS*o$|*ZR0Y*ox*S$v)e*t*u+V/v0d0e4R4g5R5S5W7p8U:R:x=p=}>O!d.j(u)c*[*e.l.m.q/_/k/|0v1e3h4[4h4l5r7]7`7w7z8X8Z9t9|:S:};R;e;j;v>Z>[U/h*S.j7ca7c3}7e7f7j9h:t:w;yQ0a*tQ3i.lU4}0a3i9kR9k7e|*U$v)e*t*u+V/g/v0d0e4R4g4|5R5S5W7p8U:R:x=p=}>O!h.k(u)c*[*e.l.m.q/_/k/|0v1e3f3h4[4h4l5r7]7^7`7w7z8X8Z9t9|:S:};R;e;j;v>Z>[U/j*U.k7de7d3}7e7f7j9h9i:t:u:w;yQ0c*uQ3j.mU5P0c3j9lR9l7fQ*z%UR0g*zQ5]0vR8Y5]Q+_%kR0u+_Q5v1jS8j5v:[R:[8kQ,[&_R1m,[Q5{1oR8m5{Q1{,fS6]1{8zR8z6_Q1U+rW5h1U5j8a:VQ5j1XQ8a5iR:V8bQ+w&QR1[+wQ2_,xR6m2_YrOXst#dQ&v!ZQ+a%mQ,r&rQ,t&tQ,u&uQ,w&wQ2Y,sS2],x2_R6l2[Q%opQ&z!_Q&}!aQ'P!bQ'R!cQ'q!uQ+`%lQ+l%zQ,Q&XQ,h&mQ-P&|W-p'k's't'wQ-w'oQ0X*nQ1P+mQ1c,PS2O,i,lQ2g-OQ2h-RQ2i-SQ2}-oW3P-r-s-v-xQ5a1QQ5m1_Q5q1eQ6V1uQ6a2QQ6k2ZU6z3O3R3UQ6}3SQ8]5bQ8e5oQ8g5rQ8l5zQ8u6WQ8{6`S9[6{7PQ9^7OQ:W8cQ:b8vQ:g8|Q:n9]Q;U:XQ;]:cQ;a:oQ;l;VR;o;^Q%zyQ'd!iQ'o!uU+m%{%|%}Q-W'VU-k'e'f'gS-o'k'uQ0Q*jS1Q+n+oQ2o-YS2{-l-mQ3S-tS4p0R0UQ5b1RQ6v2uQ6y2|Q7O3TU7{4r4s4vQ9z7}R;O9{S$wi>PR*{%VU%Ui%V>PR0f*yQ$viS(u#v+iS)c$b$cQ)e$dQ*[$xS*e${*YQ*t%OQ*u%QQ+Q%^Q+R%_Q+V%cQ.lPQ=}>XQ>O>YQ>Z>]R>[>^Q+O%]Q.nSR#[WR'Z!el!tQ!r!v!y!z'`'l'm'n-e-u1o5{5}S'V!e-]U*j$|*Z*oS-Y'W'_S0U*k*qQ0^*rQ2u-cQ4v0[R4{0_R({#xQ!fQT-d'`-e]!qQ!r'`-e1o5{Q#p]R'i < TypeParamList in out const TypeDefinition extends ThisType this LiteralType ArithOp Number BooleanLiteral TemplateType InterpolationEnd Interpolation InterpolationStart NullType null VoidType void TypeofType typeof MemberExpression . PropertyName [ TemplateString Escape Interpolation super RegExp ] ArrayExpression Spread , } { ObjectExpression Property async get set PropertyDefinition Block : NewTarget new NewExpression ) ( ArgList UnaryExpression delete LogicOp BitOp YieldExpression yield AwaitExpression await ParenthesizedExpression ClassExpression class ClassBody MethodDeclaration Decorator @ MemberExpression PrivatePropertyName CallExpression TypeArgList CompareOp < declare Privacy static abstract override PrivatePropertyDefinition PropertyDeclaration readonly accessor Optional TypeAnnotation Equals StaticBlock FunctionExpression ArrowFunction ParamList ParamList ArrayPattern ObjectPattern PatternProperty Privacy readonly Arrow MemberExpression BinaryExpression ArithOp ArithOp ArithOp ArithOp BitOp CompareOp instanceof satisfies CompareOp BitOp BitOp BitOp LogicOp LogicOp ConditionalExpression LogicOp LogicOp AssignmentExpression UpdateOp PostfixExpression CallExpression InstantiationExpression TaggedTemplateExpression DynamicImport import ImportMeta JSXElement JSXSelfCloseEndTag JSXSelfClosingTag JSXIdentifier JSXBuiltin JSXIdentifier JSXNamespacedName JSXMemberExpression JSXSpreadAttribute JSXAttribute JSXAttributeValue JSXEscape JSXEndTag JSXOpenTag JSXFragmentTag JSXText JSXEscape JSXStartCloseTag JSXCloseTag PrefixCast < ArrowFunction TypeParamList SequenceExpression InstantiationExpression KeyofType keyof UniqueType unique ImportType InferredType infer TypeName ParenthesizedType FunctionSignature ParamList NewSignature IndexedType TupleType Label ArrayType ReadonlyType ObjectType MethodType PropertyType IndexSignature PropertyDefinition CallSignature TypePredicate asserts is NewSignature new UnionType LogicOp IntersectionType LogicOp ConditionalType ParameterizedType ClassDeclaration abstract implements type VariableDeclaration let var using TypeAliasDeclaration InterfaceDeclaration interface EnumDeclaration enum EnumBody NamespaceDeclaration namespace module AmbientDeclaration declare GlobalDeclaration global ClassDeclaration ClassBody AmbientFunctionDeclaration ExportGroup VariableName VariableName ImportDeclaration defer ImportGroup ForStatement for ForSpec ForInSpec ForOfSpec of WhileStatement while WithStatement with DoStatement do IfStatement if else SwitchStatement switch SwitchBody CaseLabel case DefaultLabel TryStatement try CatchClause catch FinallyClause finally ReturnStatement return ThrowStatement throw BreakStatement break ContinueStatement continue DebuggerStatement debugger LabeledStatement ExpressionStatement SingleExpression SingleClassItem`,maxTerm:380,context:k,nodeProps:[[`isolate`,-8,5,6,14,37,39,51,53,55,``],[`group`,-26,9,17,19,68,207,211,215,216,218,221,224,234,237,243,245,247,249,252,258,264,266,268,270,272,274,275,`Statement`,-34,13,14,32,35,36,42,51,54,55,57,62,70,72,76,80,82,84,85,110,111,120,121,136,139,141,142,143,144,145,147,148,167,169,171,`Expression`,-23,31,33,37,41,43,45,173,175,177,178,180,181,182,184,185,186,188,189,190,201,203,205,206,`Type`,-3,88,103,109,`ClassItem`],[`openedBy`,23,`<`,38,`InterpolationStart`,56,`[`,60,`{`,73,`(`,160,`JSXStartCloseTag`],[`closedBy`,-2,24,168,`>`,40,`InterpolationEnd`,50,`]`,61,`}`,74,`)`,165,`JSXEndTag`]],propSources:[xe],skippedNodes:[0,5,6,278],repeatNodeCount:37,tokenData:"$Fq07[R!bOX%ZXY+gYZ-yZ[+g[]%Z]^.c^p%Zpq+gqr/mrs3cst:_tuEruvJSvwLkwx! Yxy!'iyz!(sz{!)}{|!,q|}!.O}!O!,q!O!P!/Y!P!Q!9j!Q!R#:O!R![#<_![!]#I_!]!^#Jk!^!_#Ku!_!`$![!`!a$$v!a!b$*T!b!c$,r!c!}Er!}#O$-|#O#P$/W#P#Q$4o#Q#R$5y#R#SEr#S#T$7W#T#o$8b#o#p$x#r#s$@U#s$f%Z$f$g+g$g#BYEr#BY#BZ$A`#BZ$ISEr$IS$I_$A`$I_$I|Er$I|$I}$Dk$I}$JO$Dk$JO$JTEr$JT$JU$A`$JU$KVEr$KV$KW$A`$KW&FUEr&FU&FV$A`&FV;'SEr;'S;=`I|<%l?HTEr?HT?HU$A`?HUOEr(n%d_$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z&j&hT$i&jO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c&j&zP;=`<%l&c'|'U]$i&j(Z!bOY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}!b(SU(Z!bOY'}Zw'}x#O'}#P;'S'};'S;=`(f<%lO'}!b(iP;=`<%l'}'|(oP;=`<%l&}'[(y]$i&j(WpOY(rYZ&cZr(rrs&cs!^(r!^!_)r!_#O(r#O#P&c#P#o(r#o#p)r#p;'S(r;'S;=`*a<%lO(rp)wU(WpOY)rZr)rs#O)r#P;'S)r;'S;=`*Z<%lO)rp*^P;=`<%l)r'[*dP;=`<%l(r#S*nX(Wp(Z!bOY*gZr*grs'}sw*gwx)rx#O*g#P;'S*g;'S;=`+Z<%lO*g#S+^P;=`<%l*g(n+dP;=`<%l%Z07[+rq$i&j(Wp(Z!b'|0/lOX%ZXY+gYZ&cZ[+g[p%Zpq+gqr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p$f%Z$f$g+g$g#BY%Z#BY#BZ+g#BZ$IS%Z$IS$I_+g$I_$JT%Z$JT$JU+g$JU$KV%Z$KV$KW+g$KW&FU%Z&FU&FV+g&FV;'S%Z;'S;=`+a<%l?HT%Z?HT?HU+g?HUO%Z07[.ST(X#S$i&j'}0/lO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c07[.n_$i&j(Wp(Z!b'}0/lOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z)3p/x`$i&j!p),Q(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`0z!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW1V`#v(Ch$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`2X!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW2d_#v(Ch$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'At3l_(V':f$i&j(Z!bOY4kYZ5qZr4krs7nsw4kwx5qx!^4k!^!_8p!_#O4k#O#P5q#P#o4k#o#p8p#p;'S4k;'S;=`:X<%lO4k(^4r_$i&j(Z!bOY4kYZ5qZr4krs7nsw4kwx5qx!^4k!^!_8p!_#O4k#O#P5q#P#o4k#o#p8p#p;'S4k;'S;=`:X<%lO4k&z5vX$i&jOr5qrs6cs!^5q!^!_6y!_#o5q#o#p6y#p;'S5q;'S;=`7h<%lO5q&z6jT$d`$i&jO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c`6|TOr6yrs7]s;'S6y;'S;=`7b<%lO6y`7bO$d``7eP;=`<%l6y&z7kP;=`<%l5q(^7w]$d`$i&j(Z!bOY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}!r8uZ(Z!bOY8pYZ6yZr8prs9hsw8pwx6yx#O8p#O#P6y#P;'S8p;'S;=`:R<%lO8p!r9oU$d`(Z!bOY'}Zw'}x#O'}#P;'S'};'S;=`(f<%lO'}!r:UP;=`<%l8p(^:[P;=`<%l4k%9[:hh$i&j(Wp(Z!bOY%ZYZ&cZq%Zqr`#P#o`x!^=^!^!_?q!_#O=^#O#P>`#P#o=^#o#p?q#p;'S=^;'S;=`@h<%lO=^&n>gXWS$i&jOY>`YZ&cZ!^>`!^!_?S!_#o>`#o#p?S#p;'S>`;'S;=`?k<%lO>`S?XSWSOY?SZ;'S?S;'S;=`?e<%lO?SS?hP;=`<%l?S&n?nP;=`<%l>`!f?xWWS(Z!bOY?qZw?qwx?Sx#O?q#O#P?S#P;'S?q;'S;=`@b<%lO?q!f@eP;=`<%l?q(Q@kP;=`<%l=^'`@w]WS$i&j(WpOY@nYZ&cZr@nrs>`s!^@n!^!_Ap!_#O@n#O#P>`#P#o@n#o#pAp#p;'S@n;'S;=`Bg<%lO@ntAwWWS(WpOYApZrAprs?Ss#OAp#O#P?S#P;'SAp;'S;=`Ba<%lOAptBdP;=`<%lAp'`BjP;=`<%l@n#WBvYWS(Wp(Z!bOYBmZrBmrs?qswBmwxApx#OBm#O#P?S#P;'SBm;'S;=`Cf<%lOBm#WCiP;=`<%lBm(rCoP;=`<%l^!Q^$i&j!X7`OY!=yYZ&cZ!P!=y!P!Q!>|!Q!^!=y!^!_!@c!_!}!=y!}#O!CW#O#P!Dy#P#o!=y#o#p!@c#p;'S!=y;'S;=`!Ek<%lO!=y|#X#Z&c#Z#[!>|#[#]&c#]#^!>|#^#a&c#a#b!>|#b#g&c#g#h!>|#h#i&c#i#j!>|#j#k!>|#k#m&c#m#n!>|#n#o&c#p;'S&c;'S;=`&w<%lO&c7`!@hX!X7`OY!@cZ!P!@c!P!Q!AT!Q!}!@c!}#O!Ar#O#P!Bq#P;'S!@c;'S;=`!CQ<%lO!@c7`!AYW!X7`#W#X!AT#Z#[!AT#]#^!AT#a#b!AT#g#h!AT#i#j!AT#j#k!AT#m#n!AT7`!AuVOY!ArZ#O!Ar#O#P!B[#P#Q!@c#Q;'S!Ar;'S;=`!Bk<%lO!Ar7`!B_SOY!ArZ;'S!Ar;'S;=`!Bk<%lO!Ar7`!BnP;=`<%l!Ar7`!BtSOY!@cZ;'S!@c;'S;=`!CQ<%lO!@c7`!CTP;=`<%l!@c^!Ezl$i&j(Z!b!X7`OY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#W&}#W#X!Eq#X#Z&}#Z#[!Eq#[#]&}#]#^!Eq#^#a&}#a#b!Eq#b#g&}#g#h!Eq#h#i&}#i#j!Eq#j#k!Eq#k#m&}#m#n!Eq#n#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}8r!GyZ(Z!b!X7`OY!GrZw!Grwx!@cx!P!Gr!P!Q!Hl!Q!}!Gr!}#O!JU#O#P!Bq#P;'S!Gr;'S;=`!J|<%lO!Gr8r!Hse(Z!b!X7`OY'}Zw'}x#O'}#P#W'}#W#X!Hl#X#Z'}#Z#[!Hl#[#]'}#]#^!Hl#^#a'}#a#b!Hl#b#g'}#g#h!Hl#h#i'}#i#j!Hl#j#k!Hl#k#m'}#m#n!Hl#n;'S'};'S;=`(f<%lO'}8r!JZX(Z!bOY!JUZw!JUwx!Arx#O!JU#O#P!B[#P#Q!Gr#Q;'S!JU;'S;=`!Jv<%lO!JU8r!JyP;=`<%l!JU8r!KPP;=`<%l!Gr>^!KZ^$i&j(Z!bOY!KSYZ&cZw!KSwx!CWx!^!KS!^!_!JU!_#O!KS#O#P!DR#P#Q!^!LYP;=`<%l!KS>^!L`P;=`<%l!_#c#d#Bq#d#l%Z#l#m#Es#m#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#>j_$i&j(Wp(Z!bs'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#?rd$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!R#AQ!R!S#AQ!S!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#AQ#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#A]f$i&j(Wp(Z!bs'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!R#AQ!R!S#AQ!S!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#AQ#S#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Bzc$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!Y#DV!Y!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#DV#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Dbe$i&j(Wp(Z!bs'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!Y#DV!Y!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#DV#S#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#E|g$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![#Ge![!^%Z!^!_*g!_!c%Z!c!i#Ge!i#O%Z#O#P&c#P#R%Z#R#S#Ge#S#T%Z#T#Z#Ge#Z#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Gpi$i&j(Wp(Z!bs'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![#Ge![!^%Z!^!_*g!_!c%Z!c!i#Ge!i#O%Z#O#P&c#P#R%Z#R#S#Ge#S#T%Z#T#Z#Ge#Z#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z*)x#Il_!g$b$i&j$O)Lv(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z)[#Jv_al$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z04f#LS^h#)`#R-v$?V_!^(CdvBr$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z?O$@a_!q7`$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z07[$Aq|$i&j(Wp(Z!b'|0/l$]#t(T,2j(e$I[OX%ZXY+gYZ&cZ[+g[p%Zpq+gqr%Zrs&}st%ZtuEruw%Zwx(rx}%Z}!OGv!O!Q%Z!Q![Er![!^%Z!^!_*g!_!c%Z!c!}Er!}#O%Z#O#P&c#P#R%Z#R#SEr#S#T%Z#T#oEr#o#p*g#p$f%Z$f$g+g$g#BYEr#BY#BZ$A`#BZ$ISEr$IS$I_$A`$I_$JTEr$JT$JU$A`$JU$KVEr$KV$KW$A`$KW&FUEr&FU&FV$A`&FV;'SEr;'S;=`I|<%l?HTEr?HT?HU$A`?HUOEr07[$D|k$i&j(Wp(Z!b'}0/l$]#t(T,2j(e$I[OY%ZYZ&cZr%Zrs&}st%ZtuEruw%Zwx(rx}%Z}!OGv!O!Q%Z!Q![Er![!^%Z!^!_*g!_!c%Z!c!}Er!}#O%Z#O#P&c#P#R%Z#R#SEr#S#T%Z#T#oEr#o#p*g#p$g%Z$g;'SEr;'S;=`I|<%lOEr",tokenizers:[j,M,N,be,2,3,4,5,6,7,8,9,10,11,12,13,14,A,new p("$S~RRtu[#O#Pg#S#T#|~_P#o#pb~gOx~~jVO#i!P#i#j!U#j#l!P#l#m!q#m;'S!P;'S;=`#v<%lO!P~!UO!U~~!XS!Q![!e!c!i!e#T#Z!e#o#p#Z~!hR!Q![!q!c!i!q#T#Z!q~!tR!Q![!}!c!i!}#T#Z!}~#QR!Q![!P!c!i!P#T#Z!P~#^R!Q![#g!c!i#g#T#Z#g~#jS!Q![#g!c!i#g#T#Z#g#q#r!P~#yP;=`<%l!P~$RO(c~~",141,340),new p(`j~RQYZXz{^~^O(Q~~aP!P!Qd~iO(R~~`,25,323)],topRules:{Script:[0,7],SingleExpression:[1,276],SingleClassItem:[2,277]},dialects:{jsx:0,ts:15175},dynamicPrecedences:{80:1,82:1,94:1,169:1,199:1},specialized:[{term:327,get:e=>Se[e]||-1},{term:343,get:e=>Ce[e]||-1},{term:95,get:e=>we[e]||-1}],tokenPrec:15201}),Ee=e({autoCloseTags:()=>$,javascript:()=>Z,javascriptLanguage:()=>W,jsxLanguage:()=>q,localCompletionSource:()=>U,snippets:()=>F,tsxLanguage:()=>J,typescriptLanguage:()=>K,typescriptSnippets:()=>I}),F=[h("function ${name}(${params}) {\n ${}\n}",{label:`function`,detail:`definition`,type:`keyword`}),h("for (let ${index} = 0; ${index} < ${bound}; ${index}++) {\n ${}\n}",{label:`for`,detail:`loop`,type:`keyword`}),h("for (let ${name} of ${collection}) {\n ${}\n}",{label:`for`,detail:`of loop`,type:`keyword`}),h(`do { +import{$ as e,C as t,D as n,I as r,M as i,_ as a,b as o,c as s,d as c,f as ee,i as te,l as ne,m as re,s as l,t as ie,u,v as d,x as f}from"./index-CLJ0aycO.js";import{i as p,n as m,r as ae,t as oe}from"./dist-B2R-c1vX.js";import{i as h,n as g,r as se}from"./dist-BxWz473c.js";var ce=316,le=317,_=1,ue=2,de=3,fe=4,pe=318,me=320,he=321,ge=5,_e=6,ve=0,v=[9,10,11,12,13,32,133,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288],y=125,ye=59,b=47,x=42,S=43,C=45,w=60,T=44,E=63,D=46,O=91,k=new oe({start:!1,shift(e,t){return t==ge||t==_e||t==me?e:t==he},strict:!1}),A=new m((e,t)=>{let{next:n}=e;(n==y||n==-1||t.context)&&e.acceptToken(pe)},{contextual:!0,fallback:!0}),j=new m((e,t)=>{let{next:n}=e,r;v.indexOf(n)>-1||n==b&&((r=e.peek(1))==b||r==x)||n!=y&&n!=ye&&n!=-1&&!t.context&&e.acceptToken(ce)},{contextual:!0}),M=new m((e,t)=>{e.next==O&&!t.context&&e.acceptToken(le)},{contextual:!0}),N=new m((e,t)=>{let{next:n}=e;if(n==S||n==C){if(e.advance(),n==e.next){e.advance();let n=!t.context&&t.canShift(_);e.acceptToken(n?_:ue)}}else n==E&&e.peek(1)==D&&(e.advance(),e.advance(),(e.next<48||e.next>57)&&e.acceptToken(de))},{contextual:!0});function P(e,t){return e>=65&&e<=90||e>=97&&e<=122||e==95||e>=192||!t&&e>=48&&e<=57}var be=new m((e,t)=>{if(e.next!=w||!t.dialectEnabled(ve)||(e.advance(),e.next==b))return;let n=0;for(;v.indexOf(e.next)>-1;)e.advance(),n++;if(P(e.next,!0)){for(e.advance(),n++;P(e.next,!1);)e.advance(),n++;for(;v.indexOf(e.next)>-1;)e.advance(),n++;if(e.next==T)return;for(let t=0;;t++){if(t==7){if(!P(e.next,!0))return;break}if(e.next!=`extends`.charCodeAt(t))break;e.advance(),n++}}e.acceptToken(fe,-n)}),xe=o({"get set async static":f.modifier,"for while do if else switch try catch finally return throw break continue default case defer":f.controlKeyword,"in of await yield void typeof delete instanceof as satisfies":f.operatorKeyword,"let var const using function class extends":f.definitionKeyword,"import export from":f.moduleKeyword,"with debugger new":f.keyword,TemplateString:f.special(f.string),super:f.atom,BooleanLiteral:f.bool,this:f.self,null:f.null,Star:f.modifier,VariableName:f.variableName,"CallExpression/VariableName TaggedTemplateExpression/VariableName":f.function(f.variableName),VariableDefinition:f.definition(f.variableName),Label:f.labelName,PropertyName:f.propertyName,PrivatePropertyName:f.special(f.propertyName),"CallExpression/MemberExpression/PropertyName":f.function(f.propertyName),"FunctionDeclaration/VariableDefinition":f.function(f.definition(f.variableName)),"ClassDeclaration/VariableDefinition":f.definition(f.className),"NewExpression/VariableName":f.className,PropertyDefinition:f.definition(f.propertyName),PrivatePropertyDefinition:f.definition(f.special(f.propertyName)),UpdateOp:f.updateOperator,"LineComment Hashbang":f.lineComment,BlockComment:f.blockComment,Number:f.number,String:f.string,Escape:f.escape,ArithOp:f.arithmeticOperator,LogicOp:f.logicOperator,BitOp:f.bitwiseOperator,CompareOp:f.compareOperator,RegExp:f.regexp,Equals:f.definitionOperator,Arrow:f.function(f.punctuation),": Spread":f.punctuation,"( )":f.paren,"[ ]":f.squareBracket,"{ }":f.brace,"InterpolationStart InterpolationEnd":f.special(f.brace),".":f.derefOperator,", ;":f.separator,"@":f.meta,TypeName:f.typeName,TypeDefinition:f.definition(f.typeName),"type enum interface implements namespace module declare":f.definitionKeyword,"abstract global Privacy readonly override":f.modifier,"is keyof unique infer asserts":f.operatorKeyword,JSXAttributeValue:f.attributeValue,JSXText:f.content,"JSXStartTag JSXStartCloseTag JSXSelfCloseEndTag JSXEndTag":f.angleBracket,"JSXIdentifier JSXNameSpacedName":f.tagName,"JSXAttribute/JSXIdentifier JSXAttribute/JSXNameSpacedName":f.attributeName,"JSXBuiltin/JSXIdentifier":f.standard(f.tagName)}),Se={__proto__:null,export:20,as:25,from:33,default:36,async:41,function:42,in:52,out:55,const:56,extends:60,this:64,true:72,false:72,null:84,void:88,typeof:92,super:108,new:142,delete:154,yield:163,await:167,class:172,public:235,private:235,protected:235,readonly:237,instanceof:256,satisfies:259,import:292,keyof:349,unique:353,infer:359,asserts:395,is:397,abstract:417,implements:419,type:421,let:424,var:426,using:429,interface:435,enum:439,namespace:445,module:447,declare:451,global:455,defer:471,for:476,of:485,while:488,with:492,do:496,if:500,else:502,switch:506,case:512,try:518,catch:522,finally:526,return:530,throw:534,break:538,continue:542,debugger:546},Ce={__proto__:null,async:129,get:131,set:133,declare:195,public:197,private:197,protected:197,static:199,abstract:201,override:203,readonly:209,accessor:211,new:401},we={__proto__:null,"<":193},Te=ae.deserialize({version:14,states:"$F|Q%TQlOOO%[QlOOO'_QpOOP(lO`OOO*zQ!0MxO'#CiO+RO#tO'#CjO+aO&jO'#CjO+oO#@ItO'#DaO.QQlO'#DgO.bQlO'#DrO%[QlO'#DzO0fQlO'#ESOOQ!0Lf'#E['#E[O1PQ`O'#EXOOQO'#Ep'#EpOOQO'#Il'#IlO1XQ`O'#GsO1dQ`O'#EoO1iQ`O'#EoO3hQ!0MxO'#JrO6[Q!0MxO'#JsO6uQ`O'#F]O6zQ,UO'#FtOOQ!0Lf'#Ff'#FfO7VO7dO'#FfO9XQMhO'#F|O9`Q`O'#F{OOQ!0Lf'#Js'#JsOOQ!0Lb'#Jr'#JrO9eQ`O'#GwOOQ['#K_'#K_O9pQ`O'#IYO9uQ!0LrO'#IZOOQ['#J`'#J`OOQ['#I_'#I_Q`QlOOQ`QlOOO9}Q!L^O'#DvO:UQlO'#EOO:]QlO'#EQO9kQ`O'#GsO:dQMhO'#CoO:rQ`O'#EnO:}Q`O'#EyO;hQMhO'#FeO;xQ`O'#GsOOQO'#K`'#K`O;}Q`O'#K`O<]Q`O'#G{O<]Q`O'#G|O<]Q`O'#HOO9kQ`O'#HRO=SQ`O'#HUO>kQ`O'#CeO>{Q`O'#HcO?TQ`O'#HiO?TQ`O'#HkO`QlO'#HmO?TQ`O'#HoO?TQ`O'#HrO?YQ`O'#HxO?_Q!0LsO'#IOO%[QlO'#IQO?jQ!0LsO'#ISO?uQ!0LsO'#IUO9uQ!0LrO'#IWO@QQ!0MxO'#CiOASQpO'#DlQOQ`OOO%[QlO'#EQOAjQ`O'#ETO:dQMhO'#EnOAuQ`O'#EnOBQQ!bO'#FeOOQ['#Cg'#CgOOQ!0Lb'#Dq'#DqOOQ!0Lb'#Jv'#JvO%[QlO'#JvOOQO'#Jy'#JyOOQO'#Ih'#IhOCQQpO'#EgOOQ!0Lb'#Ef'#EfOOQ!0Lb'#J}'#J}OC|Q!0MSO'#EgODWQpO'#EWOOQO'#Jx'#JxODlQpO'#JyOEyQpO'#EWODWQpO'#EgPFWO&2DjO'#CbPOOO)CD})CD}OOOO'#I`'#I`OFcO#tO,59UOOQ!0Lh,59U,59UOOOO'#Ia'#IaOFqO&jO,59UOGPQ!L^O'#DcOOOO'#Ic'#IcOGWO#@ItO,59{OOQ!0Lf,59{,59{OGfQlO'#IdOGyQ`O'#JtOIxQ!fO'#JtO+}QlO'#JtOJPQ`O,5:ROJgQ`O'#EpOJtQ`O'#KTOKPQ`O'#KSOKPQ`O'#KSOKXQ`O,5;^OK^Q`O'#KROOQ!0Ln,5:^,5:^OKeQlO,5:^OMcQ!0MxO,5:fONSQ`O,5:nONmQ!0LrO'#KQONtQ`O'#KPO9eQ`O'#KPO! YQ`O'#KPO! bQ`O,5;]O! gQ`O'#KPO!#lQ!fO'#JsOOQ!0Lh'#Ci'#CiO%[QlO'#ESO!$[Q!fO,5:sOOQS'#Jz'#JzOOQO-EtOOQ['#Jh'#JhOOQ[,5>u,5>uOOQ[-E<]-E<]O!TO`QlO,5>VO!LOQ`O,5>XO`QlO,5>ZO!LTQ`O,5>^O!LYQlO,5>dOOQ[,5>j,5>jO%[QlO,5>jO9uQ!0LrO,5>lOOQ[,5>n,5>nO#!dQ`O,5>nOOQ[,5>p,5>pO#!dQ`O,5>pOOQ[,5>r,5>rO##QQpO'#D_O%[QlO'#JvO##sQpO'#JvO##}QpO'#DmO#$`QpO'#DmO#&qQlO'#DmO#&xQ`O'#JuO#'QQ`O,5:WO#'VQ`O'#EtO#'eQ`O'#KUO#'mQ`O,5;_O#'rQpO'#DmO#(PQpO'#EVOOQ!0Lf,5:o,5:oO%[QlO,5:oO#(WQ`O,5:oO?YQ`O,5;YO!CUQpO,5;YO!C^QMhO,5;YO:dQMhO,5;YO#(`Q`O,5@bO#(eQ07dO,5:sOOQO-EPO$6^Q`O,5>POOQ[1G3i1G3iO`QlO1G3iOOQ[1G3o1G3oOOQ[1G3q1G3qO?TQ`O1G3sO$6cQlO1G3uO$:gQlO'#HtOOQ[1G3x1G3xO$:tQ`O'#HzO?YQ`O'#H|OOQ[1G4O1G4OO$:|QlO1G4OO9uQ!0LrO1G4UOOQ[1G4W1G4WOOQ!0Lb'#G_'#G_O9uQ!0LrO1G4YO9uQ!0LrO1G4[O$?TQ`O,5@bO!)[QlO,5;`O9eQ`O,5;`O?YQ`O,5:XO!)[QlO,5:XO!CUQpO,5:XO$?YQ?MtO,5:XOOQO,5;`,5;`O$?dQpO'#IeO$?zQ`O,5@aOOQ!0Lf1G/r1G/rO$@SQpO'#IkO$@^Q`O,5@pOOQ!0Lb1G0y1G0yO#$`QpO,5:XOOQO'#Ig'#IgO$@fQpO,5:qOOQ!0Ln,5:q,5:qO#(ZQ`O1G0ZOOQ!0Lf1G0Z1G0ZO%[QlO1G0ZOOQ!0Lf1G0t1G0tO?YQ`O1G0tO!CUQpO1G0tO!C^QMhO1G0tOOQ!0Lb1G5|1G5|O!ByQ!0LrO1G0^OOQO1G0m1G0mO%[QlO1G0mO$@mQ!0LrO1G0mO$@xQ!0LrO1G0mO!CUQpO1G0^ODWQpO1G0^O$AWQ!0LrO1G0mOOQO1G0^1G0^O$AlQ!0MxO1G0mPOOO-E<[-E<[POOO1G.h1G.hOOOO1G/i1G/iO$AvQ!bO,5QQpO,5@}OOQ!0Lb1G3c1G3cOOQ[7+$V7+$VO@zQ`O7+$VO9uQ!0LrO7+$VO%>]Q`O7+$VO%[QlO1G6lO%[QlO1G6mO%>bQ!0LrO1G6lO%>lQlO1G3kO%>sQ`O1G3kO%>xQlO1G3kOOQ[7+)T7+)TO9uQ!0LrO7+)_O`QlO7+)aOOQ['#Kh'#KhOOQ['#JS'#JSO%?PQlO,5>`OOQ[,5>`,5>`O%[QlO'#HuO%?^Q`O'#HwOOQ[,5>f,5>fO9eQ`O,5>fOOQ[,5>h,5>hOOQ[7+)j7+)jOOQ[7+)p7+)pOOQ[7+)t7+)tOOQ[7+)v7+)vO%?cQpO1G5|O%?}Q?MtO1G0zO%@XQ`O1G0zOOQO1G/s1G/sO%@dQ?MtO1G/sO?YQ`O1G/sO!)[QlO'#DmOOQO,5?P,5?POOQO-ERQ`O7+,WO&>WQ`O7+,XO%[QlO7+,WO%[QlO7+,XOOQ[7+)V7+)VO&>]Q`O7+)VO&>bQlO7+)VO&>iQ`O7+)VOOQ[<nQ`O,5>aOOQ[,5>c,5>cO&>sQ`O1G4QO9eQ`O7+&fO!)[QlO7+&fOOQO7+%_7+%_O&>xQ?MtO1G6ZO?YQ`O7+%_OOQ!0Lf<yQ?MvO,5?aO'@|Q?MvO,5?cO'CPQ?MvO7+'|O'DuQMjOG27TOOQO<VO!l$xO#jROe!iOpkOrPO(T)]O(VTO(YUO(aVO(o[O~O!]$_Oa$qa'z$qa'w$qa!k$qa!Y$qa!_$qa%i$qa!g$qa~Ol)dO~P!&zOh%VOp%WOr%XOs$tOt$tOz%YO|%ZO!O%]O!S${O!_$|O!i%bO!l$xO#j%cO$W%`O$t%^O$v%_O$y%aO(T(vO(VTO(YUO(a$uO(y$}O(z%PO~Og(pP~P!,TO!Q)iO!g)hO!_$^X$Z$^X$]$^X$_$^X$f$^X~O!g)hO!_({X$Z({X$]({X$_({X$f({X~O!Q)iO~P!.^O!Q)iO!_({X$Z({X$]({X$_({X$f({X~O!_)kO$Z)oO$])jO$_)jO$f)pO~O![)sO~P!)[O$]$hO$_$gO$f)wO~On$zX!Q$zX#S$zX'y$zX(y$zX(z$zX~OgmXg$zXnmX!]mX#`mX~P!0SOx)yO(b)zO(c)|O~On*VO!Q*OO'y*PO(y$}O(z%PO~Og)}O~P!1WOg*WO~Oh%VOr%XOs$tOt$tOz%YO|%ZO!OVO!l$xO#jVO!l$xO#jROe!iOpkOrPO(VTO(YUO(aVO(o[O~O(T=QO~P#$qO!]-]O!^(iX~O!^-_O~O!g-VO#`-UO!]#hX!^#hX~O!]-`O!^(xX~O!^-bO~O!c-cO!d-cO(U!lO~P#$`O!^-fO~P'_On-iO!_'`O~O!Y-nO~Os!{a!b!{a!c!{a!d!{a#T!{a#U!{a#V!{a#W!{a#X!{a#[!{a#]!{a(U!{a(V!{a(Y!{a(e!{a(o!{a~P!#vO!p-sO#`-qO~PChO!c-uO!d-uO(U!lO~PDWOa%nO#`-qO'z%nO~Oa%nO!g#vO#`-qO'z%nO~Oa%nO!g#vO!p-sO#`-qO'z%nO(r'pO~O(P'xO(Q'xO(R-zO~Ov-{O~O!Y'Wa!]'Wa~P!:tO![.PO!Y'WX!]'WX~P%[O!](VO!Y(ha~O!Y(ha~PHRO!](^O!Y(va~O!S%hO![.TO!_%iO(T%gO!Y'^X!]'^X~O#`.VO!](ta!k(taa(ta'z(ta~O!g#vO~P#,wO!](jO!k(sa~O!S%hO!_%iO#j.ZO(T%gO~Op.`O!S%hO![.]O!_%iO!|]O#i._O#j.]O(T%gO!]'aX!k'aX~OR.dO!l#xO~Oh%VOn.gO!_'`O%i.fO~Oa#ci!]#ci'z#ci'w#ci!Y#ci!k#civ#ci!_#ci%i#ci!g#ci~P!:tOn>]O!Q*OO'y*PO(y$}O(z%PO~O#k#_aa#_a#`#_a'z#_a!]#_a!k#_a!_#_a!Y#_a~P#/sO#k(`XP(`XR(`X[(`Xa(`Xj(`Xr(`X!S(`X!l(`X!p(`X#R(`X#n(`X#o(`X#p(`X#q(`X#r(`X#s(`X#t(`X#u(`X#v(`X#x(`X#z(`X#{(`X'z(`X(a(`X(r(`X!k(`X!Y(`X'w(`Xv(`X!_(`X%i(`X!g(`X~P!6kO!].tO!k(kX~P!:tO!k.wO~O!Y.yO~OP$[OR#zO!Q#yO!S#{O!l#xO!p$[O(aVO[#mia#mij#mir#mi!]#mi#R#mi#o#mi#p#mi#q#mi#r#mi#s#mi#t#mi#u#mi#v#mi#x#mi#z#mi#{#mi'z#mi(r#mi(y#mi(z#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#n#mi~P#3cO#n$OO~P#3cOP$[OR#zOr$aO!Q#yO!S#{O!l#xO!p$[O#n$OO#o$PO#p$PO#q$PO(aVO[#mia#mij#mi!]#mi#R#mi#s#mi#t#mi#u#mi#v#mi#x#mi#z#mi#{#mi'z#mi(r#mi(y#mi(z#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#r#mi~P#6QO#r$QO~P#6QOP$[OR#zO[$cOj$ROr$aO!Q#yO!S#{O!l#xO!p$[O#R$RO#n$OO#o$PO#p$PO#q$PO#r$QO#s$RO#t$RO#u$bO(aVOa#mi!]#mi#x#mi#z#mi#{#mi'z#mi(r#mi(y#mi(z#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#v#mi~P#8oOP$[OR#zO[$cOj$ROr$aO!Q#yO!S#{O!l#xO!p$[O#R$RO#n$OO#o$PO#p$PO#q$PO#r$QO#s$RO#t$RO#u$bO#v$SO(aVO(z#}Oa#mi!]#mi#z#mi#{#mi'z#mi(r#mi(y#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#x$UO~P#;VO#x#mi~P#;VO#v$SO~P#8oOP$[OR#zO[$cOj$ROr$aO!Q#yO!S#{O!l#xO!p$[O#R$RO#n$OO#o$PO#p$PO#q$PO#r$QO#s$RO#t$RO#u$bO#v$SO#x$UO(aVO(y#|O(z#}Oa#mi!]#mi#{#mi'z#mi(r#mi'w#mi!Y#mi!k#miv#mi!_#mi%i#mi!g#mi~O#z#mi~P#={O#z$WO~P#={OP]XR]X[]Xj]Xr]X!Q]X!S]X!l]X!p]X#R]X#S]X#`]X#kfX#n]X#o]X#p]X#q]X#r]X#s]X#t]X#u]X#v]X#x]X#z]X#{]X$Q]X(a]X(r]X(y]X(z]X!]]X!^]X~O$O]X~P#@jOP$[OR#zO[]O!Q*OO'y*PO(y$}O(z%POP#miR#mi!S#mi!l#mi!p#mi#n#mi#o#mi#p#mi#q#mi(a#mi~P#EyO!]/POg(pX~P!1WOg/RO~Oa$Pi!]$Pi'z$Pi'w$Pi!Y$Pi!k$Piv$Pi!_$Pi%i$Pi!g$Pi~P!:tO$]/SO$_/SO~O$]/TO$_/TO~O!g)hO#`/UO!_$cX$Z$cX$]$cX$_$cX$f$cX~O![/VO~O!_)kO$Z/XO$])jO$_)jO$f/YO~O!]VO!l$xO#j^O!Q*OO'y*PO(y$}O(z%POP#miR#mi!S#mi!l#mi!p#mi#n#mi#o#mi#p#mi#q#mi(a#mi~P&,QO#S$dOP(`XR(`X[(`Xj(`Xn(`Xr(`X!Q(`X!S(`X!l(`X!p(`X#R(`X#n(`X#o(`X#p(`X#q(`X#r(`X#s(`X#t(`X#u(`X#v(`X#x(`X#z(`X#{(`X$O(`X'y(`X(a(`X(r(`X(y(`X(z(`X!](`X!^(`X~O$O$Pi!]$Pi!^$Pi~P#BwO$O!ri!^!ri~P$+oOg']a!]']a~P!1WO!^7nO~O!]'da!^'da~P#BwO!Y7oO~P#/sO!g#vO(r'pO!]'ea!k'ea~O!]/pO!k)Oi~O!]/pO!g#vO!k)Oi~Og$|q!]$|q#`$|q$O$|q~P!1WO!Y'ga!]'ga~P#/sO!g7vO~O!]/yO!Y)Pi~P#/sO!]/yO!Y)Pi~O!Y7yO~Oh%VOr8OO!l%eO(r'pO~Oj8QO!g#vO~Or8TO!g#vO(r'pO~O!Q*OO'y*PO(z%POn'ja(y'ja!]'ja#`'ja~Og'ja$O'ja~P&5RO!Q*OO'y*POn'la(y'la(z'la!]'la#`'la~Og'la$O'la~P&5tOg(_q!](_q~P!1WO#`8VOg(_q!](_q~P!1WO!Y8WO~Og%Oq!]%Oq#`%Oq$O%Oq~P!1WOa$oy!]$oy'z$oy'w$oy!Y$oy!k$oyv$oy!_$oy%i$oy!g$oy~P!:tO!g6rO~O!]5[O!_)Qa~O!_'`OP$TaR$Ta[$Taj$Tar$Ta!Q$Ta!S$Ta!]$Ta!l$Ta!p$Ta#R$Ta#n$Ta#o$Ta#p$Ta#q$Ta#r$Ta#s$Ta#t$Ta#u$Ta#v$Ta#x$Ta#z$Ta#{$Ta(a$Ta(r$Ta(y$Ta(z$Ta~O%i7WO~P&8fO%^8[Oa%[i!_%[i'z%[i!]%[i~Oa#cy!]#cy'z#cy'w#cy!Y#cy!k#cyv#cy!_#cy%i#cy!g#cy~P!:tO[8^O~Ob8`O(T+qO(VTO(YUO~O!]1TO!^)Xi~O`8dO~O(e(|O!]'pX!^'pX~O!]5uO!^)Ua~O!^8nO~P%;eO(o!sO~P$&YO#[8oO~O!_1oO~O!_1oO%i8qO~On8tO!_1oO%i8qO~O[8yO!]'sa!^'sa~O!]1zO!^)Vi~O!k8}O~O!k9OO~O!k9RO~O!k9RO~P%[Oa9TO~O!g9UO~O!k9VO~O!](wi!^(wi~P#BwOa%nO#`9_O'z%nO~O!](ty!k(tya(ty'z(ty~P!:tO!](jO!k(sy~O%i9bO~P&8fO!_'`O%i9bO~O#k$|qP$|qR$|q[$|qa$|qj$|qr$|q!S$|q!]$|q!l$|q!p$|q#R$|q#n$|q#o$|q#p$|q#q$|q#r$|q#s$|q#t$|q#u$|q#v$|q#x$|q#z$|q#{$|q'z$|q(a$|q(r$|q!k$|q!Y$|q'w$|q#`$|qv$|q!_$|q%i$|q!g$|q~P#/sO#k'jaP'jaR'ja['jaa'jaj'jar'ja!S'ja!l'ja!p'ja#R'ja#n'ja#o'ja#p'ja#q'ja#r'ja#s'ja#t'ja#u'ja#v'ja#x'ja#z'ja#{'ja'z'ja(a'ja(r'ja!k'ja!Y'ja'w'jav'ja!_'ja%i'ja!g'ja~P&5RO#k'laP'laR'la['laa'laj'lar'la!S'la!l'la!p'la#R'la#n'la#o'la#p'la#q'la#r'la#s'la#t'la#u'la#v'la#x'la#z'la#{'la'z'la(a'la(r'la!k'la!Y'la'w'lav'la!_'la%i'la!g'la~P&5tO#k%OqP%OqR%Oq[%Oqa%Oqj%Oqr%Oq!S%Oq!]%Oq!l%Oq!p%Oq#R%Oq#n%Oq#o%Oq#p%Oq#q%Oq#r%Oq#s%Oq#t%Oq#u%Oq#v%Oq#x%Oq#z%Oq#{%Oq'z%Oq(a%Oq(r%Oq!k%Oq!Y%Oq'w%Oq#`%Oqv%Oq!_%Oq%i%Oq!g%Oq~P#/sO!]'Yi!k'Yi~P!:tO$O#cq!]#cq!^#cq~P#BwO(y$}OP%aaR%aa[%aaj%aar%aa!S%aa!l%aa!p%aa#R%aa#n%aa#o%aa#p%aa#q%aa#r%aa#s%aa#t%aa#u%aa#v%aa#x%aa#z%aa#{%aa$O%aa(a%aa(r%aa!]%aa!^%aa~On%aa!Q%aa'y%aa(z%aa~P&IyO(z%POP%caR%ca[%caj%car%ca!S%ca!l%ca!p%ca#R%ca#n%ca#o%ca#p%ca#q%ca#r%ca#s%ca#t%ca#u%ca#v%ca#x%ca#z%ca#{%ca$O%ca(a%ca(r%ca!]%ca!^%ca~On%ca!Q%ca'y%ca(y%ca~P&LQOn>^O!Q*OO'y*PO(z%PO~P&IyOn>^O!Q*OO'y*PO(y$}O~P&LQOR0kO!Q0kO!S0lO#S$dOP}a[}aj}an}ar}a!l}a!p}a#R}a#n}a#o}a#p}a#q}a#r}a#s}a#t}a#u}a#v}a#x}a#z}a#{}a$O}a'y}a(a}a(r}a(y}a(z}a!]}a!^}a~O!Q*OO'y*POP$saR$sa[$saj$san$sar$sa!S$sa!l$sa!p$sa#R$sa#n$sa#o$sa#p$sa#q$sa#r$sa#s$sa#t$sa#u$sa#v$sa#x$sa#z$sa#{$sa$O$sa(a$sa(r$sa(y$sa(z$sa!]$sa!^$sa~O!Q*OO'y*POP$uaR$ua[$uaj$uan$uar$ua!S$ua!l$ua!p$ua#R$ua#n$ua#o$ua#p$ua#q$ua#r$ua#s$ua#t$ua#u$ua#v$ua#x$ua#z$ua#{$ua$O$ua(a$ua(r$ua(y$ua(z$ua!]$ua!^$ua~On>^O!Q*OO'y*PO(y$}O(z%PO~OP%TaR%Ta[%Taj%Tar%Ta!S%Ta!l%Ta!p%Ta#R%Ta#n%Ta#o%Ta#p%Ta#q%Ta#r%Ta#s%Ta#t%Ta#u%Ta#v%Ta#x%Ta#z%Ta#{%Ta$O%Ta(a%Ta(r%Ta!]%Ta!^%Ta~P''VO$O$mq!]$mq!^$mq~P#BwO$O$oq!]$oq!^$oq~P#BwO!^9oO~O$O9pO~P!1WO!g#vO!]'ei!k'ei~O!g#vO(r'pO!]'ei!k'ei~O!]/pO!k)Oq~O!Y'gi!]'gi~P#/sO!]/yO!Y)Pq~Or9wO!g#vO(r'pO~O[9yO!Y9xO~P#/sO!Y9xO~Oj:PO!g#vO~Og(_y!](_y~P!1WO!]'na!_'na~P#/sOa%[q!_%[q'z%[q!]%[q~P#/sO[:UO~O!]1TO!^)Xq~O`:YO~O#`:ZO!]'pa!^'pa~O!]5uO!^)Ui~P#BwO!S:]O~O!_1oO%i:`O~O(VTO(YUO(e:eO~O!]1zO!^)Vq~O!k:hO~O!k:iO~O!k:jO~O!k:jO~P%[O#`:mO!]#hy!^#hy~O!]#hy!^#hy~P#BwO%i:rO~P&8fO!_'`O%i:rO~O$O#|y!]#|y!^#|y~P#BwOP$|iR$|i[$|ij$|ir$|i!S$|i!l$|i!p$|i#R$|i#n$|i#o$|i#p$|i#q$|i#r$|i#s$|i#t$|i#u$|i#v$|i#x$|i#z$|i#{$|i$O$|i(a$|i(r$|i!]$|i!^$|i~P''VO!Q*OO'y*PO(z%POP'iaR'ia['iaj'ian'iar'ia!S'ia!l'ia!p'ia#R'ia#n'ia#o'ia#p'ia#q'ia#r'ia#s'ia#t'ia#u'ia#v'ia#x'ia#z'ia#{'ia$O'ia(a'ia(r'ia(y'ia!]'ia!^'ia~O!Q*OO'y*POP'kaR'ka['kaj'kan'kar'ka!S'ka!l'ka!p'ka#R'ka#n'ka#o'ka#p'ka#q'ka#r'ka#s'ka#t'ka#u'ka#v'ka#x'ka#z'ka#{'ka$O'ka(a'ka(r'ka(y'ka(z'ka!]'ka!^'ka~O(y$}OP%aiR%ai[%aij%ain%air%ai!Q%ai!S%ai!l%ai!p%ai#R%ai#n%ai#o%ai#p%ai#q%ai#r%ai#s%ai#t%ai#u%ai#v%ai#x%ai#z%ai#{%ai$O%ai'y%ai(a%ai(r%ai(z%ai!]%ai!^%ai~O(z%POP%ciR%ci[%cij%cin%cir%ci!Q%ci!S%ci!l%ci!p%ci#R%ci#n%ci#o%ci#p%ci#q%ci#r%ci#s%ci#t%ci#u%ci#v%ci#x%ci#z%ci#{%ci$O%ci'y%ci(a%ci(r%ci(y%ci!]%ci!^%ci~O$O$oy!]$oy!^$oy~P#BwO$O#cy!]#cy!^#cy~P#BwO!g#vO!]'eq!k'eq~O!]/pO!k)Oy~O!Y'gq!]'gq~P#/sOr:|O!g#vO(r'pO~O[;QO!Y;PO~P#/sO!Y;PO~Og(_!R!](_!R~P!1WOa%[y!_%[y'z%[y!]%[y~P#/sO!]1TO!^)Xy~O!]5uO!^)Uq~O(T;XO~O!_1oO%i;[O~O!k;_O~O%i;dO~P&8fOP$|qR$|q[$|qj$|qr$|q!S$|q!l$|q!p$|q#R$|q#n$|q#o$|q#p$|q#q$|q#r$|q#s$|q#t$|q#u$|q#v$|q#x$|q#z$|q#{$|q$O$|q(a$|q(r$|q!]$|q!^$|q~P''VO!Q*OO'y*PO(z%POP'jaR'ja['jaj'jan'jar'ja!S'ja!l'ja!p'ja#R'ja#n'ja#o'ja#p'ja#q'ja#r'ja#s'ja#t'ja#u'ja#v'ja#x'ja#z'ja#{'ja$O'ja(a'ja(r'ja(y'ja!]'ja!^'ja~O!Q*OO'y*POP'laR'la['laj'lan'lar'la!S'la!l'la!p'la#R'la#n'la#o'la#p'la#q'la#r'la#s'la#t'la#u'la#v'la#x'la#z'la#{'la$O'la(a'la(r'la(y'la(z'la!]'la!^'la~OP%OqR%Oq[%Oqj%Oqr%Oq!S%Oq!l%Oq!p%Oq#R%Oq#n%Oq#o%Oq#p%Oq#q%Oq#r%Oq#s%Oq#t%Oq#u%Oq#v%Oq#x%Oq#z%Oq#{%Oq$O%Oq(a%Oq(r%Oq!]%Oq!^%Oq~P''VOg%e!Z!]%e!Z#`%e!Z$O%e!Z~P!1WO!Y;hO~P#/sOr;iO!g#vO(r'pO~O[;kO!Y;hO~P#/sO!]'pq!^'pq~P#BwO!]#h!Z!^#h!Z~P#BwO#k%e!ZP%e!ZR%e!Z[%e!Za%e!Zj%e!Zr%e!Z!S%e!Z!]%e!Z!l%e!Z!p%e!Z#R%e!Z#n%e!Z#o%e!Z#p%e!Z#q%e!Z#r%e!Z#s%e!Z#t%e!Z#u%e!Z#v%e!Z#x%e!Z#z%e!Z#{%e!Z'z%e!Z(a%e!Z(r%e!Z!k%e!Z!Y%e!Z'w%e!Z#`%e!Zv%e!Z!_%e!Z%i%e!Z!g%e!Z~P#/sOr;tO!g#vO(r'pO~O!Y;uO~P#/sOr;|O!g#vO(r'pO~O!Y;}O~P#/sOP%e!ZR%e!Z[%e!Zj%e!Zr%e!Z!S%e!Z!l%e!Z!p%e!Z#R%e!Z#n%e!Z#o%e!Z#p%e!Z#q%e!Z#r%e!Z#s%e!Z#t%e!Z#u%e!Z#v%e!Z#x%e!Z#z%e!Z#{%e!Z$O%e!Z(a%e!Z(r%e!Z!]%e!Z!^%e!Z~P''VOrROe!iOpkOrPO(T)]O(VTO(YUO(aVO(o[O~O!]WO!l$xO#jgPPP!>oI[PPPPPPPPP!BOP!C]PPI[!DnPI[PI[I[I[I[I[PI[!FQP!I[P!LbP!Lf!Lp!Lt!LtP!IXP!Lx!LxP#!OP#!SI[PI[#!Y#%_CjA^PA^PA^A^P#&lA^A^#)OA^#+vA^#.SA^A^#.r#1W#1W#1]#1f#1W#1qPP#1WPA^#2ZA^#6YA^A^6mPPP#:_PPP#:x#:xP#:xP#;`#:xPP#;fP#;]P#;]#;y#;]#P#>V#>]#>k#>q#>{#?R#?]#?c#?s#?y#@k#@}#AT#AZ#Ai#BO#Cs#DR#DY#Et#FS#Gt#HS#HY#H`#Hf#Hp#Hv#H|#IW#Ij#IpPPPPPPPPPPP#IvPPPPPPP#Jk#Mx$ b$ i$ qPPP$']P$'f$*_$0x$0{$1O$1}$2Q$2X$2aP$2g$2jP$3W$3[$4S$5b$5g$5}PP$6S$6Y$6^$6a$6e$6i$7e$7|$8e$8i$8l$8o$8y$8|$9Q$9UR!|RoqOXst!Z#d%m&r&t&u&w,s,x2[2_Y!vQ'`-e1o5{Q%tvQ%|yQ&T|Q&j!VS'W!e-]Q'f!iS'l!r!yU*k$|*Z*oQ+o%}S+|&V&WQ,d&dQ-c'_Q-m'gQ-u'mQ0[*qQ1b,OQ1y,eR<{SU+P%]S!S!nQ!r!v!y!z$|'W'_'`'l'm'n*k*o*q*r-]-c-e-u0[0_1o5{5}%[$ti#v$b$c$d$x${%O%Q%^%_%c)y*R*T*V*Y*a*g*w*x+f+i,S,V.f/P/d/m/x/y/{0`0b0i0j0o1f1i1q3c4^4_4j4o5Q5[5_6S7W7v8Q8V8[8q9b9p9y:P:`:r;Q;[;d;kP>X>Y>]>^Q&X|Q'U!eS'[%i-`Q+t&PQ,P&WQ,f&gQ0n+SQ1Y+uQ1_+{Q2Q,jQ2R,kQ5f1TQ5o1aQ6[1zQ6_1|Q6`2PQ8`5gQ8c5lQ8|6bQ:X8dQ:f8yQ;V:YR<}*ZrnOXst!V!Z#d%m&i&r&t&u&w,s,x2[2_R,h&k&z^OPXYstuvwz!Z!`!g!j!o#S#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%m%t&R&k&n&o&r&t&u&w&{'T'b'r(V(](d(x(z)O)s)}*i+X+]+g,p,s,x-U-X-i-q.P.V.g.t.{/V/n0]0l0r1S1r2S2T2V2X2[2_2a2p3Q3W3d3l4T4z5w6T6e6f6i6s6|7[8t9T9_:Z:mR>S[#]WZ#W#Z'X(T!b%jm#h#i#l$x%e%h(^(h(i(j*Y*^*b+Z+[+^,o-V.T.Z.[.]._/m/p2d3[3]4a6r7TQ%wxQ%{yW&Q|&V&W,OQ&_!TQ'c!hQ'e!iQ(q#sS+n%|%}Q+r&PQ,_&bQ,c&dS-l'f'gQ.i(rQ1R+oQ1X+uQ1Z+vQ1^+zQ1t,`S1x,d,eQ2|-mQ5e1TQ5i1WQ5n1`Q6Z1yQ8_5gQ8b5kQ8f5pQ:T8^R;T:U!U$zi$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Y!^%yy!i!u%{%|%}'V'e'f'g'k'u*j+n+o-Y-l-m-t0R0U1R2u2|3T4r4s4v7}9{Q+h%wQ,T&[Q,W&]Q,b&dQ.h(qQ1s,_U1w,c,d,eQ3e.iQ6U1tS6Y1x1yQ8x6Z#f>T#v$b$c$x${)y*V*Y*g+f+i,S,V.f/d/m/y/{1f1i1q3c4^4j4o5[5_6S7W7v8Q8[8q9b9y:P:`:r;Q;[;d;k]>^o>UPS&[!Q&iQ&]!RQ&^!SU*}%[%d=sR,R&Y%]%Si#v$b$c$d$x${%O%Q%^%_%c)y*R*T*V*Y*a*g*w*x+f+i,S,V.f/P/d/m/x/y/{0`0b0i0j0o1f1i1q3c4^4_4j4o5Q5[5_6S7W7v8Q8V8[8q9b9p9y:P:`:r;Q;[;d;kP>X>Y>]>^T)z$u){V+P%]S$i$^c#Y#e%q%s%u(S(Y(t(y)R)S)T)U)V)W)X)Y)Z)[)^)`)b)g)q+d+x-Z-x-}.S.U.s.v.z.|.}/O/b0p2k2n3O3V3k3p3q3r3s3t3u3v3w3x3y3z3{3|4P4Q4X5X5c6u6{7Q7a7b7k7l8k9X9]9g9m9n:o;W;`SQ'Y!eR2q-]!W!nQ!e!r!v!y!z$|'W'_'`'l'm'n*Z*k*o*q*r-]-c-e-u0[0_1o5{5}R1l,ZnqOXst!Z#d%m&r&t&u&w,s,x2[2_Q&y!^Q'v!xS(s#u<^Q+l%zQ,]&_Q,^&aQ-j'dQ-w'oS.r(x=PS0q+X=ZQ1P+mQ1n,[Q2c,zQ2e,{Q2m-WQ2z-kQ2}-oS5Y0r=eQ5a1QS5d1S=fQ6t2oQ6x2{Q6}3SQ8]5bQ9Y6vQ9Z6yQ9^7OR:l9V$d$]c#Y#e%s%u(S(Y(t(y)R)S)T)U)V)W)X)Y)Z)[)^)`)b)g)q+d+x-Z-x-}.S.U.s.v.z.}/O/b0p2k2n3O3V3k3p3q3r3s3t3u3v3w3x3y3z3{3|4P4Q4X5X5c6u6{7Q7a7b7k7l8k9X9]9g9m9n:o;W;`SS#q]SU$fd)_,mS(p#p'iU*v%R(w4OU0m+O.n7gQ5^0xQ7V3`Q9d7YR:s9em!tQ!r!v!y!z'`'l'm'n-e-u1o5{5}Q't!uS(f#g2US-s'k'wQ/s*]Q0R*jQ3U-vQ4f/tQ4r0TQ4s0UQ4x0^Q7r4`S7}4t4vS8R4y4{Q9r7sQ9v7yQ9{8OQ:Q8TS:{9w9xS;g:|;PS;s;h;iS;{;t;uSSR=o>R%^bOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%m%t&R&k&n&o&r&t&u&w&{'T'b'r(T(V(](d(x(z)O)}*i+X+]+g,p,s,x-i-q.P.V.g.t.{/n0]0l0r1S1r2S2T2V2X2[2_2a3Q3W3d3l4z6T6e6f6i6|7[8t9T9_Q%fj!^%xy!i!u%{%|%}'V'e'f'g'k'u*j+n+o-Y-l-m-t0R0U1R2u2|3T4r4s4v7}9{S&Oz!jQ+k%yQ,a&dW1v,b,c,d,eU6X1w1x1yS8w6Y6ZQ:d8x!r=j$Z$n'X)s-U-X/V2p4T5w6s:Z:mSQ=t>QR=u>R%QeOPXYstuvw!Z!`!g!o#S#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%m%t&R&k&n&r&t&u&w&{'T'b'r(V(](d(x(z)O)}*i+X+]+g,p,s,x-i-q.P.V.g.t.{/n0]0l0r1S1r2S2T2V2X2[2_2a3Q3W3d3l4z6T6e6f6i6|7[8t9T9_Y#bWZ#W#Z(T!b%jm#h#i#l$x%e%h(^(h(i(j*Y*^*b+Z+[+^,o-V.T.Z.[.]._/m/p2d3[3]4a6r7TQ,n&o!p=k$Z$n)s-U-X/V2p4T5w6s:Z:mSR=n'XU']!e%i*ZR2s-`%SdOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%m%t&R&k&n&r&t&u&w&{'T'b'r(T(V(](d(x(z)O)}*i+X+],p,s,x-i-q.P.V.t.{/n0]0l0r1S1r2S2T2V2X2[2_2a3Q3W3l4z6T6e6f6i6|8t9T9_!r)_$Z$n'X)s-U-X/V2p4T5w6s:Z:mSQ,m&oQ0x+gQ3`.gQ7Y3dR9e7[!b$Tc#Y%q(S(Y(t(y)Z)[)`)g+x-x-}.S.U.s.v/b0p3O3V3k3{5X5c6{7Q7a9]:oS)^)q-Z.|2k2n3p4P4X6u7b7k7l8k9X9g9m9n;W;`=vQ>X>ZR>Y>['QkOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n%m%t&R&k&n&o&r&t&u&w&{'T'X'b'r(T(V(](d(x(z)O)s)}*i+X+]+g,p,s,x-U-X-i-q.P.V.g.t.{/V/n0]0l0r1S1r2S2T2V2X2[2_2a2p3Q3W3d3l4T4z5w6T6e6f6i6s6|7[8t9T9_:Z:mSS$oh$pR4U/U'XgOPWXYZhstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n$p%m%t&R&k&n&o&r&t&u&w&{'T'X'b'r(T(V(](d(x(z)O)s)}*i+X+]+g,p,s,x-U-X-i-q.P.V.g.t.{/U/V/n0]0l0r1S1r2S2T2V2X2[2_2a2p3Q3W3d3l4T4z5w6T6e6f6i6s6|7[8t9T9_:Z:mST$kf$qQ$ifS)j$l)nR)v$qT$jf$qT)l$l)n'XhOPWXYZhstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$Z$_$a$e$n$p%m%t&R&k&n&o&r&t&u&w&{'T'X'b'r(T(V(](d(x(z)O)s)}*i+X+]+g,p,s,x-U-X-i-q.P.V.g.t.{/U/V/n0]0l0r1S1r2S2T2V2X2[2_2a2p3Q3W3d3l4T4z5w6T6e6f6i6s6|7[8t9T9_:Z:mST$oh$pQ$rhR)u$p%^jOPWXYZstuvw!Z!`!g!o#S#W#Z#d#o#u#x#{$O$P$Q$R$S$T$U$V$W$X$_$a$e%m%t&R&k&n&o&r&t&u&w&{'T'b'r(T(V(](d(x(z)O)}*i+X+]+g,p,s,x-i-q.P.V.g.t.{/n0]0l0r1S1r2S2T2V2X2[2_2a3Q3W3d3l4z6T6e6f6i6|7[8t9T9_!s>Q$Z$n'X)s-U-X/V2p4T5w6s:Z:mS#glOPXZst!Z!`!o#S#d#o#{$n%m&k&n&o&r&t&u&w&{'T'b)O)s*i+]+g,p,s,x-i.g/V/n0]0l1r2S2T2V2X2[2_2a3d4T4z6T6e6f6i7[8t9T!U%Ri$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Y#f(w#v$b$c$x${)y*V*Y*g+f+i,S,V.f/d/m/y/{1f1i1q3c4^4j4o5[5_6S7W7v8Q8[8q9b9y:P:`:r;Q;[;d;k]>^Q+T%aQ/c*Oo4OP>X>YQ*c$zU*l$|*Z*oQ+U%bQ0W*m#f=q#v$b$c$x${)y*V*Y*g+f+i,S,V.f/d/m/y/{1f1i1q3c4^4j4o5[5_6S7W7v8Q8[8q9b9y:P:`:r;Q;[;d;k]>^n=rTQ=x>UQ=y>VR=z>W!U%Ri$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Y#f(w#v$b$c$x${)y*V*Y*g+f+i,S,V.f/d/m/y/{1f1i1q3c4^4j4o5[5_6S7W7v8Q8[8q9b9y:P:`:r;Q;[;d;k]>^o4OP>X>Y>]>^Q,U&]Q1h,WQ5s1gR8h5tV*n$|*Z*oU*n$|*Z*oT5z1o5{S0P*i/nQ4w0]T8S4z:]Q+j%xQ0V*lQ1O+kQ1u,aQ6W1vQ8v6XQ:c8wR;^:d!U%Oi$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Yx*R$v)e*S*u+V/v0d0e4R4g5R5S5W7p8U:R:x=p=}>OS0`*t0a#f]>^nZ>[`=T3}7c7f7j9h:t:w;yS=_.l3iT=`7e9k!U%Qi$d%O%Q%^%_%c*R*T*a*w*x/P/x0`0b0i0j0o4_5Q8V9p>P>X>Y|*T$v)e*U*t+V/g/v0d0e4R4g4|5R5S5W7p8U:R:x=p=}>OS0b*u0c#f]>^nZ>[d=V3}7d7e7j9h9i:t:u:w;yS=a.m3jT=b7f9lrnOXst!V!Z#d%m&i&r&t&u&w,s,x2[2_Q&f!UR,p&ornOXst!V!Z#d%m&i&r&t&u&w,s,x2[2_R&f!UQ,Y&^R1d,RsnOXst!V!Z#d%m&i&r&t&u&w,s,x2[2_Q1p,_S6R1s1tU8p6P6Q6US:_8r8sS;Y:^:aQ;m;ZR;w;nQ&m!VR,i&iR6_1|R:f8yW&Q|&V&W,OR1Z+vQ&r!WR,s&sR,y&xT2],x2_R,}&yQ,|&yR2f,}Q'y!{R-y'ySsOtQ#dXT%ps#dQ#OTR'{#OQ#RUR'}#RQ){$uR/`){Q#UVR(Q#UQ#XWU(W#X(X.QQ(X#YR.Q(YQ-^'YR2r-^Q.u(yS3m.u3nR3n.vQ-e'`R2v-eY!rQ'`-e1o5{R'j!rQ/Q)eR4S/QU#_W%h*YU(_#_(`.RQ(`#`R.R(ZQ-a']R2t-at`OXst!V!Z#d%m&i&k&r&t&u&w,s,x2[2_S#hZ%eU#r`#h.[R.[(jQ(k#jQ.X(gW.a(k.X3X7RQ3X.YR7R3YQ)n$lR/W)nQ$phR)t$pQ$`cU)a$`-|O>Z>[Q/z*eU4k/z4m7xQ4m/|R7x4lS*o$|*ZR0Y*ox*S$v)e*t*u+V/v0d0e4R4g5R5S5W7p8U:R:x=p=}>O!d.j(u)c*[*e.l.m.q/_/k/|0v1e3h4[4h4l5r7]7`7w7z8X8Z9t9|:S:};R;e;j;v>Z>[U/h*S.j7ca7c3}7e7f7j9h:t:w;yQ0a*tQ3i.lU4}0a3i9kR9k7e|*U$v)e*t*u+V/g/v0d0e4R4g4|5R5S5W7p8U:R:x=p=}>O!h.k(u)c*[*e.l.m.q/_/k/|0v1e3f3h4[4h4l5r7]7^7`7w7z8X8Z9t9|:S:};R;e;j;v>Z>[U/j*U.k7de7d3}7e7f7j9h9i:t:u:w;yQ0c*uQ3j.mU5P0c3j9lR9l7fQ*z%UR0g*zQ5]0vR8Y5]Q+_%kR0u+_Q5v1jS8j5v:[R:[8kQ,[&_R1m,[Q5{1oR8m5{Q1{,fS6]1{8zR8z6_Q1U+rW5h1U5j8a:VQ5j1XQ8a5iR:V8bQ+w&QR1[+wQ2_,xR6m2_YrOXst#dQ&v!ZQ+a%mQ,r&rQ,t&tQ,u&uQ,w&wQ2Y,sS2],x2_R6l2[Q%opQ&z!_Q&}!aQ'P!bQ'R!cQ'q!uQ+`%lQ+l%zQ,Q&XQ,h&mQ-P&|W-p'k's't'wQ-w'oQ0X*nQ1P+mQ1c,PS2O,i,lQ2g-OQ2h-RQ2i-SQ2}-oW3P-r-s-v-xQ5a1QQ5m1_Q5q1eQ6V1uQ6a2QQ6k2ZU6z3O3R3UQ6}3SQ8]5bQ8e5oQ8g5rQ8l5zQ8u6WQ8{6`S9[6{7PQ9^7OQ:W8cQ:b8vQ:g8|Q:n9]Q;U:XQ;]:cQ;a:oQ;l;VR;o;^Q%zyQ'd!iQ'o!uU+m%{%|%}Q-W'VU-k'e'f'gS-o'k'uQ0Q*jS1Q+n+oQ2o-YS2{-l-mQ3S-tS4p0R0UQ5b1RQ6v2uQ6y2|Q7O3TU7{4r4s4vQ9z7}R;O9{S$wi>PR*{%VU%Ui%V>PR0f*yQ$viS(u#v+iS)c$b$cQ)e$dQ*[$xS*e${*YQ*t%OQ*u%QQ+Q%^Q+R%_Q+V%cQ.lPQ=}>XQ>O>YQ>Z>]R>[>^Q+O%]Q.nSR#[WR'Z!el!tQ!r!v!y!z'`'l'm'n-e-u1o5{5}S'V!e-]U*j$|*Z*oS-Y'W'_S0U*k*qQ0^*rQ2u-cQ4v0[R4{0_R({#xQ!fQT-d'`-e]!qQ!r'`-e1o5{Q#p]R'i < TypeParamList in out const TypeDefinition extends ThisType this LiteralType ArithOp Number BooleanLiteral TemplateType InterpolationEnd Interpolation InterpolationStart NullType null VoidType void TypeofType typeof MemberExpression . PropertyName [ TemplateString Escape Interpolation super RegExp ] ArrayExpression Spread , } { ObjectExpression Property async get set PropertyDefinition Block : NewTarget new NewExpression ) ( ArgList UnaryExpression delete LogicOp BitOp YieldExpression yield AwaitExpression await ParenthesizedExpression ClassExpression class ClassBody MethodDeclaration Decorator @ MemberExpression PrivatePropertyName CallExpression TypeArgList CompareOp < declare Privacy static abstract override PrivatePropertyDefinition PropertyDeclaration readonly accessor Optional TypeAnnotation Equals StaticBlock FunctionExpression ArrowFunction ParamList ParamList ArrayPattern ObjectPattern PatternProperty Privacy readonly Arrow MemberExpression BinaryExpression ArithOp ArithOp ArithOp ArithOp BitOp CompareOp instanceof satisfies CompareOp BitOp BitOp BitOp LogicOp LogicOp ConditionalExpression LogicOp LogicOp AssignmentExpression UpdateOp PostfixExpression CallExpression InstantiationExpression TaggedTemplateExpression DynamicImport import ImportMeta JSXElement JSXSelfCloseEndTag JSXSelfClosingTag JSXIdentifier JSXBuiltin JSXIdentifier JSXNamespacedName JSXMemberExpression JSXSpreadAttribute JSXAttribute JSXAttributeValue JSXEscape JSXEndTag JSXOpenTag JSXFragmentTag JSXText JSXEscape JSXStartCloseTag JSXCloseTag PrefixCast < ArrowFunction TypeParamList SequenceExpression InstantiationExpression KeyofType keyof UniqueType unique ImportType InferredType infer TypeName ParenthesizedType FunctionSignature ParamList NewSignature IndexedType TupleType Label ArrayType ReadonlyType ObjectType MethodType PropertyType IndexSignature PropertyDefinition CallSignature TypePredicate asserts is NewSignature new UnionType LogicOp IntersectionType LogicOp ConditionalType ParameterizedType ClassDeclaration abstract implements type VariableDeclaration let var using TypeAliasDeclaration InterfaceDeclaration interface EnumDeclaration enum EnumBody NamespaceDeclaration namespace module AmbientDeclaration declare GlobalDeclaration global ClassDeclaration ClassBody AmbientFunctionDeclaration ExportGroup VariableName VariableName ImportDeclaration defer ImportGroup ForStatement for ForSpec ForInSpec ForOfSpec of WhileStatement while WithStatement with DoStatement do IfStatement if else SwitchStatement switch SwitchBody CaseLabel case DefaultLabel TryStatement try CatchClause catch FinallyClause finally ReturnStatement return ThrowStatement throw BreakStatement break ContinueStatement continue DebuggerStatement debugger LabeledStatement ExpressionStatement SingleExpression SingleClassItem`,maxTerm:380,context:k,nodeProps:[[`isolate`,-8,5,6,14,37,39,51,53,55,``],[`group`,-26,9,17,19,68,207,211,215,216,218,221,224,234,237,243,245,247,249,252,258,264,266,268,270,272,274,275,`Statement`,-34,13,14,32,35,36,42,51,54,55,57,62,70,72,76,80,82,84,85,110,111,120,121,136,139,141,142,143,144,145,147,148,167,169,171,`Expression`,-23,31,33,37,41,43,45,173,175,177,178,180,181,182,184,185,186,188,189,190,201,203,205,206,`Type`,-3,88,103,109,`ClassItem`],[`openedBy`,23,`<`,38,`InterpolationStart`,56,`[`,60,`{`,73,`(`,160,`JSXStartCloseTag`],[`closedBy`,-2,24,168,`>`,40,`InterpolationEnd`,50,`]`,61,`}`,74,`)`,165,`JSXEndTag`]],propSources:[xe],skippedNodes:[0,5,6,278],repeatNodeCount:37,tokenData:"$Fq07[R!bOX%ZXY+gYZ-yZ[+g[]%Z]^.c^p%Zpq+gqr/mrs3cst:_tuEruvJSvwLkwx! Yxy!'iyz!(sz{!)}{|!,q|}!.O}!O!,q!O!P!/Y!P!Q!9j!Q!R#:O!R![#<_![!]#I_!]!^#Jk!^!_#Ku!_!`$![!`!a$$v!a!b$*T!b!c$,r!c!}Er!}#O$-|#O#P$/W#P#Q$4o#Q#R$5y#R#SEr#S#T$7W#T#o$8b#o#p$x#r#s$@U#s$f%Z$f$g+g$g#BYEr#BY#BZ$A`#BZ$ISEr$IS$I_$A`$I_$I|Er$I|$I}$Dk$I}$JO$Dk$JO$JTEr$JT$JU$A`$JU$KVEr$KV$KW$A`$KW&FUEr&FU&FV$A`&FV;'SEr;'S;=`I|<%l?HTEr?HT?HU$A`?HUOEr(n%d_$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z&j&hT$i&jO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c&j&zP;=`<%l&c'|'U]$i&j(Z!bOY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}!b(SU(Z!bOY'}Zw'}x#O'}#P;'S'};'S;=`(f<%lO'}!b(iP;=`<%l'}'|(oP;=`<%l&}'[(y]$i&j(WpOY(rYZ&cZr(rrs&cs!^(r!^!_)r!_#O(r#O#P&c#P#o(r#o#p)r#p;'S(r;'S;=`*a<%lO(rp)wU(WpOY)rZr)rs#O)r#P;'S)r;'S;=`*Z<%lO)rp*^P;=`<%l)r'[*dP;=`<%l(r#S*nX(Wp(Z!bOY*gZr*grs'}sw*gwx)rx#O*g#P;'S*g;'S;=`+Z<%lO*g#S+^P;=`<%l*g(n+dP;=`<%l%Z07[+rq$i&j(Wp(Z!b'|0/lOX%ZXY+gYZ&cZ[+g[p%Zpq+gqr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p$f%Z$f$g+g$g#BY%Z#BY#BZ+g#BZ$IS%Z$IS$I_+g$I_$JT%Z$JT$JU+g$JU$KV%Z$KV$KW+g$KW&FU%Z&FU&FV+g&FV;'S%Z;'S;=`+a<%l?HT%Z?HT?HU+g?HUO%Z07[.ST(X#S$i&j'}0/lO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c07[.n_$i&j(Wp(Z!b'}0/lOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z)3p/x`$i&j!p),Q(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`0z!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW1V`#v(Ch$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_!`2X!`#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z(KW2d_#v(Ch$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'At3l_(V':f$i&j(Z!bOY4kYZ5qZr4krs7nsw4kwx5qx!^4k!^!_8p!_#O4k#O#P5q#P#o4k#o#p8p#p;'S4k;'S;=`:X<%lO4k(^4r_$i&j(Z!bOY4kYZ5qZr4krs7nsw4kwx5qx!^4k!^!_8p!_#O4k#O#P5q#P#o4k#o#p8p#p;'S4k;'S;=`:X<%lO4k&z5vX$i&jOr5qrs6cs!^5q!^!_6y!_#o5q#o#p6y#p;'S5q;'S;=`7h<%lO5q&z6jT$d`$i&jO!^&c!_#o&c#p;'S&c;'S;=`&w<%lO&c`6|TOr6yrs7]s;'S6y;'S;=`7b<%lO6y`7bO$d``7eP;=`<%l6y&z7kP;=`<%l5q(^7w]$d`$i&j(Z!bOY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}!r8uZ(Z!bOY8pYZ6yZr8prs9hsw8pwx6yx#O8p#O#P6y#P;'S8p;'S;=`:R<%lO8p!r9oU$d`(Z!bOY'}Zw'}x#O'}#P;'S'};'S;=`(f<%lO'}!r:UP;=`<%l8p(^:[P;=`<%l4k%9[:hh$i&j(Wp(Z!bOY%ZYZ&cZq%Zqr`#P#o`x!^=^!^!_?q!_#O=^#O#P>`#P#o=^#o#p?q#p;'S=^;'S;=`@h<%lO=^&n>gXWS$i&jOY>`YZ&cZ!^>`!^!_?S!_#o>`#o#p?S#p;'S>`;'S;=`?k<%lO>`S?XSWSOY?SZ;'S?S;'S;=`?e<%lO?SS?hP;=`<%l?S&n?nP;=`<%l>`!f?xWWS(Z!bOY?qZw?qwx?Sx#O?q#O#P?S#P;'S?q;'S;=`@b<%lO?q!f@eP;=`<%l?q(Q@kP;=`<%l=^'`@w]WS$i&j(WpOY@nYZ&cZr@nrs>`s!^@n!^!_Ap!_#O@n#O#P>`#P#o@n#o#pAp#p;'S@n;'S;=`Bg<%lO@ntAwWWS(WpOYApZrAprs?Ss#OAp#O#P?S#P;'SAp;'S;=`Ba<%lOAptBdP;=`<%lAp'`BjP;=`<%l@n#WBvYWS(Wp(Z!bOYBmZrBmrs?qswBmwxApx#OBm#O#P?S#P;'SBm;'S;=`Cf<%lOBm#WCiP;=`<%lBm(rCoP;=`<%l^!Q^$i&j!X7`OY!=yYZ&cZ!P!=y!P!Q!>|!Q!^!=y!^!_!@c!_!}!=y!}#O!CW#O#P!Dy#P#o!=y#o#p!@c#p;'S!=y;'S;=`!Ek<%lO!=y|#X#Z&c#Z#[!>|#[#]&c#]#^!>|#^#a&c#a#b!>|#b#g&c#g#h!>|#h#i&c#i#j!>|#j#k!>|#k#m&c#m#n!>|#n#o&c#p;'S&c;'S;=`&w<%lO&c7`!@hX!X7`OY!@cZ!P!@c!P!Q!AT!Q!}!@c!}#O!Ar#O#P!Bq#P;'S!@c;'S;=`!CQ<%lO!@c7`!AYW!X7`#W#X!AT#Z#[!AT#]#^!AT#a#b!AT#g#h!AT#i#j!AT#j#k!AT#m#n!AT7`!AuVOY!ArZ#O!Ar#O#P!B[#P#Q!@c#Q;'S!Ar;'S;=`!Bk<%lO!Ar7`!B_SOY!ArZ;'S!Ar;'S;=`!Bk<%lO!Ar7`!BnP;=`<%l!Ar7`!BtSOY!@cZ;'S!@c;'S;=`!CQ<%lO!@c7`!CTP;=`<%l!@c^!Ezl$i&j(Z!b!X7`OY&}YZ&cZw&}wx&cx!^&}!^!_'}!_#O&}#O#P&c#P#W&}#W#X!Eq#X#Z&}#Z#[!Eq#[#]&}#]#^!Eq#^#a&}#a#b!Eq#b#g&}#g#h!Eq#h#i&}#i#j!Eq#j#k!Eq#k#m&}#m#n!Eq#n#o&}#o#p'}#p;'S&};'S;=`(l<%lO&}8r!GyZ(Z!b!X7`OY!GrZw!Grwx!@cx!P!Gr!P!Q!Hl!Q!}!Gr!}#O!JU#O#P!Bq#P;'S!Gr;'S;=`!J|<%lO!Gr8r!Hse(Z!b!X7`OY'}Zw'}x#O'}#P#W'}#W#X!Hl#X#Z'}#Z#[!Hl#[#]'}#]#^!Hl#^#a'}#a#b!Hl#b#g'}#g#h!Hl#h#i'}#i#j!Hl#j#k!Hl#k#m'}#m#n!Hl#n;'S'};'S;=`(f<%lO'}8r!JZX(Z!bOY!JUZw!JUwx!Arx#O!JU#O#P!B[#P#Q!Gr#Q;'S!JU;'S;=`!Jv<%lO!JU8r!JyP;=`<%l!JU8r!KPP;=`<%l!Gr>^!KZ^$i&j(Z!bOY!KSYZ&cZw!KSwx!CWx!^!KS!^!_!JU!_#O!KS#O#P!DR#P#Q!^!LYP;=`<%l!KS>^!L`P;=`<%l!_#c#d#Bq#d#l%Z#l#m#Es#m#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#>j_$i&j(Wp(Z!bs'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#?rd$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!R#AQ!R!S#AQ!S!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#AQ#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#A]f$i&j(Wp(Z!bs'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!R#AQ!R!S#AQ!S!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#AQ#S#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Bzc$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!Y#DV!Y!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#DV#S#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Dbe$i&j(Wp(Z!bs'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q!Y#DV!Y!^%Z!^!_*g!_#O%Z#O#P&c#P#R%Z#R#S#DV#S#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#E|g$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![#Ge![!^%Z!^!_*g!_!c%Z!c!i#Ge!i#O%Z#O#P&c#P#R%Z#R#S#Ge#S#T%Z#T#Z#Ge#Z#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z'Ad#Gpi$i&j(Wp(Z!bs'9tOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!Q%Z!Q![#Ge![!^%Z!^!_*g!_!c%Z!c!i#Ge!i#O%Z#O#P&c#P#R%Z#R#S#Ge#S#T%Z#T#Z#Ge#Z#b%Z#b#c#>_#c#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z*)x#Il_!g$b$i&j$O)Lv(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z)[#Jv_al$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z04f#LS^h#)`#R-v$?V_!^(CdvBr$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z?O$@a_!q7`$i&j(Wp(Z!bOY%ZYZ&cZr%Zrs&}sw%Zwx(rx!^%Z!^!_*g!_#O%Z#O#P&c#P#o%Z#o#p*g#p;'S%Z;'S;=`+a<%lO%Z07[$Aq|$i&j(Wp(Z!b'|0/l$]#t(T,2j(e$I[OX%ZXY+gYZ&cZ[+g[p%Zpq+gqr%Zrs&}st%ZtuEruw%Zwx(rx}%Z}!OGv!O!Q%Z!Q![Er![!^%Z!^!_*g!_!c%Z!c!}Er!}#O%Z#O#P&c#P#R%Z#R#SEr#S#T%Z#T#oEr#o#p*g#p$f%Z$f$g+g$g#BYEr#BY#BZ$A`#BZ$ISEr$IS$I_$A`$I_$JTEr$JT$JU$A`$JU$KVEr$KV$KW$A`$KW&FUEr&FU&FV$A`&FV;'SEr;'S;=`I|<%l?HTEr?HT?HU$A`?HUOEr07[$D|k$i&j(Wp(Z!b'}0/l$]#t(T,2j(e$I[OY%ZYZ&cZr%Zrs&}st%ZtuEruw%Zwx(rx}%Z}!OGv!O!Q%Z!Q![Er![!^%Z!^!_*g!_!c%Z!c!}Er!}#O%Z#O#P&c#P#R%Z#R#SEr#S#T%Z#T#oEr#o#p*g#p$g%Z$g;'SEr;'S;=`I|<%lOEr",tokenizers:[j,M,N,be,2,3,4,5,6,7,8,9,10,11,12,13,14,A,new p("$S~RRtu[#O#Pg#S#T#|~_P#o#pb~gOx~~jVO#i!P#i#j!U#j#l!P#l#m!q#m;'S!P;'S;=`#v<%lO!P~!UO!U~~!XS!Q![!e!c!i!e#T#Z!e#o#p#Z~!hR!Q![!q!c!i!q#T#Z!q~!tR!Q![!}!c!i!}#T#Z!}~#QR!Q![!P!c!i!P#T#Z!P~#^R!Q![#g!c!i#g#T#Z#g~#jS!Q![#g!c!i#g#T#Z#g#q#r!P~#yP;=`<%l!P~$RO(c~~",141,340),new p(`j~RQYZXz{^~^O(Q~~aP!P!Qd~iO(R~~`,25,323)],topRules:{Script:[0,7],SingleExpression:[1,276],SingleClassItem:[2,277]},dialects:{jsx:0,ts:15175},dynamicPrecedences:{80:1,82:1,94:1,169:1,199:1},specialized:[{term:327,get:e=>Se[e]||-1},{term:343,get:e=>Ce[e]||-1},{term:95,get:e=>we[e]||-1}],tokenPrec:15201}),Ee=e({autoCloseTags:()=>$,javascript:()=>Z,javascriptLanguage:()=>W,jsxLanguage:()=>q,localCompletionSource:()=>U,snippets:()=>F,tsxLanguage:()=>J,typescriptLanguage:()=>K,typescriptSnippets:()=>I}),F=[h("function ${name}(${params}) {\n ${}\n}",{label:`function`,detail:`definition`,type:`keyword`}),h("for (let ${index} = 0; ${index} < ${bound}; ${index}++) {\n ${}\n}",{label:`for`,detail:`loop`,type:`keyword`}),h("for (let ${name} of ${collection}) {\n ${}\n}",{label:`for`,detail:`of loop`,type:`keyword`}),h(`do { \${} } while (\${})`,{label:`do`,detail:`loop`,type:`keyword`}),h(`while (\${}) { \${} diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/dist-CuvUDais.js b/mcp/src/agents_remember/package_data/dashboard/assets/dist-B2R-c1vX.js similarity index 99% rename from mcp/src/agents_remember/package_data/dashboard/assets/dist-CuvUDais.js rename to mcp/src/agents_remember/package_data/dashboard/assets/dist-B2R-c1vX.js index 0eead652..261b62df 100644 --- a/mcp/src/agents_remember/package_data/dashboard/assets/dist-CuvUDais.js +++ b/mcp/src/agents_remember/package_data/dashboard/assets/dist-B2R-c1vX.js @@ -1 +1 @@ -import{C as e,E as t,O as n,S as r,T as i,k as a,w as o}from"./index-BLlkJI-k.js";var s=class e{constructor(e,t,n,r,i,a,o,s,c,l=0,u){this.p=e,this.stack=t,this.state=n,this.reducePos=r,this.pos=i,this.score=a,this.buffer=o,this.bufferBase=s,this.curContext=c,this.lookAhead=l,this.parent=u}toString(){return`[${this.stack.filter((e,t)=>t%3==0).concat(this.state)}]@${this.pos}${this.score?`!`+this.score:``}`}static start(t,n,r=0){let i=t.parser.context;return new e(t,[],n,r,r,0,[],0,i?new c(i,i.start):null,0,null)}get context(){return this.curContext?this.curContext.context:null}pushState(e,t){this.stack.push(this.state,t,this.bufferBase+this.buffer.length),this.state=e}reduce(e){let t=e>>19,n=e&65535,{parser:r}=this.p,i=this.reducePos=2e3&&!this.p.parser.nodeSet.types[n]?.isAnonymous&&(s==this.p.lastBigReductionStart?(this.p.bigReductionCount++,this.p.lastBigReductionSize=c):this.p.lastBigReductionSizeo;)this.stack.pop();this.reduceContext(n,s)}storeNode(e,t,n,r=4,i=!1){if(e==0&&(!this.stack.length||this.stack[this.stack.length-1]0&&this.buffer[e-4]==0&&this.buffer[e-1]>-1){if(t==n)return;if(this.buffer[e-2]>=t){this.buffer[e-2]=n;return}}}if(!i||this.pos==n)this.buffer.push(e,t,n,r);else{let i=this.buffer.length;if(i>0&&(this.buffer[i-4]!=0||this.buffer[i-1]<0)){let e=!1;for(let t=i;t>0&&this.buffer[t-2]>n;t-=4)if(this.buffer[t-1]>=0){e=!0;break}if(e)for(;i>0&&this.buffer[i-2]>n;)this.buffer[i]=this.buffer[i-4],this.buffer[i+1]=this.buffer[i-3],this.buffer[i+2]=this.buffer[i-2],this.buffer[i+3]=this.buffer[i-1],i-=4,r>4&&(r-=4)}this.buffer[i]=e,this.buffer[i+1]=t,this.buffer[i+2]=n,this.buffer[i+3]=r}}shift(e,t,n,r){if(e&131072)this.pushState(e&65535,this.pos);else if(e&262144)this.pos=r,this.shiftContext(t,n),t<=this.p.parser.maxNode&&this.buffer.push(t,n,r,4);else{let i=e,{parser:a}=this.p;this.pos=r;let o=a.stateFlag(i,1);!o&&(r>n||t<=a.maxNode)&&(this.reducePos=r),this.pushState(i,o?n:Math.min(n,this.reducePos)),this.shiftContext(t,n),t<=a.maxNode&&this.buffer.push(t,n,r,4)}}apply(e,t,n,r){e&65536?this.reduce(e):this.shift(e,t,n,r)}useNode(e,t){let n=this.p.reused.length-1;(n<0||this.p.reused[n]!=e)&&(this.p.reused.push(e),n++);let r=this.pos;this.reducePos=this.pos=r+e.length,this.pushState(t,r),this.buffer.push(n,r,this.reducePos,-1),this.curContext&&this.updateContext(this.curContext.tracker.reuse(this.curContext.context,e,this,this.p.stream.reset(this.pos-e.length)))}split(){let t=this,n=t.buffer.length;for(n&&t.buffer[n-4]==0&&(n-=4);n>0&&t.buffer[n-2]>t.reducePos;)n-=4;let r=t.buffer.slice(n),i=t.bufferBase+n;for(;t&&i==t.bufferBase;)t=t.parent;return new e(this.p,this.stack.slice(),this.state,this.reducePos,this.pos,this.score,r,i,this.curContext,this.lookAhead,t)}recoverByDelete(e,t){let n=e<=this.p.parser.maxNode;n&&this.storeNode(e,this.pos,t,4),this.storeNode(0,this.pos,t,n?8:4),this.pos=this.reducePos=t,this.score-=190}canShift(e){for(let t=new l(this);;){let n=this.p.parser.stateSlot(t.state,4)||this.p.parser.hasAction(t.state,e);if(n==0)return!1;if(!(n&65536))return!0;t.reduce(n)}}recoverByInsert(e){if(this.stack.length>=300)return[];let t=this.p.parser.nextStates(this.state);if(t.length>8||this.stack.length>=120){let n=[];for(let r=0,i;rt&1&&e==r)||n.push(t[e],r)}t=n}let n=[];for(let e=0;e>19,r=t&65535,i=this.stack.length-n*3;if(i<0||e.getGoto(this.stack[i],r,!1)<0){let e=this.findForcedReduction();if(e==null)return!1;t=e}this.storeNode(0,this.pos,this.pos,4,!0),this.score-=100}return this.reducePos=this.pos,this.reduce(t),!0}findForcedReduction(){let{parser:e}=this.p,t=[],n=(r,i)=>{if(!t.includes(r))return t.push(r),e.allActions(r,t=>{if(!(t&393216))if(t&65536){let n=(t>>19)-i;if(n>1){let r=t&65535,i=this.stack.length-n*3;if(i>=0&&e.getGoto(this.stack[i],r,!1)>=0)return n<<19|65536|r}}else{let e=n(t,i+1);if(e!=null)return e}})};return n(this.state,0)}forceAll(){for(;!this.p.parser.stateFlag(this.state,2);)if(!this.forceReduce()){this.storeNode(0,this.pos,this.pos,4,!0);break}return this}get deadEnd(){if(this.stack.length!=3)return!1;let{parser:e}=this.p;return e.data[e.stateSlot(this.state,1)]==65535&&!e.stateSlot(this.state,4)}restart(){this.storeNode(0,this.pos,this.pos,4,!0),this.state=this.stack[0],this.stack.length=0}sameState(e){if(this.state!=e.state||this.stack.length!=e.stack.length)return!1;for(let t=0;t0&&this.emitLookAhead()}},c=class{constructor(e,t){this.tracker=e,this.context=t,this.hash=e.strict?e.hash(t):0}},l=class{constructor(e){this.start=e,this.state=e.state,this.stack=e.stack,this.base=this.stack.length}reduce(e){let t=e&65535,n=e>>19;n==0?(this.stack==this.start.stack&&(this.stack=this.stack.slice()),this.stack.push(this.state,0,0),this.base+=3):this.base-=(n-1)*3;let r=this.start.p.parser.getGoto(this.stack[this.base-3],t,!0);this.state=r}},u=class e{constructor(e,t,n){this.stack=e,this.pos=t,this.index=n,this.buffer=e.buffer,this.index==0&&this.maybeNext()}static create(t,n=t.bufferBase+t.buffer.length){return new e(t,n,n-t.bufferBase)}maybeNext(){let e=this.stack.parent;e!=null&&(this.index=this.stack.bufferBase-e.bufferBase,this.stack=e,this.buffer=e.buffer)}get id(){return this.buffer[this.index-4]}get start(){return this.buffer[this.index-3]}get end(){return this.buffer[this.index-2]}get size(){return this.buffer[this.index-1]}next(){this.index-=4,this.pos-=4,this.index==0&&this.maybeNext()}fork(){return new e(this.stack,this.pos,this.index)}};function d(e,t=Uint16Array){if(typeof e!=`string`)return e;let n=null;for(let r=0,i=0;r=92&&t--,t>=34&&t--;let i=t-32;if(i>=46&&(i-=46,n=!0),a+=i,n)break;a*=46}n?n[i++]=a:n=new t(a)}return n}var f=class{constructor(){this.start=-1,this.value=-1,this.end=-1,this.extended=-1,this.lookAhead=0,this.mask=0,this.context=0}},p=new f,m=class{constructor(e,t){this.input=e,this.ranges=t,this.chunk=``,this.chunkOff=0,this.chunk2=``,this.chunk2Pos=0,this.next=-1,this.token=p,this.rangeIndex=0,this.pos=this.chunkPos=t[0].from,this.range=t[0],this.end=t[t.length-1].to,this.readNext()}resolveOffset(e,t){let n=this.range,r=this.rangeIndex,i=this.pos+e;for(;in.to:i>=n.to;){if(r==this.ranges.length-1)return null;let e=this.ranges[++r];i+=e.from-n.to,n=e}return i}clipPos(e){if(e>=this.range.from&&ee)return Math.max(e,t.from);return this.end}peek(e){let t=this.chunkOff+e,n,r;if(t>=0&&t=this.chunk2Pos&&nt.to&&(this.chunk2=this.chunk2.slice(0,t.to-n)),r=this.chunk2.charCodeAt(0)}}return n>=this.token.lookAhead&&(this.token.lookAhead=n+1),r}acceptToken(e,t=0){let n=t?this.resolveOffset(t,-1):this.pos;if(n==null||n=this.chunk2Pos&&this.posthis.range.to?e.slice(0,this.range.to-this.pos):e,this.chunkPos=this.pos,this.chunkOff=0}}readNext(){return this.chunkOff>=this.chunk.length&&(this.getChunk(),this.chunkOff==this.chunk.length)?this.next=-1:this.next=this.chunk.charCodeAt(this.chunkOff)}advance(e=1){for(this.chunkOff+=e;this.pos+e>=this.range.to;){if(this.rangeIndex==this.ranges.length-1)return this.setDone();e-=this.range.to-this.pos,this.range=this.ranges[++this.rangeIndex],this.pos=this.range.from}return this.pos+=e,this.pos>=this.token.lookAhead&&(this.token.lookAhead=this.pos+1),this.readNext()}setDone(){return this.pos=this.chunkPos=this.end,this.range=this.ranges[this.rangeIndex=this.ranges.length-1],this.chunk=``,this.next=-1}reset(e,t){if(t?(this.token=t,t.start=e,t.lookAhead=e+1,t.value=t.extended=-1):this.token=p,this.pos!=e){if(this.pos=e,e==this.end)return this.setDone(),this;for(;e=this.range.to;)this.range=this.ranges[++this.rangeIndex];e>=this.chunkPos&&e=this.chunkPos&&t<=this.chunkPos+this.chunk.length)return this.chunk.slice(e-this.chunkPos,t-this.chunkPos);if(e>=this.chunk2Pos&&t<=this.chunk2Pos+this.chunk2.length)return this.chunk2.slice(e-this.chunk2Pos,t-this.chunk2Pos);if(e>=this.range.from&&t<=this.range.to)return this.input.read(e,t);let n=``;for(let r of this.ranges){if(r.from>=t)break;r.to>e&&(n+=this.input.read(Math.max(r.from,e),Math.min(r.to,t)))}return n}},h=class{constructor(e,t){this.data=e,this.id=t}token(e,t){let{parser:n}=t.p;v(this.data,e,t,this.id,n.data,n.tokenPrecTable)}};h.prototype.contextual=h.prototype.fallback=h.prototype.extend=!1;var g=class{constructor(e,t,n){this.precTable=t,this.elseToken=n,this.data=typeof e==`string`?d(e):e}token(e,t){let n=e.pos,r=0;for(;;){let n=e.next<0,i=e.resolveOffset(1,1);if(v(this.data,e,t,0,this.data,this.precTable),e.token.value>-1)break;if(this.elseToken==null)return;if(n||r++,i==null)break;e.reset(i,e.token)}r&&(e.reset(n,e.token),e.acceptToken(this.elseToken,r))}};g.prototype.contextual=h.prototype.fallback=h.prototype.extend=!1;var _=class{constructor(e,t={}){this.token=e,this.contextual=!!t.contextual,this.fallback=!!t.fallback,this.extend=!!t.extend}};function v(e,t,n,r,i,a){let o=0,s=1<0){let n=e[r];if(c.allows(n)&&(t.token.value==-1||t.token.value==n||b(n,t.token.value,i,a))){t.acceptToken(n);break}}let r=t.next,l=0,u=e[o+2];if(t.next<0&&u>l&&e[n+u*3-3]==65535){o=e[n+u*3-1];continue scan}for(;l>1,a=n+i+(i<<1),s=e[a],c=e[a+1]||65536;if(r=c)l=i+1;else{o=e[a+2],t.advance();continue scan}}break}}function y(e,t,n){for(let r=t,i;(i=e[r])!=65535;r++)if(i==n)return r-t;return-1}function b(e,t,n,r){let i=y(n,r,t);return i<0||y(n,r,e)n)&&!i.type.isError)return r<0?Math.max(0,Math.min(i.to-1,n-25)):Math.min(t.length,Math.max(i.from+1,n+25));if(r<0?i.prevSibling():i.nextSibling())break;if(!i.parent())return r<0?0:t.length}}var w=class{constructor(e,t){this.fragments=e,this.nodeSet=t,this.i=0,this.fragment=null,this.safeFrom=-1,this.safeTo=-1,this.trees=[],this.start=[],this.index=[],this.nextFragment()}nextFragment(){let e=this.fragment=this.i==this.fragments.length?null:this.fragments[this.i++];if(e){for(this.safeFrom=e.openStart?C(e.tree,e.from+e.offset,1)-e.offset:e.from,this.safeTo=e.openEnd?C(e.tree,e.to+e.offset,-1)-e.offset:e.to;this.trees.length;)this.trees.pop(),this.start.pop(),this.index.pop();this.trees.push(e.tree),this.start.push(-e.offset),this.index.push(0),this.nextStart=this.safeFrom}else this.nextStart=1e9}nodeAt(e){if(ee)return this.nextStart=s,null;if(i instanceof a){if(s==e){if(s=Math.max(this.safeFrom,e)&&(this.trees.push(i),this.start.push(s),this.index.push(0))}else this.index[t]++,this.nextStart=s+i.length}}},T=class{constructor(e,t){this.stream=t,this.tokens=[],this.mainToken=null,this.actions=[],this.tokens=e.tokenizers.map(e=>new f)}getActions(e){let t=0,n=null,{parser:r}=e.p,{tokenizers:i}=r,a=r.stateSlot(e.state,3),o=e.curContext?e.curContext.hash:0,s=0;for(let r=0;rl.end+25&&(s=Math.max(l.lookAhead,s)),l.value!=0)){let r=t;if(l.extended>-1&&(t=this.addActions(e,l.extended,l.end,t)),t=this.addActions(e,l.value,l.end,t),!c.extend&&(n=l,t>r))break}}for(;this.actions.length>t;)this.actions.pop();return s&&e.setLookAhead(s),!n&&e.pos==this.stream.end&&(n=new f,n.value=e.p.parser.eofTerm,n.start=n.end=e.pos,t=this.addActions(e,n.value,n.end,t)),this.mainToken=n,this.actions}getMainToken(e){if(this.mainToken)return this.mainToken;let t=new f,{pos:n,p:r}=e;return t.start=n,t.end=Math.min(n+1,r.stream.end),t.value=n==r.stream.end?r.parser.eofTerm:0,t}updateCachedToken(e,t,n){let r=this.stream.clipPos(n.pos);if(t.token(this.stream.reset(r,e),n),e.value>-1){let{parser:t}=n.p;for(let r=0;r=0&&n.p.parser.dialect.allows(i>>1)){i&1?e.extended=i>>1:e.value=i>>1;break}}}else e.value=0,e.end=this.stream.clipPos(r+1)}putAction(e,t,n,r){for(let t=0;te.bufferLength*4?new w(n,e.nodeSet):null}get parsedPos(){return this.minStackPos}advance(){let e=this.stacks,t=this.minStackPos,n=this.stacks=[],r,i;if(this.bigReductionCount>300&&e.length==1){let[t]=e;for(;t.forceReduce()&&t.stack.length&&t.stack[t.stack.length-2]>=this.lastBigReductionStart;);this.bigReductionCount=this.lastBigReductionSize=0}for(let a=0;at)n.push(o);else if(this.advanceStack(o,n,e))continue;else{r||(r=[],i=[]),r.push(o);let e=this.tokens.getMainToken(o);i.push(e.value,e.end)}break}}if(!n.length){let e=r&&N(r);if(e)return x&&console.log(`Finish with `+this.stackID(e)),this.stackToTree(e);if(this.parser.strict)throw x&&r&&console.log(`Stuck with token `+(this.tokens.mainToken?this.parser.getName(this.tokens.mainToken.value):`none`)),SyntaxError(`No parse at `+t);this.recovering||=5}if(this.recovering&&r){let e=this.stoppedAt!=null&&r[0].pos>this.stoppedAt?r[0]:this.runRecovery(r,i,n);if(e)return x&&console.log(`Force-finish `+this.stackID(e)),this.stackToTree(e.forceAll())}if(this.recovering){let e=this.recovering==1?1:this.recovering*3;if(n.length>e)for(n.sort((e,t)=>t.score-e.score);n.length>e;)n.pop();n.some(e=>e.reducePos>t)&&this.recovering--}else if(n.length>1){outer:for(let e=0;e500&&i.buffer.length>500)if((t.score-i.score||t.buffer.length-i.buffer.length)>0)n.splice(r--,1);else{n.splice(e--,1);continue outer}}}n.length>12&&(n.sort((e,t)=>t.score-e.score),n.splice(12,n.length-12))}this.minStackPos=n[0].pos;for(let e=1;e `:``;if(this.stoppedAt!=null&&r>this.stoppedAt)return e.forceReduce()?e:null;if(this.fragments){let t=e.curContext&&e.curContext.tracker.strict,n=t?e.curContext.hash:0;for(let c=this.fragments.nodeAt(r);c;){let r=this.parser.nodeSet.types[c.type.id]==c.type?i.getGoto(e.state,c.type.id):-1;if(r>-1&&c.length&&(!t||(c.prop(o.contextHash)||0)==n))return e.useNode(c,r),x&&console.log(s+this.stackID(e)+` (via reuse of ${i.getName(c.type.id)})`),!0;if(!(c instanceof a)||c.children.length==0||c.positions[0]>0)break;let l=c.children[0];if(l instanceof a&&c.positions[0]==0)c=l;else break}}let c=i.stateSlot(e.state,4);if(c>0)return e.reduce(c),x&&console.log(s+this.stackID(e)+` (via always-reduce ${i.getName(c&65535)})`),!0;if(e.stack.length>=8400)for(;e.stack.length>6e3&&e.forceReduce(););let l=this.tokens.getActions(e);for(let a=0;ar?t.push(f):n.push(f)}return!1}advanceFully(e,t){let n=e.pos;for(;;){if(!this.advanceStack(e,null,null))return!1;if(e.pos>n)return D(e,t),!0}}runRecovery(e,t,n){let r=null,i=!1;for(let a=0;a `:``;if(o.deadEnd&&(i||(i=!0,o.restart(),x&&console.log(l+this.stackID(o)+` (restarted)`),this.advanceFully(o,n))))continue;let u=o.split(),d=l;for(let e=0;e<10&&u.forceReduce()&&(x&&console.log(d+this.stackID(u)+` (via force-reduce)`),!this.advanceFully(u,n));e++)x&&(d=this.stackID(u)+` -> `);for(let e of o.recoverByInsert(s))x&&console.log(l+this.stackID(e)+` (via recover-insert)`),this.advanceFully(e,n);this.stream.end>o.pos?(c==o.pos&&(c++,s=0),o.recoverByDelete(s,c),x&&console.log(l+this.stackID(o)+` (via recover-delete ${this.parser.getName(s)})`),D(o,n)):(!r||r.scoree,A=class{constructor(e){this.start=e.start,this.shift=e.shift||k,this.reduce=e.reduce||k,this.reuse=e.reuse||k,this.hash=e.hash||(()=>0),this.strict=e.strict!==!1}},j=class e extends n{constructor(e){if(super(),this.wrappers=[],e.version!=14)throw RangeError(`Parser version (${e.version}) doesn't match runtime version (14)`);let n=e.nodeNames.split(` `);this.minRepeatTerm=n.length;for(let t=0;te.topRules[t][1]),s=[];for(let e=0;e=0)c(r,e,t[n++]);else{let i=t[n+-r];for(let a=-r;a>0;a--)c(t[n++],e,i);n++}}}this.nodeSet=new i(n.map((n,r)=>t.define({name:r>=this.minRepeatTerm?void 0:n,id:r,props:s[r],top:a.indexOf(r)>-1,error:r==0,skipped:e.skippedNodes&&e.skippedNodes.indexOf(r)>-1}))),e.propSources&&(this.nodeSet=this.nodeSet.extend(...e.propSources)),this.strict=!1,this.bufferLength=r;let l=d(e.tokenData);this.context=e.context,this.specializerSpecs=e.specialized||[],this.specialized=new Uint16Array(this.specializerSpecs.length);for(let e=0;etypeof e==`number`?new h(l,e):e),this.topRules=e.topRules,this.dialects=e.dialects||{},this.dynamicPrecedences=e.dynamicPrecedences||null,this.tokenPrecTable=e.tokenPrec,this.termNames=e.termNames||null,this.maxNode=this.nodeSet.types.length-1,this.dialect=this.parseDialect(),this.top=this.topRules[Object.keys(this.topRules)[0]]}createParse(e,t,n){let r=new E(this,e,t,n);for(let i of this.wrappers)r=i(r,e,t,n);return r}getGoto(e,t,n=!1){let r=this.goto;if(t>=r[0])return-1;for(let i=r[t+1];;){let t=r[i++],a=t&1,o=r[i++];if(a&&n)return o;for(let n=i+(t>>1);i0}validAction(e,t){return!!this.allActions(e,e=>e==t?!0:null)}allActions(e,t){let n=this.stateSlot(e,4),r=n?t(n):void 0;for(let n=this.stateSlot(e,1);r==null;n+=3){if(this.data[n]==65535)if(this.data[n+1]==1)n=M(this.data,n+2);else break;r=t(M(this.data,n+1))}return r}nextStates(e){let t=[];for(let n=this.stateSlot(e,1);;n+=3){if(this.data[n]==65535)if(this.data[n+1]==1)n=M(this.data,n+2);else break;if(!(this.data[n+2]&1)){let e=this.data[n+1];t.some((t,n)=>n&1&&t==e)||t.push(this.data[n],e)}}return t}configure(t){let n=Object.assign(Object.create(e.prototype),this);if(t.props&&(n.nodeSet=this.nodeSet.extend(...t.props)),t.top){let e=this.topRules[t.top];if(!e)throw RangeError(`Invalid top rule name ${t.top}`);n.top=e}return t.tokenizers&&(n.tokenizers=this.tokenizers.map(e=>{let n=t.tokenizers.find(t=>t.from==e);return n?n.to:e})),t.specializers&&(n.specializers=this.specializers.slice(),n.specializerSpecs=this.specializerSpecs.map((e,r)=>{let i=t.specializers.find(t=>t.from==e.external);if(!i)return e;let a=Object.assign(Object.assign({},e),{external:i.to});return n.specializers[r]=P(a),a})),t.contextTracker&&(n.context=t.contextTracker),t.dialect&&(n.dialect=this.parseDialect(t.dialect)),t.strict!=null&&(n.strict=t.strict),t.wrap&&(n.wrappers=n.wrappers.concat(t.wrap)),t.bufferLength!=null&&(n.bufferLength=t.bufferLength),n}hasWrappers(){return this.wrappers.length>0}getName(e){return this.termNames?this.termNames[e]:String(e<=this.maxNode&&this.nodeSet.types[e].name||e)}get eofTerm(){return this.maxNode+1}get topNode(){return this.nodeSet.types[this.top[1]]}dynamicPrecedence(e){let t=this.dynamicPrecedences;return t==null?0:t[e]||0}parseDialect(e){let t=Object.keys(this.dialects),n=t.map(()=>!1);if(e)for(let r of e.split(` `)){let e=t.indexOf(r);e>=0&&(n[e]=!0)}let r=null;for(let e=0;ee)&&n.p.parser.stateFlag(n.state,2)&&(!t||t.scoree.external(n,r)<<1|t}return e.get}export{g as i,_ as n,j as r,A as t}; \ No newline at end of file +import{C as e,E as t,O as n,S as r,T as i,k as a,w as o}from"./index-CLJ0aycO.js";var s=class e{constructor(e,t,n,r,i,a,o,s,c,l=0,u){this.p=e,this.stack=t,this.state=n,this.reducePos=r,this.pos=i,this.score=a,this.buffer=o,this.bufferBase=s,this.curContext=c,this.lookAhead=l,this.parent=u}toString(){return`[${this.stack.filter((e,t)=>t%3==0).concat(this.state)}]@${this.pos}${this.score?`!`+this.score:``}`}static start(t,n,r=0){let i=t.parser.context;return new e(t,[],n,r,r,0,[],0,i?new c(i,i.start):null,0,null)}get context(){return this.curContext?this.curContext.context:null}pushState(e,t){this.stack.push(this.state,t,this.bufferBase+this.buffer.length),this.state=e}reduce(e){let t=e>>19,n=e&65535,{parser:r}=this.p,i=this.reducePos=2e3&&!this.p.parser.nodeSet.types[n]?.isAnonymous&&(s==this.p.lastBigReductionStart?(this.p.bigReductionCount++,this.p.lastBigReductionSize=c):this.p.lastBigReductionSizeo;)this.stack.pop();this.reduceContext(n,s)}storeNode(e,t,n,r=4,i=!1){if(e==0&&(!this.stack.length||this.stack[this.stack.length-1]0&&this.buffer[e-4]==0&&this.buffer[e-1]>-1){if(t==n)return;if(this.buffer[e-2]>=t){this.buffer[e-2]=n;return}}}if(!i||this.pos==n)this.buffer.push(e,t,n,r);else{let i=this.buffer.length;if(i>0&&(this.buffer[i-4]!=0||this.buffer[i-1]<0)){let e=!1;for(let t=i;t>0&&this.buffer[t-2]>n;t-=4)if(this.buffer[t-1]>=0){e=!0;break}if(e)for(;i>0&&this.buffer[i-2]>n;)this.buffer[i]=this.buffer[i-4],this.buffer[i+1]=this.buffer[i-3],this.buffer[i+2]=this.buffer[i-2],this.buffer[i+3]=this.buffer[i-1],i-=4,r>4&&(r-=4)}this.buffer[i]=e,this.buffer[i+1]=t,this.buffer[i+2]=n,this.buffer[i+3]=r}}shift(e,t,n,r){if(e&131072)this.pushState(e&65535,this.pos);else if(e&262144)this.pos=r,this.shiftContext(t,n),t<=this.p.parser.maxNode&&this.buffer.push(t,n,r,4);else{let i=e,{parser:a}=this.p;this.pos=r;let o=a.stateFlag(i,1);!o&&(r>n||t<=a.maxNode)&&(this.reducePos=r),this.pushState(i,o?n:Math.min(n,this.reducePos)),this.shiftContext(t,n),t<=a.maxNode&&this.buffer.push(t,n,r,4)}}apply(e,t,n,r){e&65536?this.reduce(e):this.shift(e,t,n,r)}useNode(e,t){let n=this.p.reused.length-1;(n<0||this.p.reused[n]!=e)&&(this.p.reused.push(e),n++);let r=this.pos;this.reducePos=this.pos=r+e.length,this.pushState(t,r),this.buffer.push(n,r,this.reducePos,-1),this.curContext&&this.updateContext(this.curContext.tracker.reuse(this.curContext.context,e,this,this.p.stream.reset(this.pos-e.length)))}split(){let t=this,n=t.buffer.length;for(n&&t.buffer[n-4]==0&&(n-=4);n>0&&t.buffer[n-2]>t.reducePos;)n-=4;let r=t.buffer.slice(n),i=t.bufferBase+n;for(;t&&i==t.bufferBase;)t=t.parent;return new e(this.p,this.stack.slice(),this.state,this.reducePos,this.pos,this.score,r,i,this.curContext,this.lookAhead,t)}recoverByDelete(e,t){let n=e<=this.p.parser.maxNode;n&&this.storeNode(e,this.pos,t,4),this.storeNode(0,this.pos,t,n?8:4),this.pos=this.reducePos=t,this.score-=190}canShift(e){for(let t=new l(this);;){let n=this.p.parser.stateSlot(t.state,4)||this.p.parser.hasAction(t.state,e);if(n==0)return!1;if(!(n&65536))return!0;t.reduce(n)}}recoverByInsert(e){if(this.stack.length>=300)return[];let t=this.p.parser.nextStates(this.state);if(t.length>8||this.stack.length>=120){let n=[];for(let r=0,i;rt&1&&e==r)||n.push(t[e],r)}t=n}let n=[];for(let e=0;e>19,r=t&65535,i=this.stack.length-n*3;if(i<0||e.getGoto(this.stack[i],r,!1)<0){let e=this.findForcedReduction();if(e==null)return!1;t=e}this.storeNode(0,this.pos,this.pos,4,!0),this.score-=100}return this.reducePos=this.pos,this.reduce(t),!0}findForcedReduction(){let{parser:e}=this.p,t=[],n=(r,i)=>{if(!t.includes(r))return t.push(r),e.allActions(r,t=>{if(!(t&393216))if(t&65536){let n=(t>>19)-i;if(n>1){let r=t&65535,i=this.stack.length-n*3;if(i>=0&&e.getGoto(this.stack[i],r,!1)>=0)return n<<19|65536|r}}else{let e=n(t,i+1);if(e!=null)return e}})};return n(this.state,0)}forceAll(){for(;!this.p.parser.stateFlag(this.state,2);)if(!this.forceReduce()){this.storeNode(0,this.pos,this.pos,4,!0);break}return this}get deadEnd(){if(this.stack.length!=3)return!1;let{parser:e}=this.p;return e.data[e.stateSlot(this.state,1)]==65535&&!e.stateSlot(this.state,4)}restart(){this.storeNode(0,this.pos,this.pos,4,!0),this.state=this.stack[0],this.stack.length=0}sameState(e){if(this.state!=e.state||this.stack.length!=e.stack.length)return!1;for(let t=0;t0&&this.emitLookAhead()}},c=class{constructor(e,t){this.tracker=e,this.context=t,this.hash=e.strict?e.hash(t):0}},l=class{constructor(e){this.start=e,this.state=e.state,this.stack=e.stack,this.base=this.stack.length}reduce(e){let t=e&65535,n=e>>19;n==0?(this.stack==this.start.stack&&(this.stack=this.stack.slice()),this.stack.push(this.state,0,0),this.base+=3):this.base-=(n-1)*3;let r=this.start.p.parser.getGoto(this.stack[this.base-3],t,!0);this.state=r}},u=class e{constructor(e,t,n){this.stack=e,this.pos=t,this.index=n,this.buffer=e.buffer,this.index==0&&this.maybeNext()}static create(t,n=t.bufferBase+t.buffer.length){return new e(t,n,n-t.bufferBase)}maybeNext(){let e=this.stack.parent;e!=null&&(this.index=this.stack.bufferBase-e.bufferBase,this.stack=e,this.buffer=e.buffer)}get id(){return this.buffer[this.index-4]}get start(){return this.buffer[this.index-3]}get end(){return this.buffer[this.index-2]}get size(){return this.buffer[this.index-1]}next(){this.index-=4,this.pos-=4,this.index==0&&this.maybeNext()}fork(){return new e(this.stack,this.pos,this.index)}};function d(e,t=Uint16Array){if(typeof e!=`string`)return e;let n=null;for(let r=0,i=0;r=92&&t--,t>=34&&t--;let i=t-32;if(i>=46&&(i-=46,n=!0),a+=i,n)break;a*=46}n?n[i++]=a:n=new t(a)}return n}var f=class{constructor(){this.start=-1,this.value=-1,this.end=-1,this.extended=-1,this.lookAhead=0,this.mask=0,this.context=0}},p=new f,m=class{constructor(e,t){this.input=e,this.ranges=t,this.chunk=``,this.chunkOff=0,this.chunk2=``,this.chunk2Pos=0,this.next=-1,this.token=p,this.rangeIndex=0,this.pos=this.chunkPos=t[0].from,this.range=t[0],this.end=t[t.length-1].to,this.readNext()}resolveOffset(e,t){let n=this.range,r=this.rangeIndex,i=this.pos+e;for(;in.to:i>=n.to;){if(r==this.ranges.length-1)return null;let e=this.ranges[++r];i+=e.from-n.to,n=e}return i}clipPos(e){if(e>=this.range.from&&ee)return Math.max(e,t.from);return this.end}peek(e){let t=this.chunkOff+e,n,r;if(t>=0&&t=this.chunk2Pos&&nt.to&&(this.chunk2=this.chunk2.slice(0,t.to-n)),r=this.chunk2.charCodeAt(0)}}return n>=this.token.lookAhead&&(this.token.lookAhead=n+1),r}acceptToken(e,t=0){let n=t?this.resolveOffset(t,-1):this.pos;if(n==null||n=this.chunk2Pos&&this.posthis.range.to?e.slice(0,this.range.to-this.pos):e,this.chunkPos=this.pos,this.chunkOff=0}}readNext(){return this.chunkOff>=this.chunk.length&&(this.getChunk(),this.chunkOff==this.chunk.length)?this.next=-1:this.next=this.chunk.charCodeAt(this.chunkOff)}advance(e=1){for(this.chunkOff+=e;this.pos+e>=this.range.to;){if(this.rangeIndex==this.ranges.length-1)return this.setDone();e-=this.range.to-this.pos,this.range=this.ranges[++this.rangeIndex],this.pos=this.range.from}return this.pos+=e,this.pos>=this.token.lookAhead&&(this.token.lookAhead=this.pos+1),this.readNext()}setDone(){return this.pos=this.chunkPos=this.end,this.range=this.ranges[this.rangeIndex=this.ranges.length-1],this.chunk=``,this.next=-1}reset(e,t){if(t?(this.token=t,t.start=e,t.lookAhead=e+1,t.value=t.extended=-1):this.token=p,this.pos!=e){if(this.pos=e,e==this.end)return this.setDone(),this;for(;e=this.range.to;)this.range=this.ranges[++this.rangeIndex];e>=this.chunkPos&&e=this.chunkPos&&t<=this.chunkPos+this.chunk.length)return this.chunk.slice(e-this.chunkPos,t-this.chunkPos);if(e>=this.chunk2Pos&&t<=this.chunk2Pos+this.chunk2.length)return this.chunk2.slice(e-this.chunk2Pos,t-this.chunk2Pos);if(e>=this.range.from&&t<=this.range.to)return this.input.read(e,t);let n=``;for(let r of this.ranges){if(r.from>=t)break;r.to>e&&(n+=this.input.read(Math.max(r.from,e),Math.min(r.to,t)))}return n}},h=class{constructor(e,t){this.data=e,this.id=t}token(e,t){let{parser:n}=t.p;v(this.data,e,t,this.id,n.data,n.tokenPrecTable)}};h.prototype.contextual=h.prototype.fallback=h.prototype.extend=!1;var g=class{constructor(e,t,n){this.precTable=t,this.elseToken=n,this.data=typeof e==`string`?d(e):e}token(e,t){let n=e.pos,r=0;for(;;){let n=e.next<0,i=e.resolveOffset(1,1);if(v(this.data,e,t,0,this.data,this.precTable),e.token.value>-1)break;if(this.elseToken==null)return;if(n||r++,i==null)break;e.reset(i,e.token)}r&&(e.reset(n,e.token),e.acceptToken(this.elseToken,r))}};g.prototype.contextual=h.prototype.fallback=h.prototype.extend=!1;var _=class{constructor(e,t={}){this.token=e,this.contextual=!!t.contextual,this.fallback=!!t.fallback,this.extend=!!t.extend}};function v(e,t,n,r,i,a){let o=0,s=1<0){let n=e[r];if(c.allows(n)&&(t.token.value==-1||t.token.value==n||b(n,t.token.value,i,a))){t.acceptToken(n);break}}let r=t.next,l=0,u=e[o+2];if(t.next<0&&u>l&&e[n+u*3-3]==65535){o=e[n+u*3-1];continue scan}for(;l>1,a=n+i+(i<<1),s=e[a],c=e[a+1]||65536;if(r=c)l=i+1;else{o=e[a+2],t.advance();continue scan}}break}}function y(e,t,n){for(let r=t,i;(i=e[r])!=65535;r++)if(i==n)return r-t;return-1}function b(e,t,n,r){let i=y(n,r,t);return i<0||y(n,r,e)n)&&!i.type.isError)return r<0?Math.max(0,Math.min(i.to-1,n-25)):Math.min(t.length,Math.max(i.from+1,n+25));if(r<0?i.prevSibling():i.nextSibling())break;if(!i.parent())return r<0?0:t.length}}var w=class{constructor(e,t){this.fragments=e,this.nodeSet=t,this.i=0,this.fragment=null,this.safeFrom=-1,this.safeTo=-1,this.trees=[],this.start=[],this.index=[],this.nextFragment()}nextFragment(){let e=this.fragment=this.i==this.fragments.length?null:this.fragments[this.i++];if(e){for(this.safeFrom=e.openStart?C(e.tree,e.from+e.offset,1)-e.offset:e.from,this.safeTo=e.openEnd?C(e.tree,e.to+e.offset,-1)-e.offset:e.to;this.trees.length;)this.trees.pop(),this.start.pop(),this.index.pop();this.trees.push(e.tree),this.start.push(-e.offset),this.index.push(0),this.nextStart=this.safeFrom}else this.nextStart=1e9}nodeAt(e){if(ee)return this.nextStart=s,null;if(i instanceof a){if(s==e){if(s=Math.max(this.safeFrom,e)&&(this.trees.push(i),this.start.push(s),this.index.push(0))}else this.index[t]++,this.nextStart=s+i.length}}},T=class{constructor(e,t){this.stream=t,this.tokens=[],this.mainToken=null,this.actions=[],this.tokens=e.tokenizers.map(e=>new f)}getActions(e){let t=0,n=null,{parser:r}=e.p,{tokenizers:i}=r,a=r.stateSlot(e.state,3),o=e.curContext?e.curContext.hash:0,s=0;for(let r=0;rl.end+25&&(s=Math.max(l.lookAhead,s)),l.value!=0)){let r=t;if(l.extended>-1&&(t=this.addActions(e,l.extended,l.end,t)),t=this.addActions(e,l.value,l.end,t),!c.extend&&(n=l,t>r))break}}for(;this.actions.length>t;)this.actions.pop();return s&&e.setLookAhead(s),!n&&e.pos==this.stream.end&&(n=new f,n.value=e.p.parser.eofTerm,n.start=n.end=e.pos,t=this.addActions(e,n.value,n.end,t)),this.mainToken=n,this.actions}getMainToken(e){if(this.mainToken)return this.mainToken;let t=new f,{pos:n,p:r}=e;return t.start=n,t.end=Math.min(n+1,r.stream.end),t.value=n==r.stream.end?r.parser.eofTerm:0,t}updateCachedToken(e,t,n){let r=this.stream.clipPos(n.pos);if(t.token(this.stream.reset(r,e),n),e.value>-1){let{parser:t}=n.p;for(let r=0;r=0&&n.p.parser.dialect.allows(i>>1)){i&1?e.extended=i>>1:e.value=i>>1;break}}}else e.value=0,e.end=this.stream.clipPos(r+1)}putAction(e,t,n,r){for(let t=0;te.bufferLength*4?new w(n,e.nodeSet):null}get parsedPos(){return this.minStackPos}advance(){let e=this.stacks,t=this.minStackPos,n=this.stacks=[],r,i;if(this.bigReductionCount>300&&e.length==1){let[t]=e;for(;t.forceReduce()&&t.stack.length&&t.stack[t.stack.length-2]>=this.lastBigReductionStart;);this.bigReductionCount=this.lastBigReductionSize=0}for(let a=0;at)n.push(o);else if(this.advanceStack(o,n,e))continue;else{r||(r=[],i=[]),r.push(o);let e=this.tokens.getMainToken(o);i.push(e.value,e.end)}break}}if(!n.length){let e=r&&N(r);if(e)return x&&console.log(`Finish with `+this.stackID(e)),this.stackToTree(e);if(this.parser.strict)throw x&&r&&console.log(`Stuck with token `+(this.tokens.mainToken?this.parser.getName(this.tokens.mainToken.value):`none`)),SyntaxError(`No parse at `+t);this.recovering||=5}if(this.recovering&&r){let e=this.stoppedAt!=null&&r[0].pos>this.stoppedAt?r[0]:this.runRecovery(r,i,n);if(e)return x&&console.log(`Force-finish `+this.stackID(e)),this.stackToTree(e.forceAll())}if(this.recovering){let e=this.recovering==1?1:this.recovering*3;if(n.length>e)for(n.sort((e,t)=>t.score-e.score);n.length>e;)n.pop();n.some(e=>e.reducePos>t)&&this.recovering--}else if(n.length>1){outer:for(let e=0;e500&&i.buffer.length>500)if((t.score-i.score||t.buffer.length-i.buffer.length)>0)n.splice(r--,1);else{n.splice(e--,1);continue outer}}}n.length>12&&(n.sort((e,t)=>t.score-e.score),n.splice(12,n.length-12))}this.minStackPos=n[0].pos;for(let e=1;e `:``;if(this.stoppedAt!=null&&r>this.stoppedAt)return e.forceReduce()?e:null;if(this.fragments){let t=e.curContext&&e.curContext.tracker.strict,n=t?e.curContext.hash:0;for(let c=this.fragments.nodeAt(r);c;){let r=this.parser.nodeSet.types[c.type.id]==c.type?i.getGoto(e.state,c.type.id):-1;if(r>-1&&c.length&&(!t||(c.prop(o.contextHash)||0)==n))return e.useNode(c,r),x&&console.log(s+this.stackID(e)+` (via reuse of ${i.getName(c.type.id)})`),!0;if(!(c instanceof a)||c.children.length==0||c.positions[0]>0)break;let l=c.children[0];if(l instanceof a&&c.positions[0]==0)c=l;else break}}let c=i.stateSlot(e.state,4);if(c>0)return e.reduce(c),x&&console.log(s+this.stackID(e)+` (via always-reduce ${i.getName(c&65535)})`),!0;if(e.stack.length>=8400)for(;e.stack.length>6e3&&e.forceReduce(););let l=this.tokens.getActions(e);for(let a=0;ar?t.push(f):n.push(f)}return!1}advanceFully(e,t){let n=e.pos;for(;;){if(!this.advanceStack(e,null,null))return!1;if(e.pos>n)return D(e,t),!0}}runRecovery(e,t,n){let r=null,i=!1;for(let a=0;a `:``;if(o.deadEnd&&(i||(i=!0,o.restart(),x&&console.log(l+this.stackID(o)+` (restarted)`),this.advanceFully(o,n))))continue;let u=o.split(),d=l;for(let e=0;e<10&&u.forceReduce()&&(x&&console.log(d+this.stackID(u)+` (via force-reduce)`),!this.advanceFully(u,n));e++)x&&(d=this.stackID(u)+` -> `);for(let e of o.recoverByInsert(s))x&&console.log(l+this.stackID(e)+` (via recover-insert)`),this.advanceFully(e,n);this.stream.end>o.pos?(c==o.pos&&(c++,s=0),o.recoverByDelete(s,c),x&&console.log(l+this.stackID(o)+` (via recover-delete ${this.parser.getName(s)})`),D(o,n)):(!r||r.scoree,A=class{constructor(e){this.start=e.start,this.shift=e.shift||k,this.reduce=e.reduce||k,this.reuse=e.reuse||k,this.hash=e.hash||(()=>0),this.strict=e.strict!==!1}},j=class e extends n{constructor(e){if(super(),this.wrappers=[],e.version!=14)throw RangeError(`Parser version (${e.version}) doesn't match runtime version (14)`);let n=e.nodeNames.split(` `);this.minRepeatTerm=n.length;for(let t=0;te.topRules[t][1]),s=[];for(let e=0;e=0)c(r,e,t[n++]);else{let i=t[n+-r];for(let a=-r;a>0;a--)c(t[n++],e,i);n++}}}this.nodeSet=new i(n.map((n,r)=>t.define({name:r>=this.minRepeatTerm?void 0:n,id:r,props:s[r],top:a.indexOf(r)>-1,error:r==0,skipped:e.skippedNodes&&e.skippedNodes.indexOf(r)>-1}))),e.propSources&&(this.nodeSet=this.nodeSet.extend(...e.propSources)),this.strict=!1,this.bufferLength=r;let l=d(e.tokenData);this.context=e.context,this.specializerSpecs=e.specialized||[],this.specialized=new Uint16Array(this.specializerSpecs.length);for(let e=0;etypeof e==`number`?new h(l,e):e),this.topRules=e.topRules,this.dialects=e.dialects||{},this.dynamicPrecedences=e.dynamicPrecedences||null,this.tokenPrecTable=e.tokenPrec,this.termNames=e.termNames||null,this.maxNode=this.nodeSet.types.length-1,this.dialect=this.parseDialect(),this.top=this.topRules[Object.keys(this.topRules)[0]]}createParse(e,t,n){let r=new E(this,e,t,n);for(let i of this.wrappers)r=i(r,e,t,n);return r}getGoto(e,t,n=!1){let r=this.goto;if(t>=r[0])return-1;for(let i=r[t+1];;){let t=r[i++],a=t&1,o=r[i++];if(a&&n)return o;for(let n=i+(t>>1);i0}validAction(e,t){return!!this.allActions(e,e=>e==t?!0:null)}allActions(e,t){let n=this.stateSlot(e,4),r=n?t(n):void 0;for(let n=this.stateSlot(e,1);r==null;n+=3){if(this.data[n]==65535)if(this.data[n+1]==1)n=M(this.data,n+2);else break;r=t(M(this.data,n+1))}return r}nextStates(e){let t=[];for(let n=this.stateSlot(e,1);;n+=3){if(this.data[n]==65535)if(this.data[n+1]==1)n=M(this.data,n+2);else break;if(!(this.data[n+2]&1)){let e=this.data[n+1];t.some((t,n)=>n&1&&t==e)||t.push(this.data[n],e)}}return t}configure(t){let n=Object.assign(Object.create(e.prototype),this);if(t.props&&(n.nodeSet=this.nodeSet.extend(...t.props)),t.top){let e=this.topRules[t.top];if(!e)throw RangeError(`Invalid top rule name ${t.top}`);n.top=e}return t.tokenizers&&(n.tokenizers=this.tokenizers.map(e=>{let n=t.tokenizers.find(t=>t.from==e);return n?n.to:e})),t.specializers&&(n.specializers=this.specializers.slice(),n.specializerSpecs=this.specializerSpecs.map((e,r)=>{let i=t.specializers.find(t=>t.from==e.external);if(!i)return e;let a=Object.assign(Object.assign({},e),{external:i.to});return n.specializers[r]=P(a),a})),t.contextTracker&&(n.context=t.contextTracker),t.dialect&&(n.dialect=this.parseDialect(t.dialect)),t.strict!=null&&(n.strict=t.strict),t.wrap&&(n.wrappers=n.wrappers.concat(t.wrap)),t.bufferLength!=null&&(n.bufferLength=t.bufferLength),n}hasWrappers(){return this.wrappers.length>0}getName(e){return this.termNames?this.termNames[e]:String(e<=this.maxNode&&this.nodeSet.types[e].name||e)}get eofTerm(){return this.maxNode+1}get topNode(){return this.nodeSet.types[this.top[1]]}dynamicPrecedence(e){let t=this.dynamicPrecedences;return t==null?0:t[e]||0}parseDialect(e){let t=Object.keys(this.dialects),n=t.map(()=>!1);if(e)for(let r of e.split(` `)){let e=t.indexOf(r);e>=0&&(n[e]=!0)}let r=null;for(let e=0;ee)&&n.p.parser.stateFlag(n.state,2)&&(!t||t.scoree.external(n,r)<<1|t}return e.get}export{g as i,_ as n,j as r,A as t}; \ No newline at end of file diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/dist-OF7YcNEr.js b/mcp/src/agents_remember/package_data/dashboard/assets/dist-BJusfjLN.js similarity index 99% rename from mcp/src/agents_remember/package_data/dashboard/assets/dist-OF7YcNEr.js rename to mcp/src/agents_remember/package_data/dashboard/assets/dist-BJusfjLN.js index 30052b33..b5056685 100644 --- a/mcp/src/agents_remember/package_data/dashboard/assets/dist-OF7YcNEr.js +++ b/mcp/src/agents_remember/package_data/dashboard/assets/dist-BJusfjLN.js @@ -1 +1 @@ -import{$ as e,C as t,D as n,b as r,d as i,f as a,i as o,m as s,s as c,t as ee,v as l,x as u}from"./index-BLlkJI-k.js";import{i as d,n as f,r as p}from"./dist-CuvUDais.js";var m=145,h=1,te=146,ne=147,g=2,_=148,v=3,re=4,y=[9,10,11,12,13,32,133,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288],b=58,x=40,S=95,ie=91,C=45,ae=46,oe=35,se=37,w=38,T=92,E=10,D=42;function O(e){return e>=65&&e<=90||e>=97&&e<=122||e>=161}function k(e){return e>=48&&e<=57}function A(e){return k(e)||e>=97&&e<=102||e>=65&&e<=70}var j=(e,t,n)=>(r,i)=>{for(let a=!1,o=0,s=0;;s++){let{next:c}=r;if(O(c)||c==C||c==S||a&&k(c))!a&&(c!=C||s>0)&&(a=!0),o===s&&c==C&&o++,r.advance();else if(c==T&&r.peek(1)!=E){if(r.advance(),A(r.next)){do r.advance();while(A(r.next));r.next==32&&r.advance()}else r.next>-1&&r.advance();a=!0}else{a&&r.acceptToken(o==2&&i.canShift(g)?t:c==x?n:e);break}}},M=new f(j(te,g,ne),{contextual:!0}),N=new f(j(_,v,re),{contextual:!0}),P=new f(e=>{if(y.includes(e.peek(-1))){let{next:t}=e;(O(t)||t==S||t==oe||t==ae||t==D||t==ie||t==b&&O(e.peek(1))||t==C||t==w)&&e.acceptToken(m)}}),F=new f(e=>{if(!y.includes(e.peek(-1))){let{next:t}=e;if(t==se&&(e.advance(),e.acceptToken(h)),O(t)){do e.advance();while(O(e.next)||k(e.next));e.acceptToken(h)}}}),I=r({"AtKeyword import charset namespace keyframes media supports font-feature-values":u.definitionKeyword,"from to selector scope MatchFlag":u.keyword,NamespaceName:u.namespace,KeyframeName:u.labelName,KeyframeRangeName:u.operatorKeyword,TagName:u.tagName,ClassName:u.className,PseudoClassName:u.constant(u.className),IdName:u.labelName,"FeatureName PropertyName":u.propertyName,AttributeName:u.attributeName,NumberLiteral:u.number,KeywordQuery:u.keyword,UnaryQueryOp:u.operatorKeyword,"CallTag ValueName FontName":u.atom,VariableName:u.variableName,Callee:u.operatorKeyword,Unit:u.unit,"UniversalSelector NestingSelector":u.definitionOperator,"MatchOp CompareOp":u.compareOperator,"ChildOp SiblingOp, LogicOp":u.logicOperator,BinOp:u.arithmeticOperator,Important:u.modifier,Comment:u.blockComment,ColorLiteral:u.color,"ParenthesizedContent StringLiteral":u.string,":":u.punctuation,"PseudoOp #":u.derefOperator,"; , |":u.separator,"( )":u.paren,"[ ]":u.squareBracket,"{ }":u.brace}),L={__proto__:null,lang:44,"nth-child":44,"nth-last-child":44,"nth-of-type":44,"nth-last-of-type":44,dir:44,"host-context":44,if:90,url:152,"url-prefix":152,domain:152,regexp:152},R={__proto__:null,or:104,and:104,not:112,only:112,layer:206},z={__proto__:null,selector:118,style:124,layer:202},ce={__proto__:null,"@import":198,"@media":210,"@charset":214,"@namespace":218,"@keyframes":224,"@supports":236,"@scope":240,"@font-feature-values":246},B={__proto__:null,to:243},V=p.deserialize({version:14,states:"MlQYQdOOO#}QdOOP$UO`OOO%OQaO'#CfOOQP'#Ce'#CeO%VQdO'#CgO%[Q`O'#CgO%aQaO'#FnO&XQdO'#CkO&xQaO'#CcO'SQdO'#CnO'_QdO'#EOO'dQdO'#EQO'oQdO'#EXO'oQdO'#E[OOQP'#Fn'#FnO)RQhO'#E}OOQS'#Fm'#FmOOQS'#FQ'#FQQYQdOOO)YQdO'#EbO*iQhO'#EhO)YQdO'#EjO*pQdO'#ElO*{QdO'#EoO)}QhO'#EuO+TQdO'#EwO+`QdO'#EzO+eQaO'#CfO+lQ`O'#E_O+qQ`O'#F{O+|QdO'#F{QOQ`OOP,WO&jO'#CaPOOO)CA])CA]OOQP'#Ci'#CiOOQP,59R,59RO%VQdO,59ROOQP'#Cm'#CmOOQP,59V,59VO&XQdO,59VO,cQdO,59YO'_QdO,5:jO'dQdO,5:lO'oQdO,5:sO'oQdO,5:uO'oQdO,5:vO'oQdO'#FXO,nQ`O,58}O,vQdO'#E^OOQS,58},58}OOQP'#Cq'#CqOOQO'#D|'#D|OOQP,59Y,59YO,}Q`O,59YO-SQ`O,59YOOQP'#EP'#EPOOQP,5:j,5:jO-XQpO'#ERO-dQdO'#ESO-iQ`O'#ESO-nQpO,5:lO.XQaO,5:sO.oQaO,5:vOOQW'#D^'#D^O/nQhO'#DgO0RQhO,5;iO)}QhO'#DeO0`Q`O'#DnO0eQhO'#DxOOQW'#Ft'#FtOOQS,5;i,5;iO0jQ`O'#DhO0oQ`O'#DkOOQS-E9O-E9OOOQ['#Cv'#CvO0tQdO'#CwO1[QdO'#C}O1rQdO'#DQO2YQ!pO'#DSO4fQ!jO,5:|OOQO'#DX'#DXO-SQ`O'#DWO4vQ!nO'#FqO6|Q`O'#DYO7RQ`O'#DyOOQ['#Fq'#FqO7WQhO'#GOO7fQ`O,5;SO7kQ!bO,5;UOOQS'#En'#EnO7sQ`O,5;WO7xQdO,5;WOOQO'#Eq'#EqO8QQ`O,5;ZO8VQhO,5;aO'oQdO'#DjOOQS,5;c,5;cO0jQ`O,5;cO8_QdO,5;cOOQS'#F`'#F`O8gQdO'#E|O7fQ`O,5;fO8oQdO,5:yO9PQdO'#FZO9^Q`O,5lQhO'#DoOOQW,5:Y,5:YOOQW,5:d,5:dOOQW,5:S,5:SO>vQhO,5:VO?bQ!fO'#FrOOQS'#Fr'#FrOOQS'#FS'#FSO@rQdO,59cOOQ[,59c,59cOAYQdO,59iOOQ[,59i,59iOApQdO,59lOOQ[,59l,59lOOQ[,59n,59nO)YQdO,59pOBWQhO'#EdOOQW'#Ed'#EdOBuQ`O1G0hO4oQhO1G0hOOQ[,59r,59rO)}QhO'#D[OOQ[,59t,59tOBzQ#tO,5:eOCVQhO'#F]OCdQ`O,5vQhO'#DmOI_QhO'#DqOIgQhO'#DsOIlQhO'#FwOOQO'#Fw'#FwOItQ!bO'#DwOOQO'#Fy'#FyOOQO'#Fv'#FvOIyQ`O1G/qOOQS-E9Q-E9QOOQ[1G.}1G.}OOQ[1G/T1G/TOOQ[1G/W1G/WOOQ[1G/[1G/[OJOQdO,5;OOOQS7+&S7+&SOJTQ`O7+&SOJYQhO'#D]OJbQ`O,59vO)}QhO,59vOOQ[1G0P1G0POJjQ`O1G0POJoQhO,5;wOOQO-E9Z-E9ZOOQS7+&^7+&^OJ}QbO'#DSOOQO'#Et'#EtOK]Q`O'#EsOOQO'#Es'#EsOKhQ`O'#F^OKpQdO,5;^OOQS,5;^,5;^OOQ[1G/p1G/pOOQS7+&i7+&iO7fQ`O7+&iOK{Q!fO'#FYO)YQdO'#FYOMSQdO7+&POOQO7+&P7+&POOQO,5:{,5:{OOQO1G1a1G1aOMgQ!bO<vQhO'#DrOOQO,5:],5:]O! hQhO,5:_OGUQhO,5:cOOQW7+%]7+%]OOQO'#Ef'#EfO! pQ`O1G0jOOQS<xAN>xO!#zQ`OAN>xO!$PQaO,5;rOOQO-E9U-E9UO!$ZQdO,5;qOOQO-E9T-E9TOOQW<vQhO'#DuOOQO1G/y1G/yO!%vQ!bO1G/}OJOQdO'#F[O!&OQ`O7+&UOOQW7+&U7+&UO!&WQ!bO1G/cOOQ[7+$|7+$|O!&cQhO7+$|P!&jQ`O'#FTOOQO,5;y,5;yOOQO-E9]-E9]OOQS1G1d1G1dOOQPG24dG24dO!&oQ`OAN>ZO)YQdO1G1[O!&tQ`O7+'jOOQO1G/x1G/xO!&|Q`O,5:aO!$eQhO7+%iOOQO,5;v,5;vOOQO-E9Y-E9YOOQW<Q!]!^>|!^!_?_!_!`@Z!`!a@n!a!b%Z!b!cAo!c!k%Z!k!lC|!l!u%Z!u!vC|!v!}%Z!}#OD_#O#P%Z#P#QDp#Q#R2X#R#]%Z#]#^ER#^#g%Z#g#hC|#h#o%Z#o#pIf#p#qIw#q#rJ`#r#sJq#s#y%Z#y#z&R#z$f%Z$f$g&R$g#BY%Z#BY#BZ&R#BZ$IS%Z$IS$I_&R$I_$I|%Z$I|$JO&R$JO$JT%Z$JT$JU&R$JU$KV%Z$KV$KW&R$KW&FU%Z&FU&FV&R&FV;'S%Z;'S;=`KY<%lO%Z`%^SOy%jz;'S%j;'S;=`%{<%lO%j`%oS!o`Oy%jz;'S%j;'S;=`%{<%lO%j`&OP;=`<%l%j~&Wh$[~OX%jX^'r^p%jpq'rqy%jz#y%j#y#z'r#z$f%j$f$g'r$g#BY%j#BY#BZ'r#BZ$IS%j$IS$I_'r$I_$I|%j$I|$JO'r$JO$JT%j$JT$JU'r$JU$KV%j$KV$KW'r$KW&FU%j&FU&FV'r&FV;'S%j;'S;=`%{<%lO%j~'yh$[~!o`OX%jX^'r^p%jpq'rqy%jz#y%j#y#z'r#z$f%j$f$g'r$g#BY%j#BY#BZ'r#BZ$IS%j$IS$I_'r$I_$I|%j$I|$JO'r$JO$JT%j$JT$JU'r$JU$KV%j$KV$KW'r$KW&FU%j&FU&FV'r&FV;'S%j;'S;=`%{<%lO%jj)jS$qYOy%jz;'S%j;'S;=`%{<%lO%j~)yWOY)vZr)vrs*cs#O)v#O#P*h#P;'S)v;'S;=`+d<%lO)v~*hOw~~*kRO;'S)v;'S;=`*t;=`O)v~*wXOY)vZr)vrs*cs#O)v#O#P*h#P;'S)v;'S;=`+d;=`<%l)v<%lO)v~+gP;=`<%l)vj+oYmYOy%jz!Q%j!Q![,_![!c%j!c!i,_!i#T%j#T#Z,_#Z;'S%j;'S;=`%{<%lO%jj,dY!o`Oy%jz!Q%j!Q![-S![!c%j!c!i-S!i#T%j#T#Z-S#Z;'S%j;'S;=`%{<%lO%jj-XY!o`Oy%jz!Q%j!Q![-w![!c%j!c!i-w!i#T%j#T#Z-w#Z;'S%j;'S;=`%{<%lO%jj.OYuY!o`Oy%jz!Q%j!Q![.n![!c%j!c!i.n!i#T%j#T#Z.n#Z;'S%j;'S;=`%{<%lO%jj.uYuY!o`Oy%jz!Q%j!Q![/e![!c%j!c!i/e!i#T%j#T#Z/e#Z;'S%j;'S;=`%{<%lO%jj/jY!o`Oy%jz!Q%j!Q![0Y![!c%j!c!i0Y!i#T%j#T#Z0Y#Z;'S%j;'S;=`%{<%lO%jj0aYuY!o`Oy%jz!Q%j!Q![1P![!c%j!c!i1P!i#T%j#T#Z1P#Z;'S%j;'S;=`%{<%lO%jj1UY!o`Oy%jz!Q%j!Q![1t![!c%j!c!i1t!i#T%j#T#Z1t#Z;'S%j;'S;=`%{<%lO%jj1{SuY!o`Oy%jz;'S%j;'S;=`%{<%lO%jd2[UOy%jz!_%j!_!`2n!`;'S%j;'S;=`%{<%lO%jd2uS!yS!o`Oy%jz;'S%j;'S;=`%{<%lO%jb3WS^QOy%jz;'S%j;'S;=`%{<%lO%j~3gWOY3dZw3dwx*cx#O3d#O#P4P#P;'S3d;'S;=`4{<%lO3d~4SRO;'S3d;'S;=`4];=`O3d~4`XOY3dZw3dwx*cx#O3d#O#P4P#P;'S3d;'S;=`4{;=`<%l3d<%lO3d~5OP;=`<%l3dj5WShYOy%jz;'S%j;'S;=`%{<%lO%j~5iOg~n5pUWQyWOy%jz!_%j!_!`2n!`;'S%j;'S;=`%{<%lO%jj6ZWyW#PQOy%jz!O%j!O!P6s!P!Q%j!Q![9x![;'S%j;'S;=`%{<%lO%jj6xU!o`Oy%jz!Q%j!Q![7[![;'S%j;'S;=`%{<%lO%jj7cY!o`$gYOy%jz!Q%j!Q![7[![!g%j!g!h8R!h#X%j#X#Y8R#Y;'S%j;'S;=`%{<%lO%jj8WY!o`Oy%jz{%j{|8v|}%j}!O8v!O!Q%j!Q![9_![;'S%j;'S;=`%{<%lO%jj8{U!o`Oy%jz!Q%j!Q![9_![;'S%j;'S;=`%{<%lO%jj9fU!o`$gYOy%jz!Q%j!Q![9_![;'S%j;'S;=`%{<%lO%jj:P[!o`$gYOy%jz!O%j!O!P7[!P!Q%j!Q![9x![!g%j!g!h8R!h#X%j#X#Y8R#Y;'S%j;'S;=`%{<%lO%jj:zS!dYOy%jz;'S%j;'S;=`%{<%lO%jj;]WyWOy%jz!O%j!O!P6s!P!Q%j!Q![9x![;'S%j;'S;=`%{<%lO%jj;zU`YOy%jz!Q%j!Q![7[![;'S%j;'S;=`%{<%lO%j~VUcYOy%jz![%j![!]>i!];'S%j;'S;=`%{<%lO%jj>pSdY!o`Oy%jz;'S%j;'S;=`%{<%lO%jj?RSnYOy%jz;'S%j;'S;=`%{<%lO%jh?dU!WWOy%jz!_%j!_!`?v!`;'S%j;'S;=`%{<%lO%jh?}S!WW!o`Oy%jz;'S%j;'S;=`%{<%lO%jl@bS!WW!ySOy%jz;'S%j;'S;=`%{<%lO%jj@uV!|Q!WWOy%jz!_%j!_!`?v!`!aA[!a;'S%j;'S;=`%{<%lO%jbAcS!|Q!o`Oy%jz;'S%j;'S;=`%{<%lO%jjArYOy%jz}%j}!OBb!O!c%j!c!}CP!}#T%j#T#oCP#o;'S%j;'S;=`%{<%lO%jjBgW!o`Oy%jz!c%j!c!}CP!}#T%j#T#oCP#o;'S%j;'S;=`%{<%lO%jjCW[lY!o`Oy%jz}%j}!OCP!O!Q%j!Q![CP![!c%j!c!}CP!}#T%j#T#oCP#o;'S%j;'S;=`%{<%lO%jhDRS!zWOy%jz;'S%j;'S;=`%{<%lO%jjDdSpYOy%jz;'S%j;'S;=`%{<%lO%jnDuSo^Oy%jz;'S%j;'S;=`%{<%lO%jjEWU!zWOy%jz#a%j#a#bEj#b;'S%j;'S;=`%{<%lO%jbEoU!o`Oy%jz#d%j#d#eFR#e;'S%j;'S;=`%{<%lO%jbFWU!o`Oy%jz#c%j#c#dFj#d;'S%j;'S;=`%{<%lO%jbFoU!o`Oy%jz#f%j#f#gGR#g;'S%j;'S;=`%{<%lO%jbGWU!o`Oy%jz#h%j#h#iGj#i;'S%j;'S;=`%{<%lO%jbGoU!o`Oy%jz#T%j#T#UHR#U;'S%j;'S;=`%{<%lO%jbHWU!o`Oy%jz#b%j#b#cHj#c;'S%j;'S;=`%{<%lO%jbHoU!o`Oy%jz#h%j#h#iIR#i;'S%j;'S;=`%{<%lO%jbIYS$pQ!o`Oy%jz;'S%j;'S;=`%{<%lO%jjIkSsYOy%jz;'S%j;'S;=`%{<%lO%jfI|U$cUOy%jz!_%j!_!`2n!`;'S%j;'S;=`%{<%lO%jjJeSrYOy%jz;'S%j;'S;=`%{<%lO%jfJvU#PQOy%jz!_%j!_!`2n!`;'S%j;'S;=`%{<%lO%j`K]P;=`<%l%Z",tokenizers:[P,F,M,N,1,2,3,4,new d("m~RRYZ[z{a~~g~aO$_~~dP!P!Qg~lO$`~~",28,152)],topRules:{StyleSheet:[0,6],Styles:[1,126]},dynamicPrecedences:{94:1},specialized:[{term:147,get:e=>L[e]||-1},{term:148,get:e=>R[e]||-1},{term:4,get:e=>z[e]||-1},{term:28,get:e=>ce[e]||-1},{term:146,get:e=>B[e]||-1}],tokenPrec:2405}),H=e({css:()=>$,cssCompletionSource:()=>Z,cssLanguage:()=>Q,defineCSSCompletionSource:()=>X}),U=null;function W(){if(!U&&typeof document==`object`&&document.body){let{style:e}=document.body,t=[],n=new Set;for(let r in e)r!=`cssText`&&r!=`cssFloat`&&typeof e[r]==`string`&&(/[A-Z]/.test(r)&&(r=r.replace(/[A-Z]/g,e=>`-`+e.toLowerCase())),n.has(r)||(t.push(r),n.add(r)));U=t.sort().map(e=>({type:`property`,label:e,apply:e+`: `}))}return U||[]}var G=`active.after.any-link.autofill.backdrop.before.checked.cue.default.defined.disabled.empty.enabled.file-selector-button.first.first-child.first-letter.first-line.first-of-type.focus.focus-visible.focus-within.fullscreen.has.host.host-context.hover.in-range.indeterminate.invalid.is.lang.last-child.last-of-type.left.link.marker.modal.not.nth-child.nth-last-child.nth-last-of-type.nth-of-type.only-child.only-of-type.optional.out-of-range.part.placeholder.placeholder-shown.read-only.read-write.required.right.root.scope.selection.slotted.target.target-text.valid.visited.where`.split(`.`).map(e=>({type:`class`,label:e})),K=`above.absolute.activeborder.additive.activecaption.after-white-space.ahead.alias.all.all-scroll.alphabetic.alternate.always.antialiased.appworkspace.asterisks.attr.auto.auto-flow.avoid.avoid-column.avoid-page.avoid-region.axis-pan.background.backwards.baseline.below.bidi-override.blink.block.block-axis.bold.bolder.border.border-box.both.bottom.break.break-all.break-word.bullets.button.button-bevel.buttonface.buttonhighlight.buttonshadow.buttontext.calc.capitalize.caps-lock-indicator.caption.captiontext.caret.cell.center.checkbox.circle.cjk-decimal.clear.clip.close-quote.col-resize.collapse.color.color-burn.color-dodge.column.column-reverse.compact.condensed.contain.content.contents.content-box.context-menu.continuous.copy.counter.counters.cover.crop.cross.crosshair.currentcolor.cursive.cyclic.darken.dashed.decimal.decimal-leading-zero.default.default-button.dense.destination-atop.destination-in.destination-out.destination-over.difference.disc.discard.disclosure-closed.disclosure-open.document.dot-dash.dot-dot-dash.dotted.double.down.e-resize.ease.ease-in.ease-in-out.ease-out.element.ellipse.ellipsis.embed.end.ethiopic-abegede-gez.ethiopic-halehame-aa-er.ethiopic-halehame-gez.ew-resize.exclusion.expanded.extends.extra-condensed.extra-expanded.fantasy.fast.fill.fill-box.fixed.flat.flex.flex-end.flex-start.footnotes.forwards.from.geometricPrecision.graytext.grid.groove.hand.hard-light.help.hidden.hide.higher.highlight.highlighttext.horizontal.hsl.hsla.hue.icon.ignore.inactiveborder.inactivecaption.inactivecaptiontext.infinite.infobackground.infotext.inherit.initial.inline.inline-axis.inline-block.inline-flex.inline-grid.inline-table.inset.inside.intrinsic.invert.italic.justify.keep-all.landscape.large.larger.left.level.lighter.lighten.line-through.linear.linear-gradient.lines.list-item.listbox.listitem.local.logical.loud.lower.lower-hexadecimal.lower-latin.lower-norwegian.lowercase.ltr.luminosity.manipulation.match.matrix.matrix3d.medium.menu.menutext.message-box.middle.min-intrinsic.mix.monospace.move.multiple.multiple_mask_images.multiply.n-resize.narrower.ne-resize.nesw-resize.no-close-quote.no-drop.no-open-quote.no-repeat.none.normal.not-allowed.nowrap.ns-resize.numbers.numeric.nw-resize.nwse-resize.oblique.opacity.open-quote.optimizeLegibility.optimizeSpeed.outset.outside.outside-shape.overlay.overline.padding.padding-box.painted.page.paused.perspective.pinch-zoom.plus-darker.plus-lighter.pointer.polygon.portrait.pre.pre-line.pre-wrap.preserve-3d.progress.push-button.radial-gradient.radio.read-only.read-write.read-write-plaintext-only.rectangle.region.relative.repeat.repeating-linear-gradient.repeating-radial-gradient.repeat-x.repeat-y.reset.reverse.rgb.rgba.ridge.right.rotate.rotate3d.rotateX.rotateY.rotateZ.round.row.row-resize.row-reverse.rtl.run-in.running.s-resize.sans-serif.saturation.scale.scale3d.scaleX.scaleY.scaleZ.screen.scroll.scrollbar.scroll-position.se-resize.self-start.self-end.semi-condensed.semi-expanded.separate.serif.show.single.skew.skewX.skewY.skip-white-space.slide.slider-horizontal.slider-vertical.sliderthumb-horizontal.sliderthumb-vertical.slow.small.small-caps.small-caption.smaller.soft-light.solid.source-atop.source-in.source-out.source-over.space.space-around.space-between.space-evenly.spell-out.square.start.static.status-bar.stretch.stroke.stroke-box.sub.subpixel-antialiased.svg_masks.super.sw-resize.symbolic.symbols.system-ui.table.table-caption.table-cell.table-column.table-column-group.table-footer-group.table-header-group.table-row.table-row-group.text.text-bottom.text-top.textarea.textfield.thick.thin.threeddarkshadow.threedface.threedhighlight.threedlightshadow.threedshadow.to.top.transform.translate.translate3d.translateX.translateY.translateZ.transparent.ultra-condensed.ultra-expanded.underline.unidirectional-pan.unset.up.upper-latin.uppercase.url.var.vertical.vertical-text.view-box.visible.visibleFill.visiblePainted.visibleStroke.visual.w-resize.wait.wave.wider.window.windowframe.windowtext.words.wrap.wrap-reverse.x-large.x-small.xor.xx-large.xx-small`.split(`.`).map(e=>({type:`keyword`,label:e})).concat(`aliceblue.antiquewhite.aqua.aquamarine.azure.beige.bisque.black.blanchedalmond.blue.blueviolet.brown.burlywood.cadetblue.chartreuse.chocolate.coral.cornflowerblue.cornsilk.crimson.cyan.darkblue.darkcyan.darkgoldenrod.darkgray.darkgreen.darkkhaki.darkmagenta.darkolivegreen.darkorange.darkorchid.darkred.darksalmon.darkseagreen.darkslateblue.darkslategray.darkturquoise.darkviolet.deeppink.deepskyblue.dimgray.dodgerblue.firebrick.floralwhite.forestgreen.fuchsia.gainsboro.ghostwhite.gold.goldenrod.gray.grey.green.greenyellow.honeydew.hotpink.indianred.indigo.ivory.khaki.lavender.lavenderblush.lawngreen.lemonchiffon.lightblue.lightcoral.lightcyan.lightgoldenrodyellow.lightgray.lightgreen.lightpink.lightsalmon.lightseagreen.lightskyblue.lightslategray.lightsteelblue.lightyellow.lime.limegreen.linen.magenta.maroon.mediumaquamarine.mediumblue.mediumorchid.mediumpurple.mediumseagreen.mediumslateblue.mediumspringgreen.mediumturquoise.mediumvioletred.midnightblue.mintcream.mistyrose.moccasin.navajowhite.navy.oldlace.olive.olivedrab.orange.orangered.orchid.palegoldenrod.palegreen.paleturquoise.palevioletred.papayawhip.peachpuff.peru.pink.plum.powderblue.purple.rebeccapurple.red.rosybrown.royalblue.saddlebrown.salmon.sandybrown.seagreen.seashell.sienna.silver.skyblue.slateblue.slategray.snow.springgreen.steelblue.tan.teal.thistle.tomato.turquoise.violet.wheat.white.whitesmoke.yellow.yellowgreen`.split(`.`).map(e=>({type:`constant`,label:e}))),le=`a.abbr.address.article.aside.b.bdi.bdo.blockquote.body.br.button.canvas.caption.cite.code.col.colgroup.dd.del.details.dfn.dialog.div.dl.dt.em.figcaption.figure.footer.form.header.hgroup.h1.h2.h3.h4.h5.h6.hr.html.i.iframe.img.input.ins.kbd.label.legend.li.main.meter.nav.ol.output.p.pre.ruby.section.select.small.source.span.strong.sub.summary.sup.table.tbody.td.template.textarea.tfoot.th.thead.tr.u.ul`.split(`.`).map(e=>({type:`type`,label:e})),ue=[`@charset`,`@color-profile`,`@container`,`@counter-style`,`@font-face`,`@font-feature-values`,`@font-palette-values`,`@import`,`@keyframes`,`@layer`,`@media`,`@namespace`,`@page`,`@position-try`,`@property`,`@scope`,`@starting-style`,`@supports`,`@view-transition`].map(e=>({type:`keyword`,label:e})),q=/^(\w[\w-]*|-\w[\w-]*|)$/,de=/^-(-[\w-]*)?$/;function fe(e,t){if((e.name==`(`||e.type.isError)&&(e=e.parent||e),e.name!=`ArgList`)return!1;let n=e.parent?.firstChild;return n?.name==`Callee`?t.sliceString(n.from,n.to)==`var`:!1}var J=new n,pe=[`Declaration`];function me(e){for(let t=e;;){if(t.type.isTop)return t;if(!(t=t.parent))return e}}function Y(e,n,r){if(n.to-n.from>4096){let i=J.get(n);if(i)return i;let a=[],o=new Set,s=n.cursor(t.IncludeAnonymous);if(s.firstChild())do for(let t of Y(e,s.node,r))o.has(t.label)||(o.add(t.label),a.push(t));while(s.nextSibling());return J.set(n,a),a}else{let t=[],i=new Set;return n.cursor().iterate(n=>{if(r(n)&&n.matchContext(pe)&&n.node.nextSibling?.name==`:`){let r=e.sliceString(n.from,n.to);i.has(r)||(i.add(r),t.push({label:r,type:`variable`}))}}),t}}var X=e=>t=>{let{state:n,pos:r}=t,i=l(n).resolveInner(r,-1),a=i.type.isError&&i.from==i.to-1&&n.doc.sliceString(i.from,i.to)==`-`;if(i.name==`PropertyName`||(a||i.name==`TagName`)&&/^(Block|Styles)$/.test(i.resolve(i.to).name))return{from:i.from,options:W(),validFor:q};if(i.name==`ValueName`)return{from:i.from,options:K,validFor:q};if(i.name==`PseudoClassName`)return{from:i.from,options:G,validFor:q};if(e(i)||(t.explicit||a)&&fe(i,n.doc))return{from:e(i)||a?i.from:r,options:Y(n.doc,me(i),e),validFor:de};if(i.name==`TagName`){for(let{parent:e}=i;e;e=e.parent)if(e.name==`Block`)return{from:i.from,options:W(),validFor:q};return{from:i.from,options:le,validFor:q}}if(i.name==`AtKeyword`)return{from:i.from,options:ue,validFor:q};if(!t.explicit)return null;let o=i.resolve(r),s=o.childBefore(r);return s&&s.name==`:`&&o.name==`PseudoClassSelector`?{from:r,options:G,validFor:q}:s&&s.name==`:`&&o.name==`Declaration`||o.name==`ArgList`?{from:r,options:K,validFor:q}:o.name==`Block`||o.name==`Styles`?{from:r,options:W(),validFor:q}:null},Z=X(e=>e.name==`VariableName`),Q=ee.define({name:`css`,parser:V.configure({props:[s.add({Declaration:c()}),a.add({"Block KeyframeList":i})]}),languageData:{commentTokens:{block:{open:`/*`,close:`*/`}},indentOnInput:/^\s*\}$/,wordChars:`-`}});function $(){return new o(Q,Q.data.of({autocomplete:Z}))}export{Q as n,H as r,$ as t}; \ No newline at end of file +import{$ as e,C as t,D as n,b as r,d as i,f as a,i as o,m as s,s as c,t as ee,v as l,x as u}from"./index-CLJ0aycO.js";import{i as d,n as f,r as p}from"./dist-B2R-c1vX.js";var m=145,h=1,te=146,ne=147,g=2,_=148,v=3,re=4,y=[9,10,11,12,13,32,133,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288],b=58,x=40,S=95,ie=91,C=45,ae=46,oe=35,se=37,w=38,T=92,E=10,D=42;function O(e){return e>=65&&e<=90||e>=97&&e<=122||e>=161}function k(e){return e>=48&&e<=57}function A(e){return k(e)||e>=97&&e<=102||e>=65&&e<=70}var j=(e,t,n)=>(r,i)=>{for(let a=!1,o=0,s=0;;s++){let{next:c}=r;if(O(c)||c==C||c==S||a&&k(c))!a&&(c!=C||s>0)&&(a=!0),o===s&&c==C&&o++,r.advance();else if(c==T&&r.peek(1)!=E){if(r.advance(),A(r.next)){do r.advance();while(A(r.next));r.next==32&&r.advance()}else r.next>-1&&r.advance();a=!0}else{a&&r.acceptToken(o==2&&i.canShift(g)?t:c==x?n:e);break}}},M=new f(j(te,g,ne),{contextual:!0}),N=new f(j(_,v,re),{contextual:!0}),P=new f(e=>{if(y.includes(e.peek(-1))){let{next:t}=e;(O(t)||t==S||t==oe||t==ae||t==D||t==ie||t==b&&O(e.peek(1))||t==C||t==w)&&e.acceptToken(m)}}),F=new f(e=>{if(!y.includes(e.peek(-1))){let{next:t}=e;if(t==se&&(e.advance(),e.acceptToken(h)),O(t)){do e.advance();while(O(e.next)||k(e.next));e.acceptToken(h)}}}),I=r({"AtKeyword import charset namespace keyframes media supports font-feature-values":u.definitionKeyword,"from to selector scope MatchFlag":u.keyword,NamespaceName:u.namespace,KeyframeName:u.labelName,KeyframeRangeName:u.operatorKeyword,TagName:u.tagName,ClassName:u.className,PseudoClassName:u.constant(u.className),IdName:u.labelName,"FeatureName PropertyName":u.propertyName,AttributeName:u.attributeName,NumberLiteral:u.number,KeywordQuery:u.keyword,UnaryQueryOp:u.operatorKeyword,"CallTag ValueName FontName":u.atom,VariableName:u.variableName,Callee:u.operatorKeyword,Unit:u.unit,"UniversalSelector NestingSelector":u.definitionOperator,"MatchOp CompareOp":u.compareOperator,"ChildOp SiblingOp, LogicOp":u.logicOperator,BinOp:u.arithmeticOperator,Important:u.modifier,Comment:u.blockComment,ColorLiteral:u.color,"ParenthesizedContent StringLiteral":u.string,":":u.punctuation,"PseudoOp #":u.derefOperator,"; , |":u.separator,"( )":u.paren,"[ ]":u.squareBracket,"{ }":u.brace}),L={__proto__:null,lang:44,"nth-child":44,"nth-last-child":44,"nth-of-type":44,"nth-last-of-type":44,dir:44,"host-context":44,if:90,url:152,"url-prefix":152,domain:152,regexp:152},R={__proto__:null,or:104,and:104,not:112,only:112,layer:206},z={__proto__:null,selector:118,style:124,layer:202},ce={__proto__:null,"@import":198,"@media":210,"@charset":214,"@namespace":218,"@keyframes":224,"@supports":236,"@scope":240,"@font-feature-values":246},B={__proto__:null,to:243},V=p.deserialize({version:14,states:"MlQYQdOOO#}QdOOP$UO`OOO%OQaO'#CfOOQP'#Ce'#CeO%VQdO'#CgO%[Q`O'#CgO%aQaO'#FnO&XQdO'#CkO&xQaO'#CcO'SQdO'#CnO'_QdO'#EOO'dQdO'#EQO'oQdO'#EXO'oQdO'#E[OOQP'#Fn'#FnO)RQhO'#E}OOQS'#Fm'#FmOOQS'#FQ'#FQQYQdOOO)YQdO'#EbO*iQhO'#EhO)YQdO'#EjO*pQdO'#ElO*{QdO'#EoO)}QhO'#EuO+TQdO'#EwO+`QdO'#EzO+eQaO'#CfO+lQ`O'#E_O+qQ`O'#F{O+|QdO'#F{QOQ`OOP,WO&jO'#CaPOOO)CA])CA]OOQP'#Ci'#CiOOQP,59R,59RO%VQdO,59ROOQP'#Cm'#CmOOQP,59V,59VO&XQdO,59VO,cQdO,59YO'_QdO,5:jO'dQdO,5:lO'oQdO,5:sO'oQdO,5:uO'oQdO,5:vO'oQdO'#FXO,nQ`O,58}O,vQdO'#E^OOQS,58},58}OOQP'#Cq'#CqOOQO'#D|'#D|OOQP,59Y,59YO,}Q`O,59YO-SQ`O,59YOOQP'#EP'#EPOOQP,5:j,5:jO-XQpO'#ERO-dQdO'#ESO-iQ`O'#ESO-nQpO,5:lO.XQaO,5:sO.oQaO,5:vOOQW'#D^'#D^O/nQhO'#DgO0RQhO,5;iO)}QhO'#DeO0`Q`O'#DnO0eQhO'#DxOOQW'#Ft'#FtOOQS,5;i,5;iO0jQ`O'#DhO0oQ`O'#DkOOQS-E9O-E9OOOQ['#Cv'#CvO0tQdO'#CwO1[QdO'#C}O1rQdO'#DQO2YQ!pO'#DSO4fQ!jO,5:|OOQO'#DX'#DXO-SQ`O'#DWO4vQ!nO'#FqO6|Q`O'#DYO7RQ`O'#DyOOQ['#Fq'#FqO7WQhO'#GOO7fQ`O,5;SO7kQ!bO,5;UOOQS'#En'#EnO7sQ`O,5;WO7xQdO,5;WOOQO'#Eq'#EqO8QQ`O,5;ZO8VQhO,5;aO'oQdO'#DjOOQS,5;c,5;cO0jQ`O,5;cO8_QdO,5;cOOQS'#F`'#F`O8gQdO'#E|O7fQ`O,5;fO8oQdO,5:yO9PQdO'#FZO9^Q`O,5lQhO'#DoOOQW,5:Y,5:YOOQW,5:d,5:dOOQW,5:S,5:SO>vQhO,5:VO?bQ!fO'#FrOOQS'#Fr'#FrOOQS'#FS'#FSO@rQdO,59cOOQ[,59c,59cOAYQdO,59iOOQ[,59i,59iOApQdO,59lOOQ[,59l,59lOOQ[,59n,59nO)YQdO,59pOBWQhO'#EdOOQW'#Ed'#EdOBuQ`O1G0hO4oQhO1G0hOOQ[,59r,59rO)}QhO'#D[OOQ[,59t,59tOBzQ#tO,5:eOCVQhO'#F]OCdQ`O,5vQhO'#DmOI_QhO'#DqOIgQhO'#DsOIlQhO'#FwOOQO'#Fw'#FwOItQ!bO'#DwOOQO'#Fy'#FyOOQO'#Fv'#FvOIyQ`O1G/qOOQS-E9Q-E9QOOQ[1G.}1G.}OOQ[1G/T1G/TOOQ[1G/W1G/WOOQ[1G/[1G/[OJOQdO,5;OOOQS7+&S7+&SOJTQ`O7+&SOJYQhO'#D]OJbQ`O,59vO)}QhO,59vOOQ[1G0P1G0POJjQ`O1G0POJoQhO,5;wOOQO-E9Z-E9ZOOQS7+&^7+&^OJ}QbO'#DSOOQO'#Et'#EtOK]Q`O'#EsOOQO'#Es'#EsOKhQ`O'#F^OKpQdO,5;^OOQS,5;^,5;^OOQ[1G/p1G/pOOQS7+&i7+&iO7fQ`O7+&iOK{Q!fO'#FYO)YQdO'#FYOMSQdO7+&POOQO7+&P7+&POOQO,5:{,5:{OOQO1G1a1G1aOMgQ!bO<vQhO'#DrOOQO,5:],5:]O! hQhO,5:_OGUQhO,5:cOOQW7+%]7+%]OOQO'#Ef'#EfO! pQ`O1G0jOOQS<xAN>xO!#zQ`OAN>xO!$PQaO,5;rOOQO-E9U-E9UO!$ZQdO,5;qOOQO-E9T-E9TOOQW<vQhO'#DuOOQO1G/y1G/yO!%vQ!bO1G/}OJOQdO'#F[O!&OQ`O7+&UOOQW7+&U7+&UO!&WQ!bO1G/cOOQ[7+$|7+$|O!&cQhO7+$|P!&jQ`O'#FTOOQO,5;y,5;yOOQO-E9]-E9]OOQS1G1d1G1dOOQPG24dG24dO!&oQ`OAN>ZO)YQdO1G1[O!&tQ`O7+'jOOQO1G/x1G/xO!&|Q`O,5:aO!$eQhO7+%iOOQO,5;v,5;vOOQO-E9Y-E9YOOQW<Q!]!^>|!^!_?_!_!`@Z!`!a@n!a!b%Z!b!cAo!c!k%Z!k!lC|!l!u%Z!u!vC|!v!}%Z!}#OD_#O#P%Z#P#QDp#Q#R2X#R#]%Z#]#^ER#^#g%Z#g#hC|#h#o%Z#o#pIf#p#qIw#q#rJ`#r#sJq#s#y%Z#y#z&R#z$f%Z$f$g&R$g#BY%Z#BY#BZ&R#BZ$IS%Z$IS$I_&R$I_$I|%Z$I|$JO&R$JO$JT%Z$JT$JU&R$JU$KV%Z$KV$KW&R$KW&FU%Z&FU&FV&R&FV;'S%Z;'S;=`KY<%lO%Z`%^SOy%jz;'S%j;'S;=`%{<%lO%j`%oS!o`Oy%jz;'S%j;'S;=`%{<%lO%j`&OP;=`<%l%j~&Wh$[~OX%jX^'r^p%jpq'rqy%jz#y%j#y#z'r#z$f%j$f$g'r$g#BY%j#BY#BZ'r#BZ$IS%j$IS$I_'r$I_$I|%j$I|$JO'r$JO$JT%j$JT$JU'r$JU$KV%j$KV$KW'r$KW&FU%j&FU&FV'r&FV;'S%j;'S;=`%{<%lO%j~'yh$[~!o`OX%jX^'r^p%jpq'rqy%jz#y%j#y#z'r#z$f%j$f$g'r$g#BY%j#BY#BZ'r#BZ$IS%j$IS$I_'r$I_$I|%j$I|$JO'r$JO$JT%j$JT$JU'r$JU$KV%j$KV$KW'r$KW&FU%j&FU&FV'r&FV;'S%j;'S;=`%{<%lO%jj)jS$qYOy%jz;'S%j;'S;=`%{<%lO%j~)yWOY)vZr)vrs*cs#O)v#O#P*h#P;'S)v;'S;=`+d<%lO)v~*hOw~~*kRO;'S)v;'S;=`*t;=`O)v~*wXOY)vZr)vrs*cs#O)v#O#P*h#P;'S)v;'S;=`+d;=`<%l)v<%lO)v~+gP;=`<%l)vj+oYmYOy%jz!Q%j!Q![,_![!c%j!c!i,_!i#T%j#T#Z,_#Z;'S%j;'S;=`%{<%lO%jj,dY!o`Oy%jz!Q%j!Q![-S![!c%j!c!i-S!i#T%j#T#Z-S#Z;'S%j;'S;=`%{<%lO%jj-XY!o`Oy%jz!Q%j!Q![-w![!c%j!c!i-w!i#T%j#T#Z-w#Z;'S%j;'S;=`%{<%lO%jj.OYuY!o`Oy%jz!Q%j!Q![.n![!c%j!c!i.n!i#T%j#T#Z.n#Z;'S%j;'S;=`%{<%lO%jj.uYuY!o`Oy%jz!Q%j!Q![/e![!c%j!c!i/e!i#T%j#T#Z/e#Z;'S%j;'S;=`%{<%lO%jj/jY!o`Oy%jz!Q%j!Q![0Y![!c%j!c!i0Y!i#T%j#T#Z0Y#Z;'S%j;'S;=`%{<%lO%jj0aYuY!o`Oy%jz!Q%j!Q![1P![!c%j!c!i1P!i#T%j#T#Z1P#Z;'S%j;'S;=`%{<%lO%jj1UY!o`Oy%jz!Q%j!Q![1t![!c%j!c!i1t!i#T%j#T#Z1t#Z;'S%j;'S;=`%{<%lO%jj1{SuY!o`Oy%jz;'S%j;'S;=`%{<%lO%jd2[UOy%jz!_%j!_!`2n!`;'S%j;'S;=`%{<%lO%jd2uS!yS!o`Oy%jz;'S%j;'S;=`%{<%lO%jb3WS^QOy%jz;'S%j;'S;=`%{<%lO%j~3gWOY3dZw3dwx*cx#O3d#O#P4P#P;'S3d;'S;=`4{<%lO3d~4SRO;'S3d;'S;=`4];=`O3d~4`XOY3dZw3dwx*cx#O3d#O#P4P#P;'S3d;'S;=`4{;=`<%l3d<%lO3d~5OP;=`<%l3dj5WShYOy%jz;'S%j;'S;=`%{<%lO%j~5iOg~n5pUWQyWOy%jz!_%j!_!`2n!`;'S%j;'S;=`%{<%lO%jj6ZWyW#PQOy%jz!O%j!O!P6s!P!Q%j!Q![9x![;'S%j;'S;=`%{<%lO%jj6xU!o`Oy%jz!Q%j!Q![7[![;'S%j;'S;=`%{<%lO%jj7cY!o`$gYOy%jz!Q%j!Q![7[![!g%j!g!h8R!h#X%j#X#Y8R#Y;'S%j;'S;=`%{<%lO%jj8WY!o`Oy%jz{%j{|8v|}%j}!O8v!O!Q%j!Q![9_![;'S%j;'S;=`%{<%lO%jj8{U!o`Oy%jz!Q%j!Q![9_![;'S%j;'S;=`%{<%lO%jj9fU!o`$gYOy%jz!Q%j!Q![9_![;'S%j;'S;=`%{<%lO%jj:P[!o`$gYOy%jz!O%j!O!P7[!P!Q%j!Q![9x![!g%j!g!h8R!h#X%j#X#Y8R#Y;'S%j;'S;=`%{<%lO%jj:zS!dYOy%jz;'S%j;'S;=`%{<%lO%jj;]WyWOy%jz!O%j!O!P6s!P!Q%j!Q![9x![;'S%j;'S;=`%{<%lO%jj;zU`YOy%jz!Q%j!Q![7[![;'S%j;'S;=`%{<%lO%j~VUcYOy%jz![%j![!]>i!];'S%j;'S;=`%{<%lO%jj>pSdY!o`Oy%jz;'S%j;'S;=`%{<%lO%jj?RSnYOy%jz;'S%j;'S;=`%{<%lO%jh?dU!WWOy%jz!_%j!_!`?v!`;'S%j;'S;=`%{<%lO%jh?}S!WW!o`Oy%jz;'S%j;'S;=`%{<%lO%jl@bS!WW!ySOy%jz;'S%j;'S;=`%{<%lO%jj@uV!|Q!WWOy%jz!_%j!_!`?v!`!aA[!a;'S%j;'S;=`%{<%lO%jbAcS!|Q!o`Oy%jz;'S%j;'S;=`%{<%lO%jjArYOy%jz}%j}!OBb!O!c%j!c!}CP!}#T%j#T#oCP#o;'S%j;'S;=`%{<%lO%jjBgW!o`Oy%jz!c%j!c!}CP!}#T%j#T#oCP#o;'S%j;'S;=`%{<%lO%jjCW[lY!o`Oy%jz}%j}!OCP!O!Q%j!Q![CP![!c%j!c!}CP!}#T%j#T#oCP#o;'S%j;'S;=`%{<%lO%jhDRS!zWOy%jz;'S%j;'S;=`%{<%lO%jjDdSpYOy%jz;'S%j;'S;=`%{<%lO%jnDuSo^Oy%jz;'S%j;'S;=`%{<%lO%jjEWU!zWOy%jz#a%j#a#bEj#b;'S%j;'S;=`%{<%lO%jbEoU!o`Oy%jz#d%j#d#eFR#e;'S%j;'S;=`%{<%lO%jbFWU!o`Oy%jz#c%j#c#dFj#d;'S%j;'S;=`%{<%lO%jbFoU!o`Oy%jz#f%j#f#gGR#g;'S%j;'S;=`%{<%lO%jbGWU!o`Oy%jz#h%j#h#iGj#i;'S%j;'S;=`%{<%lO%jbGoU!o`Oy%jz#T%j#T#UHR#U;'S%j;'S;=`%{<%lO%jbHWU!o`Oy%jz#b%j#b#cHj#c;'S%j;'S;=`%{<%lO%jbHoU!o`Oy%jz#h%j#h#iIR#i;'S%j;'S;=`%{<%lO%jbIYS$pQ!o`Oy%jz;'S%j;'S;=`%{<%lO%jjIkSsYOy%jz;'S%j;'S;=`%{<%lO%jfI|U$cUOy%jz!_%j!_!`2n!`;'S%j;'S;=`%{<%lO%jjJeSrYOy%jz;'S%j;'S;=`%{<%lO%jfJvU#PQOy%jz!_%j!_!`2n!`;'S%j;'S;=`%{<%lO%j`K]P;=`<%l%Z",tokenizers:[P,F,M,N,1,2,3,4,new d("m~RRYZ[z{a~~g~aO$_~~dP!P!Qg~lO$`~~",28,152)],topRules:{StyleSheet:[0,6],Styles:[1,126]},dynamicPrecedences:{94:1},specialized:[{term:147,get:e=>L[e]||-1},{term:148,get:e=>R[e]||-1},{term:4,get:e=>z[e]||-1},{term:28,get:e=>ce[e]||-1},{term:146,get:e=>B[e]||-1}],tokenPrec:2405}),H=e({css:()=>$,cssCompletionSource:()=>Z,cssLanguage:()=>Q,defineCSSCompletionSource:()=>X}),U=null;function W(){if(!U&&typeof document==`object`&&document.body){let{style:e}=document.body,t=[],n=new Set;for(let r in e)r!=`cssText`&&r!=`cssFloat`&&typeof e[r]==`string`&&(/[A-Z]/.test(r)&&(r=r.replace(/[A-Z]/g,e=>`-`+e.toLowerCase())),n.has(r)||(t.push(r),n.add(r)));U=t.sort().map(e=>({type:`property`,label:e,apply:e+`: `}))}return U||[]}var G=`active.after.any-link.autofill.backdrop.before.checked.cue.default.defined.disabled.empty.enabled.file-selector-button.first.first-child.first-letter.first-line.first-of-type.focus.focus-visible.focus-within.fullscreen.has.host.host-context.hover.in-range.indeterminate.invalid.is.lang.last-child.last-of-type.left.link.marker.modal.not.nth-child.nth-last-child.nth-last-of-type.nth-of-type.only-child.only-of-type.optional.out-of-range.part.placeholder.placeholder-shown.read-only.read-write.required.right.root.scope.selection.slotted.target.target-text.valid.visited.where`.split(`.`).map(e=>({type:`class`,label:e})),K=`above.absolute.activeborder.additive.activecaption.after-white-space.ahead.alias.all.all-scroll.alphabetic.alternate.always.antialiased.appworkspace.asterisks.attr.auto.auto-flow.avoid.avoid-column.avoid-page.avoid-region.axis-pan.background.backwards.baseline.below.bidi-override.blink.block.block-axis.bold.bolder.border.border-box.both.bottom.break.break-all.break-word.bullets.button.button-bevel.buttonface.buttonhighlight.buttonshadow.buttontext.calc.capitalize.caps-lock-indicator.caption.captiontext.caret.cell.center.checkbox.circle.cjk-decimal.clear.clip.close-quote.col-resize.collapse.color.color-burn.color-dodge.column.column-reverse.compact.condensed.contain.content.contents.content-box.context-menu.continuous.copy.counter.counters.cover.crop.cross.crosshair.currentcolor.cursive.cyclic.darken.dashed.decimal.decimal-leading-zero.default.default-button.dense.destination-atop.destination-in.destination-out.destination-over.difference.disc.discard.disclosure-closed.disclosure-open.document.dot-dash.dot-dot-dash.dotted.double.down.e-resize.ease.ease-in.ease-in-out.ease-out.element.ellipse.ellipsis.embed.end.ethiopic-abegede-gez.ethiopic-halehame-aa-er.ethiopic-halehame-gez.ew-resize.exclusion.expanded.extends.extra-condensed.extra-expanded.fantasy.fast.fill.fill-box.fixed.flat.flex.flex-end.flex-start.footnotes.forwards.from.geometricPrecision.graytext.grid.groove.hand.hard-light.help.hidden.hide.higher.highlight.highlighttext.horizontal.hsl.hsla.hue.icon.ignore.inactiveborder.inactivecaption.inactivecaptiontext.infinite.infobackground.infotext.inherit.initial.inline.inline-axis.inline-block.inline-flex.inline-grid.inline-table.inset.inside.intrinsic.invert.italic.justify.keep-all.landscape.large.larger.left.level.lighter.lighten.line-through.linear.linear-gradient.lines.list-item.listbox.listitem.local.logical.loud.lower.lower-hexadecimal.lower-latin.lower-norwegian.lowercase.ltr.luminosity.manipulation.match.matrix.matrix3d.medium.menu.menutext.message-box.middle.min-intrinsic.mix.monospace.move.multiple.multiple_mask_images.multiply.n-resize.narrower.ne-resize.nesw-resize.no-close-quote.no-drop.no-open-quote.no-repeat.none.normal.not-allowed.nowrap.ns-resize.numbers.numeric.nw-resize.nwse-resize.oblique.opacity.open-quote.optimizeLegibility.optimizeSpeed.outset.outside.outside-shape.overlay.overline.padding.padding-box.painted.page.paused.perspective.pinch-zoom.plus-darker.plus-lighter.pointer.polygon.portrait.pre.pre-line.pre-wrap.preserve-3d.progress.push-button.radial-gradient.radio.read-only.read-write.read-write-plaintext-only.rectangle.region.relative.repeat.repeating-linear-gradient.repeating-radial-gradient.repeat-x.repeat-y.reset.reverse.rgb.rgba.ridge.right.rotate.rotate3d.rotateX.rotateY.rotateZ.round.row.row-resize.row-reverse.rtl.run-in.running.s-resize.sans-serif.saturation.scale.scale3d.scaleX.scaleY.scaleZ.screen.scroll.scrollbar.scroll-position.se-resize.self-start.self-end.semi-condensed.semi-expanded.separate.serif.show.single.skew.skewX.skewY.skip-white-space.slide.slider-horizontal.slider-vertical.sliderthumb-horizontal.sliderthumb-vertical.slow.small.small-caps.small-caption.smaller.soft-light.solid.source-atop.source-in.source-out.source-over.space.space-around.space-between.space-evenly.spell-out.square.start.static.status-bar.stretch.stroke.stroke-box.sub.subpixel-antialiased.svg_masks.super.sw-resize.symbolic.symbols.system-ui.table.table-caption.table-cell.table-column.table-column-group.table-footer-group.table-header-group.table-row.table-row-group.text.text-bottom.text-top.textarea.textfield.thick.thin.threeddarkshadow.threedface.threedhighlight.threedlightshadow.threedshadow.to.top.transform.translate.translate3d.translateX.translateY.translateZ.transparent.ultra-condensed.ultra-expanded.underline.unidirectional-pan.unset.up.upper-latin.uppercase.url.var.vertical.vertical-text.view-box.visible.visibleFill.visiblePainted.visibleStroke.visual.w-resize.wait.wave.wider.window.windowframe.windowtext.words.wrap.wrap-reverse.x-large.x-small.xor.xx-large.xx-small`.split(`.`).map(e=>({type:`keyword`,label:e})).concat(`aliceblue.antiquewhite.aqua.aquamarine.azure.beige.bisque.black.blanchedalmond.blue.blueviolet.brown.burlywood.cadetblue.chartreuse.chocolate.coral.cornflowerblue.cornsilk.crimson.cyan.darkblue.darkcyan.darkgoldenrod.darkgray.darkgreen.darkkhaki.darkmagenta.darkolivegreen.darkorange.darkorchid.darkred.darksalmon.darkseagreen.darkslateblue.darkslategray.darkturquoise.darkviolet.deeppink.deepskyblue.dimgray.dodgerblue.firebrick.floralwhite.forestgreen.fuchsia.gainsboro.ghostwhite.gold.goldenrod.gray.grey.green.greenyellow.honeydew.hotpink.indianred.indigo.ivory.khaki.lavender.lavenderblush.lawngreen.lemonchiffon.lightblue.lightcoral.lightcyan.lightgoldenrodyellow.lightgray.lightgreen.lightpink.lightsalmon.lightseagreen.lightskyblue.lightslategray.lightsteelblue.lightyellow.lime.limegreen.linen.magenta.maroon.mediumaquamarine.mediumblue.mediumorchid.mediumpurple.mediumseagreen.mediumslateblue.mediumspringgreen.mediumturquoise.mediumvioletred.midnightblue.mintcream.mistyrose.moccasin.navajowhite.navy.oldlace.olive.olivedrab.orange.orangered.orchid.palegoldenrod.palegreen.paleturquoise.palevioletred.papayawhip.peachpuff.peru.pink.plum.powderblue.purple.rebeccapurple.red.rosybrown.royalblue.saddlebrown.salmon.sandybrown.seagreen.seashell.sienna.silver.skyblue.slateblue.slategray.snow.springgreen.steelblue.tan.teal.thistle.tomato.turquoise.violet.wheat.white.whitesmoke.yellow.yellowgreen`.split(`.`).map(e=>({type:`constant`,label:e}))),le=`a.abbr.address.article.aside.b.bdi.bdo.blockquote.body.br.button.canvas.caption.cite.code.col.colgroup.dd.del.details.dfn.dialog.div.dl.dt.em.figcaption.figure.footer.form.header.hgroup.h1.h2.h3.h4.h5.h6.hr.html.i.iframe.img.input.ins.kbd.label.legend.li.main.meter.nav.ol.output.p.pre.ruby.section.select.small.source.span.strong.sub.summary.sup.table.tbody.td.template.textarea.tfoot.th.thead.tr.u.ul`.split(`.`).map(e=>({type:`type`,label:e})),ue=[`@charset`,`@color-profile`,`@container`,`@counter-style`,`@font-face`,`@font-feature-values`,`@font-palette-values`,`@import`,`@keyframes`,`@layer`,`@media`,`@namespace`,`@page`,`@position-try`,`@property`,`@scope`,`@starting-style`,`@supports`,`@view-transition`].map(e=>({type:`keyword`,label:e})),q=/^(\w[\w-]*|-\w[\w-]*|)$/,de=/^-(-[\w-]*)?$/;function fe(e,t){if((e.name==`(`||e.type.isError)&&(e=e.parent||e),e.name!=`ArgList`)return!1;let n=e.parent?.firstChild;return n?.name==`Callee`?t.sliceString(n.from,n.to)==`var`:!1}var J=new n,pe=[`Declaration`];function me(e){for(let t=e;;){if(t.type.isTop)return t;if(!(t=t.parent))return e}}function Y(e,n,r){if(n.to-n.from>4096){let i=J.get(n);if(i)return i;let a=[],o=new Set,s=n.cursor(t.IncludeAnonymous);if(s.firstChild())do for(let t of Y(e,s.node,r))o.has(t.label)||(o.add(t.label),a.push(t));while(s.nextSibling());return J.set(n,a),a}else{let t=[],i=new Set;return n.cursor().iterate(n=>{if(r(n)&&n.matchContext(pe)&&n.node.nextSibling?.name==`:`){let r=e.sliceString(n.from,n.to);i.has(r)||(i.add(r),t.push({label:r,type:`variable`}))}}),t}}var X=e=>t=>{let{state:n,pos:r}=t,i=l(n).resolveInner(r,-1),a=i.type.isError&&i.from==i.to-1&&n.doc.sliceString(i.from,i.to)==`-`;if(i.name==`PropertyName`||(a||i.name==`TagName`)&&/^(Block|Styles)$/.test(i.resolve(i.to).name))return{from:i.from,options:W(),validFor:q};if(i.name==`ValueName`)return{from:i.from,options:K,validFor:q};if(i.name==`PseudoClassName`)return{from:i.from,options:G,validFor:q};if(e(i)||(t.explicit||a)&&fe(i,n.doc))return{from:e(i)||a?i.from:r,options:Y(n.doc,me(i),e),validFor:de};if(i.name==`TagName`){for(let{parent:e}=i;e;e=e.parent)if(e.name==`Block`)return{from:i.from,options:W(),validFor:q};return{from:i.from,options:le,validFor:q}}if(i.name==`AtKeyword`)return{from:i.from,options:ue,validFor:q};if(!t.explicit)return null;let o=i.resolve(r),s=o.childBefore(r);return s&&s.name==`:`&&o.name==`PseudoClassSelector`?{from:r,options:G,validFor:q}:s&&s.name==`:`&&o.name==`Declaration`||o.name==`ArgList`?{from:r,options:K,validFor:q}:o.name==`Block`||o.name==`Styles`?{from:r,options:W(),validFor:q}:null},Z=X(e=>e.name==`VariableName`),Q=ee.define({name:`css`,parser:V.configure({props:[s.add({Declaration:c()}),a.add({"Block KeyframeList":i})]}),languageData:{commentTokens:{block:{open:`/*`,close:`*/`}},indentOnInput:/^\s*\}$/,wordChars:`-`}});function $(){return new o(Q,Q.data.of({autocomplete:Z}))}export{Q as n,H as r,$ as t}; \ No newline at end of file diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/dist-BMmyzswS.js b/mcp/src/agents_remember/package_data/dashboard/assets/dist-BiIHlEw9.js similarity index 99% rename from mcp/src/agents_remember/package_data/dashboard/assets/dist-BMmyzswS.js rename to mcp/src/agents_remember/package_data/dashboard/assets/dist-BiIHlEw9.js index d0596588..64c7b64e 100644 --- a/mcp/src/agents_remember/package_data/dashboard/assets/dist-BMmyzswS.js +++ b/mcp/src/agents_remember/package_data/dashboard/assets/dist-BiIHlEw9.js @@ -1,4 +1,4 @@ -import{C as e,D as t,b as n,d as r,f as i,i as a,l as o,m as s,t as ee,v as te,x as c}from"./index-BLlkJI-k.js";import{n as l,r as ne,t as re}from"./dist-CuvUDais.js";import{i as u,n as ie,r as ae}from"./dist-DeLSDQE4.js";var oe=1,d=194,f=195,se=196,p=197,ce=198,le=199,ue=200,de=2,m=3,h=201,g=24,fe=25,pe=49,me=50,he=55,ge=56,_e=57,ve=59,ye=60,be=61,xe=62,Se=63,Ce=65,we=238,Te=71,Ee=241,De=242,Oe=243,ke=244,Ae=245,_=246,v=247,y=248,b=72,x=249,S=250,C=251,je=252,Me=253,Ne=254,Pe=255,Fe=256,Ie=73,Le=77,Re=263,ze=112,Be=130,Ve=151,He=152,Ue=155,w=10,T=13,E=32,D=9,O=35,We=40,Ge=46,k=123,A=125,j=39,M=34,N=92,Ke=111,P=120,qe=78,Je=117,Ye=85,Xe=new Set([fe,pe,me,Re,Ce,Be,ge,_e,we,xe,Se,b,Ie,Le,ye,be,Ve,He,Ue,ze]);function F(e){return e==w||e==T}function I(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}var Ze=new l((e,t)=>{let n;if(e.next<0)e.acceptToken(le);else if(t.context.flags&L)F(e.next)&&e.acceptToken(ce,1);else if(((n=e.peek(-1))<0||F(n))&&t.canShift(p)){let t=0;for(;e.next==E||e.next==D;)e.advance(),t++;(e.next==w||e.next==T||e.next==O)&&e.acceptToken(p,-t)}else F(e.next)&&e.acceptToken(se,1)},{contextual:!0}),Qe=new l((e,t)=>{let n=t.context;if(n.flags)return;let r=e.peek(-1);if(r==w||r==T){let t=0,r=0;for(;;){if(e.next==E)t++;else if(e.next==D)t+=8-t%8;else break;e.advance(),r++}t!=n.indent&&e.next!=w&&e.next!=T&&e.next!=O&&(t[e,t|R])),tt=new re({start:$e,reduce(e,t,n,r){return e.flags&L&&Xe.has(t)||(t==Te||t==b)&&e.flags&R?e.parent:e},shift(e,t,n,r){return t==d?new U(e,et(r.read(r.pos,n.pos)),0):t==f?e.parent:t==g||t==he||t==ve||t==m?new U(e,0,L):W.has(t)?new U(e,0,W.get(t)|e.flags&L):e},hash(e){return e.hash}}),nt=new l(e=>{for(let t=0;t<5;t++){if(e.next!=`print`.charCodeAt(t))return;e.advance()}if(!/\w/.test(String.fromCharCode(e.next)))for(let t=0;;t++){let n=e.peek(t);if(!(n==E||n==D)){n!=We&&n!=Ge&&n!=w&&n!=T&&n!=O&&e.acceptToken(oe);return}}}),rt=new l((e,t)=>{let{flags:n}=t.context,r=n&z?M:j,i=(n&B)>0,a=!(n&V),o=(n&H)>0,s=e.pos;for(;!(e.next<0);)if(o&&e.next==k)if(e.peek(1)==k)e.advance(2);else{if(e.pos==s){e.acceptToken(m,1);return}break}else if(a&&e.next==N){if(e.pos==s){e.advance();let t=e.next;t>=0&&(e.advance(),it(e,t)),e.acceptToken(de);return}break}else if(e.next==N&&!a&&e.peek(1)>-1)e.advance(2);else if(e.next==r&&(!i||e.peek(1)==r&&e.peek(2)==r)){if(e.pos==s){e.acceptToken(h,i?3:1);return}break}else if(e.next==w){if(i)e.advance();else if(e.pos==s){e.acceptToken(h);return}break}else e.advance();e.pos>s&&e.acceptToken(ue)});function it(e,t){if(t==Ke)for(let t=0;t<2&&e.next>=48&&e.next<=55;t++)e.advance();else if(t==P)for(let t=0;t<2&&I(e.next);t++)e.advance();else if(t==Je)for(let t=0;t<4&&I(e.next);t++)e.advance();else if(t==Ye)for(let t=0;t<8&&I(e.next);t++)e.advance();else if(t==qe&&e.next==k){for(e.advance();e.next>=0&&e.next!=A&&e.next!=j&&e.next!=M&&e.next!=w;)e.advance();e.next==A&&e.advance()}}var at=n({'async "*" "**" FormatConversion FormatSpec':c.modifier,"for while if elif else try except finally return raise break continue with pass assert await yield match case":c.controlKeyword,"in not and or is del":c.operatorKeyword,"from def class global nonlocal lambda":c.definitionKeyword,import:c.moduleKeyword,"with as print":c.keyword,Boolean:c.bool,None:c.null,VariableName:c.variableName,"CallExpression/VariableName":c.function(c.variableName),"FunctionDefinition/VariableName":c.function(c.definition(c.variableName)),"ClassDefinition/VariableName":c.definition(c.className),PropertyName:c.propertyName,"CallExpression/MemberExpression/PropertyName":c.function(c.propertyName),Comment:c.lineComment,Number:c.number,String:c.string,FormatString:c.special(c.string),Escape:c.escape,UpdateOp:c.updateOperator,"ArithOp!":c.arithmeticOperator,BitOp:c.bitwiseOperator,CompareOp:c.compareOperator,AssignOp:c.definitionOperator,Ellipsis:c.punctuation,At:c.meta,"( )":c.paren,"[ ]":c.squareBracket,"{ }":c.brace,".":c.derefOperator,", ;":c.separator}),ot={__proto__:null,await:44,or:54,and:56,in:60,not:62,is:64,if:70,else:72,lambda:76,yield:94,from:96,async:102,for:104,None:162,True:164,False:164,del:178,pass:182,break:186,continue:190,return:194,raise:202,import:206,as:208,global:212,nonlocal:214,assert:218,type:223,elif:236,while:240,try:246,except:248,finally:250,with:254,def:258,class:268,match:279,case:285},st=ne.deserialize({version:14,states:"##jQ`QeOOP$}OSOOO&WQtO'#HUOOQS'#Co'#CoOOQS'#Cp'#CpO'vQdO'#CnO*UQtO'#HTOOQS'#HU'#HUOOQS'#DU'#DUOOQS'#HT'#HTO*rQdO'#D_O+VQdO'#DfO+gQdO'#DjO+zOWO'#DuO,VOWO'#DvO.[QtO'#GuOOQS'#Gu'#GuO'vQdO'#GtO0ZQtO'#GtOOQS'#Eb'#EbO0rQdO'#EcOOQS'#Gs'#GsO0|QdO'#GrOOQV'#Gr'#GrO1XQdO'#FYOOQS'#G^'#G^O1^QdO'#FXOOQV'#IS'#ISOOQV'#Gq'#GqOOQV'#Fq'#FqQ`QeOOO'vQdO'#CqO1lQdO'#C}O1sQdO'#DRO2RQdO'#HYO2cQtO'#EVO'vQdO'#EWOOQS'#EY'#EYOOQS'#E['#E[OOQS'#E^'#E^O2wQdO'#E`O3_QdO'#EdO3rQdO'#EfO3zQtO'#EfO1XQdO'#EiO0rQdO'#ElO1XQdO'#EnO0rQdO'#EtO0rQdO'#EwO4VQdO'#EyO4^QdO'#FOO4iQdO'#EzO0rQdO'#FOO1XQdO'#FQO1XQdO'#FVO4nQdO'#F[P4uOdO'#GpPOOO)CBd)CBdOOQS'#Ce'#CeOOQS'#Cf'#CfOOQS'#Cg'#CgOOQS'#Ch'#ChOOQS'#Ci'#CiOOQS'#Cj'#CjOOQS'#Cl'#ClO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO5TQdO'#DoOOQS,5:Y,5:YO5hQdO'#HdOOQS,5:],5:]O5uQ!fO,5:]O5zQtO,59YO1lQdO,59bO1lQdO,59bO1lQdO,59bO8jQdO,59bO8oQdO,59bO8vQdO,59jO8}QdO'#HTO:TQdO'#HSOOQS'#HS'#HSOOQS'#D['#D[O:lQdO,59aO'vQdO,59aO:zQdO,59aOOQS,59y,59yO;PQdO,5:RO'vQdO,5:ROOQS,5:Q,5:QO;_QdO,5:QO;dQdO,5:XO'vQdO,5:XO'vQdO,5:VOOQS,5:U,5:UO;uQdO,5:UO;zQdO,5:WOOOW'#Fy'#FyOOOOQS'#Ds'#DsOOQS1G/w1G/wOOQS1G.|1G.|O!/[QtO1G.|O!/cQtO1G.|O1lQdO1G.|O!0OQdO1G/UOOQS'#DZ'#DZO0rQdO,59tOOQS1G.{1G.{O!0VQdO1G/eO!0gQdO1G/eO!0oQdO1G/fO'vQdO'#H[O!0tQdO'#H[O!0yQtO1G.{O!1ZQdO,59iO!2aQdO,5=zO!2qQdO,5=zO!2yQdO1G/mO!3OQtO1G/mOOQS1G/l1G/lO!3`QdO,5=uO!4VQdO,5=uO0rQdO1G/qO!4tQdO1G/sO!4yQtO1G/sO!5ZQtO1G/qOOQS1G/p1G/pOOQS1G/r1G/rOOOW-E9w-E9wOOQS1G/{1G/{O!5kQdO'#HxO0rQdO'#HxO!5|QdO,5>cOOOW-E9x-E9xOOQS1G/|1G/|OOQS-E9{-E9{O!6[Q#xO1G2zO!6{QtO1G2zO'vQdO,5kOOQS1G1`1G1`O!8RQdO1G1`OOQS'#DV'#DVO0rQdO,5=qOOQS,5=q,5=qO!8WQdO'#FrO!8cQdO,59oO!8kQdO1G/XO!8uQtO,5=uOOQS1G3`1G3`OOQS,5:m,5:mO!9fQdO'#GtOOQS,5jO!;ZQdO,5>jO1XQdO,5>jO!;lQdO,5>iOOQS-E:R-E:RO!;qQdO1G0lO!;|QdO1G0lO!lO!lO!hO!=VQdO,5>hO!=hQdO'#EpO0rQdO1G0tO!=sQdO1G0tO!=xQgO1G0zO!AvQgO1G0}O!EqQdO,5>oO!E{QdO,5>oO!FTQtO,5>oO0rQdO1G1PO!F_QdO1G1PO4iQdO1G1UO!!vQdO1G1WOOQV,5;a,5;aO!FdQfO,5;aO!FiQgO1G1QO!JjQdO'#GZO4iQdO1G1QO4iQdO1G1QO!JzQdO,5>pO!KXQdO,5>pO1XQdO,5>pOOQV1G1U1G1UO!KaQdO'#FSO!KrQ!fO1G1WO!KzQdO1G1WOOQV1G1]1G1]O4iQdO1G1]O!LPQdO1G1]O!LXQdO'#F^OOQV1G1b1G1bO!#ZQtO1G1bPOOO1G2v1G2vP!L^OSO1G2vOOQS,5=},5=}OOQS'#Dp'#DpO0rQdO,5=}O!LfQdO,5=|O!LyQdO,5=|OOQS1G/u1G/uO!MRQdO,5>PO!McQdO,5>PO!MkQdO,5>PO!NOQdO,5>PO!N`QdO,5>POOQS1G3j1G3jOOQS7+$h7+$hO!8kQdO7+$pO#!RQdO1G.|O#!YQdO1G.|OOQS1G/`1G/`OOQS,5<`,5<`O'vQdO,5<`OOQS7+%P7+%PO#!aQdO7+%POOQS-E9r-E9rOOQS7+%Q7+%QO#!qQdO,5=vO'vQdO,5=vOOQS7+$g7+$gO#!vQdO7+%PO##OQdO7+%QO##TQdO1G3fOOQS7+%X7+%XO##eQdO1G3fO##mQdO7+%XOOQS,5<_,5<_O'vQdO,5<_O##rQdO1G3aOOQS-E9q-E9qO#$iQdO7+%]OOQS7+%_7+%_O#$wQdO1G3aO#%fQdO7+%_O#%kQdO1G3gO#%{QdO1G3gO#&TQdO7+%]O#&YQdO,5>dO#&sQdO,5>dO#&sQdO,5>dOOQS'#Dx'#DxO#'UO&jO'#DzO#'aO`O'#HyOOOW1G3}1G3}O#'fQdO1G3}O#'nQdO1G3}O#'yQ#xO7+(fO#(jQtO1G2UP#)TQdO'#GOOOQS,5nQdO,5sQdO1G4OOOQS-E9y-E9yO#?^QdO1G4OO<[QdO'#H{OOOO'#D{'#D{OOOO'#F|'#F|O#?oO&jO,5:fOOOW,5>e,5>eOOOW7+)i7+)iO#?zQdO7+)iO#@SQdO1G2zO#@mQdO1G2zP'vQdO'#FuO0rQdO<mO#BQQdO,5>mOOQS1G0v1G0vOOQS<rO#KgQdO,5>rO#KrQdO,5>rO#K}QdO,5>qO#L`QdO,5>qOOQS1G1Y1G1YOOQS,5;p,5;pOOQV<VAN>VO$ oQdO<cAN>cO0rQdO1G1|O$!PQtO1G1|P$!ZQdO'#FvOOQS1G2R1G2RP$!hQdO'#F{O$!uQdO7+)jO$#`QdO,5>gOOOO-E9z-E9zOOOW<tO$4{QdO,5>tO1XQdO,5vO$)nQdO,5>vOOQS1G1p1G1pOOQS,5<[,5<[OOQU7+'P7+'PO$+zQdO1G/iO$)nQdO,5wO$8zQdO,5>wOOQS1G1s1G1sOOQS7+'S7+'SP$)nQdO'#GdO$9SQdO1G4bO$9^QdO1G4bO$9fQdO1G4bOOQS7+%T7+%TO$9tQdO1G1tO$:SQtO'#FaO$:ZQdO,5<}OOQS,5<},5<}O$:iQdO1G4cOOQS-E:a-E:aO$)nQdO,5<|O$:pQdO,5<|O$:uQdO7+)|OOQS-E:`-E:`O$;PQdO7+)|O$)nQdO,5S~O%cOS%^OSSOS%]PQ~OPdOVaOfoOhYOopOs!POvqO!PrO!Q{O!T!SO!U!RO!XZO!][O!h`O!r`O!s`O!t`O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO#l!QO#o!TO#s!UO#u!VO#z!WO#}hO$P!XO%oRO%pRO%tSO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O~O%]!YO~OV!aO_!aOa!bOh!iO!X!kO!f!mO%j![O%k!]O%l!^O%m!_O%n!_O%o!`O%p!`O%q!aO%r!aO%s!aO~Ok%xXl%xXm%xXn%xXo%xXp%xXs%xXz%xX{%xX!x%xX#g%xX%[%xX%_%xX%z%xXg%xX!T%xX!U%xX%{%xX!W%xX![%xX!Q%xX#[%xXt%xX!m%xX~P%SOfoOhYO!XZO!][O!h`O!r`O!s`O!t`O%oRO%pRO%tSO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O~Oz%wX{%wX#g%wX%[%wX%_%wX%z%wX~Ok!pOl!qOm!oOn!oOo!rOp!sOs!tO!x%wX~P)pOV!zOg!|Oo0cOv0qO!PrO~P'vOV#OOo0cOv0qO!W#PO~P'vOV#SOa#TOo0cOv0qO![#UO~P'vOQ#XO%`#XO%a#ZO~OQ#^OR#[O%`#^O%a#`O~OV%iX_%iXa%iXh%iXk%iXl%iXm%iXn%iXo%iXp%iXs%iXz%iX!X%iX!f%iX%j%iX%k%iX%l%iX%m%iX%n%iX%o%iX%p%iX%q%iX%r%iX%s%iXg%iX!T%iX!U%iX~O&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O{%iX!x%iX#g%iX%[%iX%_%iX%z%iX%{%iX!W%iX![%iX!Q%iX#[%iXt%iX!m%iX~P,eOz#dO{%hX!x%hX#g%hX%[%hX%_%hX%z%hX~Oo0cOv0qO~P'vO#g#gO%[#iO%_#iO~O%uWO~O!T#nO#u!VO#z!WO#}hO~OopO~P'vOV#sOa#tO%uWO{wP~OV#xOo0cOv0qO!Q#yO~P'vO{#{O!x$QO%z#|O#g!yX%[!yX%_!yX~OV#xOo0cOv0qO#g#SX%[#SX%_#SX~P'vOo0cOv0qO#g#WX%[#WX%_#WX~P'vOh$WO%uWO~O!f$YO!r$YO%uWO~OV$eO~P'vO!U$gO#s$hO#u$iO~O{$jO~OV$qO~P'vOS$sO%[$rO%_$rO%c$tO~OV$}Oa$}Og%POo0cOv0qO~P'vOo0cOv0qO{%SO~P'vO&Y%UO~Oa!bOh!iO!X!kO!f!mOVba_bakbalbambanbaobapbasbazba{ba!xba#gba%[ba%_ba%jba%kba%lba%mba%nba%oba%pba%qba%rba%sba%zbagba!Tba!Uba%{ba!Wba![ba!Qba#[batba!mba~On%ZO~Oo%ZO~P'vOo0cO~P'vOk0eOl0fOm0dOn0dOo0mOp0nOs0rOg%wX!T%wX!U%wX%{%wX!W%wX![%wX!Q%wX#[%wX!m%wX~P)pO%{%]Og%vXz%vX!T%vX!U%vX!W%vX{%vX~Og%_Oz%`O!T%dO!U%cO~Og%_O~Oz%gO!T%dO!U%cO!W&SX~O!W%kO~Oz%lO{%nO!T%dO!U%cO![%}X~O![%rO~O![%sO~OQ#XO%`#XO%a%uO~OV%wOo0cOv0qO!PrO~P'vOQ#^OR#[O%`#^O%a%zO~OV!qa_!qaa!qah!qak!qal!qam!qan!qao!qap!qas!qaz!qa{!qa!X!qa!f!qa!x!qa#g!qa%[!qa%_!qa%j!qa%k!qa%l!qa%m!qa%n!qa%o!qa%p!qa%q!qa%r!qa%s!qa%z!qag!qa!T!qa!U!qa%{!qa!W!qa![!qa!Q!qa#[!qat!qa!m!qa~P#yOz%|O{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~P%SOV&OOopOvqO{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~P'vOz%|O{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~OPdOVaOopOvqO!PrO!Q{O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO#g$zX%[$zX%_$zX~P'vO#g#gO%[&TO%_&TO~O!f&UOh&sX%[&sXz&sX#[&sX#g&sX%_&sX#Z&sXg&sX~Oh!iO%[&WO~Okealeameaneaoeapeaseazea{ea!xea#gea%[ea%_ea%zeagea!Tea!Uea%{ea!Wea![ea!Qea#[eatea!mea~P%SOsqazqa{qa#gqa%[qa%_qa%zqa~Ok!pOl!qOm!oOn!oOo!rOp!sO!xqa~PEcO%z&YOz%yX{%yX~O%uWOz%yX{%yX~Oz&]O{wX~O{&_O~Oz%lO#g%}X%[%}X%_%}Xg%}X{%}X![%}X!m%}X%z%}X~OV0lOo0cOv0qO!PrO~P'vO%z#|O#gUa%[Ua%_Ua~Oz&hO#g&PX%[&PX%_&PXn&PX~P%SOz&kO!Q&jO#g#Wa%[#Wa%_#Wa~Oz&lO#[&nO#g&rX%[&rX%_&rXg&rX~O!f$YO!r$YO#Z&qO%uWO~O#Z&qO~Oz&sO#g&tX%[&tX%_&tX~Oz&uO#g&pX%[&pX%_&pX{&pX~O!X&wO%z&xO~Oz&|On&wX~P%SOn'PO~OPdOVaOopOvqO!PrO!Q{O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO%['UO~P'vOt'YO#p'WO#q'XOP#naV#naf#nah#nao#nas#nav#na!P#na!Q#na!T#na!U#na!X#na!]#na!h#na!r#na!s#na!t#na!{#na!}#na#P#na#R#na#T#na#X#na#Z#na#^#na#_#na#a#na#c#na#l#na#o#na#s#na#u#na#z#na#}#na$P#na%X#na%o#na%p#na%t#na%u#na&Z#na&[#na&]#na&^#na&_#na&`#na&a#na&b#na&c#na&d#na&e#na&f#na&g#na&h#na&i#na&j#na%Z#na%_#na~Oz'ZO#[']O{&xX~Oh'_O!X&wO~Oh!iO{$jO!X&wO~O{'eO~P%SO%['hO%_'hO~OS'iO%['hO%_'hO~OV!aO_!aOa!bOh!iO!X!kO!f!mO%l!^O%m!_O%n!_O%o!`O%p!`O%q!aO%r!aO%s!aOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~O%k!]O~P!#uO%kWi~P!#uOV!aO_!aOa!bOh!iO!X!kO!f!mO%o!`O%p!`O%q!aO%r!aO%s!aOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%kWi%lWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~O%m!_O%n!_O~P!&pO%mWi%nWi~P!&pOa!bOh!iO!X!kO!f!mOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%kWi%lWi%mWi%nWi%oWi%pWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~OV!aO_!aO%q!aO%r!aO%s!aO~P!)nOVWi_Wi%qWi%rWi%sWi~P!)nO!T%dO!U%cOg&VXz&VX~O%z'kO%{'kO~P,eOz'mOg&UX~Og'oO~Oz'pO{'rO!W&XX~Oo0cOv0qOz'pO{'sO!W&XX~P'vO!W'uO~Om!oOn!oOo!rOp!sOkjisjizji{ji!xji#gji%[ji%_ji%zji~Ol!qO~P!.aOlji~P!.aOk0eOl0fOm0dOn0dOo0mOp0nO~Ot'wO~P!/jOV'|Og'}Oo0cOv0qO~P'vOg'}Oz(OO~Og(QO~O!U(SO~Og(TOz(OO!T%dO!U%cO~P%SOk0eOl0fOm0dOn0dOo0mOp0nOgqa!Tqa!Uqa%{qa!Wqa![qa!Qqa#[qatqa!mqa~PEcOV'|Oo0cOv0qO!W&Sa~P'vOz(WO!W&Sa~O!W(XO~Oz(WO!T%dO!U%cO!W&Sa~P%SOV(]Oo0cOv0qO![%}a#g%}a%[%}a%_%}ag%}a{%}a!m%}a%z%}a~P'vOz(^O![%}a#g%}a%[%}a%_%}ag%}a{%}a!m%}a%z%}a~O![(aO~Oz(^O!T%dO!U%cO![%}a~P%SOz(dO!T%dO!U%cO![&Ta~P%SOz(gO{&lX![&lX!m&lX%z&lX~O{(kO![(mO!m(nO%z(jO~OV&OOopOvqO{%hi!x%hi#g%hi%[%hi%_%hi%z%hi~P'vOz(pO{%hi!x%hi#g%hi%[%hi%_%hi%z%hi~O!f&UOh&sa%[&saz&sa#[&sa#g&sa%_&sa#Z&sag&sa~O%[(uO~OV#sOa#tO%uWO~Oz&]O{wa~OopOvqO~P'vOz(^O#g%}a%[%}a%_%}ag%}a{%}a![%}a!m%}a%z%}a~P%SOz(zO#g%hX%[%hX%_%hX%z%hX~O%z#|O#gUi%[Ui%_Ui~O#g&Pa%[&Pa%_&Pan&Pa~P'vOz(}O#g&Pa%[&Pa%_&Pan&Pa~O%uWO#g&ra%[&ra%_&rag&ra~Oz)SO#g&ra%[&ra%_&rag&ra~Og)VO~OV)WOh$WO%uWO~O#Z)XO~O%uWO#g&ta%[&ta%_&ta~Oz)ZO#g&ta%[&ta%_&ta~Oo0cOv0qO#g&pa%[&pa%_&pa{&pa~P'vOz)^O#g&pa%[&pa%_&pa{&pa~OV)`Oa)`O%uWO~O%z)eO~Ot)hO#j)gOP#hiV#hif#hih#hio#his#hiv#hi!P#hi!Q#hi!T#hi!U#hi!X#hi!]#hi!h#hi!r#hi!s#hi!t#hi!{#hi!}#hi#P#hi#R#hi#T#hi#X#hi#Z#hi#^#hi#_#hi#a#hi#c#hi#l#hi#o#hi#s#hi#u#hi#z#hi#}#hi$P#hi%X#hi%o#hi%p#hi%t#hi%u#hi&Z#hi&[#hi&]#hi&^#hi&_#hi&`#hi&a#hi&b#hi&c#hi&d#hi&e#hi&f#hi&g#hi&h#hi&i#hi&j#hi%Z#hi%_#hi~Ot)iOP#kiV#kif#kih#kio#kis#kiv#ki!P#ki!Q#ki!T#ki!U#ki!X#ki!]#ki!h#ki!r#ki!s#ki!t#ki!{#ki!}#ki#P#ki#R#ki#T#ki#X#ki#Z#ki#^#ki#_#ki#a#ki#c#ki#l#ki#o#ki#s#ki#u#ki#z#ki#}#ki$P#ki%X#ki%o#ki%p#ki%t#ki%u#ki&Z#ki&[#ki&]#ki&^#ki&_#ki&`#ki&a#ki&b#ki&c#ki&d#ki&e#ki&f#ki&g#ki&h#ki&i#ki&j#ki%Z#ki%_#ki~OV)kOn&wa~P'vOz)lOn&wa~Oz)lOn&wa~P%SOn)pO~O%Y)tO~Ot)wO#p'WO#q)vOP#niV#nif#nih#nio#nis#niv#ni!P#ni!Q#ni!T#ni!U#ni!X#ni!]#ni!h#ni!r#ni!s#ni!t#ni!{#ni!}#ni#P#ni#R#ni#T#ni#X#ni#Z#ni#^#ni#_#ni#a#ni#c#ni#l#ni#o#ni#s#ni#u#ni#z#ni#}#ni$P#ni%X#ni%o#ni%p#ni%t#ni%u#ni&Z#ni&[#ni&]#ni&^#ni&_#ni&`#ni&a#ni&b#ni&c#ni&d#ni&e#ni&f#ni&g#ni&h#ni&i#ni&j#ni%Z#ni%_#ni~OV)zOo0cOv0qO{$jO~P'vOo0cOv0qO{&xa~P'vOz*OO{&xa~OV*SOa*TOg*WO%q*UO%uWO~O{$jO&{*YO~Oh'_O~Oh!iO{$jO~O%[*_O~O%[*aO%_*aO~OV$}Oa$}Oo0cOv0qOg&Ua~P'vOz*dOg&Ua~Oo0cOv0qO{*gO!W&Xa~P'vOz*hO!W&Xa~Oo0cOv0qOz*hO{*kO!W&Xa~P'vOo0cOv0qOz*hO!W&Xa~P'vOz*hO{*kO!W&Xa~Om0dOn0dOo0mOp0nOgjikjisjizji!Tji!Uji%{ji!Wji{ji![ji#gji%[ji%_ji!Qji#[jitji!mji%zji~Ol0fO~P!NkOlji~P!NkOV'|Og*pOo0cOv0qO~P'vOn*rO~Og*pOz*tO~Og*uO~OV'|Oo0cOv0qO!W&Si~P'vOz*vO!W&Si~O!W*wO~OV(]Oo0cOv0qO![%}i#g%}i%[%}i%_%}ig%}i{%}i!m%}i%z%}i~P'vOz*zO!T%dO!U%cO![&Ti~Oz*}O![%}i#g%}i%[%}i%_%}ig%}i{%}i!m%}i%z%}i~O![+OO~Oa+QOo0cOv0qO![&Ti~P'vOz*zO![&Ti~O![+SO~OV+UOo0cOv0qO{&la![&la!m&la%z&la~P'vOz+VO{&la![&la!m&la%z&la~O!]+YO&n+[O![!nX~O![+^O~O{(kO![+_O~O{(kO![+_O!m+`O~OV&OOopOvqO{%hq!x%hq#g%hq%[%hq%_%hq%z%hq~P'vOz$ri{$ri!x$ri#g$ri%[$ri%_$ri%z$ri~P%SOV&OOopOvqO~P'vOV&OOo0cOv0qO#g%ha%[%ha%_%ha%z%ha~P'vOz+aO#g%ha%[%ha%_%ha%z%ha~Oz$ia#g$ia%[$ia%_$ian$ia~P%SO#g&Pi%[&Pi%_&Pin&Pi~P'vOz+dO#g#Wq%[#Wq%_#Wq~O#[+eOz$va#g$va%[$va%_$vag$va~O%uWO#g&ri%[&ri%_&rig&ri~Oz+gO#g&ri%[&ri%_&rig&ri~OV+iOh$WO%uWO~O%uWO#g&ti%[&ti%_&ti~Oo0cOv0qO#g&pi%[&pi%_&pi{&pi~P'vO{#{Oz#eX!W#eX~Oz+mO!W&uX~O!W+oO~Ot+rO#j)gOP#hqV#hqf#hqh#hqo#hqs#hqv#hq!P#hq!Q#hq!T#hq!U#hq!X#hq!]#hq!h#hq!r#hq!s#hq!t#hq!{#hq!}#hq#P#hq#R#hq#T#hq#X#hq#Z#hq#^#hq#_#hq#a#hq#c#hq#l#hq#o#hq#s#hq#u#hq#z#hq#}#hq$P#hq%X#hq%o#hq%p#hq%t#hq%u#hq&Z#hq&[#hq&]#hq&^#hq&_#hq&`#hq&a#hq&b#hq&c#hq&d#hq&e#hq&f#hq&g#hq&h#hq&i#hq&j#hq%Z#hq%_#hq~On$|az$|a~P%SOV)kOn&wi~P'vOz+yOn&wi~Oz,TO{$jO#[,TO~O#q,VOP#nqV#nqf#nqh#nqo#nqs#nqv#nq!P#nq!Q#nq!T#nq!U#nq!X#nq!]#nq!h#nq!r#nq!s#nq!t#nq!{#nq!}#nq#P#nq#R#nq#T#nq#X#nq#Z#nq#^#nq#_#nq#a#nq#c#nq#l#nq#o#nq#s#nq#u#nq#z#nq#}#nq$P#nq%X#nq%o#nq%p#nq%t#nq%u#nq&Z#nq&[#nq&]#nq&^#nq&_#nq&`#nq&a#nq&b#nq&c#nq&d#nq&e#nq&f#nq&g#nq&h#nq&i#nq&j#nq%Z#nq%_#nq~O#[,WOz%Oa{%Oa~Oo0cOv0qO{&xi~P'vOz,YO{&xi~O{#{O%z,[Og&zXz&zX~O%uWOg&zXz&zX~Oz,`Og&yX~Og,bO~O%Y,eO~O!T%dO!U%cOg&Viz&Vi~OV$}Oa$}Oo0cOv0qOg&Ui~P'vO{,hOz$la!W$la~Oo0cOv0qO{,iOz$la!W$la~P'vOo0cOv0qO{*gO!W&Xi~P'vOz,lO!W&Xi~Oo0cOv0qOz,lO!W&Xi~P'vOz,lO{,oO!W&Xi~Og$hiz$hi!W$hi~P%SOV'|Oo0cOv0qO~P'vOn,qO~OV'|Og,rOo0cOv0qO~P'vOV'|Oo0cOv0qO!W&Sq~P'vOz$gi![$gi#g$gi%[$gi%_$gig$gi{$gi!m$gi%z$gi~P%SOV(]Oo0cOv0qO~P'vOa+QOo0cOv0qO![&Tq~P'vOz,sO![&Tq~O![,tO~OV(]Oo0cOv0qO![%}q#g%}q%[%}q%_%}qg%}q{%}q!m%}q%z%}q~P'vO{,uO~OV+UOo0cOv0qO{&li![&li!m&li%z&li~P'vOz,zO{&li![&li!m&li%z&li~O!]+YO&n+[O![!na~O{(kO![,}O~OV&OOo0cOv0qO#g%hi%[%hi%_%hi%z%hi~P'vOz-OO#g%hi%[%hi%_%hi%z%hi~O%uWO#g&rq%[&rq%_&rqg&rq~Oz-RO#g&rq%[&rq%_&rqg&rq~OV)`Oa)`O%uWO!W&ua~Oz-TO!W&ua~On$|iz$|i~P%SOV)kO~P'vOV)kOn&wq~P'vOt-XOP#myV#myf#myh#myo#mys#myv#my!P#my!Q#my!T#my!U#my!X#my!]#my!h#my!r#my!s#my!t#my!{#my!}#my#P#my#R#my#T#my#X#my#Z#my#^#my#_#my#a#my#c#my#l#my#o#my#s#my#u#my#z#my#}#my$P#my%X#my%o#my%p#my%t#my%u#my&Z#my&[#my&]#my&^#my&_#my&`#my&a#my&b#my&c#my&d#my&e#my&f#my&g#my&h#my&i#my&j#my%Z#my%_#my~O%Z-]O%_-]O~P`O#q-^OP#nyV#nyf#nyh#nyo#nys#nyv#ny!P#ny!Q#ny!T#ny!U#ny!X#ny!]#ny!h#ny!r#ny!s#ny!t#ny!{#ny!}#ny#P#ny#R#ny#T#ny#X#ny#Z#ny#^#ny#_#ny#a#ny#c#ny#l#ny#o#ny#s#ny#u#ny#z#ny#}#ny$P#ny%X#ny%o#ny%p#ny%t#ny%u#ny&Z#ny&[#ny&]#ny&^#ny&_#ny&`#ny&a#ny&b#ny&c#ny&d#ny&e#ny&f#ny&g#ny&h#ny&i#ny&j#ny%Z#ny%_#ny~Oz-aO{$jO#[-aO~Oo0cOv0qO{&xq~P'vOz-dO{&xq~O%z,[Og&zaz&za~O{#{Og&zaz&za~OV*SOa*TO%q*UO%uWOg&ya~Oz-hOg&ya~O$S-lO~OV$}Oa$}Oo0cOv0qO~P'vOo0cOv0qO{-mOz$li!W$li~P'vOo0cOv0qOz$li!W$li~P'vO{-mOz$li!W$li~Oo0cOv0qO{*gO~P'vOo0cOv0qO{*gO!W&Xq~P'vOz-pO!W&Xq~Oo0cOv0qOz-pO!W&Xq~P'vOs-sO!T%dO!U%cOg&Oq!W&Oq![&Oqz&Oq~P!/jOa+QOo0cOv0qO![&Ty~P'vOz$ji![$ji~P%SOa+QOo0cOv0qO~P'vOV+UOo0cOv0qO~P'vOV+UOo0cOv0qO{&lq![&lq!m&lq%z&lq~P'vO{(kO![-xO!m-yO%z-wO~OV&OOo0cOv0qO#g%hq%[%hq%_%hq%z%hq~P'vO%uWO#g&ry%[&ry%_&ryg&ry~OV)`Oa)`O%uWO!W&ui~Ot-}OP#m!RV#m!Rf#m!Rh#m!Ro#m!Rs#m!Rv#m!R!P#m!R!Q#m!R!T#m!R!U#m!R!X#m!R!]#m!R!h#m!R!r#m!R!s#m!R!t#m!R!{#m!R!}#m!R#P#m!R#R#m!R#T#m!R#X#m!R#Z#m!R#^#m!R#_#m!R#a#m!R#c#m!R#l#m!R#o#m!R#s#m!R#u#m!R#z#m!R#}#m!R$P#m!R%X#m!R%o#m!R%p#m!R%t#m!R%u#m!R&Z#m!R&[#m!R&]#m!R&^#m!R&_#m!R&`#m!R&a#m!R&b#m!R&c#m!R&d#m!R&e#m!R&f#m!R&g#m!R&h#m!R&i#m!R&j#m!R%Z#m!R%_#m!R~Oo0cOv0qO{&xy~P'vOV*SOa*TO%q*UO%uWOg&yi~O$S-lO%Z.VO%_.VO~OV.aOh._O!X.^O!].`O!h.YO!s.[O!t.[O%p.XO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O~Oo0cOv0qOz$lq!W$lq~P'vO{.fOz$lq!W$lq~Oo0cOv0qO{*gO!W&Xy~P'vOz.gO!W&Xy~Oo0cOv.kO~P'vOs-sO!T%dO!U%cOg&Oy!W&Oy![&Oyz&Oy~P!/jO{(kO![.nO~O{(kO![.nO!m.oO~OV*SOa*TO%q*UO%uWO~Oh.tO!f.rOz$TX#[$TX%j$TXg$TX~Os$TX{$TX!W$TX![$TX~P$-bO%o.vO%p.vOs$UXz$UX{$UX#[$UX%j$UX!W$UXg$UX![$UX~O!h.xO~Oz.|O#[/OO%j.yOs&|X{&|X!W&|Xg&|X~Oa/RO~P$)zOh.tOs&}Xz&}X{&}X#[&}X%j&}X!W&}Xg&}X![&}X~Os/VO{$jO~Oo0cOv0qOz$ly!W$ly~P'vOo0cOv0qO{*gO!W&X!R~P'vOz/ZO!W&X!R~Og&RXs&RX!T&RX!U&RX!W&RX![&RXz&RX~P!/jOs-sO!T%dO!U%cOg&Qa!W&Qa![&Qaz&Qa~O{(kO![/^O~O!f.rOh$[as$[az$[a{$[a#[$[a%j$[a!W$[ag$[a![$[a~O!h/eO~O%o.vO%p.vOs$Uaz$Ua{$Ua#[$Ua%j$Ua!W$Uag$Ua![$Ua~O%j.yOs$Yaz$Ya{$Ya#[$Ya!W$Yag$Ya![$Ya~Os&|a{&|a!W&|ag&|a~P$)nOz/jOs&|a{&|a!W&|ag&|a~O!W/mO~Og/mO~O{/oO~O![/pO~Oo0cOv0qO{*gO!W&X!Z~P'vO{/sO~O%z/tO~P$-bOz/uO#[/OO%j.yOg'PX~Oz/uOg'PX~Og/wO~O!h/xO~O#[/OOs%Saz%Sa{%Sa%j%Sa!W%Sag%Sa![%Sa~O#[/OO%j.yOs%Waz%Wa{%Wa!W%Wag%Wa~Os&|i{&|i!W&|ig&|i~P$)nOz/zO#[/OO%j.yO!['Oa~Og'Pa~P$)nOz0SOg'Pa~Oa0UO!['Oi~P$)zOz0WO!['Oi~Oz0WO#[/OO%j.yO!['Oi~O#[/OO%j.yOg$biz$bi~O%z0ZO~P$-bO#[/OO%j.yOg%Vaz%Va~Og'Pi~P$)nO{0^O~Oa0UO!['Oq~P$)zOz0`O!['Oq~O#[/OO%j.yOz%Ui![%Ui~Oa0UO~P$)zOa0UO!['Oy~P$)zO#[/OO%j.yOg$ciz$ci~O#[/OO%j.yOz%Uq![%Uq~Oz+aO#g%ha%[%ha%_%ha%z%ha~P%SOV&OOo0cOv0qO~P'vOn0hO~Oo0hO~P'vO{0iO~Ot0jO~P!/jO&]&Z&j&h&i&g&f&d&e&c&b&`&a&_&^&[%u~",goto:"!=j'QPPPPPP'RP'Z*s+[+t,_,y-fP.SP'Z.r.r'ZPPP'Z2[PPPPPP2[5PPP5PP7b7k=sPP=v>h>kPP'Z'ZPP>zPP'Z'ZPP'Z'Z'Z'Z'Z?O?w'ZP?zP@QDXGuGyPG|HWH['ZPPPH_Hk'RP'R'RP'RP'RP'RP'RP'R'R'RP'RPP'RPP'RP'RPHqH}IVPI^IdPI^PI^I^PPPI^PKrPK{LVL]KrPI^LfPI^PLmLsPLwM]MzNeLwLwNkNxLwLwLwLw! ^! d! g! l! o! y!!P!!]!!o!!u!#P!#V!#s!#y!$P!$Z!$a!$g!$y!%T!%Z!%a!%k!%q!%w!%}!&T!&Z!&e!&k!&u!&{!'U!'[!'k!'s!'}!(UPPPPPPPPPPP!([!(_!(e!(n!(x!)TPPPPPPPPPPPP!-u!/Z!3^!6oPP!6w!7W!7a!8Y!8P!8c!8i!8l!8o!8r!8z!9jPPPPPPPPPPPPPPPPP!9m!9q!9wP!:]!:a!:m!:v!;S!;j!;m!;p!;v!;|!_![!]Do!]!^Es!^!_FZ!_!`Gk!`!aHX!a!b%T!b!cIf!c!dJU!d!eK^!e!hJU!h!i!#f!i!tJU!t!u!,|!u!wJU!w!x!.t!x!}JU!}#O!0S#O#P&o#P#Q!0j#Q#R!1Q#R#SJU#S#T%T#T#UJU#U#VK^#V#YJU#Y#Z!#f#Z#fJU#f#g!,|#g#iJU#i#j!.t#j#oJU#o#p!1n#p#q!1s#q#r!2a#r#s!2f#s$g%T$g;'SJU;'S;=`KW<%lOJU`%YT&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%T`%lP;=`<%l%To%v]&n`%c_OX%TXY%oY[%T[]%o]p%Tpq%oq#O%T#O#P&o#P#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To&tX&n`OY%TYZ%oZ]%T]^%o^#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc'f[&n`O!_%T!_!`([!`#T%T#T#U(r#U#f%T#f#g(r#g#h(r#h#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc(cTmR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc(yT!mR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk)aV&n`&[ZOr%Trs)vs#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk){V&n`Or%Trs*bs#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk*iT&n`&^ZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To+PZS_&n`OY*xYZ%TZ]*x]^%T^#o*x#o#p+r#p#q*x#q#r+r#r;'S*x;'S;=`,^<%lO*x_+wTS_OY+rZ]+r^;'S+r;'S;=`,W<%lO+r_,ZP;=`<%l+ro,aP;=`<%l*xj,kV%rQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tj-XT!xY&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tj-oV%lQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk.]V&n`&ZZOw%Twx.rx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk.wV&n`Ow%Twx/^x#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk/eT&n`&]ZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk/{ThZ&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc0cTgR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk0yXVZ&n`Oz%Tz{1f{!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk1mVaR&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk2ZV%oZ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc2wTzR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To3_W%pZ&n`O!_%T!_!`-Q!`!a3w!a#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Td4OT&{S&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk4fX!fQ&n`O!O%T!O!P5R!P!Q%T!Q![6T![#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk5WV&n`O!O%T!O!P5m!P#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk5tT!rZ&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti6[a!hX&n`O!Q%T!Q![6T![!g%T!g!h7a!h!l%T!l!m9s!m#R%T#R#S6T#S#X%T#X#Y7a#Y#^%T#^#_9s#_#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti7fZ&n`O{%T{|8X|}%T}!O8X!O!Q%T!Q![8s![#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti8^V&n`O!Q%T!Q![8s![#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti8z]!hX&n`O!Q%T!Q![8s![!l%T!l!m9s!m#R%T#R#S8s#S#^%T#^#_9s#_#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti9zT!hX&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk:bX%qR&n`O!P%T!P!Q:}!Q!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tj;UV%sQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti;ro!hX&n`O!O%T!O!P=s!P!Q%T!Q![>_![!d%T!d!e?q!e!g%T!g!h7a!h!l%T!l!m9s!m!q%T!q!rA]!r!z%T!z!{Bq!{#R%T#R#S>_#S#U%T#U#V?q#V#X%T#X#Y7a#Y#^%T#^#_9s#_#c%T#c#dA]#d#l%T#l#mBq#m#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti=xV&n`O!Q%T!Q![6T![#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti>fc!hX&n`O!O%T!O!P=s!P!Q%T!Q![>_![!g%T!g!h7a!h!l%T!l!m9s!m#R%T#R#S>_#S#X%T#X#Y7a#Y#^%T#^#_9s#_#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti?vY&n`O!Q%T!Q!R@f!R!S@f!S#R%T#R#S@f#S#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti@mY!hX&n`O!Q%T!Q!R@f!R!S@f!S#R%T#R#S@f#S#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TiAbX&n`O!Q%T!Q!YA}!Y#R%T#R#SA}#S#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TiBUX!hX&n`O!Q%T!Q!YA}!Y#R%T#R#SA}#S#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TiBv]&n`O!Q%T!Q![Co![!c%T!c!iCo!i#R%T#R#SCo#S#T%T#T#ZCo#Z#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TiCv]!hX&n`O!Q%T!Q![Co![!c%T!c!iCo!i#R%T#R#SCo#S#T%T#T#ZCo#Z#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%ToDvV{_&n`O!_%T!_!`E]!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TcEdT%{R&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkEzT#gZ&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkFbXmR&n`O!^%T!^!_F}!_!`([!`!a([!a#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TjGUV%mQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkGrV%zZ&n`O!_%T!_!`([!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkH`WmR&n`O!_%T!_!`([!`!aHx!a#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TjIPV%nQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkIoV_Q#}P&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%ToJ_]&n`&YS%uZO!Q%T!Q![JU![!c%T!c!}JU!}#R%T#R#SJU#S#T%T#T#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUoKZP;=`<%lJUoKge&n`&YS%uZOr%Trs)Ysw%Twx.Ux!Q%T!Q![JU![!c%T!c!tJU!t!uLx!u!}JU!}#R%T#R#SJU#S#T%T#T#fJU#f#gLx#g#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUoMRa&n`&YS%uZOr%TrsNWsw%Twx! vx!Q%T!Q![JU![!c%T!c!}JU!}#R%T#R#SJU#S#T%T#T#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUkN_V&n`&`ZOr%TrsNts#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkNyV&n`Or%Trs! `s#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk! gT&n`&bZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk! }V&n`&_ZOw%Twx!!dx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!!iV&n`Ow%Twx!#Ox#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!#VT&n`&aZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To!#oe&n`&YS%uZOr%Trs!%Qsw%Twx!&px!Q%T!Q![JU![!c%T!c!tJU!t!u!(`!u!}JU!}#R%T#R#SJU#S#T%T#T#fJU#f#g!(`#g#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUk!%XV&n`&dZOr%Trs!%ns#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!%sV&n`Or%Trs!&Ys#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!&aT&n`&fZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!&wV&n`&cZOw%Twx!'^x#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!'cV&n`Ow%Twx!'xx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!(PT&n`&eZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To!(ia&n`&YS%uZOr%Trs!)nsw%Twx!+^x!Q%T!Q![JU![!c%T!c!}JU!}#R%T#R#SJU#S#T%T#T#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUk!)uV&n`&hZOr%Trs!*[s#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!*aV&n`Or%Trs!*vs#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!*}T&n`&jZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!+eV&n`&gZOw%Twx!+zx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!,PV&n`Ow%Twx!,fx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!,mT&n`&iZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To!-Vi&n`&YS%uZOr%TrsNWsw%Twx! vx!Q%T!Q![JU![!c%T!c!dJU!d!eLx!e!hJU!h!i!(`!i!}JU!}#R%T#R#SJU#S#T%T#T#UJU#U#VLx#V#YJU#Y#Z!(`#Z#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUo!.}a&n`&YS%uZOr%Trs)Ysw%Twx.Ux!Q%T!Q![JU![!c%T!c!}JU!}#R%T#R#SJU#S#T%T#T#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUk!0ZT!XZ&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc!0qT!WR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tj!1XV%kQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%T~!1sO!]~k!1zV%jR&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%T~!2fO![~i!2mT%tX&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%T",tokenizers:[nt,Qe,Ze,rt,0,1,2,3,4],topRules:{Script:[0,5]},specialized:[{term:221,get:e=>ot[e]||-1}],tokenPrec:7668}),G=new t,K=new Set([`Script`,`Body`,`FunctionDefinition`,`ClassDefinition`,`LambdaExpression`,`ForStatement`,`MatchClause`]);function q(e){return(t,n,r)=>{if(r)return!1;let i=t.node.getChild(`VariableName`);return i&&n(i,e),!0}}var ct={FunctionDefinition:q(`function`),ClassDefinition:q(`class`),ForStatement(e,t,n){if(n){for(let n=e.node.firstChild;n;n=n.nextSibling)if(n.name==`VariableName`)t(n,`variable`);else if(n.name==`in`)break}},ImportStatement(e,t){let{node:n}=e,r=n.firstChild?.name==`from`;for(let e=n.getChild(`import`);e;e=e.nextSibling)e.name==`VariableName`&&e.nextSibling?.name!=`as`&&t(e,r?`variable`:`namespace`)},AssignStatement(e,t){for(let n=e.node.firstChild;n;n=n.nextSibling)if(n.name==`VariableName`)t(n,`variable`);else if(n.name==`:`||n.name==`AssignOp`)break},ParamList(e,t){for(let n=null,r=e.node.firstChild;r;r=r.nextSibling)r.name==`VariableName`&&(!n||!/\*|AssignOp/.test(n.name))&&t(r,`variable`),n=r},CapturePattern:q(`variable`),AsPattern:q(`variable`),__proto__:null};function J(t,n){let r=G.get(n);if(r)return r;let i=[],a=!0;function o(e,n){let r=t.sliceString(e.from,e.to);i.push({label:r,type:n})}return n.cursor(e.IncludeAnonymous).iterate(e=>{if(e.name){let t=ct[e.name];if(t&&t(e,o,a)||!a&&K.has(e.name))return!1;a=!1}else if(e.to-e.from>8192){for(let n of J(t,e.node))i.push(n);return!1}}),G.set(n,i),i}var Y=/^[\w\xa1-\uffff][\w\d\xa1-\uffff]*$/,X=[`String`,`FormatString`,`Comment`,`PropertyName`];function lt(e){let t=te(e.state).resolveInner(e.pos,-1);if(X.indexOf(t.name)>-1)return null;let n=t.name==`VariableName`||t.to-t.from<20&&Y.test(e.state.sliceDoc(t.from,t.to));if(!n&&!e.explicit)return null;let r=[];for(let n=t;n;n=n.parent)K.has(n.name)&&(r=r.concat(J(e.state.doc,n)));return{options:r,from:n?t.from:e.pos,validFor:Y}}var ut=[`__annotations__`,`__builtins__`,`__debug__`,`__doc__`,`__import__`,`__name__`,`__loader__`,`__package__`,`__spec__`,`False`,`None`,`True`].map(e=>({label:e,type:`constant`})).concat(`ArithmeticError.AssertionError.AttributeError.BaseException.BlockingIOError.BrokenPipeError.BufferError.BytesWarning.ChildProcessError.ConnectionAbortedError.ConnectionError.ConnectionRefusedError.ConnectionResetError.DeprecationWarning.EOFError.Ellipsis.EncodingWarning.EnvironmentError.Exception.FileExistsError.FileNotFoundError.FloatingPointError.FutureWarning.GeneratorExit.IOError.ImportError.ImportWarning.IndentationError.IndexError.InterruptedError.IsADirectoryError.KeyError.KeyboardInterrupt.LookupError.MemoryError.ModuleNotFoundError.NameError.NotADirectoryError.NotImplemented.NotImplementedError.OSError.OverflowError.PendingDeprecationWarning.PermissionError.ProcessLookupError.RecursionError.ReferenceError.ResourceWarning.RuntimeError.RuntimeWarning.StopAsyncIteration.StopIteration.SyntaxError.SyntaxWarning.SystemError.SystemExit.TabError.TimeoutError.TypeError.UnboundLocalError.UnicodeDecodeError.UnicodeEncodeError.UnicodeError.UnicodeTranslateError.UnicodeWarning.UserWarning.ValueError.Warning.ZeroDivisionError`.split(`.`).map(e=>({label:e,type:`type`}))).concat([`bool`,`bytearray`,`bytes`,`classmethod`,`complex`,`float`,`frozenset`,`int`,`list`,`map`,`memoryview`,`object`,`range`,`set`,`staticmethod`,`str`,`super`,`tuple`,`type`].map(e=>({label:e,type:`class`}))).concat(`abs.aiter.all.anext.any.ascii.bin.breakpoint.callable.chr.compile.delattr.dict.dir.divmod.enumerate.eval.exec.exit.filter.format.getattr.globals.hasattr.hash.help.hex.id.input.isinstance.issubclass.iter.len.license.locals.max.min.next.oct.open.ord.pow.print.property.quit.repr.reversed.round.setattr.slice.sorted.sum.vars.zip`.split(`.`).map(e=>({label:e,type:`function`}))),dt=[u("def ${name}(${params}):\n ${}",{label:`def`,detail:`function`,type:`keyword`}),u("for ${name} in ${collection}:\n ${}",{label:`for`,detail:`loop`,type:`keyword`}),u("while ${}:\n ${}",{label:`while`,detail:`loop`,type:`keyword`}),u(`try: +import{C as e,D as t,b as n,d as r,f as i,i as a,l as o,m as s,t as ee,v as te,x as c}from"./index-CLJ0aycO.js";import{n as l,r as ne,t as re}from"./dist-B2R-c1vX.js";import{i as u,n as ie,r as ae}from"./dist-BxWz473c.js";var oe=1,d=194,f=195,se=196,p=197,ce=198,le=199,ue=200,de=2,m=3,h=201,g=24,fe=25,pe=49,me=50,he=55,ge=56,_e=57,ve=59,ye=60,be=61,xe=62,Se=63,Ce=65,we=238,Te=71,Ee=241,De=242,Oe=243,ke=244,Ae=245,_=246,v=247,y=248,b=72,x=249,S=250,C=251,je=252,Me=253,Ne=254,Pe=255,Fe=256,Ie=73,Le=77,Re=263,ze=112,Be=130,Ve=151,He=152,Ue=155,w=10,T=13,E=32,D=9,O=35,We=40,Ge=46,k=123,A=125,j=39,M=34,N=92,Ke=111,P=120,qe=78,Je=117,Ye=85,Xe=new Set([fe,pe,me,Re,Ce,Be,ge,_e,we,xe,Se,b,Ie,Le,ye,be,Ve,He,Ue,ze]);function F(e){return e==w||e==T}function I(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}var Ze=new l((e,t)=>{let n;if(e.next<0)e.acceptToken(le);else if(t.context.flags&L)F(e.next)&&e.acceptToken(ce,1);else if(((n=e.peek(-1))<0||F(n))&&t.canShift(p)){let t=0;for(;e.next==E||e.next==D;)e.advance(),t++;(e.next==w||e.next==T||e.next==O)&&e.acceptToken(p,-t)}else F(e.next)&&e.acceptToken(se,1)},{contextual:!0}),Qe=new l((e,t)=>{let n=t.context;if(n.flags)return;let r=e.peek(-1);if(r==w||r==T){let t=0,r=0;for(;;){if(e.next==E)t++;else if(e.next==D)t+=8-t%8;else break;e.advance(),r++}t!=n.indent&&e.next!=w&&e.next!=T&&e.next!=O&&(t[e,t|R])),tt=new re({start:$e,reduce(e,t,n,r){return e.flags&L&&Xe.has(t)||(t==Te||t==b)&&e.flags&R?e.parent:e},shift(e,t,n,r){return t==d?new U(e,et(r.read(r.pos,n.pos)),0):t==f?e.parent:t==g||t==he||t==ve||t==m?new U(e,0,L):W.has(t)?new U(e,0,W.get(t)|e.flags&L):e},hash(e){return e.hash}}),nt=new l(e=>{for(let t=0;t<5;t++){if(e.next!=`print`.charCodeAt(t))return;e.advance()}if(!/\w/.test(String.fromCharCode(e.next)))for(let t=0;;t++){let n=e.peek(t);if(!(n==E||n==D)){n!=We&&n!=Ge&&n!=w&&n!=T&&n!=O&&e.acceptToken(oe);return}}}),rt=new l((e,t)=>{let{flags:n}=t.context,r=n&z?M:j,i=(n&B)>0,a=!(n&V),o=(n&H)>0,s=e.pos;for(;!(e.next<0);)if(o&&e.next==k)if(e.peek(1)==k)e.advance(2);else{if(e.pos==s){e.acceptToken(m,1);return}break}else if(a&&e.next==N){if(e.pos==s){e.advance();let t=e.next;t>=0&&(e.advance(),it(e,t)),e.acceptToken(de);return}break}else if(e.next==N&&!a&&e.peek(1)>-1)e.advance(2);else if(e.next==r&&(!i||e.peek(1)==r&&e.peek(2)==r)){if(e.pos==s){e.acceptToken(h,i?3:1);return}break}else if(e.next==w){if(i)e.advance();else if(e.pos==s){e.acceptToken(h);return}break}else e.advance();e.pos>s&&e.acceptToken(ue)});function it(e,t){if(t==Ke)for(let t=0;t<2&&e.next>=48&&e.next<=55;t++)e.advance();else if(t==P)for(let t=0;t<2&&I(e.next);t++)e.advance();else if(t==Je)for(let t=0;t<4&&I(e.next);t++)e.advance();else if(t==Ye)for(let t=0;t<8&&I(e.next);t++)e.advance();else if(t==qe&&e.next==k){for(e.advance();e.next>=0&&e.next!=A&&e.next!=j&&e.next!=M&&e.next!=w;)e.advance();e.next==A&&e.advance()}}var at=n({'async "*" "**" FormatConversion FormatSpec':c.modifier,"for while if elif else try except finally return raise break continue with pass assert await yield match case":c.controlKeyword,"in not and or is del":c.operatorKeyword,"from def class global nonlocal lambda":c.definitionKeyword,import:c.moduleKeyword,"with as print":c.keyword,Boolean:c.bool,None:c.null,VariableName:c.variableName,"CallExpression/VariableName":c.function(c.variableName),"FunctionDefinition/VariableName":c.function(c.definition(c.variableName)),"ClassDefinition/VariableName":c.definition(c.className),PropertyName:c.propertyName,"CallExpression/MemberExpression/PropertyName":c.function(c.propertyName),Comment:c.lineComment,Number:c.number,String:c.string,FormatString:c.special(c.string),Escape:c.escape,UpdateOp:c.updateOperator,"ArithOp!":c.arithmeticOperator,BitOp:c.bitwiseOperator,CompareOp:c.compareOperator,AssignOp:c.definitionOperator,Ellipsis:c.punctuation,At:c.meta,"( )":c.paren,"[ ]":c.squareBracket,"{ }":c.brace,".":c.derefOperator,", ;":c.separator}),ot={__proto__:null,await:44,or:54,and:56,in:60,not:62,is:64,if:70,else:72,lambda:76,yield:94,from:96,async:102,for:104,None:162,True:164,False:164,del:178,pass:182,break:186,continue:190,return:194,raise:202,import:206,as:208,global:212,nonlocal:214,assert:218,type:223,elif:236,while:240,try:246,except:248,finally:250,with:254,def:258,class:268,match:279,case:285},st=ne.deserialize({version:14,states:"##jQ`QeOOP$}OSOOO&WQtO'#HUOOQS'#Co'#CoOOQS'#Cp'#CpO'vQdO'#CnO*UQtO'#HTOOQS'#HU'#HUOOQS'#DU'#DUOOQS'#HT'#HTO*rQdO'#D_O+VQdO'#DfO+gQdO'#DjO+zOWO'#DuO,VOWO'#DvO.[QtO'#GuOOQS'#Gu'#GuO'vQdO'#GtO0ZQtO'#GtOOQS'#Eb'#EbO0rQdO'#EcOOQS'#Gs'#GsO0|QdO'#GrOOQV'#Gr'#GrO1XQdO'#FYOOQS'#G^'#G^O1^QdO'#FXOOQV'#IS'#ISOOQV'#Gq'#GqOOQV'#Fq'#FqQ`QeOOO'vQdO'#CqO1lQdO'#C}O1sQdO'#DRO2RQdO'#HYO2cQtO'#EVO'vQdO'#EWOOQS'#EY'#EYOOQS'#E['#E[OOQS'#E^'#E^O2wQdO'#E`O3_QdO'#EdO3rQdO'#EfO3zQtO'#EfO1XQdO'#EiO0rQdO'#ElO1XQdO'#EnO0rQdO'#EtO0rQdO'#EwO4VQdO'#EyO4^QdO'#FOO4iQdO'#EzO0rQdO'#FOO1XQdO'#FQO1XQdO'#FVO4nQdO'#F[P4uOdO'#GpPOOO)CBd)CBdOOQS'#Ce'#CeOOQS'#Cf'#CfOOQS'#Cg'#CgOOQS'#Ch'#ChOOQS'#Ci'#CiOOQS'#Cj'#CjOOQS'#Cl'#ClO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO5TQdO'#DoOOQS,5:Y,5:YO5hQdO'#HdOOQS,5:],5:]O5uQ!fO,5:]O5zQtO,59YO1lQdO,59bO1lQdO,59bO1lQdO,59bO8jQdO,59bO8oQdO,59bO8vQdO,59jO8}QdO'#HTO:TQdO'#HSOOQS'#HS'#HSOOQS'#D['#D[O:lQdO,59aO'vQdO,59aO:zQdO,59aOOQS,59y,59yO;PQdO,5:RO'vQdO,5:ROOQS,5:Q,5:QO;_QdO,5:QO;dQdO,5:XO'vQdO,5:XO'vQdO,5:VOOQS,5:U,5:UO;uQdO,5:UO;zQdO,5:WOOOW'#Fy'#FyOOOOQS'#Ds'#DsOOQS1G/w1G/wOOQS1G.|1G.|O!/[QtO1G.|O!/cQtO1G.|O1lQdO1G.|O!0OQdO1G/UOOQS'#DZ'#DZO0rQdO,59tOOQS1G.{1G.{O!0VQdO1G/eO!0gQdO1G/eO!0oQdO1G/fO'vQdO'#H[O!0tQdO'#H[O!0yQtO1G.{O!1ZQdO,59iO!2aQdO,5=zO!2qQdO,5=zO!2yQdO1G/mO!3OQtO1G/mOOQS1G/l1G/lO!3`QdO,5=uO!4VQdO,5=uO0rQdO1G/qO!4tQdO1G/sO!4yQtO1G/sO!5ZQtO1G/qOOQS1G/p1G/pOOQS1G/r1G/rOOOW-E9w-E9wOOQS1G/{1G/{O!5kQdO'#HxO0rQdO'#HxO!5|QdO,5>cOOOW-E9x-E9xOOQS1G/|1G/|OOQS-E9{-E9{O!6[Q#xO1G2zO!6{QtO1G2zO'vQdO,5kOOQS1G1`1G1`O!8RQdO1G1`OOQS'#DV'#DVO0rQdO,5=qOOQS,5=q,5=qO!8WQdO'#FrO!8cQdO,59oO!8kQdO1G/XO!8uQtO,5=uOOQS1G3`1G3`OOQS,5:m,5:mO!9fQdO'#GtOOQS,5jO!;ZQdO,5>jO1XQdO,5>jO!;lQdO,5>iOOQS-E:R-E:RO!;qQdO1G0lO!;|QdO1G0lO!lO!lO!hO!=VQdO,5>hO!=hQdO'#EpO0rQdO1G0tO!=sQdO1G0tO!=xQgO1G0zO!AvQgO1G0}O!EqQdO,5>oO!E{QdO,5>oO!FTQtO,5>oO0rQdO1G1PO!F_QdO1G1PO4iQdO1G1UO!!vQdO1G1WOOQV,5;a,5;aO!FdQfO,5;aO!FiQgO1G1QO!JjQdO'#GZO4iQdO1G1QO4iQdO1G1QO!JzQdO,5>pO!KXQdO,5>pO1XQdO,5>pOOQV1G1U1G1UO!KaQdO'#FSO!KrQ!fO1G1WO!KzQdO1G1WOOQV1G1]1G1]O4iQdO1G1]O!LPQdO1G1]O!LXQdO'#F^OOQV1G1b1G1bO!#ZQtO1G1bPOOO1G2v1G2vP!L^OSO1G2vOOQS,5=},5=}OOQS'#Dp'#DpO0rQdO,5=}O!LfQdO,5=|O!LyQdO,5=|OOQS1G/u1G/uO!MRQdO,5>PO!McQdO,5>PO!MkQdO,5>PO!NOQdO,5>PO!N`QdO,5>POOQS1G3j1G3jOOQS7+$h7+$hO!8kQdO7+$pO#!RQdO1G.|O#!YQdO1G.|OOQS1G/`1G/`OOQS,5<`,5<`O'vQdO,5<`OOQS7+%P7+%PO#!aQdO7+%POOQS-E9r-E9rOOQS7+%Q7+%QO#!qQdO,5=vO'vQdO,5=vOOQS7+$g7+$gO#!vQdO7+%PO##OQdO7+%QO##TQdO1G3fOOQS7+%X7+%XO##eQdO1G3fO##mQdO7+%XOOQS,5<_,5<_O'vQdO,5<_O##rQdO1G3aOOQS-E9q-E9qO#$iQdO7+%]OOQS7+%_7+%_O#$wQdO1G3aO#%fQdO7+%_O#%kQdO1G3gO#%{QdO1G3gO#&TQdO7+%]O#&YQdO,5>dO#&sQdO,5>dO#&sQdO,5>dOOQS'#Dx'#DxO#'UO&jO'#DzO#'aO`O'#HyOOOW1G3}1G3}O#'fQdO1G3}O#'nQdO1G3}O#'yQ#xO7+(fO#(jQtO1G2UP#)TQdO'#GOOOQS,5nQdO,5sQdO1G4OOOQS-E9y-E9yO#?^QdO1G4OO<[QdO'#H{OOOO'#D{'#D{OOOO'#F|'#F|O#?oO&jO,5:fOOOW,5>e,5>eOOOW7+)i7+)iO#?zQdO7+)iO#@SQdO1G2zO#@mQdO1G2zP'vQdO'#FuO0rQdO<mO#BQQdO,5>mOOQS1G0v1G0vOOQS<rO#KgQdO,5>rO#KrQdO,5>rO#K}QdO,5>qO#L`QdO,5>qOOQS1G1Y1G1YOOQS,5;p,5;pOOQV<VAN>VO$ oQdO<cAN>cO0rQdO1G1|O$!PQtO1G1|P$!ZQdO'#FvOOQS1G2R1G2RP$!hQdO'#F{O$!uQdO7+)jO$#`QdO,5>gOOOO-E9z-E9zOOOW<tO$4{QdO,5>tO1XQdO,5vO$)nQdO,5>vOOQS1G1p1G1pOOQS,5<[,5<[OOQU7+'P7+'PO$+zQdO1G/iO$)nQdO,5wO$8zQdO,5>wOOQS1G1s1G1sOOQS7+'S7+'SP$)nQdO'#GdO$9SQdO1G4bO$9^QdO1G4bO$9fQdO1G4bOOQS7+%T7+%TO$9tQdO1G1tO$:SQtO'#FaO$:ZQdO,5<}OOQS,5<},5<}O$:iQdO1G4cOOQS-E:a-E:aO$)nQdO,5<|O$:pQdO,5<|O$:uQdO7+)|OOQS-E:`-E:`O$;PQdO7+)|O$)nQdO,5S~O%cOS%^OSSOS%]PQ~OPdOVaOfoOhYOopOs!POvqO!PrO!Q{O!T!SO!U!RO!XZO!][O!h`O!r`O!s`O!t`O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO#l!QO#o!TO#s!UO#u!VO#z!WO#}hO$P!XO%oRO%pRO%tSO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O~O%]!YO~OV!aO_!aOa!bOh!iO!X!kO!f!mO%j![O%k!]O%l!^O%m!_O%n!_O%o!`O%p!`O%q!aO%r!aO%s!aO~Ok%xXl%xXm%xXn%xXo%xXp%xXs%xXz%xX{%xX!x%xX#g%xX%[%xX%_%xX%z%xXg%xX!T%xX!U%xX%{%xX!W%xX![%xX!Q%xX#[%xXt%xX!m%xX~P%SOfoOhYO!XZO!][O!h`O!r`O!s`O!t`O%oRO%pRO%tSO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O~Oz%wX{%wX#g%wX%[%wX%_%wX%z%wX~Ok!pOl!qOm!oOn!oOo!rOp!sOs!tO!x%wX~P)pOV!zOg!|Oo0cOv0qO!PrO~P'vOV#OOo0cOv0qO!W#PO~P'vOV#SOa#TOo0cOv0qO![#UO~P'vOQ#XO%`#XO%a#ZO~OQ#^OR#[O%`#^O%a#`O~OV%iX_%iXa%iXh%iXk%iXl%iXm%iXn%iXo%iXp%iXs%iXz%iX!X%iX!f%iX%j%iX%k%iX%l%iX%m%iX%n%iX%o%iX%p%iX%q%iX%r%iX%s%iXg%iX!T%iX!U%iX~O&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O{%iX!x%iX#g%iX%[%iX%_%iX%z%iX%{%iX!W%iX![%iX!Q%iX#[%iXt%iX!m%iX~P,eOz#dO{%hX!x%hX#g%hX%[%hX%_%hX%z%hX~Oo0cOv0qO~P'vO#g#gO%[#iO%_#iO~O%uWO~O!T#nO#u!VO#z!WO#}hO~OopO~P'vOV#sOa#tO%uWO{wP~OV#xOo0cOv0qO!Q#yO~P'vO{#{O!x$QO%z#|O#g!yX%[!yX%_!yX~OV#xOo0cOv0qO#g#SX%[#SX%_#SX~P'vOo0cOv0qO#g#WX%[#WX%_#WX~P'vOh$WO%uWO~O!f$YO!r$YO%uWO~OV$eO~P'vO!U$gO#s$hO#u$iO~O{$jO~OV$qO~P'vOS$sO%[$rO%_$rO%c$tO~OV$}Oa$}Og%POo0cOv0qO~P'vOo0cOv0qO{%SO~P'vO&Y%UO~Oa!bOh!iO!X!kO!f!mOVba_bakbalbambanbaobapbasbazba{ba!xba#gba%[ba%_ba%jba%kba%lba%mba%nba%oba%pba%qba%rba%sba%zbagba!Tba!Uba%{ba!Wba![ba!Qba#[batba!mba~On%ZO~Oo%ZO~P'vOo0cO~P'vOk0eOl0fOm0dOn0dOo0mOp0nOs0rOg%wX!T%wX!U%wX%{%wX!W%wX![%wX!Q%wX#[%wX!m%wX~P)pO%{%]Og%vXz%vX!T%vX!U%vX!W%vX{%vX~Og%_Oz%`O!T%dO!U%cO~Og%_O~Oz%gO!T%dO!U%cO!W&SX~O!W%kO~Oz%lO{%nO!T%dO!U%cO![%}X~O![%rO~O![%sO~OQ#XO%`#XO%a%uO~OV%wOo0cOv0qO!PrO~P'vOQ#^OR#[O%`#^O%a%zO~OV!qa_!qaa!qah!qak!qal!qam!qan!qao!qap!qas!qaz!qa{!qa!X!qa!f!qa!x!qa#g!qa%[!qa%_!qa%j!qa%k!qa%l!qa%m!qa%n!qa%o!qa%p!qa%q!qa%r!qa%s!qa%z!qag!qa!T!qa!U!qa%{!qa!W!qa![!qa!Q!qa#[!qat!qa!m!qa~P#yOz%|O{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~P%SOV&OOopOvqO{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~P'vOz%|O{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~OPdOVaOopOvqO!PrO!Q{O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO#g$zX%[$zX%_$zX~P'vO#g#gO%[&TO%_&TO~O!f&UOh&sX%[&sXz&sX#[&sX#g&sX%_&sX#Z&sXg&sX~Oh!iO%[&WO~Okealeameaneaoeapeaseazea{ea!xea#gea%[ea%_ea%zeagea!Tea!Uea%{ea!Wea![ea!Qea#[eatea!mea~P%SOsqazqa{qa#gqa%[qa%_qa%zqa~Ok!pOl!qOm!oOn!oOo!rOp!sO!xqa~PEcO%z&YOz%yX{%yX~O%uWOz%yX{%yX~Oz&]O{wX~O{&_O~Oz%lO#g%}X%[%}X%_%}Xg%}X{%}X![%}X!m%}X%z%}X~OV0lOo0cOv0qO!PrO~P'vO%z#|O#gUa%[Ua%_Ua~Oz&hO#g&PX%[&PX%_&PXn&PX~P%SOz&kO!Q&jO#g#Wa%[#Wa%_#Wa~Oz&lO#[&nO#g&rX%[&rX%_&rXg&rX~O!f$YO!r$YO#Z&qO%uWO~O#Z&qO~Oz&sO#g&tX%[&tX%_&tX~Oz&uO#g&pX%[&pX%_&pX{&pX~O!X&wO%z&xO~Oz&|On&wX~P%SOn'PO~OPdOVaOopOvqO!PrO!Q{O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO%['UO~P'vOt'YO#p'WO#q'XOP#naV#naf#nah#nao#nas#nav#na!P#na!Q#na!T#na!U#na!X#na!]#na!h#na!r#na!s#na!t#na!{#na!}#na#P#na#R#na#T#na#X#na#Z#na#^#na#_#na#a#na#c#na#l#na#o#na#s#na#u#na#z#na#}#na$P#na%X#na%o#na%p#na%t#na%u#na&Z#na&[#na&]#na&^#na&_#na&`#na&a#na&b#na&c#na&d#na&e#na&f#na&g#na&h#na&i#na&j#na%Z#na%_#na~Oz'ZO#[']O{&xX~Oh'_O!X&wO~Oh!iO{$jO!X&wO~O{'eO~P%SO%['hO%_'hO~OS'iO%['hO%_'hO~OV!aO_!aOa!bOh!iO!X!kO!f!mO%l!^O%m!_O%n!_O%o!`O%p!`O%q!aO%r!aO%s!aOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~O%k!]O~P!#uO%kWi~P!#uOV!aO_!aOa!bOh!iO!X!kO!f!mO%o!`O%p!`O%q!aO%r!aO%s!aOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%kWi%lWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~O%m!_O%n!_O~P!&pO%mWi%nWi~P!&pOa!bOh!iO!X!kO!f!mOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%kWi%lWi%mWi%nWi%oWi%pWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~OV!aO_!aO%q!aO%r!aO%s!aO~P!)nOVWi_Wi%qWi%rWi%sWi~P!)nO!T%dO!U%cOg&VXz&VX~O%z'kO%{'kO~P,eOz'mOg&UX~Og'oO~Oz'pO{'rO!W&XX~Oo0cOv0qOz'pO{'sO!W&XX~P'vO!W'uO~Om!oOn!oOo!rOp!sOkjisjizji{ji!xji#gji%[ji%_ji%zji~Ol!qO~P!.aOlji~P!.aOk0eOl0fOm0dOn0dOo0mOp0nO~Ot'wO~P!/jOV'|Og'}Oo0cOv0qO~P'vOg'}Oz(OO~Og(QO~O!U(SO~Og(TOz(OO!T%dO!U%cO~P%SOk0eOl0fOm0dOn0dOo0mOp0nOgqa!Tqa!Uqa%{qa!Wqa![qa!Qqa#[qatqa!mqa~PEcOV'|Oo0cOv0qO!W&Sa~P'vOz(WO!W&Sa~O!W(XO~Oz(WO!T%dO!U%cO!W&Sa~P%SOV(]Oo0cOv0qO![%}a#g%}a%[%}a%_%}ag%}a{%}a!m%}a%z%}a~P'vOz(^O![%}a#g%}a%[%}a%_%}ag%}a{%}a!m%}a%z%}a~O![(aO~Oz(^O!T%dO!U%cO![%}a~P%SOz(dO!T%dO!U%cO![&Ta~P%SOz(gO{&lX![&lX!m&lX%z&lX~O{(kO![(mO!m(nO%z(jO~OV&OOopOvqO{%hi!x%hi#g%hi%[%hi%_%hi%z%hi~P'vOz(pO{%hi!x%hi#g%hi%[%hi%_%hi%z%hi~O!f&UOh&sa%[&saz&sa#[&sa#g&sa%_&sa#Z&sag&sa~O%[(uO~OV#sOa#tO%uWO~Oz&]O{wa~OopOvqO~P'vOz(^O#g%}a%[%}a%_%}ag%}a{%}a![%}a!m%}a%z%}a~P%SOz(zO#g%hX%[%hX%_%hX%z%hX~O%z#|O#gUi%[Ui%_Ui~O#g&Pa%[&Pa%_&Pan&Pa~P'vOz(}O#g&Pa%[&Pa%_&Pan&Pa~O%uWO#g&ra%[&ra%_&rag&ra~Oz)SO#g&ra%[&ra%_&rag&ra~Og)VO~OV)WOh$WO%uWO~O#Z)XO~O%uWO#g&ta%[&ta%_&ta~Oz)ZO#g&ta%[&ta%_&ta~Oo0cOv0qO#g&pa%[&pa%_&pa{&pa~P'vOz)^O#g&pa%[&pa%_&pa{&pa~OV)`Oa)`O%uWO~O%z)eO~Ot)hO#j)gOP#hiV#hif#hih#hio#his#hiv#hi!P#hi!Q#hi!T#hi!U#hi!X#hi!]#hi!h#hi!r#hi!s#hi!t#hi!{#hi!}#hi#P#hi#R#hi#T#hi#X#hi#Z#hi#^#hi#_#hi#a#hi#c#hi#l#hi#o#hi#s#hi#u#hi#z#hi#}#hi$P#hi%X#hi%o#hi%p#hi%t#hi%u#hi&Z#hi&[#hi&]#hi&^#hi&_#hi&`#hi&a#hi&b#hi&c#hi&d#hi&e#hi&f#hi&g#hi&h#hi&i#hi&j#hi%Z#hi%_#hi~Ot)iOP#kiV#kif#kih#kio#kis#kiv#ki!P#ki!Q#ki!T#ki!U#ki!X#ki!]#ki!h#ki!r#ki!s#ki!t#ki!{#ki!}#ki#P#ki#R#ki#T#ki#X#ki#Z#ki#^#ki#_#ki#a#ki#c#ki#l#ki#o#ki#s#ki#u#ki#z#ki#}#ki$P#ki%X#ki%o#ki%p#ki%t#ki%u#ki&Z#ki&[#ki&]#ki&^#ki&_#ki&`#ki&a#ki&b#ki&c#ki&d#ki&e#ki&f#ki&g#ki&h#ki&i#ki&j#ki%Z#ki%_#ki~OV)kOn&wa~P'vOz)lOn&wa~Oz)lOn&wa~P%SOn)pO~O%Y)tO~Ot)wO#p'WO#q)vOP#niV#nif#nih#nio#nis#niv#ni!P#ni!Q#ni!T#ni!U#ni!X#ni!]#ni!h#ni!r#ni!s#ni!t#ni!{#ni!}#ni#P#ni#R#ni#T#ni#X#ni#Z#ni#^#ni#_#ni#a#ni#c#ni#l#ni#o#ni#s#ni#u#ni#z#ni#}#ni$P#ni%X#ni%o#ni%p#ni%t#ni%u#ni&Z#ni&[#ni&]#ni&^#ni&_#ni&`#ni&a#ni&b#ni&c#ni&d#ni&e#ni&f#ni&g#ni&h#ni&i#ni&j#ni%Z#ni%_#ni~OV)zOo0cOv0qO{$jO~P'vOo0cOv0qO{&xa~P'vOz*OO{&xa~OV*SOa*TOg*WO%q*UO%uWO~O{$jO&{*YO~Oh'_O~Oh!iO{$jO~O%[*_O~O%[*aO%_*aO~OV$}Oa$}Oo0cOv0qOg&Ua~P'vOz*dOg&Ua~Oo0cOv0qO{*gO!W&Xa~P'vOz*hO!W&Xa~Oo0cOv0qOz*hO{*kO!W&Xa~P'vOo0cOv0qOz*hO!W&Xa~P'vOz*hO{*kO!W&Xa~Om0dOn0dOo0mOp0nOgjikjisjizji!Tji!Uji%{ji!Wji{ji![ji#gji%[ji%_ji!Qji#[jitji!mji%zji~Ol0fO~P!NkOlji~P!NkOV'|Og*pOo0cOv0qO~P'vOn*rO~Og*pOz*tO~Og*uO~OV'|Oo0cOv0qO!W&Si~P'vOz*vO!W&Si~O!W*wO~OV(]Oo0cOv0qO![%}i#g%}i%[%}i%_%}ig%}i{%}i!m%}i%z%}i~P'vOz*zO!T%dO!U%cO![&Ti~Oz*}O![%}i#g%}i%[%}i%_%}ig%}i{%}i!m%}i%z%}i~O![+OO~Oa+QOo0cOv0qO![&Ti~P'vOz*zO![&Ti~O![+SO~OV+UOo0cOv0qO{&la![&la!m&la%z&la~P'vOz+VO{&la![&la!m&la%z&la~O!]+YO&n+[O![!nX~O![+^O~O{(kO![+_O~O{(kO![+_O!m+`O~OV&OOopOvqO{%hq!x%hq#g%hq%[%hq%_%hq%z%hq~P'vOz$ri{$ri!x$ri#g$ri%[$ri%_$ri%z$ri~P%SOV&OOopOvqO~P'vOV&OOo0cOv0qO#g%ha%[%ha%_%ha%z%ha~P'vOz+aO#g%ha%[%ha%_%ha%z%ha~Oz$ia#g$ia%[$ia%_$ian$ia~P%SO#g&Pi%[&Pi%_&Pin&Pi~P'vOz+dO#g#Wq%[#Wq%_#Wq~O#[+eOz$va#g$va%[$va%_$vag$va~O%uWO#g&ri%[&ri%_&rig&ri~Oz+gO#g&ri%[&ri%_&rig&ri~OV+iOh$WO%uWO~O%uWO#g&ti%[&ti%_&ti~Oo0cOv0qO#g&pi%[&pi%_&pi{&pi~P'vO{#{Oz#eX!W#eX~Oz+mO!W&uX~O!W+oO~Ot+rO#j)gOP#hqV#hqf#hqh#hqo#hqs#hqv#hq!P#hq!Q#hq!T#hq!U#hq!X#hq!]#hq!h#hq!r#hq!s#hq!t#hq!{#hq!}#hq#P#hq#R#hq#T#hq#X#hq#Z#hq#^#hq#_#hq#a#hq#c#hq#l#hq#o#hq#s#hq#u#hq#z#hq#}#hq$P#hq%X#hq%o#hq%p#hq%t#hq%u#hq&Z#hq&[#hq&]#hq&^#hq&_#hq&`#hq&a#hq&b#hq&c#hq&d#hq&e#hq&f#hq&g#hq&h#hq&i#hq&j#hq%Z#hq%_#hq~On$|az$|a~P%SOV)kOn&wi~P'vOz+yOn&wi~Oz,TO{$jO#[,TO~O#q,VOP#nqV#nqf#nqh#nqo#nqs#nqv#nq!P#nq!Q#nq!T#nq!U#nq!X#nq!]#nq!h#nq!r#nq!s#nq!t#nq!{#nq!}#nq#P#nq#R#nq#T#nq#X#nq#Z#nq#^#nq#_#nq#a#nq#c#nq#l#nq#o#nq#s#nq#u#nq#z#nq#}#nq$P#nq%X#nq%o#nq%p#nq%t#nq%u#nq&Z#nq&[#nq&]#nq&^#nq&_#nq&`#nq&a#nq&b#nq&c#nq&d#nq&e#nq&f#nq&g#nq&h#nq&i#nq&j#nq%Z#nq%_#nq~O#[,WOz%Oa{%Oa~Oo0cOv0qO{&xi~P'vOz,YO{&xi~O{#{O%z,[Og&zXz&zX~O%uWOg&zXz&zX~Oz,`Og&yX~Og,bO~O%Y,eO~O!T%dO!U%cOg&Viz&Vi~OV$}Oa$}Oo0cOv0qOg&Ui~P'vO{,hOz$la!W$la~Oo0cOv0qO{,iOz$la!W$la~P'vOo0cOv0qO{*gO!W&Xi~P'vOz,lO!W&Xi~Oo0cOv0qOz,lO!W&Xi~P'vOz,lO{,oO!W&Xi~Og$hiz$hi!W$hi~P%SOV'|Oo0cOv0qO~P'vOn,qO~OV'|Og,rOo0cOv0qO~P'vOV'|Oo0cOv0qO!W&Sq~P'vOz$gi![$gi#g$gi%[$gi%_$gig$gi{$gi!m$gi%z$gi~P%SOV(]Oo0cOv0qO~P'vOa+QOo0cOv0qO![&Tq~P'vOz,sO![&Tq~O![,tO~OV(]Oo0cOv0qO![%}q#g%}q%[%}q%_%}qg%}q{%}q!m%}q%z%}q~P'vO{,uO~OV+UOo0cOv0qO{&li![&li!m&li%z&li~P'vOz,zO{&li![&li!m&li%z&li~O!]+YO&n+[O![!na~O{(kO![,}O~OV&OOo0cOv0qO#g%hi%[%hi%_%hi%z%hi~P'vOz-OO#g%hi%[%hi%_%hi%z%hi~O%uWO#g&rq%[&rq%_&rqg&rq~Oz-RO#g&rq%[&rq%_&rqg&rq~OV)`Oa)`O%uWO!W&ua~Oz-TO!W&ua~On$|iz$|i~P%SOV)kO~P'vOV)kOn&wq~P'vOt-XOP#myV#myf#myh#myo#mys#myv#my!P#my!Q#my!T#my!U#my!X#my!]#my!h#my!r#my!s#my!t#my!{#my!}#my#P#my#R#my#T#my#X#my#Z#my#^#my#_#my#a#my#c#my#l#my#o#my#s#my#u#my#z#my#}#my$P#my%X#my%o#my%p#my%t#my%u#my&Z#my&[#my&]#my&^#my&_#my&`#my&a#my&b#my&c#my&d#my&e#my&f#my&g#my&h#my&i#my&j#my%Z#my%_#my~O%Z-]O%_-]O~P`O#q-^OP#nyV#nyf#nyh#nyo#nys#nyv#ny!P#ny!Q#ny!T#ny!U#ny!X#ny!]#ny!h#ny!r#ny!s#ny!t#ny!{#ny!}#ny#P#ny#R#ny#T#ny#X#ny#Z#ny#^#ny#_#ny#a#ny#c#ny#l#ny#o#ny#s#ny#u#ny#z#ny#}#ny$P#ny%X#ny%o#ny%p#ny%t#ny%u#ny&Z#ny&[#ny&]#ny&^#ny&_#ny&`#ny&a#ny&b#ny&c#ny&d#ny&e#ny&f#ny&g#ny&h#ny&i#ny&j#ny%Z#ny%_#ny~Oz-aO{$jO#[-aO~Oo0cOv0qO{&xq~P'vOz-dO{&xq~O%z,[Og&zaz&za~O{#{Og&zaz&za~OV*SOa*TO%q*UO%uWOg&ya~Oz-hOg&ya~O$S-lO~OV$}Oa$}Oo0cOv0qO~P'vOo0cOv0qO{-mOz$li!W$li~P'vOo0cOv0qOz$li!W$li~P'vO{-mOz$li!W$li~Oo0cOv0qO{*gO~P'vOo0cOv0qO{*gO!W&Xq~P'vOz-pO!W&Xq~Oo0cOv0qOz-pO!W&Xq~P'vOs-sO!T%dO!U%cOg&Oq!W&Oq![&Oqz&Oq~P!/jOa+QOo0cOv0qO![&Ty~P'vOz$ji![$ji~P%SOa+QOo0cOv0qO~P'vOV+UOo0cOv0qO~P'vOV+UOo0cOv0qO{&lq![&lq!m&lq%z&lq~P'vO{(kO![-xO!m-yO%z-wO~OV&OOo0cOv0qO#g%hq%[%hq%_%hq%z%hq~P'vO%uWO#g&ry%[&ry%_&ryg&ry~OV)`Oa)`O%uWO!W&ui~Ot-}OP#m!RV#m!Rf#m!Rh#m!Ro#m!Rs#m!Rv#m!R!P#m!R!Q#m!R!T#m!R!U#m!R!X#m!R!]#m!R!h#m!R!r#m!R!s#m!R!t#m!R!{#m!R!}#m!R#P#m!R#R#m!R#T#m!R#X#m!R#Z#m!R#^#m!R#_#m!R#a#m!R#c#m!R#l#m!R#o#m!R#s#m!R#u#m!R#z#m!R#}#m!R$P#m!R%X#m!R%o#m!R%p#m!R%t#m!R%u#m!R&Z#m!R&[#m!R&]#m!R&^#m!R&_#m!R&`#m!R&a#m!R&b#m!R&c#m!R&d#m!R&e#m!R&f#m!R&g#m!R&h#m!R&i#m!R&j#m!R%Z#m!R%_#m!R~Oo0cOv0qO{&xy~P'vOV*SOa*TO%q*UO%uWOg&yi~O$S-lO%Z.VO%_.VO~OV.aOh._O!X.^O!].`O!h.YO!s.[O!t.[O%p.XO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O~Oo0cOv0qOz$lq!W$lq~P'vO{.fOz$lq!W$lq~Oo0cOv0qO{*gO!W&Xy~P'vOz.gO!W&Xy~Oo0cOv.kO~P'vOs-sO!T%dO!U%cOg&Oy!W&Oy![&Oyz&Oy~P!/jO{(kO![.nO~O{(kO![.nO!m.oO~OV*SOa*TO%q*UO%uWO~Oh.tO!f.rOz$TX#[$TX%j$TXg$TX~Os$TX{$TX!W$TX![$TX~P$-bO%o.vO%p.vOs$UXz$UX{$UX#[$UX%j$UX!W$UXg$UX![$UX~O!h.xO~Oz.|O#[/OO%j.yOs&|X{&|X!W&|Xg&|X~Oa/RO~P$)zOh.tOs&}Xz&}X{&}X#[&}X%j&}X!W&}Xg&}X![&}X~Os/VO{$jO~Oo0cOv0qOz$ly!W$ly~P'vOo0cOv0qO{*gO!W&X!R~P'vOz/ZO!W&X!R~Og&RXs&RX!T&RX!U&RX!W&RX![&RXz&RX~P!/jOs-sO!T%dO!U%cOg&Qa!W&Qa![&Qaz&Qa~O{(kO![/^O~O!f.rOh$[as$[az$[a{$[a#[$[a%j$[a!W$[ag$[a![$[a~O!h/eO~O%o.vO%p.vOs$Uaz$Ua{$Ua#[$Ua%j$Ua!W$Uag$Ua![$Ua~O%j.yOs$Yaz$Ya{$Ya#[$Ya!W$Yag$Ya![$Ya~Os&|a{&|a!W&|ag&|a~P$)nOz/jOs&|a{&|a!W&|ag&|a~O!W/mO~Og/mO~O{/oO~O![/pO~Oo0cOv0qO{*gO!W&X!Z~P'vO{/sO~O%z/tO~P$-bOz/uO#[/OO%j.yOg'PX~Oz/uOg'PX~Og/wO~O!h/xO~O#[/OOs%Saz%Sa{%Sa%j%Sa!W%Sag%Sa![%Sa~O#[/OO%j.yOs%Waz%Wa{%Wa!W%Wag%Wa~Os&|i{&|i!W&|ig&|i~P$)nOz/zO#[/OO%j.yO!['Oa~Og'Pa~P$)nOz0SOg'Pa~Oa0UO!['Oi~P$)zOz0WO!['Oi~Oz0WO#[/OO%j.yO!['Oi~O#[/OO%j.yOg$biz$bi~O%z0ZO~P$-bO#[/OO%j.yOg%Vaz%Va~Og'Pi~P$)nO{0^O~Oa0UO!['Oq~P$)zOz0`O!['Oq~O#[/OO%j.yOz%Ui![%Ui~Oa0UO~P$)zOa0UO!['Oy~P$)zO#[/OO%j.yOg$ciz$ci~O#[/OO%j.yOz%Uq![%Uq~Oz+aO#g%ha%[%ha%_%ha%z%ha~P%SOV&OOo0cOv0qO~P'vOn0hO~Oo0hO~P'vO{0iO~Ot0jO~P!/jO&]&Z&j&h&i&g&f&d&e&c&b&`&a&_&^&[%u~",goto:"!=j'QPPPPPP'RP'Z*s+[+t,_,y-fP.SP'Z.r.r'ZPPP'Z2[PPPPPP2[5PPP5PP7b7k=sPP=v>h>kPP'Z'ZPP>zPP'Z'ZPP'Z'Z'Z'Z'Z?O?w'ZP?zP@QDXGuGyPG|HWH['ZPPPH_Hk'RP'R'RP'RP'RP'RP'RP'R'R'RP'RPP'RPP'RP'RPHqH}IVPI^IdPI^PI^I^PPPI^PKrPK{LVL]KrPI^LfPI^PLmLsPLwM]MzNeLwLwNkNxLwLwLwLw! ^! d! g! l! o! y!!P!!]!!o!!u!#P!#V!#s!#y!$P!$Z!$a!$g!$y!%T!%Z!%a!%k!%q!%w!%}!&T!&Z!&e!&k!&u!&{!'U!'[!'k!'s!'}!(UPPPPPPPPPPP!([!(_!(e!(n!(x!)TPPPPPPPPPPPP!-u!/Z!3^!6oPP!6w!7W!7a!8Y!8P!8c!8i!8l!8o!8r!8z!9jPPPPPPPPPPPPPPPPP!9m!9q!9wP!:]!:a!:m!:v!;S!;j!;m!;p!;v!;|!_![!]Do!]!^Es!^!_FZ!_!`Gk!`!aHX!a!b%T!b!cIf!c!dJU!d!eK^!e!hJU!h!i!#f!i!tJU!t!u!,|!u!wJU!w!x!.t!x!}JU!}#O!0S#O#P&o#P#Q!0j#Q#R!1Q#R#SJU#S#T%T#T#UJU#U#VK^#V#YJU#Y#Z!#f#Z#fJU#f#g!,|#g#iJU#i#j!.t#j#oJU#o#p!1n#p#q!1s#q#r!2a#r#s!2f#s$g%T$g;'SJU;'S;=`KW<%lOJU`%YT&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%T`%lP;=`<%l%To%v]&n`%c_OX%TXY%oY[%T[]%o]p%Tpq%oq#O%T#O#P&o#P#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To&tX&n`OY%TYZ%oZ]%T]^%o^#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc'f[&n`O!_%T!_!`([!`#T%T#T#U(r#U#f%T#f#g(r#g#h(r#h#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc(cTmR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc(yT!mR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk)aV&n`&[ZOr%Trs)vs#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk){V&n`Or%Trs*bs#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk*iT&n`&^ZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To+PZS_&n`OY*xYZ%TZ]*x]^%T^#o*x#o#p+r#p#q*x#q#r+r#r;'S*x;'S;=`,^<%lO*x_+wTS_OY+rZ]+r^;'S+r;'S;=`,W<%lO+r_,ZP;=`<%l+ro,aP;=`<%l*xj,kV%rQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tj-XT!xY&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tj-oV%lQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk.]V&n`&ZZOw%Twx.rx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk.wV&n`Ow%Twx/^x#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk/eT&n`&]ZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk/{ThZ&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc0cTgR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk0yXVZ&n`Oz%Tz{1f{!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk1mVaR&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk2ZV%oZ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc2wTzR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To3_W%pZ&n`O!_%T!_!`-Q!`!a3w!a#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Td4OT&{S&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk4fX!fQ&n`O!O%T!O!P5R!P!Q%T!Q![6T![#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk5WV&n`O!O%T!O!P5m!P#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk5tT!rZ&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti6[a!hX&n`O!Q%T!Q![6T![!g%T!g!h7a!h!l%T!l!m9s!m#R%T#R#S6T#S#X%T#X#Y7a#Y#^%T#^#_9s#_#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti7fZ&n`O{%T{|8X|}%T}!O8X!O!Q%T!Q![8s![#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti8^V&n`O!Q%T!Q![8s![#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti8z]!hX&n`O!Q%T!Q![8s![!l%T!l!m9s!m#R%T#R#S8s#S#^%T#^#_9s#_#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti9zT!hX&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk:bX%qR&n`O!P%T!P!Q:}!Q!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tj;UV%sQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti;ro!hX&n`O!O%T!O!P=s!P!Q%T!Q![>_![!d%T!d!e?q!e!g%T!g!h7a!h!l%T!l!m9s!m!q%T!q!rA]!r!z%T!z!{Bq!{#R%T#R#S>_#S#U%T#U#V?q#V#X%T#X#Y7a#Y#^%T#^#_9s#_#c%T#c#dA]#d#l%T#l#mBq#m#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti=xV&n`O!Q%T!Q![6T![#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti>fc!hX&n`O!O%T!O!P=s!P!Q%T!Q![>_![!g%T!g!h7a!h!l%T!l!m9s!m#R%T#R#S>_#S#X%T#X#Y7a#Y#^%T#^#_9s#_#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti?vY&n`O!Q%T!Q!R@f!R!S@f!S#R%T#R#S@f#S#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Ti@mY!hX&n`O!Q%T!Q!R@f!R!S@f!S#R%T#R#S@f#S#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TiAbX&n`O!Q%T!Q!YA}!Y#R%T#R#SA}#S#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TiBUX!hX&n`O!Q%T!Q!YA}!Y#R%T#R#SA}#S#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TiBv]&n`O!Q%T!Q![Co![!c%T!c!iCo!i#R%T#R#SCo#S#T%T#T#ZCo#Z#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TiCv]!hX&n`O!Q%T!Q![Co![!c%T!c!iCo!i#R%T#R#SCo#S#T%T#T#ZCo#Z#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%ToDvV{_&n`O!_%T!_!`E]!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TcEdT%{R&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkEzT#gZ&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkFbXmR&n`O!^%T!^!_F}!_!`([!`!a([!a#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TjGUV%mQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkGrV%zZ&n`O!_%T!_!`([!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkH`WmR&n`O!_%T!_!`([!`!aHx!a#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TjIPV%nQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkIoV_Q#}P&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%ToJ_]&n`&YS%uZO!Q%T!Q![JU![!c%T!c!}JU!}#R%T#R#SJU#S#T%T#T#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUoKZP;=`<%lJUoKge&n`&YS%uZOr%Trs)Ysw%Twx.Ux!Q%T!Q![JU![!c%T!c!tJU!t!uLx!u!}JU!}#R%T#R#SJU#S#T%T#T#fJU#f#gLx#g#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUoMRa&n`&YS%uZOr%TrsNWsw%Twx! vx!Q%T!Q![JU![!c%T!c!}JU!}#R%T#R#SJU#S#T%T#T#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUkN_V&n`&`ZOr%TrsNts#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%TkNyV&n`Or%Trs! `s#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk! gT&n`&bZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk! }V&n`&_ZOw%Twx!!dx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!!iV&n`Ow%Twx!#Ox#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!#VT&n`&aZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To!#oe&n`&YS%uZOr%Trs!%Qsw%Twx!&px!Q%T!Q![JU![!c%T!c!tJU!t!u!(`!u!}JU!}#R%T#R#SJU#S#T%T#T#fJU#f#g!(`#g#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUk!%XV&n`&dZOr%Trs!%ns#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!%sV&n`Or%Trs!&Ys#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!&aT&n`&fZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!&wV&n`&cZOw%Twx!'^x#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!'cV&n`Ow%Twx!'xx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!(PT&n`&eZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To!(ia&n`&YS%uZOr%Trs!)nsw%Twx!+^x!Q%T!Q![JU![!c%T!c!}JU!}#R%T#R#SJU#S#T%T#T#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUk!)uV&n`&hZOr%Trs!*[s#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!*aV&n`Or%Trs!*vs#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!*}T&n`&jZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!+eV&n`&gZOw%Twx!+zx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!,PV&n`Ow%Twx!,fx#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tk!,mT&n`&iZO#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%To!-Vi&n`&YS%uZOr%TrsNWsw%Twx! vx!Q%T!Q![JU![!c%T!c!dJU!d!eLx!e!hJU!h!i!(`!i!}JU!}#R%T#R#SJU#S#T%T#T#UJU#U#VLx#V#YJU#Y#Z!(`#Z#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUo!.}a&n`&YS%uZOr%Trs)Ysw%Twx.Ux!Q%T!Q![JU![!c%T!c!}JU!}#R%T#R#SJU#S#T%T#T#oJU#p#q%T#r$g%T$g;'SJU;'S;=`KW<%lOJUk!0ZT!XZ&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tc!0qT!WR&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%Tj!1XV%kQ&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%T~!1sO!]~k!1zV%jR&n`O!_%T!_!`-Q!`#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%T~!2fO![~i!2mT%tX&n`O#o%T#p#q%T#r;'S%T;'S;=`%i<%lO%T",tokenizers:[nt,Qe,Ze,rt,0,1,2,3,4],topRules:{Script:[0,5]},specialized:[{term:221,get:e=>ot[e]||-1}],tokenPrec:7668}),G=new t,K=new Set([`Script`,`Body`,`FunctionDefinition`,`ClassDefinition`,`LambdaExpression`,`ForStatement`,`MatchClause`]);function q(e){return(t,n,r)=>{if(r)return!1;let i=t.node.getChild(`VariableName`);return i&&n(i,e),!0}}var ct={FunctionDefinition:q(`function`),ClassDefinition:q(`class`),ForStatement(e,t,n){if(n){for(let n=e.node.firstChild;n;n=n.nextSibling)if(n.name==`VariableName`)t(n,`variable`);else if(n.name==`in`)break}},ImportStatement(e,t){let{node:n}=e,r=n.firstChild?.name==`from`;for(let e=n.getChild(`import`);e;e=e.nextSibling)e.name==`VariableName`&&e.nextSibling?.name!=`as`&&t(e,r?`variable`:`namespace`)},AssignStatement(e,t){for(let n=e.node.firstChild;n;n=n.nextSibling)if(n.name==`VariableName`)t(n,`variable`);else if(n.name==`:`||n.name==`AssignOp`)break},ParamList(e,t){for(let n=null,r=e.node.firstChild;r;r=r.nextSibling)r.name==`VariableName`&&(!n||!/\*|AssignOp/.test(n.name))&&t(r,`variable`),n=r},CapturePattern:q(`variable`),AsPattern:q(`variable`),__proto__:null};function J(t,n){let r=G.get(n);if(r)return r;let i=[],a=!0;function o(e,n){let r=t.sliceString(e.from,e.to);i.push({label:r,type:n})}return n.cursor(e.IncludeAnonymous).iterate(e=>{if(e.name){let t=ct[e.name];if(t&&t(e,o,a)||!a&&K.has(e.name))return!1;a=!1}else if(e.to-e.from>8192){for(let n of J(t,e.node))i.push(n);return!1}}),G.set(n,i),i}var Y=/^[\w\xa1-\uffff][\w\d\xa1-\uffff]*$/,X=[`String`,`FormatString`,`Comment`,`PropertyName`];function lt(e){let t=te(e.state).resolveInner(e.pos,-1);if(X.indexOf(t.name)>-1)return null;let n=t.name==`VariableName`||t.to-t.from<20&&Y.test(e.state.sliceDoc(t.from,t.to));if(!n&&!e.explicit)return null;let r=[];for(let n=t;n;n=n.parent)K.has(n.name)&&(r=r.concat(J(e.state.doc,n)));return{options:r,from:n?t.from:e.pos,validFor:Y}}var ut=[`__annotations__`,`__builtins__`,`__debug__`,`__doc__`,`__import__`,`__name__`,`__loader__`,`__package__`,`__spec__`,`False`,`None`,`True`].map(e=>({label:e,type:`constant`})).concat(`ArithmeticError.AssertionError.AttributeError.BaseException.BlockingIOError.BrokenPipeError.BufferError.BytesWarning.ChildProcessError.ConnectionAbortedError.ConnectionError.ConnectionRefusedError.ConnectionResetError.DeprecationWarning.EOFError.Ellipsis.EncodingWarning.EnvironmentError.Exception.FileExistsError.FileNotFoundError.FloatingPointError.FutureWarning.GeneratorExit.IOError.ImportError.ImportWarning.IndentationError.IndexError.InterruptedError.IsADirectoryError.KeyError.KeyboardInterrupt.LookupError.MemoryError.ModuleNotFoundError.NameError.NotADirectoryError.NotImplemented.NotImplementedError.OSError.OverflowError.PendingDeprecationWarning.PermissionError.ProcessLookupError.RecursionError.ReferenceError.ResourceWarning.RuntimeError.RuntimeWarning.StopAsyncIteration.StopIteration.SyntaxError.SyntaxWarning.SystemError.SystemExit.TabError.TimeoutError.TypeError.UnboundLocalError.UnicodeDecodeError.UnicodeEncodeError.UnicodeError.UnicodeTranslateError.UnicodeWarning.UserWarning.ValueError.Warning.ZeroDivisionError`.split(`.`).map(e=>({label:e,type:`type`}))).concat([`bool`,`bytearray`,`bytes`,`classmethod`,`complex`,`float`,`frozenset`,`int`,`list`,`map`,`memoryview`,`object`,`range`,`set`,`staticmethod`,`str`,`super`,`tuple`,`type`].map(e=>({label:e,type:`class`}))).concat(`abs.aiter.all.anext.any.ascii.bin.breakpoint.callable.chr.compile.delattr.dict.dir.divmod.enumerate.eval.exec.exit.filter.format.getattr.globals.hasattr.hash.help.hex.id.input.isinstance.issubclass.iter.len.license.locals.max.min.next.oct.open.ord.pow.print.property.quit.repr.reversed.round.setattr.slice.sorted.sum.vars.zip`.split(`.`).map(e=>({label:e,type:`function`}))),dt=[u("def ${name}(${params}):\n ${}",{label:`def`,detail:`function`,type:`keyword`}),u("for ${name} in ${collection}:\n ${}",{label:`for`,detail:`loop`,type:`keyword`}),u("while ${}:\n ${}",{label:`while`,detail:`loop`,type:`keyword`}),u(`try: \${} except \${error}: \${}`,{label:`try`,detail:`/ except block`,type:`keyword`}),u(`if \${}: diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/dist-DeLSDQE4.js b/mcp/src/agents_remember/package_data/dashboard/assets/dist-BxWz473c.js similarity index 99% rename from mcp/src/agents_remember/package_data/dashboard/assets/dist-DeLSDQE4.js rename to mcp/src/agents_remember/package_data/dashboard/assets/dist-BxWz473c.js index 33d8ae51..18cc3ef3 100644 --- a/mcp/src/agents_remember/package_data/dashboard/assets/dist-DeLSDQE4.js +++ b/mcp/src/agents_remember/package_data/dashboard/assets/dist-BxWz473c.js @@ -1 +1 @@ -import{B as e,F as t,G as n,H as r,I as i,M as a,N as o,P as s,R as c,U as l,V as u,W as d,h as f,j as p,v as m,z as h}from"./index-BLlkJI-k.js";var g=class{constructor(e,t,n,r){this.state=e,this.pos=t,this.explicit=n,this.view=r,this.abortListeners=[],this.abortOnDocChange=!1}tokenBefore(e){let t=m(this.state).resolveInner(this.pos,-1);for(;t&&e.indexOf(t.name)<0;)t=t.parent;return t?{from:t.from,to:this.pos,text:this.state.sliceDoc(t.from,this.pos),type:t.type}:null}matchBefore(e){let t=this.state.doc.lineAt(this.pos),n=Math.max(t.from,this.pos-250),r=t.text.slice(n-t.from,this.pos-t.from),i=r.search(x(e,!1));return i<0?null:{from:n+i,to:this.pos,text:r.slice(i)}}get aborted(){return this.abortListeners==null}addEventListener(e,t,n){e==`abort`&&this.abortListeners&&(this.abortListeners.push(t),n&&n.onDocChange&&(this.abortOnDocChange=!0))}};function _(e){let t=Object.keys(e).join(``),n=/\w/.test(t);return n&&(t=t.replace(/\w/g,``)),`[${n?`\\w`:``}${t.replace(/[^\w\s]/g,`\\$&`)}]`}function v(e){let t=Object.create(null),n=Object.create(null);for(let{label:r}of e){t[r[0]]=!0;for(let e=1;etypeof e==`string`?{label:e}:e),[n,r]=t.every(e=>/^\w+$/.test(e.label))?[/\w*$/,/\w+$/]:v(t);return e=>{let i=e.matchBefore(r);return i||e.explicit?{from:i?i.from:e.pos,options:t,validFor:n}:null}}function b(e,t){return n=>{for(let t=m(n.state).resolveInner(n.pos,-1);t;t=t.parent){if(e.indexOf(t.name)>-1)return null;if(t.type.isTop)break}return t(n)}}function x(e,t){let{source:n}=e,r=t&&n[0]!=`^`,i=n[n.length-1]!=`$`;return!r&&!i?e:RegExp(`${r?`^`:``}(?:${n})${i?`$`:``}`,e.flags??(e.ignoreCase?`i`:``))}var S=t.define();typeof navigator==`object`&&navigator.platform;var C=a.baseTheme({".cm-tooltip.cm-tooltip-autocomplete":{"& > ul":{fontFamily:`monospace`,whiteSpace:`nowrap`,overflow:`hidden auto`,maxWidth_fallback:`700px`,maxWidth:`min(700px, 95vw)`,minWidth:`250px`,maxHeight:`10em`,height:`100%`,listStyle:`none`,margin:0,padding:0,"& > li, & > completion-section":{padding:`1px 3px`,lineHeight:1.2},"& > li":{overflowX:`hidden`,textOverflow:`ellipsis`,cursor:`pointer`},"& > completion-section":{display:`list-item`,borderBottom:`1px solid silver`,paddingLeft:`0.5em`,opacity:.7}}},"&light .cm-tooltip-autocomplete ul li[aria-selected]":{background:`#17c`,color:`white`},"&light .cm-tooltip-autocomplete-disabled ul li[aria-selected]":{background:`#777`},"&dark .cm-tooltip-autocomplete ul li[aria-selected]":{background:`#347`,color:`white`},"&dark .cm-tooltip-autocomplete-disabled ul li[aria-selected]":{background:`#444`},".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after":{content:`"···"`,opacity:.5,display:`block`,textAlign:`center`,cursor:`pointer`},".cm-tooltip.cm-completionInfo":{position:`absolute`,padding:`3px 9px`,width:`max-content`,maxWidth:`400px`,boxSizing:`border-box`,whiteSpace:`pre-line`},".cm-completionInfo.cm-completionInfo-left":{right:`100%`},".cm-completionInfo.cm-completionInfo-right":{left:`100%`},".cm-completionInfo.cm-completionInfo-left-narrow":{right:`30px`},".cm-completionInfo.cm-completionInfo-right-narrow":{left:`30px`},"&light .cm-snippetField":{backgroundColor:`#00000022`},"&dark .cm-snippetField":{backgroundColor:`#ffffff22`},".cm-snippetFieldPosition":{verticalAlign:`text-top`,width:0,height:`1.15em`,display:`inline-block`,margin:`0 -0.7px -.7em`,borderLeft:`1.4px dotted #888`},".cm-completionMatchedText":{textDecoration:`underline`},".cm-completionDetail":{marginLeft:`0.5em`,fontStyle:`italic`},".cm-completionIcon":{fontSize:`90%`,width:`.8em`,display:`inline-block`,textAlign:`center`,paddingRight:`.6em`,opacity:`0.6`,boxSizing:`content-box`},".cm-completionIcon-function, .cm-completionIcon-method":{"&:after":{content:`'ƒ'`}},".cm-completionIcon-class":{"&:after":{content:`'○'`}},".cm-completionIcon-interface":{"&:after":{content:`'◌'`}},".cm-completionIcon-variable":{"&:after":{content:`'𝑥'`}},".cm-completionIcon-constant":{"&:after":{content:`'𝐶'`}},".cm-completionIcon-type":{"&:after":{content:`'𝑡'`}},".cm-completionIcon-enum":{"&:after":{content:`'∪'`}},".cm-completionIcon-property":{"&:after":{content:`'□'`}},".cm-completionIcon-keyword":{"&:after":{content:`'🔑︎'`}},".cm-completionIcon-namespace":{"&:after":{content:`'▢'`}},".cm-completionIcon-text":{"&:after":{content:`'abc'`,fontSize:`50%`,verticalAlign:`middle`}}}),w=class{constructor(e,t,n,r){this.field=e,this.line=t,this.from=n,this.to=r}},T=class e{constructor(e,t,n){this.field=e,this.from=t,this.to=n}map(t){let n=t.mapPos(this.from,-1,h.TrackDel),r=t.mapPos(this.to,1,h.TrackDel);return n==null||r==null?null:new e(this.field,n,r)}},E=class e{constructor(e,t){this.lines=e,this.fieldPositions=t}instantiate(e,t){let n=[],r=[t],i=e.doc.lineAt(t),a=/^\s*/.exec(i.text)[0];for(let i of this.lines){if(n.length){let n=a,o=/^\t*/.exec(i)[0].length;for(let t=0;tnew T(e.field,r[e.line]+e.from,r[e.line]+e.to))}}static parse(t){let n=[],r=[],i=[],a;for(let e of t.split(/\r\n?|\n/)){for(;a=/[#$]\{(?:(\d+)(?::([^{}]*))?|((?:\\[{}]|[^{}])*))\}/.exec(e);){let t=a[1]?+a[1]:null,o=a[2]||a[3]||``,s=-1;t===0&&(t=1e9);let c=o.replace(/\\[{}]/g,e=>e[1]);for(let e=0;e=s&&e.field++}for(let e of i)if(e.line==r.length&&e.from>a.index){let t=a[2]?3+(a[1]||``).length:2;e.from-=t,e.to-=t}i.push(new w(s,r.length,a.index,a.index+c.length)),e=e.slice(0,a.index)+o+e.slice(a.index+a[0].length)}e=e.replace(/\\([{}])/g,(e,t,n)=>{for(let e of i)e.line==r.length&&e.from>n&&(e.from--,e.to--);return t}),r.push(e)}return new e(r,i)}},D=p.widget({widget:new class extends o{toDOM(){let e=document.createElement(`span`);return e.className=`cm-snippetFieldPosition`,e}ignoreEvent(){return!1}}}),O=p.mark({class:`cm-snippetField`}),k=class e{constructor(e,t){this.ranges=e,this.active=t,this.deco=p.set(e.map(e=>(e.from==e.to?D:O).range(e.from,e.to)),!0)}map(t){let n=[];for(let e of this.ranges){let r=e.map(t);if(!r)return null;n.push(r)}return new e(n,this.active)}selectionInsideField(e){return e.ranges.every(e=>this.ranges.some(t=>t.field==this.active&&t.from<=e.from&&t.to>=e.to))}},A=r.define({map(e,t){return e&&e.map(t)}}),j=r.define(),M=l.define({create(){return null},update(e,t){for(let n of t.effects){if(n.is(A))return n.value;if(n.is(j)&&e)return new k(e.ranges,n.value)}return e&&t.docChanged&&(e=e.map(t.changes)),e&&t.selection&&!e.selectionInsideField(t.selection)&&(e=null),e},provide:e=>a.decorations.from(e,e=>e?e.deco:p.none)});function N(e,t){return i.create(e.filter(e=>e.field==t).map(e=>i.range(e.from,e.to)))}function P(e){let t=E.parse(e);return(e,i,a,o)=>{let{text:s,ranges:c}=t.instantiate(e.state,a),{main:l}=e.state.selection,u={changes:{from:a,to:o==l.from?l.to:o,insert:d.of(s)},scrollIntoView:!0,annotations:i?[S.of(i),n.userEvent.of(`input.complete`)]:void 0};if(c.length&&(u.selection=N(c,0)),c.some(e=>e.field>0)){let t=new k(c,0),n=u.effects=[A.of(t)];e.state.field(M,!1)===void 0&&n.push(r.appendConfig.of([M,R,B,C]))}e.dispatch(e.state.update(u))}}function F(e){return({state:t,dispatch:n})=>{let r=t.field(M,!1);if(!r||e<0&&r.active==0)return!1;let i=r.active+e,a=e>0&&!r.ranges.some(t=>t.field==i+e);return n(t.update({selection:N(r.ranges,i),effects:A.of(a?null:new k(r.ranges,i)),scrollIntoView:!0})),!0}}var I=[{key:`Tab`,run:F(1),shift:F(-1)},{key:`Escape`,run:({state:e,dispatch:t})=>e.field(M,!1)?(t(e.update({effects:A.of(null)})),!0):!1}],L=c.define({combine(e){return e.length?e[0]:I}}),R=e.highest(s.compute([L],e=>e.facet(L)));function z(e,t){return{...t,apply:P(e)}}var B=a.domEventHandlers({mousedown(e,t){let n=t.state.field(M,!1),r;if(!n||(r=t.posAtCoords({x:e.clientX,y:e.clientY}))==null)return!1;let i=n.ranges.find(e=>e.from<=r&&e.to>=r);return!i||i.field==n.active?!1:(t.dispatch({selection:N(n.ranges,i.field),effects:A.of(n.ranges.some(e=>e.field>i.field)?new k(n.ranges,i.field):null),scrollIntoView:!0}),!0)}}),V=new class extends u{};V.startSide=1,V.endSide=-1,typeof navigator==`object`&&navigator.userAgent;export{z as i,y as n,b as r,g as t}; \ No newline at end of file +import{B as e,F as t,G as n,H as r,I as i,M as a,N as o,P as s,R as c,U as l,V as u,W as d,h as f,j as p,v as m,z as h}from"./index-CLJ0aycO.js";var g=class{constructor(e,t,n,r){this.state=e,this.pos=t,this.explicit=n,this.view=r,this.abortListeners=[],this.abortOnDocChange=!1}tokenBefore(e){let t=m(this.state).resolveInner(this.pos,-1);for(;t&&e.indexOf(t.name)<0;)t=t.parent;return t?{from:t.from,to:this.pos,text:this.state.sliceDoc(t.from,this.pos),type:t.type}:null}matchBefore(e){let t=this.state.doc.lineAt(this.pos),n=Math.max(t.from,this.pos-250),r=t.text.slice(n-t.from,this.pos-t.from),i=r.search(x(e,!1));return i<0?null:{from:n+i,to:this.pos,text:r.slice(i)}}get aborted(){return this.abortListeners==null}addEventListener(e,t,n){e==`abort`&&this.abortListeners&&(this.abortListeners.push(t),n&&n.onDocChange&&(this.abortOnDocChange=!0))}};function _(e){let t=Object.keys(e).join(``),n=/\w/.test(t);return n&&(t=t.replace(/\w/g,``)),`[${n?`\\w`:``}${t.replace(/[^\w\s]/g,`\\$&`)}]`}function v(e){let t=Object.create(null),n=Object.create(null);for(let{label:r}of e){t[r[0]]=!0;for(let e=1;etypeof e==`string`?{label:e}:e),[n,r]=t.every(e=>/^\w+$/.test(e.label))?[/\w*$/,/\w+$/]:v(t);return e=>{let i=e.matchBefore(r);return i||e.explicit?{from:i?i.from:e.pos,options:t,validFor:n}:null}}function b(e,t){return n=>{for(let t=m(n.state).resolveInner(n.pos,-1);t;t=t.parent){if(e.indexOf(t.name)>-1)return null;if(t.type.isTop)break}return t(n)}}function x(e,t){let{source:n}=e,r=t&&n[0]!=`^`,i=n[n.length-1]!=`$`;return!r&&!i?e:RegExp(`${r?`^`:``}(?:${n})${i?`$`:``}`,e.flags??(e.ignoreCase?`i`:``))}var S=t.define();typeof navigator==`object`&&navigator.platform;var C=a.baseTheme({".cm-tooltip.cm-tooltip-autocomplete":{"& > ul":{fontFamily:`monospace`,whiteSpace:`nowrap`,overflow:`hidden auto`,maxWidth_fallback:`700px`,maxWidth:`min(700px, 95vw)`,minWidth:`250px`,maxHeight:`10em`,height:`100%`,listStyle:`none`,margin:0,padding:0,"& > li, & > completion-section":{padding:`1px 3px`,lineHeight:1.2},"& > li":{overflowX:`hidden`,textOverflow:`ellipsis`,cursor:`pointer`},"& > completion-section":{display:`list-item`,borderBottom:`1px solid silver`,paddingLeft:`0.5em`,opacity:.7}}},"&light .cm-tooltip-autocomplete ul li[aria-selected]":{background:`#17c`,color:`white`},"&light .cm-tooltip-autocomplete-disabled ul li[aria-selected]":{background:`#777`},"&dark .cm-tooltip-autocomplete ul li[aria-selected]":{background:`#347`,color:`white`},"&dark .cm-tooltip-autocomplete-disabled ul li[aria-selected]":{background:`#444`},".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after":{content:`"···"`,opacity:.5,display:`block`,textAlign:`center`,cursor:`pointer`},".cm-tooltip.cm-completionInfo":{position:`absolute`,padding:`3px 9px`,width:`max-content`,maxWidth:`400px`,boxSizing:`border-box`,whiteSpace:`pre-line`},".cm-completionInfo.cm-completionInfo-left":{right:`100%`},".cm-completionInfo.cm-completionInfo-right":{left:`100%`},".cm-completionInfo.cm-completionInfo-left-narrow":{right:`30px`},".cm-completionInfo.cm-completionInfo-right-narrow":{left:`30px`},"&light .cm-snippetField":{backgroundColor:`#00000022`},"&dark .cm-snippetField":{backgroundColor:`#ffffff22`},".cm-snippetFieldPosition":{verticalAlign:`text-top`,width:0,height:`1.15em`,display:`inline-block`,margin:`0 -0.7px -.7em`,borderLeft:`1.4px dotted #888`},".cm-completionMatchedText":{textDecoration:`underline`},".cm-completionDetail":{marginLeft:`0.5em`,fontStyle:`italic`},".cm-completionIcon":{fontSize:`90%`,width:`.8em`,display:`inline-block`,textAlign:`center`,paddingRight:`.6em`,opacity:`0.6`,boxSizing:`content-box`},".cm-completionIcon-function, .cm-completionIcon-method":{"&:after":{content:`'ƒ'`}},".cm-completionIcon-class":{"&:after":{content:`'○'`}},".cm-completionIcon-interface":{"&:after":{content:`'◌'`}},".cm-completionIcon-variable":{"&:after":{content:`'𝑥'`}},".cm-completionIcon-constant":{"&:after":{content:`'𝐶'`}},".cm-completionIcon-type":{"&:after":{content:`'𝑡'`}},".cm-completionIcon-enum":{"&:after":{content:`'∪'`}},".cm-completionIcon-property":{"&:after":{content:`'□'`}},".cm-completionIcon-keyword":{"&:after":{content:`'🔑︎'`}},".cm-completionIcon-namespace":{"&:after":{content:`'▢'`}},".cm-completionIcon-text":{"&:after":{content:`'abc'`,fontSize:`50%`,verticalAlign:`middle`}}}),w=class{constructor(e,t,n,r){this.field=e,this.line=t,this.from=n,this.to=r}},T=class e{constructor(e,t,n){this.field=e,this.from=t,this.to=n}map(t){let n=t.mapPos(this.from,-1,h.TrackDel),r=t.mapPos(this.to,1,h.TrackDel);return n==null||r==null?null:new e(this.field,n,r)}},E=class e{constructor(e,t){this.lines=e,this.fieldPositions=t}instantiate(e,t){let n=[],r=[t],i=e.doc.lineAt(t),a=/^\s*/.exec(i.text)[0];for(let i of this.lines){if(n.length){let n=a,o=/^\t*/.exec(i)[0].length;for(let t=0;tnew T(e.field,r[e.line]+e.from,r[e.line]+e.to))}}static parse(t){let n=[],r=[],i=[],a;for(let e of t.split(/\r\n?|\n/)){for(;a=/[#$]\{(?:(\d+)(?::([^{}]*))?|((?:\\[{}]|[^{}])*))\}/.exec(e);){let t=a[1]?+a[1]:null,o=a[2]||a[3]||``,s=-1;t===0&&(t=1e9);let c=o.replace(/\\[{}]/g,e=>e[1]);for(let e=0;e=s&&e.field++}for(let e of i)if(e.line==r.length&&e.from>a.index){let t=a[2]?3+(a[1]||``).length:2;e.from-=t,e.to-=t}i.push(new w(s,r.length,a.index,a.index+c.length)),e=e.slice(0,a.index)+o+e.slice(a.index+a[0].length)}e=e.replace(/\\([{}])/g,(e,t,n)=>{for(let e of i)e.line==r.length&&e.from>n&&(e.from--,e.to--);return t}),r.push(e)}return new e(r,i)}},D=p.widget({widget:new class extends o{toDOM(){let e=document.createElement(`span`);return e.className=`cm-snippetFieldPosition`,e}ignoreEvent(){return!1}}}),O=p.mark({class:`cm-snippetField`}),k=class e{constructor(e,t){this.ranges=e,this.active=t,this.deco=p.set(e.map(e=>(e.from==e.to?D:O).range(e.from,e.to)),!0)}map(t){let n=[];for(let e of this.ranges){let r=e.map(t);if(!r)return null;n.push(r)}return new e(n,this.active)}selectionInsideField(e){return e.ranges.every(e=>this.ranges.some(t=>t.field==this.active&&t.from<=e.from&&t.to>=e.to))}},A=r.define({map(e,t){return e&&e.map(t)}}),j=r.define(),M=l.define({create(){return null},update(e,t){for(let n of t.effects){if(n.is(A))return n.value;if(n.is(j)&&e)return new k(e.ranges,n.value)}return e&&t.docChanged&&(e=e.map(t.changes)),e&&t.selection&&!e.selectionInsideField(t.selection)&&(e=null),e},provide:e=>a.decorations.from(e,e=>e?e.deco:p.none)});function N(e,t){return i.create(e.filter(e=>e.field==t).map(e=>i.range(e.from,e.to)))}function P(e){let t=E.parse(e);return(e,i,a,o)=>{let{text:s,ranges:c}=t.instantiate(e.state,a),{main:l}=e.state.selection,u={changes:{from:a,to:o==l.from?l.to:o,insert:d.of(s)},scrollIntoView:!0,annotations:i?[S.of(i),n.userEvent.of(`input.complete`)]:void 0};if(c.length&&(u.selection=N(c,0)),c.some(e=>e.field>0)){let t=new k(c,0),n=u.effects=[A.of(t)];e.state.field(M,!1)===void 0&&n.push(r.appendConfig.of([M,R,B,C]))}e.dispatch(e.state.update(u))}}function F(e){return({state:t,dispatch:n})=>{let r=t.field(M,!1);if(!r||e<0&&r.active==0)return!1;let i=r.active+e,a=e>0&&!r.ranges.some(t=>t.field==i+e);return n(t.update({selection:N(r.ranges,i),effects:A.of(a?null:new k(r.ranges,i)),scrollIntoView:!0})),!0}}var I=[{key:`Tab`,run:F(1),shift:F(-1)},{key:`Escape`,run:({state:e,dispatch:t})=>e.field(M,!1)?(t(e.update({effects:A.of(null)})),!0):!1}],L=c.define({combine(e){return e.length?e[0]:I}}),R=e.highest(s.compute([L],e=>e.facet(L)));function z(e,t){return{...t,apply:P(e)}}var B=a.domEventHandlers({mousedown(e,t){let n=t.state.field(M,!1),r;if(!n||(r=t.posAtCoords({x:e.clientX,y:e.clientY}))==null)return!1;let i=n.ranges.find(e=>e.from<=r&&e.to>=r);return!i||i.field==n.active?!1:(t.dispatch({selection:N(n.ranges,i.field),effects:A.of(n.ranges.some(e=>e.field>i.field)?new k(n.ranges,i.field):null),scrollIntoView:!0}),!0)}}),V=new class extends u{};V.startSide=1,V.endSide=-1,typeof navigator==`object`&&navigator.userAgent;export{z as i,y as n,b as r,g as t}; \ No newline at end of file diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/dist-DGs1L_Vy.js b/mcp/src/agents_remember/package_data/dashboard/assets/dist-DlUN4-j9.js similarity index 96% rename from mcp/src/agents_remember/package_data/dashboard/assets/dist-DGs1L_Vy.js rename to mcp/src/agents_remember/package_data/dashboard/assets/dist-DlUN4-j9.js index d82cc19e..c995020e 100644 --- a/mcp/src/agents_remember/package_data/dashboard/assets/dist-DGs1L_Vy.js +++ b/mcp/src/agents_remember/package_data/dashboard/assets/dist-DlUN4-j9.js @@ -1 +1 @@ -import{b as e,d as t,f as n,i as r,m as i,s as a,t as o,x as s}from"./index-BLlkJI-k.js";import{r as c}from"./dist-CuvUDais.js";var l=e({String:s.string,Number:s.number,"True False":s.bool,PropertyName:s.propertyName,Null:s.null,", :":s.separator,"[ ]":s.squareBracket,"{ }":s.brace}),u=c.deserialize({version:14,states:"$bOVQPOOOOQO'#Cb'#CbOnQPO'#CeOvQPO'#ClOOQO'#Cr'#CrQOQPOOOOQO'#Cg'#CgO}QPO'#CfO!SQPO'#CtOOQO,59P,59PO![QPO,59PO!aQPO'#CuOOQO,59W,59WO!iQPO,59WOVQPO,59QOqQPO'#CmO!nQPO,59`OOQO1G.k1G.kOVQPO'#CnO!vQPO,59aOOQO1G.r1G.rOOQO1G.l1G.lOOQO,59X,59XOOQO-E6k-E6kOOQO,59Y,59YOOQO-E6l-E6l",stateData:`#O~OeOS~OQSORSOSSOTSOWQO_ROgPO~OVXOgUO~O^[O~PVO[^O~O]_OVhX~OVaO~O]bO^iX~O^dO~O]_OVha~O]bO^ia~O`,goto:"!kjPPPPPPkPPkqwPPPPk{!RPPP!XP!e!hXSOR^bQWQRf_TVQ_Q`WRg`QcZRicQTOQZRQe^RhbRYQR]R",nodeNames:`⚠ JsonText True False Null Number String } { Object Property PropertyName : , ] [ Array`,maxTerm:25,nodeProps:[[`isolate`,-2,6,11,``],[`openedBy`,7,`{`,14,`[`],[`closedBy`,8,`}`,15,`]`]],propSources:[l],skippedNodes:[0],repeatNodeCount:2,tokenData:"(|~RaXY!WYZ!W]^!Wpq!Wrs!]|}$u}!O$z!Q!R%T!R![&c![!]&t!}#O&y#P#Q'O#Y#Z'T#b#c'r#h#i(Z#o#p(r#q#r(w~!]Oe~~!`Wpq!]qr!]rs!xs#O!]#O#P!}#P;'S!];'S;=`$o<%lO!]~!}Og~~#QXrs!]!P!Q!]#O#P!]#U#V!]#Y#Z!]#b#c!]#f#g!]#h#i!]#i#j#m~#pR!Q![#y!c!i#y#T#Z#y~#|R!Q![$V!c!i$V#T#Z$V~$YR!Q![$c!c!i$c#T#Z$c~$fR!Q![!]!c!i!]#T#Z!]~$rP;=`<%l!]~$zO]~~$}Q!Q!R%T!R![&c~%YRT~!O!P%c!g!h%w#X#Y%w~%fP!Q![%i~%nRT~!Q![%i!g!h%w#X#Y%w~%zR{|&T}!O&T!Q![&Z~&WP!Q![&Z~&`PT~!Q![&Z~&hST~!O!P%c!Q![&c!g!h%w#X#Y%w~&yO[~~'OO_~~'TO^~~'WP#T#U'Z~'^P#`#a'a~'dP#g#h'g~'jP#X#Y'm~'rOR~~'uP#i#j'x~'{P#`#a(O~(RP#`#a(U~(ZOS~~(^P#f#g(a~(dP#i#j(g~(jP#X#Y(m~(rOQ~~(wOW~~(|OV~",tokenizers:[0],topRules:{JsonText:[0,1]},tokenPrec:0}),d=o.define({name:`json`,parser:u.configure({props:[i.add({Object:a({except:/^\s*\}/}),Array:a({except:/^\s*\]/})}),n.add({"Object Array":t})]}),languageData:{closeBrackets:{brackets:[`[`,`{`,`"`]},indentOnInput:/^\s*[\}\]]$/}});function f(){return new r(d)}export{f as json}; \ No newline at end of file +import{b as e,d as t,f as n,i as r,m as i,s as a,t as o,x as s}from"./index-CLJ0aycO.js";import{r as c}from"./dist-B2R-c1vX.js";var l=e({String:s.string,Number:s.number,"True False":s.bool,PropertyName:s.propertyName,Null:s.null,", :":s.separator,"[ ]":s.squareBracket,"{ }":s.brace}),u=c.deserialize({version:14,states:"$bOVQPOOOOQO'#Cb'#CbOnQPO'#CeOvQPO'#ClOOQO'#Cr'#CrQOQPOOOOQO'#Cg'#CgO}QPO'#CfO!SQPO'#CtOOQO,59P,59PO![QPO,59PO!aQPO'#CuOOQO,59W,59WO!iQPO,59WOVQPO,59QOqQPO'#CmO!nQPO,59`OOQO1G.k1G.kOVQPO'#CnO!vQPO,59aOOQO1G.r1G.rOOQO1G.l1G.lOOQO,59X,59XOOQO-E6k-E6kOOQO,59Y,59YOOQO-E6l-E6l",stateData:`#O~OeOS~OQSORSOSSOTSOWQO_ROgPO~OVXOgUO~O^[O~PVO[^O~O]_OVhX~OVaO~O]bO^iX~O^dO~O]_OVha~O]bO^ia~O`,goto:"!kjPPPPPPkPPkqwPPPPk{!RPPP!XP!e!hXSOR^bQWQRf_TVQ_Q`WRg`QcZRicQTOQZRQe^RhbRYQR]R",nodeNames:`⚠ JsonText True False Null Number String } { Object Property PropertyName : , ] [ Array`,maxTerm:25,nodeProps:[[`isolate`,-2,6,11,``],[`openedBy`,7,`{`,14,`[`],[`closedBy`,8,`}`,15,`]`]],propSources:[l],skippedNodes:[0],repeatNodeCount:2,tokenData:"(|~RaXY!WYZ!W]^!Wpq!Wrs!]|}$u}!O$z!Q!R%T!R![&c![!]&t!}#O&y#P#Q'O#Y#Z'T#b#c'r#h#i(Z#o#p(r#q#r(w~!]Oe~~!`Wpq!]qr!]rs!xs#O!]#O#P!}#P;'S!];'S;=`$o<%lO!]~!}Og~~#QXrs!]!P!Q!]#O#P!]#U#V!]#Y#Z!]#b#c!]#f#g!]#h#i!]#i#j#m~#pR!Q![#y!c!i#y#T#Z#y~#|R!Q![$V!c!i$V#T#Z$V~$YR!Q![$c!c!i$c#T#Z$c~$fR!Q![!]!c!i!]#T#Z!]~$rP;=`<%l!]~$zO]~~$}Q!Q!R%T!R![&c~%YRT~!O!P%c!g!h%w#X#Y%w~%fP!Q![%i~%nRT~!Q![%i!g!h%w#X#Y%w~%zR{|&T}!O&T!Q![&Z~&WP!Q![&Z~&`PT~!Q![&Z~&hST~!O!P%c!Q![&c!g!h%w#X#Y%w~&yO[~~'OO_~~'TO^~~'WP#T#U'Z~'^P#`#a'a~'dP#g#h'g~'jP#X#Y'm~'rOR~~'uP#i#j'x~'{P#`#a(O~(RP#`#a(U~(ZOS~~(^P#f#g(a~(dP#i#j(g~(jP#X#Y(m~(rOQ~~(wOW~~(|OV~",tokenizers:[0],topRules:{JsonText:[0,1]},tokenPrec:0}),d=o.define({name:`json`,parser:u.configure({props:[i.add({Object:a({except:/^\s*\}/}),Array:a({except:/^\s*\]/})}),n.add({"Object Array":t})]}),languageData:{closeBrackets:{brackets:[`[`,`{`,`"`]},indentOnInput:/^\s*[\}\]]$/}});function f(){return new r(d)}export{f as json}; \ No newline at end of file diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/dist-CI7bovsk.js b/mcp/src/agents_remember/package_data/dashboard/assets/dist-DvbxHIw3.js similarity index 99% rename from mcp/src/agents_remember/package_data/dashboard/assets/dist-CI7bovsk.js rename to mcp/src/agents_remember/package_data/dashboard/assets/dist-DvbxHIw3.js index 1ba83071..e73bbc70 100644 --- a/mcp/src/agents_remember/package_data/dashboard/assets/dist-CI7bovsk.js +++ b/mcp/src/agents_remember/package_data/dashboard/assets/dist-DvbxHIw3.js @@ -1,4 +1,4 @@ -import{A as e,B as t,E as n,I as r,K as i,L as a,M as o,O as s,P as c,T as l,a as u,b as d,c as f,f as p,g as m,h,i as g,k as _,m as ee,n as te,p as ne,r as re,v,w as y,x as b,y as ie}from"./index-BLlkJI-k.js";import{t as ae}from"./dist-DeLSDQE4.js";import{html as oe,htmlCompletionSource as se}from"./dist-B8juTEn3.js";var ce=class e{static create(t,n,r,i,a){return new e(t,n,r,i+(i<<8)+t+(n<<4)|0,a,[],[])}constructor(e,t,n,r,i,a,o){this.type=e,this.value=t,this.from=n,this.hash=r,this.end=i,this.children=a,this.positions=o,this.hashProp=[[y.contextHash,r]]}addChild(e,t){e.prop(y.contextHash)!=this.hash&&(e=new _(e.type,e.children,e.positions,e.length,this.hashProp)),this.children.push(e),this.positions.push(t)}toTree(e,t=this.end){let r=this.children.length-1;return r>=0&&(t=Math.max(t,this.positions[r]+this.children[r].length+this.from)),new _(e.types[this.type],this.children,this.positions,t-this.from).balance({makeTree:(e,t,r)=>new _(n.none,e,t,r,this.hashProp)})}},x;(function(e){e[e.Document=1]=`Document`,e[e.CodeBlock=2]=`CodeBlock`,e[e.FencedCode=3]=`FencedCode`,e[e.Blockquote=4]=`Blockquote`,e[e.HorizontalRule=5]=`HorizontalRule`,e[e.BulletList=6]=`BulletList`,e[e.OrderedList=7]=`OrderedList`,e[e.ListItem=8]=`ListItem`,e[e.ATXHeading1=9]=`ATXHeading1`,e[e.ATXHeading2=10]=`ATXHeading2`,e[e.ATXHeading3=11]=`ATXHeading3`,e[e.ATXHeading4=12]=`ATXHeading4`,e[e.ATXHeading5=13]=`ATXHeading5`,e[e.ATXHeading6=14]=`ATXHeading6`,e[e.SetextHeading1=15]=`SetextHeading1`,e[e.SetextHeading2=16]=`SetextHeading2`,e[e.HTMLBlock=17]=`HTMLBlock`,e[e.LinkReference=18]=`LinkReference`,e[e.Paragraph=19]=`Paragraph`,e[e.CommentBlock=20]=`CommentBlock`,e[e.ProcessingInstructionBlock=21]=`ProcessingInstructionBlock`,e[e.Escape=22]=`Escape`,e[e.Entity=23]=`Entity`,e[e.HardBreak=24]=`HardBreak`,e[e.Emphasis=25]=`Emphasis`,e[e.StrongEmphasis=26]=`StrongEmphasis`,e[e.Link=27]=`Link`,e[e.Image=28]=`Image`,e[e.InlineCode=29]=`InlineCode`,e[e.HTMLTag=30]=`HTMLTag`,e[e.Comment=31]=`Comment`,e[e.ProcessingInstruction=32]=`ProcessingInstruction`,e[e.Autolink=33]=`Autolink`,e[e.HeaderMark=34]=`HeaderMark`,e[e.QuoteMark=35]=`QuoteMark`,e[e.ListMark=36]=`ListMark`,e[e.LinkMark=37]=`LinkMark`,e[e.EmphasisMark=38]=`EmphasisMark`,e[e.CodeMark=39]=`CodeMark`,e[e.CodeText=40]=`CodeText`,e[e.CodeInfo=41]=`CodeInfo`,e[e.LinkTitle=42]=`LinkTitle`,e[e.LinkLabel=43]=`LinkLabel`,e[e.URL=44]=`URL`})(x||={});var le=class{constructor(e,t){this.start=e,this.content=t,this.marks=[],this.parsers=[]}},ue=class{constructor(){this.text=``,this.baseIndent=0,this.basePos=0,this.depth=0,this.markers=[],this.pos=0,this.indent=0,this.next=-1}forward(){this.basePos>this.pos&&this.forwardInner()}forwardInner(){let e=this.skipSpace(this.basePos);this.indent=this.countIndent(e,this.pos,this.indent),this.pos=e,this.next=e==this.text.length?-1:this.text.charCodeAt(e)}skipSpace(e){return C(this.text,e)}reset(e){for(this.text=e,this.baseIndent=this.basePos=this.pos=this.indent=0,this.forwardInner(),this.depth=1;this.markers.length;)this.markers.pop()}moveBase(e){this.basePos=e,this.baseIndent=this.countIndent(e,this.pos,this.indent)}moveBaseColumn(e){this.baseIndent=e,this.basePos=this.findColumn(e)}addMarker(e){this.markers.push(e)}countIndent(e,t=0,n=0){for(let r=t;r=t.stack[n.depth+1].value+n.baseIndent)return!0;if(n.indent>=n.baseIndent+4)return!1;let r=(e.type==x.OrderedList?E:T)(n,t,!1);return r>0&&(e.type!=x.BulletList||w(n,t,!1)<0)&&n.text.charCodeAt(n.pos+r-1)==e.value}var fe={[x.Blockquote](e,t,n){return n.next==62?(n.markers.push(L(x.QuoteMark,t.lineStart+n.pos,t.lineStart+n.pos+1)),n.moveBase(n.pos+(S(n.text.charCodeAt(n.pos+1))?2:1)),e.end=t.lineStart+n.text.length,!0):!1},[x.ListItem](e,t,n){return n.indent-1?!1:(n.moveBaseColumn(n.baseIndent+e.value),!0)},[x.OrderedList]:de,[x.BulletList]:de,[x.Document](){return!0}};function S(e){return e==32||e==9||e==10||e==13}function C(e,t=0){for(;tn&&S(e.charCodeAt(t-1));)t--;return t}function me(e){if(e.next!=96&&e.next!=126)return-1;let t=e.pos+1;for(;t-1&&e.depth==t.stack.length&&t.parser.leafBlockParsers.indexOf(Te.SetextHeading)>-1||r<3?-1:1}function ge(e,t){for(let n=e.stack.length-1;n>=0;n--)if(e.stack[n].type==t)return!0;return!1}function T(e,t,n){return(e.next==45||e.next==43||e.next==42)&&(e.pos==e.text.length-1||S(e.text.charCodeAt(e.pos+1)))&&(!n||ge(t,x.BulletList)||e.skipSpace(e.pos+2)=48&&i<=57;){if(r++,r==e.text.length)return-1;i=e.text.charCodeAt(r)}return r==e.pos||r>e.pos+9||i!=46&&i!=41||re.pos+1||e.next!=49)?-1:r+1-e.pos}function _e(e){if(e.next!=35)return-1;let t=e.pos+1;for(;t6?-1:n}function ve(e){if(e.next!=45&&e.next!=61||e.indent>=e.baseIndent+4)return-1;let t=e.pos+1;for(;t/,be=/\?>/,O=[[/^<(?:script|pre|style)(?:\s|>|$)/i,/<\/(?:script|pre|style)>/i],[/^\s*/,be=/\?>/,O=[[/^<(?:script|pre|style)(?:\s|>|$)/i,/<\/(?:script|pre|style)>/i],[/^\s*`}},indentOnInput:/^\s*<\/\w+\W$/,wordChars:`-_`}}),Q=at.configure({wrap:I(rt,it)});function ot(e={}){let t=``,n;return e.matchClosingTags===!1&&(t=`noMatch`),e.selfClosingTags===!0&&(t=(t?t+` `:``)+`selfClosing`),(e.nestedLanguages&&e.nestedLanguages.length||e.nestedAttributes&&e.nestedAttributes.length)&&(n=I((e.nestedLanguages||[]).concat(rt),(e.nestedAttributes||[]).concat(it))),new a(n?at.configure({wrap:n,dialect:t}):t?Q.configure({dialect:t}):Q,[Q.data.of({autocomplete:tt(e)}),e.autoCloseTags===!1?[]:st,ae().support,ne().support])}var $=new Set(`area base br col command embed frame hr img input keygen link meta param source track wbr menuitem`.split(` `)),st=n.inputHandler.of((e,n,r,i,a)=>{if(e.composing||e.state.readOnly||n!=r||i!=`>`&&i!=`/`||!Q.isActiveAt(e.state,n,-1))return!1;let o=a(),{state:s}=o,c=s.changeByRange(e=>{let n=s.doc.sliceString(e.from-1,e.to)==i,{head:r}=e,a=l(s).resolveInner(r,-1),o;if(n&&i==`>`&&a.name==`EndTag`){let t=a.parent;if(t.parent?.lastChild?.name!=`CloseTag`&&(o=K(s.doc,t.parent,r))&&!$.has(o))return{range:e,changes:{from:r,to:r+ +(s.doc.sliceString(r,r+1)===`>`),insert:``}}}else if(n&&i==`/`&&a.name==`IncompleteCloseTag`){let e=a.parent;if(a.from==r-2&&e.lastChild?.name!=`CloseTag`&&(o=K(s.doc,e,r))&&!$.has(o)){let e=r+ +(s.doc.sliceString(r,r+1)===`>`),n=`${o}>`;return{range:t.cursor(r+n.length,-1),changes:{from:r,to:e,insert:n}}}}return{range:e}});return c.changes.empty?!1:(e.dispatch([o,s.update(c,{userEvent:`input.complete`,scrollIntoView:!0})]),!0)});export{ot as html,et as htmlCompletionSource}; \ No newline at end of file +import{A as e,I as t,M as n,b as r,f as i,i as a,m as o,o as s,t as c,v as l,x as u}from"./index-CLJ0aycO.js";import{n as d,r as ee,t as te}from"./dist-B2R-c1vX.js";import{n as f,t as ne}from"./dist-BJusfjLN.js";import{a as re,i as ie,n as ae,o as oe,r as p}from"./dist-17r-i6rR.js";var se=55,ce=1,le=56,ue=2,de=57,fe=3,m=4,pe=5,h=6,g=7,me=8,he=9,ge=10,_e=11,ve=12,ye=13,_=58,be=14,xe=15,v=59,y=21,Se=23,b=24,Ce=25,x=27,S=28,we=29,Te=32,Ee=35,De=37,Oe=38,ke=0,Ae=1,je={area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},Me={dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},C={dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}};function Ne(e){return e==45||e==46||e==58||e>=65&&e<=90||e==95||e>=97&&e<=122||e>=161}var w=null,T=null,E=0;function D(e,t){let n=e.pos+t;if(E==n&&T==e)return w;let r=e.peek(t),i=``;for(;Ne(r);)i+=String.fromCharCode(r),r=e.peek(++t);return T=e,E=n,w=i?i.toLowerCase():r==Pe||r==Fe?void 0:null}var O=60,k=62,A=47,Pe=63,Fe=33,Ie=45;function j(e,t){this.name=e,this.parent=t}var Le=[h,ge,g,me,he],Re=new te({start:null,shift(e,t,n,r){return Le.indexOf(t)>-1?new j(D(r,1)||``,e):e},reduce(e,t){return t==y&&e?e.parent:e},reuse(e,t,n,r){let i=t.type.id;return i==h||i==De?new j(D(r,1)||``,e):e},strict:!1}),ze=new d((e,t)=>{if(e.next!=O){e.next<0&&t.context&&e.acceptToken(_);return}e.advance();let n=e.next==A;n&&e.advance();let r=D(e,0);if(r===void 0)return;if(!r)return e.acceptToken(n?xe:be);let i=t.context?t.context.name:null;if(n){if(r==i)return e.acceptToken(_e);if(i&&Me[i])return e.acceptToken(_,-2);if(t.dialectEnabled(ke))return e.acceptToken(ve);for(let e=t.context;e;e=e.parent)if(e.name==r)return;e.acceptToken(ye)}else{if(r==`script`)return e.acceptToken(g);if(r==`style`)return e.acceptToken(me);if(r==`textarea`)return e.acceptToken(he);if(je.hasOwnProperty(r))return e.acceptToken(ge);i&&C[i]&&C[i][r]?e.acceptToken(_,-1):e.acceptToken(h)}},{contextual:!0}),Be=new d(e=>{for(let t=0,n=0;;n++){if(e.next<0){n&&e.acceptToken(v);break}if(e.next==Ie)t++;else if(e.next==k&&t>=2){n>=3&&e.acceptToken(v,-2);break}else t=0;e.advance()}});function Ve(e){for(;e;e=e.parent)if(e.name==`svg`||e.name==`math`)return!0;return!1}var He=new d((e,t)=>{if(e.next==A&&e.peek(1)==k){let n=t.dialectEnabled(Ae)||Ve(t.context);e.acceptToken(n?pe:m,2)}else e.next==k&&e.acceptToken(m,1)});function M(e,t,n){let r=2+e.length;return new d(i=>{for(let a=0,o=0,s=0;;s++){if(i.next<0){s&&i.acceptToken(t);break}if(a==0&&i.next==O||a==1&&i.next==A||a>=2&&ao?i.acceptToken(t,-o):i.acceptToken(n,-(o-2));break}else if((i.next==10||i.next==13)&&s){i.acceptToken(t,1);break}else a=o=0;i.advance()}})}var Ue=M(`script`,se,ce),We=M(`style`,le,ue),Ge=M(`textarea`,de,fe),Ke=r({"Text RawText IncompleteTag IncompleteCloseTag":u.content,"StartTag StartCloseTag SelfClosingEndTag EndTag":u.angleBracket,TagName:u.tagName,"MismatchedCloseTag/TagName":[u.tagName,u.invalid],AttributeName:u.attributeName,"AttributeValue UnquotedAttributeValue":u.attributeValue,Is:u.definitionOperator,"EntityReference CharacterReference":u.character,Comment:u.blockComment,ProcessingInst:u.processingInstruction,DoctypeDecl:u.documentMeta}),qe=ee.deserialize({version:14,states:",xOVO!rOOO!ZQ#tO'#CrO!`Q#tO'#C{O!eQ#tO'#DOO!jQ#tO'#DRO!oQ#tO'#DTO!tOaO'#CqO#PObO'#CqO#[OdO'#CqO$kO!rO'#CqOOO`'#Cq'#CqO$rO$fO'#DUO$zQ#tO'#DWO%PQ#tO'#DXOOO`'#Dl'#DlOOO`'#DZ'#DZQVO!rOOO%UQ&rO,59^O%aQ&rO,59gO%lQ&rO,59jO%wQ&rO,59mO&SQ&rO,59oOOOa'#D_'#D_O&_OaO'#CyO&jOaO,59]OOOb'#D`'#D`O&rObO'#C|O&}ObO,59]OOOd'#Da'#DaO'VOdO'#DPO'bOdO,59]OOO`'#Db'#DbO'jO!rO,59]O'qQ#tO'#DSOOO`,59],59]OOOp'#Dc'#DcO'vO$fO,59pOOO`,59p,59pO(OQ#|O,59rO(TQ#|O,59sOOO`-E7X-E7XO(YQ&rO'#CtOOQW'#D['#D[O(hQ&rO1G.xOOOa1G.x1G.xOOO`1G/Z1G/ZO(sQ&rO1G/ROOOb1G/R1G/RO)OQ&rO1G/UOOOd1G/U1G/UO)ZQ&rO1G/XOOO`1G/X1G/XO)fQ&rO1G/ZOOOa-E7]-E7]O)qQ#tO'#CzOOO`1G.w1G.wOOOb-E7^-E7^O)vQ#tO'#C}OOOd-E7_-E7_O){Q#tO'#DQOOO`-E7`-E7`O*QQ#|O,59nOOOp-E7a-E7aOOO`1G/[1G/[OOO`1G/^1G/^OOO`1G/_1G/_O*VQ,UO,59`OOQW-E7Y-E7YOOOa7+$d7+$dOOO`7+$u7+$uOOOb7+$m7+$mOOOd7+$p7+$pOOO`7+$s7+$sO*bQ#|O,59fO*gQ#|O,59iO*lQ#|O,59lOOO`1G/Y1G/YO*qO7[O'#CwO+SOMhO'#CwOOQW1G.z1G.zOOO`1G/Q1G/QOOO`1G/T1G/TOOO`1G/W1G/WOOOO'#D]'#D]O+eO7[O,59cOOQW,59c,59cOOOO'#D^'#D^O+vOMhO,59cOOOO-E7Z-E7ZOOQW1G.}1G.}OOOO-E7[-E7[",stateData:`,c~O!_OS~OUSOVPOWQOXROYTO[]O][O^^O_^Oa^Ob^Oc^Od^Oy^O|_O!eZO~OgaO~OgbO~OgcO~OgdO~OgeO~O!XfOPmP![mP~O!YiOQpP![pP~O!ZlORsP![sP~OUSOVPOWQOXROYTOZqO[]O][O^^O_^Oa^Ob^Oc^Od^Oy^O!eZO~O![rO~P#gO!]sO!fuO~OgvO~OgwO~OS|OT}OiyO~OS!POT}OiyO~OS!ROT}OiyO~OS!TOT}OiyO~OS}OT}OiyO~O!XfOPmX![mX~OP!WO![!XO~O!YiOQpX![pX~OQ!ZO![!XO~O!ZlORsX![sX~OR!]O![!XO~O![!XO~P#gOg!_O~O!]sO!f!aO~OS!bO~OS!cO~Oj!dOShXThXihX~OS!fOT!gOiyO~OS!hOT!gOiyO~OS!iOT!gOiyO~OS!jOT!gOiyO~OS!gOT!gOiyO~Og!kO~Og!lO~Og!mO~OS!nO~Ol!qO!a!oO!c!pO~OS!rO~OS!sO~OS!tO~Ob!uOc!uOd!uO!a!wO!b!uO~Ob!xOc!xOd!xO!c!wO!d!xO~Ob!uOc!uOd!uO!a!{O!b!uO~Ob!xOc!xOd!xO!c!{O!d!xO~OT~cbd!ey|!e~`,goto:"%q!aPPPPPPPPPPPPPPPPPPPPP!b!hP!nPP!zP!}#Q#T#Z#^#a#g#j#m#s#y!bP!b!bP$P$V$m$s$y%P%V%]%cPPPPPPPP%iX^OX`pXUOX`pezabcde{!O!Q!S!UR!q!dRhUR!XhXVOX`pRkVR!XkXWOX`pRnWR!XnXXOX`pQrXR!XpXYOX`pQ`ORx`Q{aQ!ObQ!QcQ!SdQ!UeZ!e{!O!Q!S!UQ!v!oR!z!vQ!y!pR!|!yQgUR!VgQjVR!YjQmWR![mQpXR!^pQtZR!`tS_O`ToXp",nodeNames:`⚠ StartCloseTag StartCloseTag StartCloseTag EndTag SelfClosingEndTag StartTag StartTag StartTag StartTag StartTag StartCloseTag StartCloseTag StartCloseTag IncompleteTag IncompleteCloseTag Document Text EntityReference CharacterReference InvalidEntity Element OpenTag TagName Attribute AttributeName Is AttributeValue UnquotedAttributeValue ScriptText CloseTag OpenTag StyleText CloseTag OpenTag TextareaText CloseTag OpenTag CloseTag SelfClosingTag Comment ProcessingInst MismatchedCloseTag CloseTag DoctypeDecl`,maxTerm:68,context:Re,nodeProps:[[`closedBy`,-10,1,2,3,7,8,9,10,11,12,13,`EndTag`,6,`EndTag SelfClosingEndTag`,-4,22,31,34,37,`CloseTag`],[`openedBy`,4,`StartTag StartCloseTag`,5,`StartTag`,-4,30,33,36,38,`OpenTag`],[`group`,-10,14,15,18,19,20,21,40,41,42,43,`Entity`,17,`Entity TextContent`,-3,29,32,35,`TextContent Entity`],[`isolate`,-11,22,30,31,33,34,36,37,38,39,42,43,`ltr`,-3,27,28,40,``]],propSources:[Ke],skippedNodes:[0],repeatNodeCount:9,tokenData:"!]tw8twx7Sx!P8t!P!Q5u!Q!]8t!]!^/^!^!a7S!a#S8t#S#T;{#T#s8t#s$f5u$f;'S8t;'S;=`>V<%l?Ah8t?Ah?BY5u?BY?Mn8t?MnO5u!Z5zblWOX5uXZ7SZ[5u[^7S^p5uqr5urs7Sst+Ptw5uwx7Sx!]5u!]!^7w!^!a7S!a#S5u#S#T7S#T;'S5u;'S;=`8n<%lO5u!R7VVOp7Sqs7St!]7S!]!^7l!^;'S7S;'S;=`7q<%lO7S!R7qOb!R!R7tP;=`<%l7S!Z8OYlWb!ROX+PZ[+P^p+Pqr+Psw+Px!^+P!a#S+P#T;'S+P;'S;=`+t<%lO+P!Z8qP;=`<%l5u!_8{iiSlWOX5uXZ7SZ[5u[^7S^p5uqr8trs7Sst/^tw8twx7Sx!P8t!P!Q5u!Q!]8t!]!^:j!^!a7S!a#S8t#S#T;{#T#s8t#s$f5u$f;'S8t;'S;=`>V<%l?Ah8t?Ah?BY5u?BY?Mn8t?MnO5u!_:sbiSlWb!ROX+PZ[+P^p+Pqr/^sw/^x!P/^!P!Q+P!Q!^/^!a#S/^#S#T0m#T#s/^#s$f+P$f;'S/^;'S;=`1e<%l?Ah/^?Ah?BY+P?BY?Mn/^?MnO+P!VP<%l?Ah;{?Ah?BY7S?BY?Mn;{?MnO7S!V=dXiSb!Rqr0msw0mx!P0m!Q!^0m!a#s0m$f;'S0m;'S;=`1_<%l?Ah0m?BY?Mn0m!V>SP;=`<%l;{!_>YP;=`<%l8t!_>dhiSlWOX@OXZAYZ[@O[^AY^p@OqrBwrsAYswBwwxAYx!PBw!P!Q@O!Q!]Bw!]!^/^!^!aAY!a#SBw#S#TE{#T#sBw#s$f@O$f;'SBw;'S;=`HS<%l?AhBw?Ah?BY@O?BY?MnBw?MnO@O!Z@TalWOX@OXZAYZ[@O[^AY^p@Oqr@OrsAYsw@OwxAYx!]@O!]!^Az!^!aAY!a#S@O#S#TAY#T;'S@O;'S;=`Bq<%lO@O!RA]UOpAYq!]AY!]!^Ao!^;'SAY;'S;=`At<%lOAY!RAtOc!R!RAwP;=`<%lAY!ZBRYlWc!ROX+PZ[+P^p+Pqr+Psw+Px!^+P!a#S+P#T;'S+P;'S;=`+t<%lO+P!ZBtP;=`<%l@O!_COhiSlWOX@OXZAYZ[@O[^AY^p@OqrBwrsAYswBwwxAYx!PBw!P!Q@O!Q!]Bw!]!^Dj!^!aAY!a#SBw#S#TE{#T#sBw#s$f@O$f;'SBw;'S;=`HS<%l?AhBw?Ah?BY@O?BY?MnBw?MnO@O!_DsbiSlWc!ROX+PZ[+P^p+Pqr/^sw/^x!P/^!P!Q+P!Q!^/^!a#S/^#S#T0m#T#s/^#s$f+P$f;'S/^;'S;=`1e<%l?Ah/^?Ah?BY+P?BY?Mn/^?MnO+P!VFQbiSOpAYqrE{rsAYswE{wxAYx!PE{!P!QAY!Q!]E{!]!^GY!^!aAY!a#sE{#s$fAY$f;'SE{;'S;=`G|<%l?AhE{?Ah?BYAY?BY?MnE{?MnOAY!VGaXiSc!Rqr0msw0mx!P0m!Q!^0m!a#s0m$f;'S0m;'S;=`1_<%l?Ah0m?BY?Mn0m!VHPP;=`<%lE{!_HVP;=`<%lBw!ZHcW!cxaP!b`Or(trs'ksv(tw!^(t!^!_)e!_;'S(t;'S;=`*P<%lO(t!aIYliSaPlW!b`!dpOX$qXZ&XZ[$q[^&X^p$qpq&Xqr-_rs&}sv-_vw/^wx(tx}-_}!OKQ!O!P-_!P!Q$q!Q!^-_!^!_*V!_!a&X!a#S-_#S#T1k#T#s-_#s$f$q$f;'S-_;'S;=`3X<%l?Ah-_?Ah?BY$q?BY?Mn-_?MnO$q!aK_kiSaPlW!b`!dpOX$qXZ&XZ[$q[^&X^p$qpq&Xqr-_rs&}sv-_vw/^wx(tx!P-_!P!Q$q!Q!^-_!^!_*V!_!`&X!`!aMS!a#S-_#S#T1k#T#s-_#s$f$q$f;'S-_;'S;=`3X<%l?Ah-_?Ah?BY$q?BY?Mn-_?MnO$q!TM_XaP!b`!dp!fQOr&Xrs&}sv&Xwx(tx!^&X!^!_*V!_;'S&X;'S;=`*y<%lO&X!aNZ!ZiSgQaPlW!b`!dpOX$qXZ&XZ[$q[^&X^p$qpq&Xqr-_rs&}sv-_vw/^wx(tx}-_}!OMz!O!PMz!P!Q$q!Q![Mz![!]Mz!]!^-_!^!_*V!_!a&X!a!c-_!c!}Mz!}#R-_#R#SMz#S#T1k#T#oMz#o#s-_#s$f$q$f$}-_$}%OMz%O%W-_%W%oMz%o%p-_%p&aMz&a&b-_&b1pMz1p4UMz4U4dMz4d4e-_4e$ISMz$IS$I`-_$I`$IbMz$Ib$Je-_$Je$JgMz$Jg$Kh-_$Kh%#tMz%#t&/x-_&/x&EtMz&Et&FV-_&FV;'SMz;'S;:j!#|;:j;=`3X<%l?&r-_?&r?AhMz?Ah?BY$q?BY?MnMz?MnO$q!a!$PP;=`<%lMz!R!$ZY!b`!dpOq*Vqr!$yrs(Vsv*Vwx)ex!a*V!a!b!4t!b;'S*V;'S;=`*s<%lO*V!R!%Q]!b`!dpOr*Vrs(Vsv*Vwx)ex}*V}!O!%y!O!f*V!f!g!']!g#W*V#W#X!0`#X;'S*V;'S;=`*s<%lO*V!R!&QX!b`!dpOr*Vrs(Vsv*Vwx)ex}*V}!O!&m!O;'S*V;'S;=`*s<%lO*V!R!&vV!b`!dp!ePOr*Vrs(Vsv*Vwx)ex;'S*V;'S;=`*s<%lO*V!R!'dX!b`!dpOr*Vrs(Vsv*Vwx)ex!q*V!q!r!(P!r;'S*V;'S;=`*s<%lO*V!R!(WX!b`!dpOr*Vrs(Vsv*Vwx)ex!e*V!e!f!(s!f;'S*V;'S;=`*s<%lO*V!R!(zX!b`!dpOr*Vrs(Vsv*Vwx)ex!v*V!v!w!)g!w;'S*V;'S;=`*s<%lO*V!R!)nX!b`!dpOr*Vrs(Vsv*Vwx)ex!{*V!{!|!*Z!|;'S*V;'S;=`*s<%lO*V!R!*bX!b`!dpOr*Vrs(Vsv*Vwx)ex!r*V!r!s!*}!s;'S*V;'S;=`*s<%lO*V!R!+UX!b`!dpOr*Vrs(Vsv*Vwx)ex!g*V!g!h!+q!h;'S*V;'S;=`*s<%lO*V!R!+xY!b`!dpOr!+qrs!,hsv!+qvw!-Swx!.[x!`!+q!`!a!/j!a;'S!+q;'S;=`!0Y<%lO!+qq!,mV!dpOv!,hvx!-Sx!`!,h!`!a!-q!a;'S!,h;'S;=`!.U<%lO!,hP!-VTO!`!-S!`!a!-f!a;'S!-S;'S;=`!-k<%lO!-SP!-kO|PP!-nP;=`<%l!-Sq!-xS!dp|POv(Vx;'S(V;'S;=`(h<%lO(Vq!.XP;=`<%l!,ha!.aX!b`Or!.[rs!-Ssv!.[vw!-Sw!`!.[!`!a!.|!a;'S!.[;'S;=`!/d<%lO!.[a!/TT!b`|POr)esv)ew;'S)e;'S;=`)y<%lO)ea!/gP;=`<%l!.[!R!/sV!b`!dp|POr*Vrs(Vsv*Vwx)ex;'S*V;'S;=`*s<%lO*V!R!0]P;=`<%l!+q!R!0gX!b`!dpOr*Vrs(Vsv*Vwx)ex#c*V#c#d!1S#d;'S*V;'S;=`*s<%lO*V!R!1ZX!b`!dpOr*Vrs(Vsv*Vwx)ex#V*V#V#W!1v#W;'S*V;'S;=`*s<%lO*V!R!1}X!b`!dpOr*Vrs(Vsv*Vwx)ex#h*V#h#i!2j#i;'S*V;'S;=`*s<%lO*V!R!2qX!b`!dpOr*Vrs(Vsv*Vwx)ex#m*V#m#n!3^#n;'S*V;'S;=`*s<%lO*V!R!3eX!b`!dpOr*Vrs(Vsv*Vwx)ex#d*V#d#e!4Q#e;'S*V;'S;=`*s<%lO*V!R!4XX!b`!dpOr*Vrs(Vsv*Vwx)ex#X*V#X#Y!+q#Y;'S*V;'S;=`*s<%lO*V!R!4{Y!b`!dpOr!4trs!5ksv!4tvw!6Vwx!8]x!a!4t!a!b!:]!b;'S!4t;'S;=`!;r<%lO!4tq!5pV!dpOv!5kvx!6Vx!a!5k!a!b!7W!b;'S!5k;'S;=`!8V<%lO!5kP!6YTO!a!6V!a!b!6i!b;'S!6V;'S;=`!7Q<%lO!6VP!6lTO!`!6V!`!a!6{!a;'S!6V;'S;=`!7Q<%lO!6VP!7QOyPP!7TP;=`<%l!6Vq!7]V!dpOv!5kvx!6Vx!`!5k!`!a!7r!a;'S!5k;'S;=`!8V<%lO!5kq!7yS!dpyPOv(Vx;'S(V;'S;=`(h<%lO(Vq!8YP;=`<%l!5ka!8bX!b`Or!8]rs!6Vsv!8]vw!6Vw!a!8]!a!b!8}!b;'S!8];'S;=`!:V<%lO!8]a!9SX!b`Or!8]rs!6Vsv!8]vw!6Vw!`!8]!`!a!9o!a;'S!8];'S;=`!:V<%lO!8]a!9vT!b`yPOr)esv)ew;'S)e;'S;=`)y<%lO)ea!:YP;=`<%l!8]!R!:dY!b`!dpOr!4trs!5ksv!4tvw!6Vwx!8]x!`!4t!`!a!;S!a;'S!4t;'S;=`!;r<%lO!4t!R!;]V!b`!dpyPOr*Vrs(Vsv*Vwx)ex;'S*V;'S;=`*s<%lO*V!R!;uP;=`<%l!4t!V!{let n=e.type.id;if(n==we)return F(e,t,r);if(n==Te)return F(e,t,i);if(n==Ee)return F(e,t,a);if(n==y&&o.length){let n=e.node,r=n.firstChild,i=r&&P(r,t),a;if(i){for(let e of o)if(e.tag==i&&(!e.attrs||e.attrs(a||=N(r,t)))){let t=n.lastChild,i=t.type.id==Oe?t.from:n.to;if(i>r.to)return{parser:e.parser,overlay:[{from:r.to,to:i}]}}}}if(s&&n==b){let n=e.node,r;if(r=n.firstChild){let e=s[t.read(r.from,r.to)];if(e)for(let r of e){if(r.tagName&&r.tagName!=P(n.parent,t))continue;let e=n.lastChild;if(e.type.id==x){let t=e.from+1,n=e.lastChild,i=e.to-(n&&n.isError?0:1);if(i>t)return{parser:r.parser,overlay:[{from:t,to:i}],bracketed:!0}}else if(e.type.id==S)return{parser:r.parser,overlay:[{from:e.from,to:e.to}]}}}}return null})}var L=[`_blank`,`_self`,`_top`,`_parent`],R=[`ascii`,`utf-8`,`utf-16`,`latin1`,`latin1`],z=[`get`,`post`,`put`,`delete`],B=[`application/x-www-form-urlencoded`,`multipart/form-data`,`text/plain`],V=[`true`,`false`],H={},Je={a:{attrs:{href:null,ping:null,type:null,media:null,target:L,hreflang:null}},abbr:H,address:H,area:{attrs:{alt:null,coords:null,href:null,target:null,ping:null,media:null,hreflang:null,type:null,shape:[`default`,`rect`,`circle`,`poly`]}},article:H,aside:H,audio:{attrs:{src:null,mediagroup:null,crossorigin:[`anonymous`,`use-credentials`],preload:[`none`,`metadata`,`auto`],autoplay:[`autoplay`],loop:[`loop`],controls:[`controls`]}},b:H,base:{attrs:{href:null,target:L}},bdi:H,bdo:H,blockquote:{attrs:{cite:null}},body:H,br:H,button:{attrs:{form:null,formaction:null,name:null,value:null,autofocus:[`autofocus`],disabled:[`autofocus`],formenctype:B,formmethod:z,formnovalidate:[`novalidate`],formtarget:L,type:[`submit`,`reset`,`button`]}},canvas:{attrs:{width:null,height:null}},caption:H,center:H,cite:H,code:H,col:{attrs:{span:null}},colgroup:{attrs:{span:null}},command:{attrs:{type:[`command`,`checkbox`,`radio`],label:null,icon:null,radiogroup:null,command:null,title:null,disabled:[`disabled`],checked:[`checked`]}},data:{attrs:{value:null}},datagrid:{attrs:{disabled:[`disabled`],multiple:[`multiple`]}},datalist:{attrs:{data:null}},dd:H,del:{attrs:{cite:null,datetime:null}},details:{attrs:{open:[`open`]}},dfn:H,div:H,dl:H,dt:H,em:H,embed:{attrs:{src:null,type:null,width:null,height:null}},eventsource:{attrs:{src:null}},fieldset:{attrs:{disabled:[`disabled`],form:null,name:null}},figcaption:H,figure:H,footer:H,form:{attrs:{action:null,name:null,"accept-charset":R,autocomplete:[`on`,`off`],enctype:B,method:z,novalidate:[`novalidate`],target:L}},h1:H,h2:H,h3:H,h4:H,h5:H,h6:H,head:{children:[`title`,`base`,`link`,`style`,`meta`,`script`,`noscript`,`command`]},header:H,hgroup:H,hr:H,html:{attrs:{manifest:null}},i:H,iframe:{attrs:{src:null,srcdoc:null,name:null,width:null,height:null,sandbox:[`allow-top-navigation`,`allow-same-origin`,`allow-forms`,`allow-scripts`],seamless:[`seamless`]}},img:{attrs:{alt:null,src:null,ismap:null,usemap:null,width:null,height:null,crossorigin:[`anonymous`,`use-credentials`]}},input:{attrs:{alt:null,dirname:null,form:null,formaction:null,height:null,list:null,max:null,maxlength:null,min:null,name:null,pattern:null,placeholder:null,size:null,src:null,step:null,value:null,width:null,accept:[`audio/*`,`video/*`,`image/*`],autocomplete:[`on`,`off`],autofocus:[`autofocus`],checked:[`checked`],disabled:[`disabled`],formenctype:B,formmethod:z,formnovalidate:[`novalidate`],formtarget:L,multiple:[`multiple`],readonly:[`readonly`],required:[`required`],type:[`hidden`,`text`,`search`,`tel`,`url`,`email`,`password`,`datetime`,`date`,`month`,`week`,`time`,`datetime-local`,`number`,`range`,`color`,`checkbox`,`radio`,`file`,`submit`,`image`,`reset`,`button`]}},ins:{attrs:{cite:null,datetime:null}},kbd:H,keygen:{attrs:{challenge:null,form:null,name:null,autofocus:[`autofocus`],disabled:[`disabled`],keytype:[`RSA`]}},label:{attrs:{for:null,form:null}},legend:H,li:{attrs:{value:null}},link:{attrs:{href:null,type:null,hreflang:null,media:null,sizes:[`all`,`16x16`,`16x16 32x32`,`16x16 32x32 64x64`]}},map:{attrs:{name:null}},mark:H,menu:{attrs:{label:null,type:[`list`,`context`,`toolbar`]}},meta:{attrs:{content:null,charset:R,name:[`viewport`,`application-name`,`author`,`description`,`generator`,`keywords`],"http-equiv":[`content-language`,`content-type`,`default-style`,`refresh`]}},meter:{attrs:{value:null,min:null,low:null,high:null,max:null,optimum:null}},nav:H,noscript:H,object:{attrs:{data:null,type:null,name:null,usemap:null,form:null,width:null,height:null,typemustmatch:[`typemustmatch`]}},ol:{attrs:{reversed:[`reversed`],start:null,type:[`1`,`a`,`A`,`i`,`I`]},children:[`li`,`script`,`template`,`ul`,`ol`]},optgroup:{attrs:{disabled:[`disabled`],label:null}},option:{attrs:{disabled:[`disabled`],label:null,selected:[`selected`],value:null}},output:{attrs:{for:null,form:null,name:null}},p:H,param:{attrs:{name:null,value:null}},pre:H,progress:{attrs:{value:null,max:null}},q:{attrs:{cite:null}},rp:H,rt:H,ruby:H,samp:H,script:{attrs:{type:[`text/javascript`],src:null,async:[`async`],defer:[`defer`],charset:R}},section:H,select:{attrs:{form:null,name:null,size:null,autofocus:[`autofocus`],disabled:[`disabled`],multiple:[`multiple`]}},slot:{attrs:{name:null}},small:H,source:{attrs:{src:null,type:null,media:null}},span:H,strong:H,style:{attrs:{type:[`text/css`],media:null,scoped:null}},sub:H,summary:H,sup:H,table:H,tbody:H,td:{attrs:{colspan:null,rowspan:null,headers:null}},template:H,textarea:{attrs:{dirname:null,form:null,maxlength:null,name:null,placeholder:null,rows:null,cols:null,autofocus:[`autofocus`],disabled:[`disabled`],readonly:[`readonly`],required:[`required`],wrap:[`soft`,`hard`]}},tfoot:H,th:{attrs:{colspan:null,rowspan:null,headers:null,scope:[`row`,`col`,`rowgroup`,`colgroup`]}},thead:H,time:{attrs:{datetime:null}},title:H,tr:H,track:{attrs:{src:null,label:null,default:null,kind:[`subtitles`,`captions`,`descriptions`,`chapters`,`metadata`],srclang:null}},ul:{children:[`li`,`script`,`template`,`ul`,`ol`]},var:H,video:{attrs:{src:null,poster:null,width:null,height:null,crossorigin:[`anonymous`,`use-credentials`],preload:[`auto`,`metadata`,`none`],autoplay:[`autoplay`],mediagroup:[`movie`],muted:[`muted`],controls:[`controls`]}},wbr:H},U={accesskey:null,class:null,contenteditable:V,contextmenu:null,dir:[`ltr`,`rtl`,`auto`],draggable:[`true`,`false`,`auto`],dropzone:[`copy`,`move`,`link`,`string:`,`file:`],hidden:[`hidden`],id:null,inert:[`inert`],itemid:null,itemprop:null,itemref:null,itemscope:[`itemscope`],itemtype:null,lang:[`ar`,`bn`,`de`,`en-GB`,`en-US`,`es`,`fr`,`hi`,`id`,`ja`,`pa`,`pt`,`ru`,`tr`,`zh`],spellcheck:V,autocorrect:V,autocapitalize:V,style:null,tabindex:null,title:null,translate:[`yes`,`no`],rel:[`stylesheet`,`alternate`,`author`,`bookmark`,`help`,`license`,`next`,`nofollow`,`noreferrer`,`prefetch`,`prev`,`search`,`tag`],role:`alert application article banner button cell checkbox complementary contentinfo dialog document feed figure form grid gridcell heading img list listbox listitem main navigation region row rowgroup search switch tab table tabpanel textbox timer`.split(` `),"aria-activedescendant":null,"aria-atomic":V,"aria-autocomplete":[`inline`,`list`,`both`,`none`],"aria-busy":V,"aria-checked":[`true`,`false`,`mixed`,`undefined`],"aria-controls":null,"aria-describedby":null,"aria-disabled":V,"aria-dropeffect":null,"aria-expanded":[`true`,`false`,`undefined`],"aria-flowto":null,"aria-grabbed":[`true`,`false`,`undefined`],"aria-haspopup":V,"aria-hidden":V,"aria-invalid":[`true`,`false`,`grammar`,`spelling`],"aria-label":null,"aria-labelledby":null,"aria-level":null,"aria-live":[`off`,`polite`,`assertive`],"aria-multiline":V,"aria-multiselectable":V,"aria-owns":null,"aria-posinset":null,"aria-pressed":[`true`,`false`,`mixed`,`undefined`],"aria-readonly":V,"aria-relevant":null,"aria-required":V,"aria-selected":[`true`,`false`,`undefined`],"aria-setsize":null,"aria-sort":[`ascending`,`descending`,`none`,`other`],"aria-valuemax":null,"aria-valuemin":null,"aria-valuenow":null,"aria-valuetext":null},W=`beforeunload copy cut dragstart dragover dragleave dragenter dragend drag paste focus blur change click load mousedown mouseenter mouseleave mouseup keydown keyup resize scroll unload`.split(` `).map(e=>`on`+e);for(let e of W)U[e]=null;var G=class{constructor(e,t){this.tags={...Je,...e},this.globalAttrs={...U,...t},this.allTags=Object.keys(this.tags),this.globalAttrNames=Object.keys(this.globalAttrs)}};G.default=new G;function K(e,t,n=e.length){if(!t)return``;let r=t.firstChild,i=r&&r.getChild(`TagName`);return i?e.sliceString(i.from,Math.min(i.to,n)):``}function q(e,t=!1){for(;e;e=e.parent)if(e.name==`Element`)if(t)t=!1;else return e;return null}function J(e,t,n){return n.tags[K(e,q(t))]?.children||n.allTags}function Y(e,t){let n=[];for(let r=q(t);r&&!r.type.isTop;r=q(r.parent)){let i=K(e,r);if(i&&r.lastChild.name==`CloseTag`)break;i&&n.indexOf(i)<0&&(t.name==`EndTag`||t.from>=r.firstChild.to)&&n.push(i)}return n}var X=/^[:\-\.\w\u00b7-\uffff]*$/;function Ye(e,t,n,r,i){let a=/\s*>/.test(e.sliceDoc(i,i+5))?``:`>`,o=q(n,n.name==`StartTag`||n.name==`TagName`);return{from:r,to:i,options:J(e.doc,o,t).map(e=>({label:e,type:`type`})).concat(Y(e.doc,n).map((e,t)=>({label:`/`+e,apply:`/`+e+a,type:`type`,boost:99-t}))),validFor:/^\/?[:\-\.\w\u00b7-\uffff]*$/}}function Xe(e,t,n,r){let i=/\s*>/.test(e.sliceDoc(r,r+5))?``:`>`;return{from:n,to:r,options:Y(e.doc,t).map((e,t)=>({label:e,apply:e+i,type:`type`,boost:99-t})),validFor:X}}function Ze(e,t,n,r){let i=[],a=0;for(let r of J(e.doc,n,t))i.push({label:`<`+r,type:`type`});for(let t of Y(e.doc,n))i.push({label:``,type:`type`,boost:99-a++});return{from:r,to:r,options:i,validFor:/^<\/?[:\-\.\w\u00b7-\uffff]*$/}}function Qe(e,t,n,r,i){let a=q(n),o=a?t.tags[K(e.doc,a)]:null,s=o&&o.attrs?Object.keys(o.attrs):[];return{from:r,to:i,options:(o&&o.globalAttrs===!1?s:s.length?s.concat(t.globalAttrNames):t.globalAttrNames).map(e=>({label:e,type:`property`})),validFor:X}}function $e(e,t,n,r,i){let a=n.parent?.getChild(`AttributeName`),o=[],s;if(a){let c=e.sliceDoc(a.from,a.to),l=t.globalAttrs[c];if(!l){let r=q(n),i=r?t.tags[K(e.doc,r)]:null;l=i?.attrs&&i.attrs[c]}if(l){let t=e.sliceDoc(r,i).toLowerCase(),n=`"`,a=`"`;/^['"]/.test(t)?(s=t[0]==`"`?/^[^"]*$/:/^[^']*$/,n=``,a=e.sliceDoc(i,i+1)==t[0]?``:t[0],t=t.slice(1),r++):s=/^[^\s<>='"]*$/;for(let e of l)o.push({label:e,apply:n+e+a,type:`constant`})}}return{from:r,to:i,options:o,validFor:s}}function Z(e,t){let{state:n,pos:r}=t,i=l(n).resolveInner(r,-1),a=i.resolve(r);for(let e=r,t;a==i&&(t=i.childBefore(e));){let n=t.lastChild;if(!n||!n.type.isError||n.fromZ(r,e)}var nt=p.parser.configure({top:`SingleExpression`}),rt=[{tag:`script`,attrs:e=>e.type==`text/typescript`||e.lang==`ts`,parser:oe.parser},{tag:`script`,attrs:e=>e.type==`text/babel`||e.type==`text/jsx`,parser:ie.parser},{tag:`script`,attrs:e=>e.type==`text/typescript-jsx`,parser:re.parser},{tag:`script`,attrs(e){return/^(importmap|speculationrules|application\/(.+\+)?json)$/i.test(e.type)},parser:nt},{tag:`script`,attrs(e){return!e.type||/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i.test(e.type)},parser:p.parser},{tag:`style`,attrs(e){return(!e.lang||e.lang==`css`)&&(!e.type||/^(text\/)?(x-)?(stylesheet|css)$/i.test(e.type))},parser:f.parser}],it=[{name:`style`,parser:f.parser.configure({top:`Styles`})}].concat(W.map(e=>({name:e,parser:p.parser}))),at=c.define({name:`html`,parser:qe.configure({props:[o.add({Element(e){let t=/^(\s*)(<\/)?/.exec(e.textAfter);return e.node.to<=e.pos+t[0].length?e.continue():e.lineIndent(e.node.from)+(t[2]?0:e.unit)},"OpenTag CloseTag SelfClosingTag"(e){return e.column(e.node.from)+e.unit},Document(e){if(e.pos+/\s*/.exec(e.textAfter)[0].lengthe.getChild(`TagName`)})]}),languageData:{commentTokens:{block:{open:``}},indentOnInput:/^\s*<\/\w+\W$/,wordChars:`-_`}}),Q=at.configure({wrap:I(rt,it)});function ot(e={}){let t=``,n;return e.matchClosingTags===!1&&(t=`noMatch`),e.selfClosingTags===!0&&(t=(t?t+` `:``)+`selfClosing`),(e.nestedLanguages&&e.nestedLanguages.length||e.nestedAttributes&&e.nestedAttributes.length)&&(n=I((e.nestedLanguages||[]).concat(rt),(e.nestedAttributes||[]).concat(it))),new a(n?at.configure({wrap:n,dialect:t}):t?Q.configure({dialect:t}):Q,[Q.data.of({autocomplete:tt(e)}),e.autoCloseTags===!1?[]:st,ae().support,ne().support])}var $=new Set(`area base br col command embed frame hr img input keygen link meta param source track wbr menuitem`.split(` `)),st=n.inputHandler.of((e,n,r,i,a)=>{if(e.composing||e.state.readOnly||n!=r||i!=`>`&&i!=`/`||!Q.isActiveAt(e.state,n,-1))return!1;let o=a(),{state:s}=o,c=s.changeByRange(e=>{let n=s.doc.sliceString(e.from-1,e.to)==i,{head:r}=e,a=l(s).resolveInner(r,-1),o;if(n&&i==`>`&&a.name==`EndTag`){let t=a.parent;if(t.parent?.lastChild?.name!=`CloseTag`&&(o=K(s.doc,t.parent,r))&&!$.has(o))return{range:e,changes:{from:r,to:r+ +(s.doc.sliceString(r,r+1)===`>`),insert:``}}}else if(n&&i==`/`&&a.name==`IncompleteCloseTag`){let e=a.parent;if(a.from==r-2&&e.lastChild?.name!=`CloseTag`&&(o=K(s.doc,e,r))&&!$.has(o)){let e=r+ +(s.doc.sliceString(r,r+1)===`>`),n=`${o}>`;return{range:t.cursor(r+n.length,-1),changes:{from:r,to:e,insert:n}}}}return{range:e}});return c.changes.empty?!1:(e.dispatch([o,s.update(c,{userEvent:`input.complete`,scrollIntoView:!0})]),!0)});export{ot as html,et as htmlCompletionSource}; \ No newline at end of file diff --git a/mcp/src/agents_remember/package_data/dashboard/assets/index-BLlkJI-k.js b/mcp/src/agents_remember/package_data/dashboard/assets/index-BLlkJI-k.js deleted file mode 100644 index 035b95cd..00000000 --- a/mcp/src/agents_remember/package_data/dashboard/assets/index-BLlkJI-k.js +++ /dev/null @@ -1,80 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./Terminal-ChlT6ruV.js","./Terminal-kHJ-D0s7.css","./dist-Brormx16.js","./dist-DeLSDQE4.js","./dist-CuvUDais.js","./dist-BMmyzswS.js","./dist-DGs1L_Vy.js","./dist-OF7YcNEr.js","./dist-B8juTEn3.js","./dist-CI7bovsk.js"])))=>i.map(i=>d[i]); -var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(e&&(t=e(e=0)),t),s=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),c=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},l=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},u=(n,r,a)=>(a=n==null?{}:e(i(n)),l(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n)),d=e=>a.call(e,`module.exports`)?e[`module.exports`]:l(t({},`__esModule`,{value:!0}),e);(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var f=s((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),p=s(((e,t)=>{t.exports=f()})),m=s((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function E(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function D(e,t){return E(e.type,t,e.props)}function O(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function k(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var A=/\/+/g;function j(e,t){return typeof e==`object`&&e&&e.key!=null?k(``+e.key):t.toString(36)}function M(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function N(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,N(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+j(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(A,`$&/`)+`/`),N(o,r,i,``,function(e){return e})):o!=null&&(O(o)&&(o=D(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(A,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=m()})),g=u(h(),1),_=(0,g.createContext)({});function v(e){let t=(0,g.useRef)(null);return t.current===null&&(t.current=e()),t.current}var y=typeof window<`u`?g.useLayoutEffect:g.useEffect,b=(0,g.createContext)(null);function x(e,t){e.indexOf(t)===-1&&e.push(t)}function S(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}var C=(e,t,n)=>n>t?t:n/^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(e),E=e=>typeof e==`object`&&!!e,D=e=>/^0[^.\s]+$/u.test(e);function O(e){let t;return()=>(t===void 0&&(t=e()),t)}var k=e=>e,A=(...e)=>e.reduce((e,t)=>n=>t(e(n))),j=(e,t,n)=>{let r=t-e;return r?(n-e)/r:1},M=class{constructor(){this.subscriptions=[]}add(e){return x(this.subscriptions,e),()=>S(this.subscriptions,e)}notify(e,t,n){let r=this.subscriptions.length;if(r)if(r===1)this.subscriptions[0](e,t,n);else for(let i=0;ie*1e3,P=e=>e/1e3,F=(e,t)=>t?1e3/t*e:0,ee=(e,t,n)=>(((1-3*n+3*t)*e+(3*n-6*t))*e+3*t)*e,te=1e-7,ne=12;function re(e,t,n,r,i){let a,o,s=0;do o=t+(n-t)/2,a=ee(o,r,i)-e,a>0?n=o:t=o;while(Math.abs(a)>te&&++sre(t,0,1,e,n);return e=>e===0||e===1?e:ee(i(e),t,r)}var ae=e=>t=>t<=.5?e(2*t)/2:(2-e(2*(1-t)))/2,oe=e=>t=>1-e(1-t),se=ie(.33,1.53,.69,.99),ce=oe(se),le=ae(ce),ue=e=>e>=1?1:(e*=2)<1?.5*ce(e):.5*(2-2**(-10*(e-1))),de=e=>1-Math.sin(Math.acos(e)),fe=oe(de),pe=ae(de),me=ie(.42,0,1,1),he=ie(0,0,.58,1),ge=ie(.42,0,.58,1),_e=e=>Array.isArray(e)&&typeof e[0]!=`number`,ve=e=>Array.isArray(e)&&typeof e[0]==`number`,ye={linear:k,easeIn:me,easeInOut:ge,easeOut:he,circIn:de,circInOut:pe,circOut:fe,backIn:ce,backInOut:le,backOut:se,anticipate:ue},be=e=>typeof e==`string`,xe=e=>{if(ve(e)){e.length;let[t,n,r,i]=e;return ie(t,n,r,i)}else if(be(e))return ye[e],`${e}`,ye[e];return e},Se=[`setup`,`read`,`resolveKeyframes`,`preUpdate`,`update`,`preRender`,`render`,`postRender`],Ce={value:null,addProjectionMetrics:null};function we(e,t){let n=new Set,r=new Set,i=!1,a=!1,o=new WeakSet,s={delta:0,timestamp:0,isProcessing:!1},c=0;function l(t){o.has(t)&&(u.schedule(t),e()),c++,t(s)}let u={schedule:(e,t=!1,a=!1)=>{let s=a&&i?n:r;return t&&o.add(e),s.add(e),e},cancel:e=>{r.delete(e),o.delete(e)},process:e=>{if(s=e,i){a=!0;return}i=!0;let o=n;n=r,r=o,n.forEach(l),t&&Ce.value&&Ce.value.frameloop[t].push(c),c=0,n.clear(),i=!1,a&&(a=!1,u.process(e))}};return u}var Te=40;function Ee(e,t){let n=!1,r=!0,i={delta:0,timestamp:0,isProcessing:!1},a=()=>n=!0,o=Se.reduce((e,n)=>(e[n]=we(a,t?n:void 0),e),{}),{setup:s,read:c,resolveKeyframes:l,preUpdate:u,update:d,preRender:f,render:p,postRender:m}=o,h=()=>{let a=w.useManualTiming,o=a?i.timestamp:performance.now();n=!1,a||(i.delta=r?1e3/60:Math.max(Math.min(o-i.timestamp,Te),1)),i.timestamp=o,i.isProcessing=!0,s.process(i),c.process(i),l.process(i),u.process(i),d.process(i),f.process(i),p.process(i),m.process(i),i.isProcessing=!1,n&&t&&(r=!1,e(h))},g=()=>{n=!0,r=!0,i.isProcessing||e(h)};return{schedule:Se.reduce((e,t)=>{let r=o[t];return e[t]=(e,t=!1,i=!1)=>(n||g(),r.schedule(e,t,i)),e},{}),cancel:e=>{for(let t=0;t(je===void 0&&Ne.set(ke.isProcessing||w.useManualTiming?ke.timestamp:performance.now()),je),set:e=>{je=e,queueMicrotask(Me)}},Pe={layout:0,mainThread:0,waapi:0},Fe=e=>t=>typeof t==`string`&&t.startsWith(e),Ie=Fe(`--`),Le=Fe(`var(--`),Re=e=>Le(e)?ze.test(e.split(`/*`)[0].trim()):!1,ze=/var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;function Be(e){return typeof e==`string`?e.split(`/*`)[0].includes(`var(--`):!1}var Ve={test:e=>typeof e==`number`,parse:parseFloat,transform:e=>e},He={...Ve,transform:e=>C(0,1,e)},Ue={...Ve,default:1},We=e=>Math.round(e*1e5)/1e5,Ge=/-?(?:\d+(?:\.\d+)?|\.\d+)/gu;function Ke(e){return e==null}var qe=/^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu,Je=(e,t)=>n=>!!(typeof n==`string`&&qe.test(n)&&n.startsWith(e)||t&&!Ke(n)&&Object.prototype.hasOwnProperty.call(n,t)),Ye=(e,t,n)=>r=>{if(typeof r!=`string`)return r;let[i,a,o,s]=r.match(Ge);return{[e]:parseFloat(i),[t]:parseFloat(a),[n]:parseFloat(o),alpha:s===void 0?1:parseFloat(s)}},Xe=e=>C(0,255,e),Ze={...Ve,transform:e=>Math.round(Xe(e))},Qe={test:Je(`rgb`,`red`),parse:Ye(`red`,`green`,`blue`),transform:({red:e,green:t,blue:n,alpha:r=1})=>`rgba(`+Ze.transform(e)+`, `+Ze.transform(t)+`, `+Ze.transform(n)+`, `+We(He.transform(r))+`)`};function $e(e){let t=``,n=``,r=``,i=``;return e.length>5?(t=e.substring(1,3),n=e.substring(3,5),r=e.substring(5,7),i=e.substring(7,9)):(t=e.substring(1,2),n=e.substring(2,3),r=e.substring(3,4),i=e.substring(4,5),t+=t,n+=n,r+=r,i+=i),{red:parseInt(t,16),green:parseInt(n,16),blue:parseInt(r,16),alpha:i?parseInt(i,16)/255:1}}var et={test:Je(`#`),parse:$e,transform:Qe.transform},tt=e=>({test:t=>typeof t==`string`&&t.endsWith(e)&&t.split(` `).length===1,parse:parseFloat,transform:t=>`${t}${e}`}),nt=tt(`deg`),rt=tt(`%`),I=tt(`px`),it=tt(`vh`),at=tt(`vw`),ot={...rt,parse:e=>rt.parse(e)/100,transform:e=>rt.transform(e*100)},st={test:Je(`hsl`,`hue`),parse:Ye(`hue`,`saturation`,`lightness`),transform:({hue:e,saturation:t,lightness:n,alpha:r=1})=>`hsla(`+Math.round(e)+`, `+rt.transform(We(t))+`, `+rt.transform(We(n))+`, `+We(He.transform(r))+`)`},ct={test:e=>Qe.test(e)||et.test(e)||st.test(e),parse:e=>Qe.test(e)?Qe.parse(e):st.test(e)?st.parse(e):et.parse(e),transform:e=>typeof e==`string`?e:e.hasOwnProperty(`red`)?Qe.transform(e):st.transform(e),getAnimatableNone:e=>{let t=ct.parse(e);return t.alpha=0,ct.transform(t)}},lt=/(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;function ut(e){return isNaN(e)&&typeof e==`string`&&(e.match(Ge)?.length||0)+(e.match(lt)?.length||0)>0}var dt=`number`,ft=`color`,pt=`var`,mt=`var(`,ht="${}",gt=/var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;function _t(e){let t=e.toString(),n=[],r={color:[],number:[],var:[]},i=[],a=0;return{values:n,split:t.replace(gt,e=>(ct.test(e)?(r.color.push(a),i.push(ft),n.push(ct.parse(e))):e.startsWith(mt)?(r.var.push(a),i.push(pt),n.push(e)):(r.number.push(a),i.push(dt),n.push(parseFloat(e))),++a,ht)).split(ht),indexes:r,types:i}}function vt(e){return _t(e).values}function yt({split:e,types:t}){let n=e.length;return r=>{let i=``;for(let a=0;atypeof e==`number`?0:ct.test(e)?ct.getAnimatableNone(e):e,St=(e,t)=>typeof e==`number`?t?.trim().endsWith(`/`)?e:0:xt(e);function Ct(e){let t=_t(e);return yt(t)(t.values.map((e,n)=>St(e,t.split[n])))}var wt={test:ut,parse:vt,createTransformer:bt,getAnimatableNone:Ct};function Tt(e,t,n){return n<0&&(n+=1),n>1&&--n,n<1/6?e+(t-e)*6*n:n<1/2?t:n<2/3?e+(t-e)*(2/3-n)*6:e}function Et({hue:e,saturation:t,lightness:n,alpha:r}){e/=360,t/=100,n/=100;let i=0,a=0,o=0;if(!t)i=a=o=n;else{let r=n<.5?n*(1+t):n+t-n*t,s=2*n-r;i=Tt(s,r,e+1/3),a=Tt(s,r,e),o=Tt(s,r,e-1/3)}return{red:Math.round(i*255),green:Math.round(a*255),blue:Math.round(o*255),alpha:r}}function Dt(e,t){return n=>n>0?t:e}var Ot=(e,t,n)=>e+(t-e)*n,kt=(e,t,n)=>{let r=e*e,i=n*(t*t-r)+r;return i<0?0:Math.sqrt(i)},At=[et,Qe,st],jt=e=>At.find(t=>t.test(e));function Mt(e){let t=jt(e);if(`${e}`,!t)return!1;let n=t.parse(e);return t===st&&(n=Et(n)),n}var Nt=(e,t)=>{let n=Mt(e),r=Mt(t);if(!n||!r)return Dt(e,t);let i={...n};return e=>(i.red=kt(n.red,r.red,e),i.green=kt(n.green,r.green,e),i.blue=kt(n.blue,r.blue,e),i.alpha=Ot(n.alpha,r.alpha,e),Qe.transform(i))},Pt=new Set([`none`,`hidden`]);function Ft(e,t){return Pt.has(e)?n=>n<=0?e:t:n=>n>=1?t:e}function It(e,t){return n=>Ot(e,t,n)}function Lt(e){return typeof e==`number`?It:typeof e==`string`?Re(e)?Dt:ct.test(e)?Nt:Vt:Array.isArray(e)?Rt:typeof e==`object`?ct.test(e)?Nt:zt:Dt}function Rt(e,t){let n=[...e],r=n.length,i=e.map((e,n)=>Lt(e)(e,t[n]));return e=>{for(let t=0;t{for(let t in r)n[t]=r[t](e);return n}}function Bt(e,t){let n=[],r={color:0,var:0,number:0};for(let i=0;i{let n=wt.createTransformer(t),r=_t(e),i=_t(t);return r.indexes.var.length===i.indexes.var.length&&r.indexes.color.length===i.indexes.color.length&&r.indexes.number.length>=i.indexes.number.length?Pt.has(e)&&!i.values.length||Pt.has(t)&&!r.values.length?Ft(e,t):A(Rt(Bt(r,i),i.values),n):(`${e}${t}`,Dt(e,t))};function Ht(e,t,n){return typeof e==`number`&&typeof t==`number`&&typeof n==`number`?Ot(e,t,n):Lt(e)(e,t)}var Ut=e=>{let t=({timestamp:t})=>e(t);return{start:(e=!0)=>De.update(t,e),stop:()=>Oe(t),now:()=>ke.isProcessing?ke.timestamp:Ne.now()}},Wt=(e,t,n=10)=>{let r=``,i=Math.max(Math.round(t/n),2);for(let t=0;t=2e4?1/0:t}function qt(e,t=100,n){let r=n({...e,keyframes:[0,t]}),i=Math.min(Kt(r),Gt);return{type:`keyframes`,ease:e=>r.next(i*e).value/t,duration:P(i)}}var Jt={stiffness:100,damping:10,mass:1,velocity:0,duration:800,bounce:.3,visualDuration:.3,restSpeed:{granular:.01,default:2},restDelta:{granular:.005,default:.5},minDuration:.01,maxDuration:10,minDamping:.05,maxDamping:1};function Yt(e,t){return e*Math.sqrt(1-t*t)}var Xt=12;function Zt(e,t,n){let r=n;for(let n=1;n{let r=t*o,i=r*e,a=r-n,s=Yt(t,o),c=Math.exp(-i);return Qt-a/s*c},a=t=>{let r=t*o*e,a=r*n+n,s=o**2*t**2*e,c=Math.exp(-r),l=Yt(t**2,o);return(-i(t)+Qt>0?-1:1)*((a-s)*c)/l}):(i=t=>-.001+Math.exp(-t*e)*((t-n)*e+1),a=t=>Math.exp(-t*e)*((n-t)*(e*e)));let s=5/e,c=Zt(i,a,s);if(e=N(e),isNaN(c))return{stiffness:Jt.stiffness,damping:Jt.damping,duration:e};{let t=c**2*r;return{stiffness:t,damping:o*2*Math.sqrt(r*t),duration:e}}}var en=[`duration`,`bounce`],tn=[`stiffness`,`damping`,`mass`];function nn(e,t){return t.some(t=>e[t]!==void 0)}function rn(e){let t={velocity:Jt.velocity,stiffness:Jt.stiffness,damping:Jt.damping,mass:Jt.mass,isResolvedFromDuration:!1,...e};if(!nn(e,tn)&&nn(e,en))if(t.velocity=0,e.visualDuration){let n=e.visualDuration,r=2*Math.PI/(n*1.2),i=r*r,a=2*C(.05,1,1-(e.bounce||0))*Math.sqrt(i);t={...t,mass:Jt.mass,stiffness:i,damping:a}}else{let n=$t({...e,velocity:0});t={...t,...n,mass:Jt.mass},t.isResolvedFromDuration=!0}return t}function an(e=Jt.visualDuration,t=Jt.bounce){let n=typeof e==`object`?e:{visualDuration:e,keyframes:[0,1],bounce:t},{restSpeed:r,restDelta:i}=n,a=n.keyframes[0],o=n.keyframes[n.keyframes.length-1],s={done:!1,value:a},{stiffness:c,damping:l,mass:u,duration:d,velocity:f,isResolvedFromDuration:p}=rn({...n,velocity:-P(n.velocity||0)}),m=f||0,h=l/(2*Math.sqrt(c*u)),g=o-a,_=P(Math.sqrt(c/u)),v=Math.abs(g)<5;r||=v?Jt.restSpeed.granular:Jt.restSpeed.default,i||=v?Jt.restDelta.granular:Jt.restDelta.default;let y,b,x,S,C,w;if(h<1)x=Yt(_,h),S=(m+h*_*g)/x,y=e=>o-Math.exp(-h*_*e)*(S*Math.sin(x*e)+g*Math.cos(x*e)),C=h*_*S+g*x,w=h*_*g-S*x,b=e=>Math.exp(-h*_*e)*(C*Math.sin(x*e)+w*Math.cos(x*e));else if(h===1){y=e=>o-Math.exp(-_*e)*(g+(m+_*g)*e);let e=m+_*g;b=t=>Math.exp(-_*t)*(_*e*t-m)}else{let e=_*Math.sqrt(h*h-1);y=t=>{let n=Math.exp(-h*_*t),r=Math.min(e*t,300);return o-n*((m+h*_*g)*Math.sinh(r)+e*g*Math.cosh(r))/e};let t=(m+h*_*g)/e,n=h*_*t-g*e,r=h*_*g-t*e;b=t=>{let i=Math.exp(-h*_*t),a=Math.min(e*t,300);return i*(n*Math.sinh(a)+r*Math.cosh(a))}}let T={calculatedDuration:p&&d||null,velocity:e=>N(b(e)),next:e=>{if(!p&&h<1){let t=Math.exp(-h*_*e),n=Math.sin(x*e),a=Math.cos(x*e),c=o-t*(S*n+g*a),l=N(t*(C*n+w*a));return s.done=Math.abs(l)<=r&&Math.abs(o-c)<=i,s.value=s.done?o:c,s}let t=y(e);if(p)s.done=e>=d;else{let n=N(b(e));s.done=Math.abs(n)<=r&&Math.abs(o-t)<=i}return s.value=s.done?o:t,s},toString:()=>{let e=Math.min(Kt(T),Gt),t=Wt(t=>T.next(e*t).value,e,30);return e+`ms `+t},toTransition:()=>{}};return T}an.applyToOptions=e=>{let t=qt(e,100,an);return e.ease=t.ease,e.duration=N(t.duration),e.type=`keyframes`,e};var on=5;function sn(e,t,n){let r=Math.max(t-on,0);return F(n-e(r),t-r)}function cn({keyframes:e,velocity:t=0,power:n=.8,timeConstant:r=325,bounceDamping:i=10,bounceStiffness:a=500,modifyTarget:o,min:s,max:c,restDelta:l=.5,restSpeed:u}){let d=e[0],f={done:!1,value:d},p=e=>s!==void 0&&ec,m=e=>s===void 0?c:c===void 0||Math.abs(s-e)-h*Math.exp(-e/r),y=e=>_+v(e),b=e=>{let t=v(e),n=y(e);f.done=Math.abs(t)<=l,f.value=f.done?_:n},x,S,C=e=>{p(f.value)&&(x=e,S=an({keyframes:[f.value,m(f.value)],velocity:sn(y,e,f.value),damping:i,stiffness:a,restDelta:l,restSpeed:u}))};return C(0),{calculatedDuration:null,next:e=>{let t=!1;return!S&&x===void 0&&(t=!0,b(e),C(e)),x!==void 0&&e>=x?S.next(e-x):(!t&&b(e),f)}}}function ln(e,t,n){let r=[],i=n||w.mix||Ht,a=e.length-1;for(let n=0;nt[0];if(a===2&&t[0]===t[1])return()=>t[1];let o=e[0]===e[1];e[0]>e[a-1]&&(e=[...e].reverse(),t=[...t].reverse());let s=ln(t,r,i),c=s.length,l=n=>{if(o&&n1)for(;rl(C(e[0],e[a-1],t)):l}function dn(e,t){let n=e[e.length-1];for(let r=1;r<=t;r++){let i=j(0,t,r);e.push(Ot(n,1,i))}}function fn(e){let t=[0];return dn(t,e.length-1),t}function pn(e,t){return e.map(e=>e*t)}function mn(e,t){return e.map(()=>t||ge).splice(0,e.length-1)}function hn({duration:e=300,keyframes:t,times:n,ease:r=`easeInOut`}){let i=_e(r)?r.map(xe):xe(r),a={done:!1,value:t[0]},o=un(pn(n&&n.length===t.length?n:fn(t),e),t,{ease:Array.isArray(i)?i:mn(t,i)});return{calculatedDuration:e,next:t=>(a.value=o(t),a.done=t>=e,a)}}var gn=e=>e!==null;function _n(e,{repeat:t,repeatType:n=`loop`},r,i=1){let a=e.filter(gn),o=i<0||t&&n!==`loop`&&t%2==1?0:a.length-1;return!o||r===void 0?a[o]:r}var vn={decay:cn,inertia:cn,tween:hn,keyframes:hn,spring:an};function yn(e){typeof e.type==`string`&&(e.type=vn[e.type])}var bn=class{constructor(){this.updateFinished()}get finished(){return this._finished}updateFinished(){this._finished=new Promise(e=>{this.resolve=e})}notifyFinished(){this.resolve()}then(e,t){return this.finished.then(e,t)}},xn=e=>e/100,Sn=class extends bn{constructor(e){super(),this.state=`idle`,this.startTime=null,this.isStopped=!1,this.currentTime=0,this.holdTime=null,this.playbackSpeed=1,this.delayState={done:!1,value:void 0},this.stop=()=>{let{motionValue:e}=this.options;e&&e.updatedAt!==Ne.now()&&this.tick(Ne.now()),this.isStopped=!0,this.state!==`idle`&&(this.teardown(),this.options.onStop?.())},Pe.mainThread++,this.options=e,this.initAnimation(),this.play(),e.autoplay===!1&&this.pause()}initAnimation(){let{options:e}=this;yn(e);let{type:t=hn,repeat:n=0,repeatDelay:r=0,repeatType:i,velocity:a=0}=e,{keyframes:o}=e,s=t||hn;s!==hn&&typeof o[0]!=`number`&&(this.mixKeyframes=A(xn,Ht(o[0],o[1])),o=[0,100]);let c=s({...e,keyframes:o});i===`mirror`&&(this.mirroredGenerator=s({...e,keyframes:[...o].reverse(),velocity:-a})),c.calculatedDuration===null&&(c.calculatedDuration=Kt(c));let{calculatedDuration:l}=c;this.calculatedDuration=l,this.resolvedDuration=l+r,this.totalDuration=this.resolvedDuration*(n+1)-r,this.generator=c}updateTime(e){let t=Math.round(e-this.startTime)*this.playbackSpeed;this.holdTime===null?this.currentTime=t:this.currentTime=this.holdTime}tick(e,t=!1){let{generator:n,totalDuration:r,mixKeyframes:i,mirroredGenerator:a,resolvedDuration:o,calculatedDuration:s}=this;if(this.startTime===null)return n.next(0);let{delay:c=0,keyframes:l,repeat:u,repeatType:d,repeatDelay:f,type:p,onUpdate:m,finalKeyframe:h}=this.options;this.speed>0?this.startTime=Math.min(this.startTime,e):this.speed<0&&(this.startTime=Math.min(e-r/this.speed,this.startTime)),t?this.currentTime=e:this.updateTime(e);let g=this.currentTime-c*(this.playbackSpeed>=0?1:-1),_=this.playbackSpeed>=0?g<0:g>r;this.currentTime=Math.max(g,0),this.state===`finished`&&this.holdTime===null&&(this.currentTime=r);let v=this.currentTime,y=n;if(u){let e=Math.min(this.currentTime,r)/o,t=Math.floor(e),n=e%1;!n&&e>=1&&(n=1),n===1&&t--,t=Math.min(t,u+1),t%2&&(d===`reverse`?(n=1-n,f&&(n-=f/o)):d===`mirror`&&(y=a)),v=C(0,1,n)*o}let b;_?(this.delayState.value=l[0],b=this.delayState):b=y.next(v),i&&!_&&(b.value=i(b.value));let{done:x}=b;!_&&s!==null&&(x=this.playbackSpeed>=0?this.currentTime>=r:this.currentTime<=0);let S=this.holdTime===null&&(this.state===`finished`||this.state===`running`&&x);return S&&p!==cn&&(b.value=_n(l,this.options,h,this.speed)),m&&m(b.value),S&&this.finish(),b}then(e,t){return this.finished.then(e,t)}get duration(){return P(this.calculatedDuration)}get iterationDuration(){let{delay:e=0}=this.options||{};return this.duration+P(e)}get time(){return P(this.currentTime)}set time(e){e=N(e),this.currentTime=e,this.startTime===null||this.holdTime!==null||this.playbackSpeed===0?this.holdTime=e:this.driver&&(this.startTime=this.driver.now()-e/this.playbackSpeed),this.driver?this.driver.start(!1):(this.startTime=0,this.state=`paused`,this.holdTime=e,this.tick(e))}getGeneratorVelocity(){let e=this.currentTime;if(e<=0)return this.options.velocity||0;if(this.generator.velocity)return this.generator.velocity(e);let t=this.generator.next(e).value;return sn(e=>this.generator.next(e).value,e,t)}get speed(){return this.playbackSpeed}set speed(e){let t=this.playbackSpeed!==e;t&&this.driver&&this.updateTime(Ne.now()),this.playbackSpeed=e,t&&this.driver&&(this.time=P(this.currentTime))}play(){if(this.isStopped)return;let{driver:e=Ut,startTime:t}=this.options;this.driver||=e(e=>this.tick(e)),this.options.onPlay?.();let n=this.driver.now();this.state===`finished`?(this.updateFinished(),this.startTime=n):this.holdTime===null?this.startTime||=t??n:this.startTime=n-this.holdTime,this.state===`finished`&&this.speed<0&&(this.startTime+=this.calculatedDuration),this.holdTime=null,this.state=`running`,this.driver.start()}pause(){this.state=`paused`,this.updateTime(Ne.now()),this.holdTime=this.currentTime}complete(){this.state!==`running`&&this.play(),this.state=`finished`,this.holdTime=null}finish(){this.notifyFinished(),this.teardown(),this.state=`finished`,this.options.onComplete?.()}cancel(){this.holdTime=null,this.startTime=0,this.tick(0),this.teardown(),this.options.onCancel?.()}teardown(){this.state=`idle`,this.stopDriver(),this.startTime=this.holdTime=null,Pe.mainThread--}stopDriver(){this.driver&&=(this.driver.stop(),void 0)}sample(e){return this.startTime=0,this.tick(e,!0)}attachTimeline(e){return this.options.allowFlatten&&(this.options.type=`keyframes`,this.options.ease=`linear`,this.initAnimation()),this.driver?.stop(),e.observe(this)}};function Cn(e){for(let t=1;te*180/Math.PI,Tn=e=>Dn(wn(Math.atan2(e[1],e[0]))),En={x:4,y:5,translateX:4,translateY:5,scaleX:0,scaleY:3,scale:e=>(Math.abs(e[0])+Math.abs(e[3]))/2,rotate:Tn,rotateZ:Tn,skewX:e=>wn(Math.atan(e[1])),skewY:e=>wn(Math.atan(e[2])),skew:e=>(Math.abs(e[1])+Math.abs(e[2]))/2},Dn=e=>(e%=360,e<0&&(e+=360),e),On=Tn,kn=e=>Math.sqrt(e[0]*e[0]+e[1]*e[1]),An=e=>Math.sqrt(e[4]*e[4]+e[5]*e[5]),jn={x:12,y:13,z:14,translateX:12,translateY:13,translateZ:14,scaleX:kn,scaleY:An,scale:e=>(kn(e)+An(e))/2,rotateX:e=>Dn(wn(Math.atan2(e[6],e[5]))),rotateY:e=>Dn(wn(Math.atan2(-e[2],e[0]))),rotateZ:On,rotate:On,skewX:e=>wn(Math.atan(e[4])),skewY:e=>wn(Math.atan(e[1])),skew:e=>(Math.abs(e[1])+Math.abs(e[4]))/2};function Mn(e){return+!!e.includes(`scale`)}function Nn(e,t){if(!e||e===`none`)return Mn(t);let n=e.match(/^matrix3d\(([-\d.e\s,]+)\)$/u),r,i;if(n)r=jn,i=n;else{let t=e.match(/^matrix\(([-\d.e\s,]+)\)$/u);r=En,i=t}if(!i)return Mn(t);let a=r[t],o=i[1].split(`,`).map(Fn);return typeof a==`function`?a(o):o[a]}var Pn=(e,t)=>{let{transform:n=`none`}=getComputedStyle(e);return Nn(n,t)};function Fn(e){return parseFloat(e.trim())}var In=[`transformPerspective`,`x`,`y`,`z`,`translateX`,`translateY`,`translateZ`,`scale`,`scaleX`,`scaleY`,`rotate`,`rotateX`,`rotateY`,`rotateZ`,`skew`,`skewX`,`skewY`],Ln=new Set([...In,`pathRotation`]),Rn=e=>e===Ve||e===I,zn=new Set([`x`,`y`,`z`]),Bn=In.filter(e=>!zn.has(e));function Vn(e){let t=[];return Bn.forEach(n=>{let r=e.getValue(n);r!==void 0&&(t.push([n,r.get()]),r.set(+!!n.startsWith(`scale`)))}),t}var Hn={width:({x:e},{paddingLeft:t=`0`,paddingRight:n=`0`,boxSizing:r})=>{let i=e.max-e.min;return r===`border-box`?i:i-parseFloat(t)-parseFloat(n)},height:({y:e},{paddingTop:t=`0`,paddingBottom:n=`0`,boxSizing:r})=>{let i=e.max-e.min;return r===`border-box`?i:i-parseFloat(t)-parseFloat(n)},top:(e,{top:t})=>parseFloat(t),left:(e,{left:t})=>parseFloat(t),bottom:({y:e},{top:t})=>parseFloat(t)+(e.max-e.min),right:({x:e},{left:t})=>parseFloat(t)+(e.max-e.min),x:(e,{transform:t})=>Nn(t,`x`),y:(e,{transform:t})=>Nn(t,`y`)};Hn.translateX=Hn.x,Hn.translateY=Hn.y;var Un=new Set,Wn=!1,Gn=!1,Kn=!1;function qn(){if(Gn){let e=Array.from(Un).filter(e=>e.needsMeasurement),t=new Set(e.map(e=>e.element)),n=new Map;t.forEach(e=>{let t=Vn(e);t.length&&(n.set(e,t),e.render())}),e.forEach(e=>e.measureInitialState()),t.forEach(e=>{e.render();let t=n.get(e);t&&t.forEach(([t,n])=>{e.getValue(t)?.set(n)})}),e.forEach(e=>e.measureEndState()),e.forEach(e=>{e.suspendedScrollY!==void 0&&window.scrollTo(0,e.suspendedScrollY)})}Gn=!1,Wn=!1,Un.forEach(e=>e.complete(Kn)),Un.clear()}function Jn(){Un.forEach(e=>{e.readKeyframes(),e.needsMeasurement&&(Gn=!0)})}function Yn(){Kn=!0,Jn(),qn(),Kn=!1}var Xn=class{constructor(e,t,n,r,i,a=!1){this.state=`pending`,this.isAsync=!1,this.needsMeasurement=!1,this.unresolvedKeyframes=[...e],this.onComplete=t,this.name=n,this.motionValue=r,this.element=i,this.isAsync=a}scheduleResolve(){this.state=`scheduled`,this.isAsync?(Un.add(this),Wn||(Wn=!0,De.read(Jn),De.resolveKeyframes(qn))):(this.readKeyframes(),this.complete())}readKeyframes(){let{unresolvedKeyframes:e,name:t,element:n,motionValue:r}=this;if(e[0]===null){let i=r?.get(),a=e[e.length-1];if(i!==void 0)e[0]=i;else if(n&&t){let r=n.readValue(t,a);r!=null&&(e[0]=r)}e[0]===void 0&&(e[0]=a),r&&i===void 0&&r.set(e[0])}Cn(e)}setFinalKeyframe(){}measureInitialState(){}renderEndStyles(){}measureEndState(){}complete(e=!1){this.state=`complete`,this.onComplete(this.unresolvedKeyframes,this.finalKeyframe,e),Un.delete(this)}cancel(){this.state===`scheduled`&&(Un.delete(this),this.state=`pending`)}resume(){this.state===`pending`&&this.scheduleResolve()}},Zn=e=>e.startsWith(`--`);function Qn(e,t,n){Zn(t)?e.style.setProperty(t,n):e.style[t]=n}var $n={};function er(e,t){let n=O(e);return()=>$n[t]??n()}var tr=er(()=>window.ScrollTimeline!==void 0,`scrollTimeline`),nr=er(()=>{try{document.createElement(`div`).animate({opacity:0},{easing:`linear(0, 1)`})}catch{return!1}return!0},`linearEasing`),rr=([e,t,n,r])=>`cubic-bezier(${e}, ${t}, ${n}, ${r})`,ir={linear:`linear`,ease:`ease`,easeIn:`ease-in`,easeOut:`ease-out`,easeInOut:`ease-in-out`,circIn:rr([0,.65,.55,1]),circOut:rr([.55,0,1,.45]),backIn:rr([.31,.01,.66,-.59]),backOut:rr([.33,1.53,.69,.99])};function ar(e,t){if(e)return typeof e==`function`?nr()?Wt(e,t):`ease-out`:ve(e)?rr(e):Array.isArray(e)?e.map(e=>ar(e,t)||ir.easeOut):ir[e]}function or(e,t,n,{delay:r=0,duration:i=300,repeat:a=0,repeatType:o=`loop`,ease:s=`easeOut`,times:c}={},l=void 0){let u={[t]:n};c&&(u.offset=c);let d=ar(s,i);Array.isArray(d)&&(u.easing=d),Ce.value&&Pe.waapi++;let f={delay:r,duration:i,easing:Array.isArray(d)?`linear`:d,fill:`both`,iterations:a+1,direction:o===`reverse`?`alternate`:`normal`};l&&(f.pseudoElement=l);let p=e.animate(u,f);return Ce.value&&p.finished.finally(()=>{Pe.waapi--}),p}function sr(e){return typeof e==`function`&&`applyToOptions`in e}function cr({type:e,...t}){return sr(e)&&nr()?e.applyToOptions(t):(t.duration??=300,t.ease??=`easeOut`,t)}var lr=class extends bn{constructor(e){if(super(),this.finishedTime=null,this.isStopped=!1,this.manualStartTime=null,!e)return;let{element:t,name:n,keyframes:r,pseudoElement:i,allowFlatten:a=!1,finalKeyframe:o,onComplete:s}=e;this.isPseudoElement=!!i,this.allowFlatten=a,this.options=e,e.type;let c=cr(e);this.animation=or(t,n,r,c,i),c.autoplay===!1&&this.animation.pause(),this.animation.onfinish=()=>{if(this.finishedTime=this.time,!i){let e=_n(r,this.options,o,this.speed);this.updateMotionValue&&this.updateMotionValue(e),Qn(t,n,e),this.animation.cancel()}s?.(),this.notifyFinished()}}play(){this.isStopped||(this.manualStartTime=null,this.animation.play(),this.state===`finished`&&this.updateFinished())}pause(){this.animation.pause()}complete(){this.animation.finish?.()}cancel(){try{this.animation.cancel()}catch{}}stop(){if(this.isStopped)return;this.isStopped=!0;let{state:e}=this;e===`idle`||e===`finished`||(this.updateMotionValue?this.updateMotionValue():this.commitStyles(),this.isPseudoElement||this.cancel())}commitStyles(){let e=this.options?.element;!this.isPseudoElement&&e?.isConnected&&this.animation.commitStyles?.()}get duration(){let e=this.animation.effect?.getComputedTiming?.().duration||0;return P(Number(e))}get iterationDuration(){let{delay:e=0}=this.options||{};return this.duration+P(e)}get time(){return P(Number(this.animation.currentTime)||0)}set time(e){let t=this.finishedTime!==null;this.manualStartTime=null,this.finishedTime=null,this.animation.currentTime=N(e),t&&this.animation.pause()}get speed(){return this.animation.playbackRate}set speed(e){e<0&&(this.finishedTime=null),this.animation.playbackRate=e}get state(){return this.finishedTime===null?this.animation.playState:`finished`}get startTime(){return this.manualStartTime??Number(this.animation.startTime)}set startTime(e){this.manualStartTime=this.animation.startTime=e}attachTimeline({timeline:e,rangeStart:t,rangeEnd:n,observe:r}){return this.allowFlatten&&this.animation.effect?.updateTiming({easing:`linear`}),this.animation.onfinish=null,e&&tr()?(this.animation.timeline=e,t&&(this.animation.rangeStart=t),n&&(this.animation.rangeEnd=n),k):r(this)}},ur={anticipate:ue,backInOut:le,circInOut:pe};function dr(e){return e in ur}function fr(e){typeof e.ease==`string`&&dr(e.ease)&&(e.ease=ur[e.ease])}var pr=10,mr=class extends lr{constructor(e){fr(e),yn(e),super(e),e.startTime!==void 0&&e.autoplay!==!1&&(this.startTime=e.startTime),this.options=e}updateMotionValue(e){let{motionValue:t,onUpdate:n,onComplete:r,element:i,...a}=this.options;if(!t)return;if(e!==void 0){t.set(e);return}let o=new Sn({...a,autoplay:!1}),s=Math.max(pr,Ne.now()-this.startTime),c=C(0,pr,s-pr),l=o.sample(s).value,{name:u}=this.options;i&&u&&Qn(i,u,l),t.setWithVelocity(o.sample(Math.max(0,s-c)).value,l,c),o.stop()}},hr=(e,t)=>t===`zIndex`?!1:!!(typeof e==`number`||Array.isArray(e)||typeof e==`string`&&(wt.test(e)||e===`0`)&&!e.startsWith(`url(`));function gr(e){let t=e[0];if(e.length===1)return!0;for(let n=0;nObject.hasOwnProperty.call(Element.prototype,`animate`));function wr(e){let{motionValue:t,name:n,repeatDelay:r,repeatType:i,damping:a,type:o,keyframes:s}=e;if(!(t?.owner?.current instanceof HTMLElement))return!1;let{onUpdate:c,transformTemplate:l}=t.owner.getProps();return Cr()&&n&&(yr.has(n)||Sr.has(n)&&xr(s))&&(n!==`transform`||!l)&&!c&&!r&&i!==`mirror`&&a!==0&&o!==`inertia`}var Tr=40,Er=class extends bn{constructor({autoplay:e=!0,delay:t=0,type:n=`keyframes`,repeat:r=0,repeatDelay:i=0,repeatType:a=`loop`,keyframes:o,name:s,motionValue:c,element:l,...u}){super(),this.stop=()=>{this._animation&&(this._animation.stop(),this.stopTimeline?.()),this.keyframeResolver?.cancel()},this.createdAt=Ne.now();let d={autoplay:e,delay:t,type:n,repeat:r,repeatDelay:i,repeatType:a,name:s,motionValue:c,element:l,...u},f=l?.KeyframeResolver||Xn;this.keyframeResolver=new f(o,(e,t,n)=>this.onKeyframesResolved(e,t,d,!n),s,c,l),this.keyframeResolver?.scheduleResolve()}onKeyframesResolved(e,t,n,r){this.keyframeResolver=void 0;let{name:i,type:a,velocity:o,delay:s,isHandoff:c,onUpdate:l}=n;this.resolvedAt=Ne.now();let u=!0;_r(e,i,a,o)||(u=!1,(w.instantAnimations||!s)&&l?.(_n(e,n,t)),e[0]=e[e.length-1],vr(n),n.repeat=0);let d={startTime:r?this.resolvedAt&&this.resolvedAt-this.createdAt>Tr?this.resolvedAt:this.createdAt:void 0,finalKeyframe:t,...n,keyframes:e},f=u&&!c&&wr(d),p=d.motionValue?.owner?.current,m;if(f)try{m=new mr({...d,element:p})}catch{m=new Sn(d)}else m=new Sn(d);m.finished.then(()=>{this.notifyFinished()}).catch(k),this.pendingTimeline&&=(this.stopTimeline=m.attachTimeline(this.pendingTimeline),void 0),this._animation=m}get finished(){return this._animation?this.animation.finished:this._finished}then(e,t){return this.finished.finally(e).then(()=>{})}get animation(){return this._animation||(this.keyframeResolver?.resume(),Yn()),this._animation}get duration(){return this.animation.duration}get iterationDuration(){return this.animation.iterationDuration}get time(){return this.animation.time}set time(e){this.animation.time=e}get speed(){return this.animation.speed}get state(){return this.animation.state}set speed(e){this.animation.speed=e}get startTime(){return this.animation.startTime}attachTimeline(e){return this._animation?this.stopTimeline=this.animation.attachTimeline(e):this.pendingTimeline=e,()=>this.stop()}play(){this.animation.play()}pause(){this.animation.pause()}complete(){this.animation.complete()}cancel(){this._animation&&this.animation.cancel(),this.keyframeResolver?.cancel()}};function Dr(e,t,n,r=0,i=1){let a=Array.from(e).sort((e,t)=>e.sortNodePosition(t)).indexOf(t),o=e.size,s=(o-1)*r;return typeof n==`function`?n(a,o):i===1?a*r:s-a*r}var Or=30,kr=e=>!isNaN(parseFloat(e)),Ar={current:void 0},jr=class{constructor(e,t={}){this.canTrackVelocity=null,this.events={},this.updateAndNotify=e=>{let t=Ne.now();if(this.updatedAt!==t&&this.setPrevFrameValue(),this.prev=this.current,this.setCurrent(e),this.current!==this.prev&&(this.events.change?.notify(this.current),this.dependents))for(let e of this.dependents)e.dirty()},this.hasAnimated=!1,this.setCurrent(e),this.owner=t.owner}setCurrent(e){this.current=e,this.updatedAt=Ne.now(),this.canTrackVelocity===null&&e!==void 0&&(this.canTrackVelocity=kr(this.current))}setPrevFrameValue(e=this.current){this.prevFrameValue=e,this.prevUpdatedAt=this.updatedAt}onChange(e){return this.on(`change`,e)}on(e,t){this.events[e]||(this.events[e]=new M);let n=this.events[e].add(t);return e===`change`?()=>{n(),De.read(()=>{this.events.change.getSize()||this.stop()})}:n}clearListeners(){for(let e in this.events)this.events[e].clear()}attach(e,t){this.passiveEffect=e,this.stopPassiveEffect=t}set(e){this.passiveEffect?this.passiveEffect(e,this.updateAndNotify):this.updateAndNotify(e)}setWithVelocity(e,t,n){this.set(t),this.prev=void 0,this.prevFrameValue=e,this.prevUpdatedAt=this.updatedAt-n}jump(e,t=!0){this.updateAndNotify(e),this.prev=e,this.prevUpdatedAt=this.prevFrameValue=void 0,t&&this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}dirty(){this.events.change?.notify(this.current)}addDependent(e){this.dependents||=new Set,this.dependents.add(e)}removeDependent(e){this.dependents&&this.dependents.delete(e)}get(){return Ar.current&&Ar.current.push(this),this.current}getPrevious(){return this.prev}getVelocity(){let e=Ne.now();if(!this.canTrackVelocity||this.prevFrameValue===void 0||e-this.updatedAt>Or)return 0;let t=Math.min(this.updatedAt-this.prevUpdatedAt,Or);return F(parseFloat(this.current)-parseFloat(this.prevFrameValue),t)}start(e){return this.stop(),new Promise(t=>{this.hasAnimated=!0,this.animation=e(t),this.events.animationStart&&this.events.animationStart.notify()}).then(()=>{this.events.animationComplete&&this.events.animationComplete.notify(),this.clearAnimation()})}stop(){this.animation&&(this.animation.stop(),this.events.animationCancel&&this.events.animationCancel.notify()),this.clearAnimation()}isAnimating(){return!!this.animation}clearAnimation(){delete this.animation}destroy(){this.dependents?.clear(),this.events.destroy?.notify(),this.clearListeners(),this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}};function Mr(e,t){return new jr(e,t)}function Nr(e,t){if(e?.inherit&&t){let{inherit:n,...r}=e;return{...t,...r}}return e}function Pr(e,t){let n=e?.[t]??e?.default??e;return n===e?n:Nr(n,e)}var Fr={type:`spring`,stiffness:500,damping:25,restSpeed:10},Ir=e=>({type:`spring`,stiffness:550,damping:e===0?2*Math.sqrt(550):30,restSpeed:10}),Lr={type:`keyframes`,duration:.8},Rr={type:`keyframes`,ease:[.25,.1,.35,1],duration:.3},zr=(e,{keyframes:t})=>t.length>2?Lr:Ln.has(e)?e.startsWith(`scale`)?Ir(t[1]):Fr:Rr,Br=new Set([`when`,`delay`,`delayChildren`,`staggerChildren`,`staggerDirection`,`repeat`,`repeatType`,`repeatDelay`,`from`,`elapsed`]);function Vr(e){for(let t in e)if(!Br.has(t))return!0;return!1}var Hr=(e,t,n,r={},i,a)=>o=>{let s=Pr(r,e)||{},c=s.delay||r.delay||0,{elapsed:l=0}=r;l-=N(c);let u={keyframes:Array.isArray(n)?n:[null,n],ease:`easeOut`,velocity:t.getVelocity(),...s,delay:-l,onUpdate:e=>{t.set(e),s.onUpdate&&s.onUpdate(e)},onComplete:()=>{o(),s.onComplete&&s.onComplete()},name:e,motionValue:t,element:a?void 0:i};Vr(s)||Object.assign(u,zr(e,u)),u.duration&&=N(u.duration),u.repeatDelay&&=N(u.repeatDelay),u.from!==void 0&&(u.keyframes[0]=u.from);let d=!1;if((u.type===!1||u.duration===0&&!u.repeatDelay)&&(vr(u),u.delay===0&&(d=!0)),(w.instantAnimations||w.skipAnimations||i?.shouldSkipAnimations||s.skipAnimations)&&(d=!0,vr(u),u.delay=0),u.allowFlatten=!s.type&&!s.ease,d&&!a&&t.get()!==void 0){let e=_n(u.keyframes,s);if(e!==void 0){De.update(()=>{u.onUpdate(e),u.onComplete()});return}}return s.isSync?new Sn(u):new Er(u)},Ur=/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;function Wr(e){let t=Ur.exec(e);if(!t)return[,];let[,n,r,i]=t;return[`--${n??r}`,i]}function Gr(e,t,n=1){`${e}`;let[r,i]=Wr(e);if(!r)return;let a=window.getComputedStyle(t).getPropertyValue(r);if(a){let e=a.trim();return T(e)?parseFloat(e):e}return Re(i)?Gr(i,t,n+1):i}function Kr(e){let t=[{},{}];return e?.values.forEach((e,n)=>{t[0][n]=e.get(),t[1][n]=e.getVelocity()}),t}function qr(e,t,n,r){if(typeof t==`function`){let[i,a]=Kr(r);t=t(n===void 0?e.custom:n,i,a)}if(typeof t==`string`&&(t=e.variants&&e.variants[t]),typeof t==`function`){let[i,a]=Kr(r);t=t(n===void 0?e.custom:n,i,a)}return t}function Jr(e,t,n){let r=e.getProps();return qr(r,t,n===void 0?r.custom:n,e)}var Yr=new Set([`width`,`height`,`top`,`left`,`right`,`bottom`,...In]),Xr=e=>Array.isArray(e);function Zr(e,t,n){e.hasValue(t)?e.getValue(t).set(n):e.addValue(t,Mr(n))}function Qr(e){return Xr(e)?e[e.length-1]||0:e}function $r(e,t){let{transitionEnd:n={},transition:r={},...i}=Jr(e,t)||{};i={...i,...n};for(let t in i)Zr(e,t,Qr(i[t]))}var ei=e=>!!(e&&e.getVelocity);function ti(e){return!!(ei(e)&&e.add)}function ni(e,t){let n=e.getValue(`willChange`);if(ti(n))return n.add(t);if(!n&&w.WillChange){let n=new w.WillChange(`auto`);e.addValue(`willChange`,n),n.add(t)}}function ri(e){return e.replace(/([A-Z])/g,e=>`-${e.toLowerCase()}`)}var ii=`data-`+ri(`framerAppearId`);function ai(e){return e.props[ii]}function oi({protectedKeys:e,needsAnimating:t},n){let r=e.hasOwnProperty(n)&&t[n]!==!0;return t[n]=!1,r}function si(e,t,{delay:n=0,transitionOverride:r,type:i}={}){let{transition:a,transitionEnd:o,...s}=t,c=e.getDefaultTransition();a=a?Nr(a,c):c;let l=a?.reduceMotion,u=a?.skipAnimations;r&&(a=r);let d=[],f=i&&e.animationState&&e.animationState.getState()[i],p=a?.path;p&&p.animateVisualElement(e,s,a,n,d);for(let t in s){let r=e.getValue(t,e.latestValues[t]??null),i=s[t];if(i===void 0||f&&oi(f,t))continue;let o={delay:n,...Pr(a||{},t)};u&&(o.skipAnimations=!0);let c=r.get();if(c!==void 0&&!r.isAnimating()&&!Array.isArray(i)&&i===c&&!o.velocity){De.update(()=>r.set(i));continue}let p=!1;if(window.MotionHandoffAnimation){let n=ai(e);if(n){let e=window.MotionHandoffAnimation(n,t,De);e!==null&&(o.startTime=e,p=!0)}}ni(e,t);let m=l??e.shouldReduceMotion;r.start(Hr(t,r,i,m&&Yr.has(t)?{type:!1}:o,e,p));let h=r.animation;h&&d.push(h)}if(o){let t=()=>De.update(()=>{o&&$r(e,o)});d.length?Promise.all(d).then(t):t()}return d}function ci(e,t,n={}){let r=Jr(e,t,n.type===`exit`?e.presenceContext?.custom:void 0),{transition:i=e.getDefaultTransition()||{}}=r||{};n.transitionOverride&&(i=n.transitionOverride);let a=r?()=>Promise.all(si(e,r,n)):()=>Promise.resolve(),o=e.variantChildren&&e.variantChildren.size?(r=0)=>{let{delayChildren:a=0,staggerChildren:o,staggerDirection:s}=i;return li(e,t,r,a,o,s,n)}:()=>Promise.resolve(),{when:s}=i;if(s){let[e,t]=s===`beforeChildren`?[a,o]:[o,a];return e().then(()=>t())}else return Promise.all([a(),o(n.delay)])}function li(e,t,n=0,r=0,i=0,a=1,o){let s=[];for(let c of e.variantChildren)c.notify(`AnimationStart`,t),s.push(ci(c,t,{...o,delay:n+(typeof r==`function`?0:r)+Dr(e.variantChildren,c,r,i,a)}).then(()=>c.notify(`AnimationComplete`,t)));return Promise.all(s)}function ui(e,t,n={}){e.notify(`AnimationStart`,t);let r;if(Array.isArray(t)){let i=t.map(t=>ci(e,t,n));r=Promise.all(i)}else if(typeof t==`string`)r=ci(e,t,n);else{let i=typeof t==`function`?Jr(e,t,n.custom):t;r=Promise.all(si(e,i,n))}return r.then(()=>{e.notify(`AnimationComplete`,t)})}var di={test:e=>e===`auto`,parse:e=>e},fi=e=>t=>t.test(e),pi=[Ve,I,rt,nt,at,it,di],mi=e=>pi.find(fi(e));function hi(e){return typeof e==`number`?e===0:e===null?!0:e===`none`||e===`0`||D(e)}var gi=new Set([`brightness`,`contrast`,`saturate`,`opacity`]);function _i(e){let[t,n]=e.slice(0,-1).split(`(`);if(t===`drop-shadow`)return e;let[r]=n.match(Ge)||[];if(!r)return e;let i=n.replace(r,``),a=+!!gi.has(t);return r!==n&&(a*=100),t+`(`+a+i+`)`}var vi=/\b([a-z-]*)\(.*?\)/gu,yi={...wt,getAnimatableNone:e=>{let t=e.match(vi);return t?t.map(_i).join(` `):e}},bi={...wt,getAnimatableNone:e=>{let t=wt.parse(e);return wt.createTransformer(e)(t.map(e=>typeof e==`number`?0:typeof e==`object`?{...e,alpha:1}:e))}},xi={...Ve,transform:Math.round},Si={borderWidth:I,borderTopWidth:I,borderRightWidth:I,borderBottomWidth:I,borderLeftWidth:I,borderRadius:I,borderTopLeftRadius:I,borderTopRightRadius:I,borderBottomRightRadius:I,borderBottomLeftRadius:I,width:I,maxWidth:I,height:I,maxHeight:I,top:I,right:I,bottom:I,left:I,inset:I,insetBlock:I,insetBlockStart:I,insetBlockEnd:I,insetInline:I,insetInlineStart:I,insetInlineEnd:I,padding:I,paddingTop:I,paddingRight:I,paddingBottom:I,paddingLeft:I,paddingBlock:I,paddingBlockStart:I,paddingBlockEnd:I,paddingInline:I,paddingInlineStart:I,paddingInlineEnd:I,margin:I,marginTop:I,marginRight:I,marginBottom:I,marginLeft:I,marginBlock:I,marginBlockStart:I,marginBlockEnd:I,marginInline:I,marginInlineStart:I,marginInlineEnd:I,fontSize:I,backgroundPositionX:I,backgroundPositionY:I,rotate:nt,pathRotation:nt,rotateX:nt,rotateY:nt,rotateZ:nt,scale:Ue,scaleX:Ue,scaleY:Ue,scaleZ:Ue,skew:nt,skewX:nt,skewY:nt,distance:I,translateX:I,translateY:I,translateZ:I,x:I,y:I,z:I,perspective:I,transformPerspective:I,opacity:He,originX:ot,originY:ot,originZ:I,zIndex:xi,fillOpacity:He,strokeOpacity:He,numOctaves:xi},Ci={...Si,color:ct,backgroundColor:ct,outlineColor:ct,fill:ct,stroke:ct,borderColor:ct,borderTopColor:ct,borderRightColor:ct,borderBottomColor:ct,borderLeftColor:ct,filter:yi,WebkitFilter:yi,mask:bi,WebkitMask:bi},wi=e=>Ci[e],Ti=new Set([yi,bi]);function Ei(e,t){let n=wi(e);return Ti.has(n)||(n=wt),n.getAnimatableNone?n.getAnimatableNone(t):void 0}var Di=new Set([`auto`,`none`,`0`]);function Oi(e,t,n){let r=0,i;for(;r{e.getValue(t).set(n)}),this.resolveNoneKeyframes()}};function Ai(e,t,n){if(e==null)return[];if(e instanceof EventTarget)return[e];if(typeof e==`string`){let r=document;t&&(r=t.current);let i=n?.[e]??r.querySelectorAll(e);return i?Array.from(i):[]}return Array.from(e).filter(e=>e!=null)}var ji=(e,t)=>t&&typeof e==`number`?t.transform(e):e;function Mi(e){return E(e)&&`offsetHeight`in e&&!(`ownerSVGElement`in e)}var{schedule:Ni,cancel:Pi}=Ee(queueMicrotask,!1),L={x:!1,y:!1};function Fi(){return L.x||L.y}function Ii(e){return e===`x`||e===`y`?L[e]?null:(L[e]=!0,()=>{L[e]=!1}):L.x||L.y?null:(L.x=L.y=!0,()=>{L.x=L.y=!1})}function Li(e,t){let n=Ai(e),r=new AbortController;return[n,{passive:!0,...t,signal:r.signal},()=>r.abort()]}function Ri(e){return!(e.pointerType===`touch`||Fi())}function zi(e,t,n={}){let[r,i,a]=Li(e,n);return r.forEach(e=>{let n=!1,r=!1,a,o=()=>{e.removeEventListener(`pointerleave`,u)},s=e=>{a&&=(a(e),void 0),o()},c=e=>{n=!1,window.removeEventListener(`pointerup`,c),window.removeEventListener(`pointercancel`,c),r&&(r=!1,s(e))},l=()=>{n=!0,window.addEventListener(`pointerup`,c,i),window.addEventListener(`pointercancel`,c,i)},u=e=>{if(e.pointerType!==`touch`){if(n){r=!0;return}s(e)}};e.addEventListener(`pointerenter`,n=>{if(!Ri(n))return;r=!1;let o=t(e,n);typeof o==`function`&&(a=o,e.addEventListener(`pointerleave`,u,i))},i),e.addEventListener(`pointerdown`,l,i)}),a}var Bi=(e,t)=>t?e===t?!0:Bi(e,t.parentElement):!1,Vi=e=>e.pointerType===`mouse`?typeof e.button!=`number`||e.button<=0:e.isPrimary!==!1,Hi=new Set([`BUTTON`,`INPUT`,`SELECT`,`TEXTAREA`,`A`]);function Ui(e){return Hi.has(e.tagName)||e.isContentEditable===!0}var Wi=new Set([`INPUT`,`SELECT`,`TEXTAREA`]);function Gi(e){return Wi.has(e.tagName)||e.isContentEditable===!0}var Ki=new WeakSet;function qi(e){return t=>{t.key===`Enter`&&e(t)}}function Ji(e,t){e.dispatchEvent(new PointerEvent(`pointer`+t,{isPrimary:!0,bubbles:!0}))}var Yi=(e,t)=>{let n=e.currentTarget;if(!n)return;let r=qi(()=>{if(Ki.has(n))return;Ji(n,`down`);let e=qi(()=>{Ji(n,`up`)});n.addEventListener(`keyup`,e,t),n.addEventListener(`blur`,()=>Ji(n,`cancel`),t)});n.addEventListener(`keydown`,r,t),n.addEventListener(`blur`,()=>n.removeEventListener(`keydown`,r),t)};function Xi(e){return Vi(e)&&!Fi()}var Zi=new WeakSet;function Qi(e,t,n={}){let[r,i,a]=Li(e,n),o=e=>{let r=e.currentTarget;if(!Xi(e)||Zi.has(e))return;Ki.add(r),n.stopPropagation&&Zi.add(e);let a=t(r,e),o=(e,t)=>{window.removeEventListener(`pointerup`,s),window.removeEventListener(`pointercancel`,c),Ki.has(r)&&Ki.delete(r),Xi(e)&&typeof a==`function`&&a(e,{success:t})},s=e=>{o(e,r===window||r===document||n.useGlobalTarget||Bi(r,e.target))},c=e=>{o(e,!1)};window.addEventListener(`pointerup`,s,i),window.addEventListener(`pointercancel`,c,i)};return r.forEach(e=>{(n.useGlobalTarget?window:e).addEventListener(`pointerdown`,o,i),Mi(e)&&(e.addEventListener(`focus`,e=>Yi(e,i)),!Ui(e)&&!e.hasAttribute(`tabindex`)&&(e.tabIndex=0))}),a}function $i(e){return E(e)&&`ownerSVGElement`in e}var ea=new WeakMap,ta,na=(e,t,n)=>(r,i)=>i&&i[0]?i[0][e+`Size`]:$i(r)&&`getBBox`in r?r.getBBox()[t]:r[n],ra=na(`inline`,`width`,`offsetWidth`),ia=na(`block`,`height`,`offsetHeight`);function aa({target:e,borderBoxSize:t}){ea.get(e)?.forEach(n=>{n(e,{get width(){return ra(e,t)},get height(){return ia(e,t)}})})}function oa(e){e.forEach(aa)}function sa(){typeof ResizeObserver>`u`||(ta=new ResizeObserver(oa))}function ca(e,t){ta||sa();let n=Ai(e);return n.forEach(e=>{let n=ea.get(e);n||(n=new Set,ea.set(e,n)),n.add(t),ta?.observe(e)}),()=>{n.forEach(e=>{let n=ea.get(e);n?.delete(t),n?.size||ta?.unobserve(e)})}}var la=new Set,ua;function da(){ua=()=>{let e={get width(){return window.innerWidth},get height(){return window.innerHeight}};la.forEach(t=>t(e))},window.addEventListener(`resize`,ua)}function fa(e){return la.add(e),ua||da(),()=>{la.delete(e),!la.size&&typeof ua==`function`&&(window.removeEventListener(`resize`,ua),ua=void 0)}}function pa(e,t){return typeof e==`function`?fa(e):ca(e,t)}function ma(e){return $i(e)&&e.tagName===`svg`}var ha=[...pi,ct,wt],ga=e=>ha.find(fi(e)),_a=()=>({translate:0,scale:1,origin:0,originPoint:0}),va=()=>({x:_a(),y:_a()}),ya=()=>({min:0,max:0}),ba=()=>({x:ya(),y:ya()}),xa=new WeakMap;function Sa(e){return typeof e==`object`&&!!e&&typeof e.start==`function`}function Ca(e){return typeof e==`string`||Array.isArray(e)}var wa=[`animate`,`whileInView`,`whileFocus`,`whileHover`,`whileTap`,`whileDrag`,`exit`],Ta=[`initial`,...wa];function Ea(e){return Sa(e.animate)||Ta.some(t=>Ca(e[t]))}function Da(e){return!!(Ea(e)||e.variants)}function Oa(e,t,n){for(let r in t){let i=t[r],a=n[r];if(ei(i))e.addValue(r,i);else if(ei(a))e.addValue(r,Mr(i,{owner:e}));else if(a!==i)if(e.hasValue(r)){let t=e.getValue(r);t.liveStyle===!0?t.jump(i):t.hasAnimated||t.set(i)}else{let t=e.getStaticValue(r);e.addValue(r,Mr(t===void 0?i:t,{owner:e}))}}for(let r in n)t[r]===void 0&&e.removeValue(r);return t}var ka={current:null},Aa={current:!1},ja=typeof window<`u`;function Ma(){if(Aa.current=!0,ja)if(window.matchMedia){let e=window.matchMedia(`(prefers-reduced-motion)`),t=()=>ka.current=e.matches;e.addEventListener(`change`,t),t()}else ka.current=!1}var Na=[`AnimationStart`,`AnimationComplete`,`Update`,`BeforeLayoutMeasure`,`LayoutMeasure`,`LayoutAnimationStart`,`LayoutAnimationComplete`],Pa={};function Fa(e){Pa=e}function Ia(){return Pa}var La=class{scrapeMotionValuesFromProps(e,t,n){return{}}constructor({parent:e,props:t,presenceContext:n,reducedMotionConfig:r,skipAnimations:i,blockInitialAnimation:a,visualState:o},s={}){this.current=null,this.children=new Set,this.isVariantNode=!1,this.isControllingVariants=!1,this.shouldReduceMotion=null,this.shouldSkipAnimations=!1,this.values=new Map,this.KeyframeResolver=Xn,this.features={},this.valueSubscriptions=new Map,this.prevMotionValues={},this.hasBeenMounted=!1,this.events={},this.propEventSubscriptions={},this.notifyUpdate=()=>this.notify(`Update`,this.latestValues),this.render=()=>{this.current&&(this.triggerBuild(),this.renderInstance(this.current,this.renderState,this.props.style,this.projection))},this.renderScheduledAt=0,this.scheduleRender=()=>{let e=Ne.now();this.renderScheduledAtthis.bindToMotionValue(t,e)),this.reducedMotionConfig===`never`?this.shouldReduceMotion=!1:this.reducedMotionConfig===`always`?this.shouldReduceMotion=!0:(Aa.current||Ma(),this.shouldReduceMotion=ka.current),this.shouldSkipAnimations=this.skipAnimationsConfig??!1,this.parent?.addChild(this),this.update(this.props,this.presenceContext),this.hasBeenMounted=!0}unmount(){this.projection&&this.projection.unmount(),Oe(this.notifyUpdate),Oe(this.render),this.valueSubscriptions.forEach(e=>e()),this.valueSubscriptions.clear(),this.removeFromVariantTree&&this.removeFromVariantTree(),this.parent?.removeChild(this);for(let e in this.events)this.events[e].clear();for(let e in this.features){let t=this.features[e];t&&(t.unmount(),t.isMounted=!1)}this.current=null}addChild(e){this.children.add(e),this.enteringChildren??=new Set,this.enteringChildren.add(e)}removeChild(e){this.children.delete(e),this.enteringChildren&&this.enteringChildren.delete(e)}bindToMotionValue(e,t){if(this.valueSubscriptions.has(e)&&this.valueSubscriptions.get(e)(),t.accelerate&&yr.has(e)&&this.current instanceof HTMLElement){let{factory:n,keyframes:r,times:i,ease:a,duration:o}=t.accelerate,s=new lr({element:this.current,name:e,keyframes:r,times:i,ease:a,duration:N(o)}),c=n(s);this.valueSubscriptions.set(e,()=>{c(),s.cancel()});return}let n=Ln.has(e);n&&this.onBindTransform&&this.onBindTransform();let r=t.on(`change`,t=>{this.latestValues[e]=t,this.props.onUpdate&&De.preRender(this.notifyUpdate),n&&this.projection&&(this.projection.isTransformDirty=!0),this.scheduleRender()}),i;typeof window<`u`&&window.MotionCheckAppearSync&&(i=window.MotionCheckAppearSync(this,e,t)),this.valueSubscriptions.set(e,()=>{r(),i&&i()})}sortNodePosition(e){return!this.current||!this.sortInstanceNodePosition||this.type!==e.type?0:this.sortInstanceNodePosition(this.current,e.current)}updateFeatures(){let e=`animation`;for(e in Pa){let t=Pa[e];if(!t)continue;let{isEnabled:n,Feature:r}=t;if(!this.features[e]&&r&&n(this.props)&&(this.features[e]=new r(this)),this.features[e]){let t=this.features[e];t.isMounted?t.update():(t.mount(),t.isMounted=!0)}}}triggerBuild(){this.build(this.renderState,this.latestValues,this.props)}measureViewportBox(){return this.current?this.measureInstanceViewportBox(this.current,this.props):ba()}getStaticValue(e){return this.latestValues[e]}setStaticValue(e,t){this.latestValues[e]=t}update(e,t){(e.transformTemplate||this.props.transformTemplate)&&this.scheduleRender(),this.prevProps=this.props,this.props=e,this.prevPresenceContext=this.presenceContext,this.presenceContext=t;for(let t=0;tt.variantChildren.delete(e)}addValue(e,t){let n=this.values.get(e);t!==n&&(n&&this.removeValue(e),this.bindToMotionValue(e,t),this.values.set(e,t),this.latestValues[e]=t.get())}removeValue(e){this.values.delete(e);let t=this.valueSubscriptions.get(e);t&&(t(),this.valueSubscriptions.delete(e)),delete this.latestValues[e],this.removeValueFromRenderState(e,this.renderState)}hasValue(e){return this.values.has(e)}getValue(e,t){if(this.props.values&&this.props.values[e])return this.props.values[e];let n=this.values.get(e);return n===void 0&&t!==void 0&&(n=Mr(t===null?void 0:t,{owner:this}),this.addValue(e,n)),n}readValue(e,t){let n=this.latestValues[e]!==void 0||!this.current?this.latestValues[e]:this.getBaseTargetFromProps(this.props,e)??this.readValueFromInstance(this.current,e,this.options);return n!=null&&(typeof n==`string`&&(T(n)||D(n))?n=parseFloat(n):!ga(n)&&wt.test(t)&&(n=Ei(e,t)),this.setBaseTarget(e,ei(n)?n.get():n)),ei(n)?n.get():n}setBaseTarget(e,t){this.baseTarget[e]=t}getBaseTarget(e){let{initial:t}=this.props,n;if(typeof t==`string`||typeof t==`object`){let r=qr(this.props,t,this.presenceContext?.custom);r&&(n=r[e])}if(t&&n!==void 0)return n;let r=this.getBaseTargetFromProps(this.props,e);return r!==void 0&&!ei(r)?r:this.initialValues[e]!==void 0&&n===void 0?void 0:this.baseTarget[e]}on(e,t){return this.events[e]||(this.events[e]=new M),this.events[e].add(t)}notify(e,...t){this.events[e]&&this.events[e].notify(...t)}scheduleRenderMicrotask(){Ni.render(this.render)}},Ra=class extends La{constructor(){super(...arguments),this.KeyframeResolver=ki}sortInstanceNodePosition(e,t){return e.compareDocumentPosition(t)&2?1:-1}getBaseTargetFromProps(e,t){let n=e.style;return n?n[t]:void 0}removeValueFromRenderState(e,{vars:t,style:n}){delete t[e],delete n[e]}handleChildMotionValue(){this.childSubscription&&(this.childSubscription(),delete this.childSubscription);let{children:e}=this.props;ei(e)&&(this.childSubscription=e.on(`change`,e=>{this.current&&(this.current.textContent=`${e}`)}))}},za=class{constructor(e){this.isMounted=!1,this.node=e}update(){}};function Ba({top:e,left:t,right:n,bottom:r}){return{x:{min:t,max:n},y:{min:e,max:r}}}function Va({x:e,y:t}){return{top:t.min,right:e.max,bottom:t.max,left:e.min}}function Ha(e,t){if(!t)return e;let n=t({x:e.left,y:e.top}),r=t({x:e.right,y:e.bottom});return{top:n.y,left:n.x,bottom:r.y,right:r.x}}function Ua(e){return e===void 0||e===1}function Wa({scale:e,scaleX:t,scaleY:n}){return!Ua(e)||!Ua(t)||!Ua(n)}function Ga(e){return Wa(e)||Ka(e)||e.z||e.rotate||e.rotateX||e.rotateY||e.skewX||e.skewY}function Ka(e){return qa(e.x)||qa(e.y)}function qa(e){return e&&e!==`0%`}function Ja(e,t,n){return n+t*(e-n)}function Ya(e,t,n,r,i){return i!==void 0&&(e=Ja(e,i,r)),Ja(e,n,r)+t}function Xa(e,t=0,n=1,r,i){e.min=Ya(e.min,t,n,r,i),e.max=Ya(e.max,t,n,r,i)}function Za(e,{x:t,y:n}){Xa(e.x,t.translate,t.scale,t.originPoint),Xa(e.y,n.translate,n.scale,n.originPoint)}var Qa=.999999999999,$a=1.0000000000001;function eo(e,t,n,r=!1){let i=n.length;if(!i)return;t.x=t.y=1;let a,o;for(let s=0;sQa&&(t.x=1),t.y<$a&&t.y>Qa&&(t.y=1)}function to(e,t){e.min+=t,e.max+=t}function no(e,t,n,r,i=.5){Xa(e,t,n,Ot(e.min,e.max,i),r)}function ro(e,t){return typeof e==`string`?parseFloat(e)/100*(t.max-t.min):e}function io(e,t,n){let r=n??e;no(e.x,ro(t.x,r.x),t.scaleX,t.scale,t.originX),no(e.y,ro(t.y,r.y),t.scaleY,t.scale,t.originY)}function ao(e,t){return Ba(Ha(e.getBoundingClientRect(),t))}function oo(e,t,n){let r=ao(e,n),{scroll:i}=t;return i&&(to(r.x,i.offset.x),to(r.y,i.offset.y)),r}var so={x:`translateX`,y:`translateY`,z:`translateZ`,transformPerspective:`perspective`},co=In.length;function lo(e,t,n){let r=``,i=!0;for(let a=0;a{if(!t.target)return e;if(typeof e==`string`)if(I.test(e))e=parseFloat(e);else return e;return`${po(e,t.target.x)}% ${po(e,t.target.y)}%`}},mo={correct:(e,{treeScale:t,projectionDelta:n})=>{let r=e,i=wt.parse(e);if(i.length>5)return r;let a=wt.createTransformer(e),o=typeof i[0]==`number`?0:1,s=n.x.scale*t.x,c=n.y.scale*t.y;i[0+o]/=s,i[1+o]/=c;let l=Ot(s,c,.5);return typeof i[2+o]==`number`&&(i[2+o]/=l),typeof i[3+o]==`number`&&(i[3+o]/=l),a(i)}},ho={borderRadius:{...R,applyTo:[`borderTopLeftRadius`,`borderTopRightRadius`,`borderBottomLeftRadius`,`borderBottomRightRadius`]},borderTopLeftRadius:R,borderTopRightRadius:R,borderBottomLeftRadius:R,borderBottomRightRadius:R,boxShadow:mo};function go(e,{layout:t,layoutId:n}){return Ln.has(e)||e.startsWith(`origin`)||(t||n!==void 0)&&(!!ho[e]||e===`opacity`)}function _o(e,t,n){let r=e.style,i=t?.style,a={};if(!r)return a;for(let t in r)(ei(r[t])||i&&ei(i[t])||go(t,e)||n?.getValue(t)?.liveStyle!==void 0)&&(a[t]=r[t]);return a}function vo(e){return window.getComputedStyle(e)}var yo=class extends Ra{constructor(){super(...arguments),this.type=`html`,this.renderInstance=fo}readValueFromInstance(e,t){if(Ln.has(t))return this.projection?.isProjecting?Mn(t):Pn(e,t);{let n=vo(e),r=(Ie(t)?n.getPropertyValue(t):n[t])||0;return typeof r==`string`?r.trim():r}}measureInstanceViewportBox(e,{transformPagePoint:t}){return ao(e,t)}build(e,t,n){uo(e,t,n.transformTemplate)}scrapeMotionValuesFromProps(e,t,n){return _o(e,t,n)}},bo={offset:`stroke-dashoffset`,array:`stroke-dasharray`},xo={offset:`strokeDashoffset`,array:`strokeDasharray`};function So(e,t,n=1,r=0,i=!0){e.pathLength=1;let a=i?bo:xo;e[a.offset]=`${-r}`,e[a.array]=`${t} ${n}`}var Co=[`offsetDistance`,`offsetPath`,`offsetRotate`,`offsetAnchor`];function wo(e,{attrX:t,attrY:n,attrScale:r,pathLength:i,pathSpacing:a=1,pathOffset:o=0,...s},c,l,u){if(uo(e,s,l),c){e.style.viewBox&&(e.attrs.viewBox=e.style.viewBox);return}e.attrs=e.style,e.style={};let{attrs:d,style:f}=e;d.transform&&(f.transform=d.transform,delete d.transform),(f.transform||d.transformOrigin)&&(f.transformOrigin=d.transformOrigin??`50% 50%`,delete d.transformOrigin),f.transform&&(f.transformBox=u?.transformBox??`fill-box`,delete d.transformBox);for(let e of Co)d[e]!==void 0&&(f[e]=d[e],delete d[e]);t!==void 0&&(d.x=t),n!==void 0&&(d.y=n),r!==void 0&&(d.scale=r),i!==void 0&&So(d,i,a,o,!1)}var To=new Set([`baseFrequency`,`diffuseConstant`,`kernelMatrix`,`kernelUnitLength`,`keySplines`,`keyTimes`,`limitingConeAngle`,`markerHeight`,`markerWidth`,`numOctaves`,`targetX`,`targetY`,`surfaceScale`,`specularConstant`,`specularExponent`,`stdDeviation`,`tableValues`,`viewBox`,`gradientTransform`,`pathLength`,`startOffset`,`textLength`,`lengthAdjust`]),Eo=e=>typeof e==`string`&&e.toLowerCase()===`svg`;function Do(e,t,n,r){fo(e,t,void 0,r);for(let n in t.attrs)e.setAttribute(To.has(n)?n:ri(n),t.attrs[n])}function Oo(e,t,n){let r=_o(e,t,n);for(let n in e)if(ei(e[n])||ei(t[n])){let t=In.indexOf(n)===-1?n:`attr`+n.charAt(0).toUpperCase()+n.substring(1);r[t]=e[n]}return r}var ko=class extends Ra{constructor(){super(...arguments),this.type=`svg`,this.isSVGTag=!1,this.measureInstanceViewportBox=ba}getBaseTargetFromProps(e,t){return e[t]}readValueFromInstance(e,t){if(Ln.has(t)){let e=wi(t);return e&&e.default||0}return t=To.has(t)?t:ri(t),e.getAttribute(t)}scrapeMotionValuesFromProps(e,t,n){return Oo(e,t,n)}build(e,t,n){wo(e,t,this.isSVGTag,n.transformTemplate,n.style)}renderInstance(e,t,n,r){Do(e,t,n,r)}mount(e){this.isSVGTag=Eo(e.tagName),super.mount(e)}},Ao=Ta.length;function jo(e){if(!e)return;if(!e.isControllingVariants){let t=e.parent&&jo(e.parent)||{};return e.props.initial!==void 0&&(t.initial=e.props.initial),t}let t={};for(let n=0;nPromise.all(t.map(({animation:t,options:n})=>ui(e,t,n)))}function Io(e){let t=Fo(e),n=zo(),r=!0,i=!1,a=t=>(n,r)=>{let i=Jr(e,r,t===`exit`?e.presenceContext?.custom:void 0);if(i){let{transition:e,transitionEnd:t,...r}=i;n={...n,...r,...t}}return n};function o(n){t=n(e)}function s(o){let{props:s}=e,c=jo(e.parent)||{},l=[],u=new Set,d={},f=1/0;for(let t=0;tf&&g,x=!1,S=Array.isArray(h)?h:[h],C=S.reduce(a(p),{});_===!1&&(C={});let{prevResolvedValues:w={}}=m,T={...w,...C},E=t=>{b=!0,u.has(t)&&(x=!0,u.delete(t)),m.needsAnimating[t]=!0;let n=e.getValue(t);n&&(n.liveStyle=!1)};for(let e in T){let t=C[e],n=w[e];if(d.hasOwnProperty(e))continue;let r=!1;r=Xr(t)&&Xr(n)?!Mo(t,n)||y:t!==n,r?t==null?u.add(e):E(e):t!==void 0&&u.has(e)?E(e):m.protectedKeys[e]=!0}m.prevProp=h,m.prevResolvedValues=C,m.isActive&&(d={...d,...C}),(r||i)&&e.blockInitialAnimation&&(b=!1);let D=v&&y;b&&(!D||x)&&l.push(...S.map(t=>{let n={type:p};if(typeof t==`string`&&(r||i)&&!D&&e.manuallyAnimateOnMount&&e.parent){let{parent:r}=e,i=Jr(r,t);if(r.enteringChildren&&i){let{delayChildren:t}=i.transition||{};n.delay=Dr(r.enteringChildren,e,t)}}return{animation:t,options:n}}))}if(u.size){let t={};if(typeof s.initial!=`boolean`){let n=Jr(e,Array.isArray(s.initial)?s.initial[0]:s.initial);n&&n.transition&&(t.transition=n.transition)}u.forEach(n=>{let r=e.getBaseTarget(n),i=e.getValue(n);i&&(i.liveStyle=!0),t[n]=r??null}),l.push({animation:t})}let p=!!l.length;return r&&(s.initial===!1||s.initial===s.animate)&&!e.manuallyAnimateOnMount&&(p=!1),r=!1,i=!1,p?t(l):Promise.resolve()}function c(t,r){if(n[t].isActive===r)return Promise.resolve();e.variantChildren?.forEach(e=>e.animationState?.setActive(t,r)),n[t].isActive=r;let i=s(t);for(let e in n)n[e].protectedKeys={};return i}return{animateChanges:s,setActive:c,setAnimateFunction:o,getState:()=>n,reset:()=>{n=zo(),i=!0}}}function Lo(e,t){return typeof t==`string`?t!==e:Array.isArray(t)?!Mo(t,e):!1}function Ro(e=!1){return{isActive:e,protectedKeys:{},needsAnimating:{},prevResolvedValues:{}}}function zo(){return{animate:Ro(!0),whileInView:Ro(),whileHover:Ro(),whileTap:Ro(),whileDrag:Ro(),whileFocus:Ro(),exit:Ro()}}function Bo(e,t){e.min=t.min,e.max=t.max}function Vo(e,t){Bo(e.x,t.x),Bo(e.y,t.y)}function Ho(e,t){e.translate=t.translate,e.scale=t.scale,e.originPoint=t.originPoint,e.origin=t.origin}var Uo=.9999,Wo=1.0001,Go=-.01,Ko=.01;function qo(e){return e.max-e.min}function Jo(e,t,n){return Math.abs(e-t)<=n}function Yo(e,t,n,r=.5){e.origin=r,e.originPoint=Ot(t.min,t.max,e.origin),e.scale=qo(n)/qo(t),e.translate=Ot(n.min,n.max,e.origin)-e.originPoint,(e.scale>=Uo&&e.scale<=Wo||isNaN(e.scale))&&(e.scale=1),(e.translate>=Go&&e.translate<=Ko||isNaN(e.translate))&&(e.translate=0)}function Xo(e,t,n,r){Yo(e.x,t.x,n.x,r?r.originX:void 0),Yo(e.y,t.y,n.y,r?r.originY:void 0)}function Zo(e,t,n,r=0){e.min=(r?Ot(n.min,n.max,r):n.min)+t.min,e.max=e.min+qo(t)}function Qo(e,t,n,r){Zo(e.x,t.x,n.x,r?.x),Zo(e.y,t.y,n.y,r?.y)}function $o(e,t,n,r=0){let i=r?Ot(n.min,n.max,r):n.min;e.min=t.min-i,e.max=e.min+qo(t)}function es(e,t,n,r){$o(e.x,t.x,n.x,r?.x),$o(e.y,t.y,n.y,r?.y)}function ts(e,t,n,r,i){return e-=t,e=Ja(e,1/n,r),i!==void 0&&(e=Ja(e,1/i,r)),e}function ns(e,t=0,n=1,r=.5,i,a=e,o=e){if(rt.test(t)&&(t=parseFloat(t),t=Ot(o.min,o.max,t/100)-o.min),typeof t!=`number`)return;let s=Ot(a.min,a.max,r);e===a&&(s-=t),e.min=ts(e.min,t,n,s,i),e.max=ts(e.max,t,n,s,i)}function rs(e,t,[n,r,i],a,o){ns(e,t[n],t[r],t[i],t.scale,a,o)}var is=[`x`,`scaleX`,`originX`],as=[`y`,`scaleY`,`originY`];function os(e,t,n,r){rs(e.x,t,is,n?n.x:void 0,r?r.x:void 0),rs(e.y,t,as,n?n.y:void 0,r?r.y:void 0)}function ss(e){return e.translate===0&&e.scale===1}function cs(e){return ss(e.x)&&ss(e.y)}function ls(e,t){return e.min===t.min&&e.max===t.max}function us(e,t){return ls(e.x,t.x)&&ls(e.y,t.y)}function ds(e,t){return Math.round(e.min)===Math.round(t.min)&&Math.round(e.max)===Math.round(t.max)}function fs(e,t){return ds(e.x,t.x)&&ds(e.y,t.y)}function ps(e){return qo(e.x)/qo(e.y)}function ms(e,t){return e.translate===t.translate&&e.scale===t.scale&&e.originPoint===t.originPoint}function hs(e){return[e(`x`),e(`y`)]}function gs(e,t,n){let r=``,i=e.x.translate/t.x,a=e.y.translate/t.y,o=n?.z||0;if((i||a||o)&&(r=`translate3d(${i}px, ${a}px, ${o}px) `),(t.x!==1||t.y!==1)&&(r+=`scale(${1/t.x}, ${1/t.y}) `),n){let{transformPerspective:e,rotate:t,pathRotation:i,rotateX:a,rotateY:o,skewX:s,skewY:c}=n;e&&(r=`perspective(${e}px) ${r}`),t&&(r+=`rotate(${t}deg) `),i&&(r+=`rotate(${i}deg) `),a&&(r+=`rotateX(${a}deg) `),o&&(r+=`rotateY(${o}deg) `),s&&(r+=`skewX(${s}deg) `),c&&(r+=`skewY(${c}deg) `)}let s=e.x.scale*t.x,c=e.y.scale*t.y;return(s!==1||c!==1)&&(r+=`scale(${s}, ${c})`),r||`none`}var _s=[`borderTopLeftRadius`,`borderTopRightRadius`,`borderBottomLeftRadius`,`borderBottomRightRadius`],vs=_s.length,ys=e=>typeof e==`string`?parseFloat(e):e,bs=e=>typeof e==`number`||I.test(e);function xs(e,t,n,r,i,a){i?(e.opacity=Ot(0,n.opacity??1,Cs(r)),e.opacityExit=Ot(t.opacity??1,0,ws(r))):a&&(e.opacity=Ot(t.opacity??1,n.opacity??1,r));for(let i=0;irt?1:n(j(e,t,r))}function Es(e,t,n){let r=ei(e)?e:Mr(e);return r.start(Hr(``,r,t,n)),r.animation}function Ds(e,t,n,r={passive:!0}){return e.addEventListener(t,n,r),()=>e.removeEventListener(t,n)}var Os=(e,t)=>e.depth-t.depth,ks=class{constructor(){this.children=[],this.isDirty=!1}add(e){x(this.children,e),this.isDirty=!0}remove(e){S(this.children,e),this.isDirty=!0}forEach(e){this.isDirty&&this.children.sort(Os),this.isDirty=!1,this.children.forEach(e)}};function As(e,t){let n=Ne.now(),r=({timestamp:i})=>{let a=i-n;a>=t&&(Oe(r),e(a-t))};return De.setup(r,!0),()=>Oe(r)}function js(e){return ei(e)?e.get():e}var Ms=class{constructor(){this.members=[]}add(e){x(this.members,e);for(let t=this.members.length-1;t>=0;t--){let n=this.members[t];if(n===e||n===this.lead||n===this.prevLead)continue;let r=n.instance;(!r||r.isConnected===!1)&&!n.snapshot&&(S(this.members,n),n.unmount())}e.scheduleRender()}remove(e){if(S(this.members,e),e===this.prevLead&&(this.prevLead=void 0),e===this.lead){let e=this.members[this.members.length-1];e&&this.promote(e)}}relegate(e){for(let t=this.members.indexOf(e)-1;t>=0;t--){let e=this.members[t];if(e.isPresent!==!1&&e.instance?.isConnected!==!1)return this.promote(e),!0}return!1}promote(e,t){let n=this.lead;if(e!==n&&(this.prevLead=n,this.lead=e,e.show(),n)){n.updateSnapshot(),e.scheduleRender();let{layoutDependency:r}=n.options,{layoutDependency:i}=e.options;(r===void 0||r!==i)&&(e.resumeFrom=n,t&&(n.preserveOpacity=!0),n.snapshot&&(e.snapshot=n.snapshot,e.snapshot.latestValues=n.animationValues||n.latestValues),e.root?.isUpdating&&(e.isLayoutDirty=!0)),e.options.crossfade===!1&&n.hide()}}exitAnimationComplete(){this.members.forEach(e=>{e.options.onExitComplete?.(),e.resumingFrom?.options.onExitComplete?.()})}scheduleRender(){this.members.forEach(e=>e.instance&&e.scheduleRender(!1))}removeLeadSnapshot(){this.lead?.snapshot&&(this.lead.snapshot=void 0)}},Ns={hasAnimatedSinceResize:!0,hasEverUpdated:!1},Ps={nodes:0,calculatedTargetDeltas:0,calculatedProjections:0},Fs=[``,`X`,`Y`,`Z`],Is=1e3,Ls=0;function Rs(e,t,n,r){let{latestValues:i}=t;i[e]&&(n[e]=i[e],t.setStaticValue(e,0),r&&(r[e]=0))}function zs(e){if(e.hasCheckedOptimisedAppear=!0,e.root===e)return;let{visualElement:t}=e.options;if(!t)return;let n=ai(t);if(window.MotionHasOptimisedAnimation(n,`transform`)){let{layout:t,layoutId:r}=e.options;window.MotionCancelOptimisedAnimation(n,`transform`,De,!(t||r))}let{parent:r}=e;r&&!r.hasCheckedOptimisedAppear&&zs(r)}function Bs({attachResizeListener:e,defaultParent:t,measureScroll:n,checkIsScrollRoot:r,resetTransform:i}){return class{constructor(e={},n=t?.()){this.id=Ls++,this.animationId=0,this.animationCommitId=0,this.children=new Set,this.options={},this.isTreeAnimating=!1,this.isAnimationBlocked=!1,this.isLayoutDirty=!1,this.isProjectionDirty=!1,this.isSharedProjectionDirty=!1,this.isTransformDirty=!1,this.updateManuallyBlocked=!1,this.updateBlockedByResize=!1,this.isUpdating=!1,this.isSVG=!1,this.needsReset=!1,this.shouldResetTransform=!1,this.hasCheckedOptimisedAppear=!1,this.treeScale={x:1,y:1},this.eventHandlers=new Map,this.hasTreeAnimated=!1,this.layoutVersion=0,this.updateScheduled=!1,this.scheduleUpdate=()=>this.update(),this.projectionUpdateScheduled=!1,this.checkUpdateFailed=()=>{this.isUpdating&&(this.isUpdating=!1,this.clearAllSnapshots())},this.updateProjection=()=>{this.projectionUpdateScheduled=!1,Ce.value&&(Ps.nodes=Ps.calculatedTargetDeltas=Ps.calculatedProjections=0),this.nodes.forEach(Us),this.nodes.forEach(Qs),this.nodes.forEach($s),this.nodes.forEach(Ws),Ce.addProjectionMetrics&&Ce.addProjectionMetrics(Ps)},this.resolvedRelativeTargetAt=0,this.linkedParentVersion=0,this.hasProjected=!1,this.isVisible=!0,this.animationProgress=0,this.sharedNodes=new Map,this.latestValues=e,this.root=n?n.root||n:this,this.path=n?[...n.path,n]:[],this.parent=n,this.depth=n?n.depth+1:0;for(let e=0;ethis.root.updateBlockedByResize=!1;De.read(()=>{r=window.innerWidth}),e(t,()=>{let e=window.innerWidth;e!==r&&(r=e,this.root.updateBlockedByResize=!0,n&&n(),n=As(i,250),Ns.hasAnimatedSinceResize&&(Ns.hasAnimatedSinceResize=!1,this.nodes.forEach(Zs)))})}n&&this.root.registerSharedNode(n,this),this.options.animate!==!1&&i&&(n||r)&&this.addEventListener(`didUpdate`,({delta:e,hasLayoutChanged:t,hasRelativeLayoutChanged:n,layout:r})=>{if(this.isTreeAnimationBlocked()){this.target=void 0,this.relativeTarget=void 0;return}let a=this.options.transition||i.getDefaultTransition()||oc,{onLayoutAnimationStart:o,onLayoutAnimationComplete:s}=i.getProps(),c=!this.targetLayout||!fs(this.targetLayout,r),l=!t&&n;if(this.options.layoutRoot||this.resumeFrom||l||t&&(c||!this.currentAnimation)){this.resumeFrom&&(this.resumingFrom=this.resumeFrom,this.resumingFrom.resumingFrom=void 0);let t={...Pr(a,`layout`),onPlay:o,onComplete:s};(i.shouldReduceMotion||this.options.layoutRoot)&&(t.delay=0,t.type=!1),this.startAnimation(t),this.setAnimationOrigin(e,l,t.path)}else t||Zs(this),this.isLead()&&this.options.onExitComplete&&this.options.onExitComplete();this.targetLayout=r})}unmount(){this.options.layoutId&&this.willUpdate(),this.root.nodes.remove(this);let e=this.getStack();e&&e.remove(this),this.parent&&this.parent.children.delete(this),this.instance=void 0,this.eventHandlers.clear(),Oe(this.updateProjection)}blockUpdate(){this.updateManuallyBlocked=!0}unblockUpdate(){this.updateManuallyBlocked=!1}isUpdateBlocked(){return this.updateManuallyBlocked||this.updateBlockedByResize}isTreeAnimationBlocked(){return this.isAnimationBlocked||this.parent&&this.parent.isTreeAnimationBlocked()||!1}startUpdate(){this.isUpdateBlocked()||(this.isUpdating=!0,this.nodes&&this.nodes.forEach(ec),this.animationId++)}getTransformTemplate(){let{visualElement:e}=this.options;return e&&e.getProps().transformTemplate}willUpdate(e=!0){if(this.root.hasTreeAnimated=!0,this.root.isUpdateBlocked()){this.options.onExitComplete&&this.options.onExitComplete();return}if(window.MotionCancelOptimisedAnimation&&!this.hasCheckedOptimisedAppear&&zs(this),!this.root.isUpdating&&this.root.startUpdate(),this.isLayoutDirty)return;this.isLayoutDirty=!0;for(let e=0;e{this.isLayoutDirty?this.root.didUpdate():this.root.checkUpdateFailed()})}updateSnapshot(){this.snapshot||!this.instance||(this.snapshot=this.measure(),this.snapshot&&!qo(this.snapshot.measuredBox.x)&&!qo(this.snapshot.measuredBox.y)&&(this.snapshot=void 0))}updateLayout(){if(!this.instance||(this.updateScroll(),!(this.options.alwaysMeasureLayout&&this.isLead())&&!this.isLayoutDirty))return;if(this.resumeFrom&&!this.resumeFrom.instance)for(let e=0;e{let n=t/1e3,r=p?.(n);r?(o.x.translate=r.x,o.x.scale=Ot(e.x.scale,1,n),o.x.origin=e.x.origin,o.x.originPoint=e.x.originPoint,o.y.translate=r.y,o.y.scale=Ot(e.y.scale,1,n),o.y.origin=e.y.origin,o.y.originPoint=e.y.originPoint):(nc(o.x,e.x,n),nc(o.y,e.y,n)),this.setTargetDelta(o),this.relativeTarget&&this.relativeTargetOrigin&&this.layout&&this.relativeParent&&this.relativeParent.layout&&(es(s,this.layout.layoutBox,this.relativeParent.layout.layoutBox,this.options.layoutAnchor||void 0),ic(this.relativeTarget,this.relativeTargetOrigin,s,n),f&&us(this.relativeTarget,f)&&(this.isProjectionDirty=!1),f||=ba(),Vo(f,this.relativeTarget)),c&&(this.animationValues=a,xs(a,i,this.latestValues,n,d,u)),r&&r.rotate!==void 0&&(this.animationValues||=a,this.animationValues.pathRotation=r.rotate),this.root.scheduleUpdateProjection(),this.scheduleRender(),this.animationProgress=n},this.mixTargetDelta(this.options.layoutRoot?1e3:0)}startAnimation(e){this.notifyListeners(`animationStart`),this.currentAnimation?.stop(),this.resumingFrom?.currentAnimation?.stop(),this.pendingAnimation&&=(Oe(this.pendingAnimation),void 0),this.pendingAnimation=De.update(()=>{Ns.hasAnimatedSinceResize=!0,Pe.layout++,this.motionValue||=Mr(0),this.motionValue.jump(0,!1),this.currentAnimation=Es(this.motionValue,[0,1e3],{...e,velocity:0,isSync:!0,onUpdate:t=>{this.mixTargetDelta(t),e.onUpdate&&e.onUpdate(t)},onStop:()=>{Pe.layout--},onComplete:()=>{Pe.layout--,e.onComplete&&e.onComplete(),this.completeAnimation()}}),this.resumingFrom&&(this.resumingFrom.currentAnimation=this.currentAnimation),this.pendingAnimation=void 0})}completeAnimation(){this.resumingFrom&&(this.resumingFrom.currentAnimation=void 0,this.resumingFrom.preserveOpacity=void 0);let e=this.getStack();e&&e.exitAnimationComplete(),this.resumingFrom=this.currentAnimation=this.animationValues=void 0,this.notifyListeners(`animationComplete`)}finishAnimation(){this.currentAnimation&&(this.mixTargetDelta&&this.mixTargetDelta(Is),this.currentAnimation.stop()),this.completeAnimation()}applyTransformsToTarget(){let e=this.getLead(),{targetWithTransforms:t,target:n,layout:r,latestValues:i}=e;if(!(!t||!n||!r)){if(this!==e&&this.layout&&r&&dc(this.options.animationType,this.layout.layoutBox,r.layoutBox)){n=this.target||ba();let t=qo(this.layout.layoutBox.x);n.x.min=e.target.x.min,n.x.max=n.x.min+t;let r=qo(this.layout.layoutBox.y);n.y.min=e.target.y.min,n.y.max=n.y.min+r}Vo(t,n),io(t,i),Xo(this.projectionDeltaWithTransform,this.layoutCorrected,t,i)}}registerSharedNode(e,t){this.sharedNodes.has(e)||this.sharedNodes.set(e,new Ms),this.sharedNodes.get(e).add(t);let n=t.options.initialPromotionConfig;t.promote({transition:n?n.transition:void 0,preserveFollowOpacity:n&&n.shouldPreserveFollowOpacity?n.shouldPreserveFollowOpacity(t):void 0})}isLead(){let e=this.getStack();return e?e.lead===this:!0}getLead(){let{layoutId:e}=this.options;return e&&this.getStack()?.lead||this}getPrevLead(){let{layoutId:e}=this.options;return e?this.getStack()?.prevLead:void 0}getStack(){let{layoutId:e}=this.options;if(e)return this.root.sharedNodes.get(e)}promote({needsReset:e,transition:t,preserveFollowOpacity:n}={}){let r=this.getStack();r&&r.promote(this,n),e&&(this.projectionDelta=void 0,this.needsReset=!0),t&&this.setOptions({transition:t})}relegate(){let e=this.getStack();return e?e.relegate(this):!1}resetSkewAndRotation(){let{visualElement:e}=this.options;if(!e)return;let t=!1,{latestValues:n}=e;if((n.z||n.rotate||n.rotateX||n.rotateY||n.rotateZ||n.skewX||n.skewY)&&(t=!0),!t)return;let r={};n.z&&Rs(`z`,e,r,this.animationValues);for(let t=0;te.currentAnimation?.stop()),this.root.nodes.forEach(Ks),this.root.sharedNodes.clear()}}}function Vs(e){e.updateLayout()}function Hs(e){let t=e.resumeFrom?.snapshot||e.snapshot;if(e.isLead()&&e.layout&&t&&e.hasListeners(`didUpdate`)){let{layoutBox:n,measuredBox:r}=e.layout,{animationType:i}=e.options,a=t.source!==e.layout.source;if(i===`size`)hs(e=>{let r=a?t.measuredBox[e]:t.layoutBox[e],i=qo(r);r.min=n[e].min,r.max=r.min+i});else if(i===`x`||i===`y`){let e=i===`x`?`y`:`x`;Bo(a?t.measuredBox[e]:t.layoutBox[e],n[e])}else dc(i,t.layoutBox,n)&&hs(r=>{let i=a?t.measuredBox[r]:t.layoutBox[r],o=qo(n[r]);i.max=i.min+o,e.relativeTarget&&!e.currentAnimation&&(e.isProjectionDirty=!0,e.relativeTarget[r].max=e.relativeTarget[r].min+o)});let o=va();Xo(o,n,t.layoutBox);let s=va();a?Xo(s,e.applyTransform(r,!0),t.measuredBox):Xo(s,n,t.layoutBox);let c=!cs(o),l=!1;if(!e.resumeFrom){let r=e.getClosestProjectingParent();if(r&&!r.resumeFrom){let{snapshot:i,layout:a}=r;if(i&&a){let o=e.options.layoutAnchor||void 0,s=ba();es(s,t.layoutBox,i.layoutBox,o);let c=ba();es(c,n,a.layoutBox,o),fs(s,c)||(l=!0),r.options.layoutRoot&&(e.relativeTarget=c,e.relativeTargetOrigin=s,e.relativeParent=r)}}}e.notifyListeners(`didUpdate`,{layout:n,snapshot:t,delta:s,layoutDelta:o,hasLayoutChanged:c,hasRelativeLayoutChanged:l})}else if(e.isLead()){let{onExitComplete:t}=e.options;t&&t()}e.options.transition=void 0}function Us(e){Ce.value&&Ps.nodes++,e.parent&&(e.isProjecting()||(e.isProjectionDirty=e.parent.isProjectionDirty),e.isSharedProjectionDirty||=!!(e.isProjectionDirty||e.parent.isProjectionDirty||e.parent.isSharedProjectionDirty),e.isTransformDirty||=e.parent.isTransformDirty)}function Ws(e){e.isProjectionDirty=e.isSharedProjectionDirty=e.isTransformDirty=!1}function Gs(e){e.clearSnapshot()}function Ks(e){e.clearMeasurements()}function qs(e){e.isLayoutDirty=!0,e.updateLayout()}function Js(e){e.isLayoutDirty=!1}function Ys(e){e.isAnimationBlocked&&e.layout&&!e.isLayoutDirty&&(e.snapshot=e.layout,e.isLayoutDirty=!0)}function Xs(e){let{visualElement:t}=e.options;t&&t.getProps().onBeforeLayoutMeasure&&t.notify(`BeforeLayoutMeasure`),e.resetTransform()}function Zs(e){e.finishAnimation(),e.targetDelta=e.relativeTarget=e.target=void 0,e.isProjectionDirty=!0}function Qs(e){e.resolveTargetDelta()}function $s(e){e.calcProjection()}function ec(e){e.resetSkewAndRotation()}function tc(e){e.removeLeadSnapshot()}function nc(e,t,n){e.translate=Ot(t.translate,0,n),e.scale=Ot(t.scale,1,n),e.origin=t.origin,e.originPoint=t.originPoint}function rc(e,t,n,r){e.min=Ot(t.min,n.min,r),e.max=Ot(t.max,n.max,r)}function ic(e,t,n,r){rc(e.x,t.x,n.x,r),rc(e.y,t.y,n.y,r)}function ac(e){return e.animationValues&&e.animationValues.opacityExit!==void 0}var oc={duration:.45,ease:[.4,0,.1,1]},sc=e=>typeof navigator<`u`&&navigator.userAgent&&navigator.userAgent.toLowerCase().includes(e),cc=sc(`applewebkit/`)&&!sc(`chrome/`)?Math.round:k;function lc(e){e.min=cc(e.min),e.max=cc(e.max)}function uc(e){lc(e.x),lc(e.y)}function dc(e,t,n){return e===`position`||e===`preserve-aspect`&&!Jo(ps(t),ps(n),.2)}function fc(e){return e!==e.root&&e.scroll?.wasRoot}var pc=Bs({attachResizeListener:(e,t)=>Ds(e,`resize`,t),measureScroll:()=>({x:document.documentElement.scrollLeft||document.body?.scrollLeft||0,y:document.documentElement.scrollTop||document.body?.scrollTop||0}),checkIsScrollRoot:()=>!0}),mc={current:void 0},hc=Bs({measureScroll:e=>({x:e.scrollLeft,y:e.scrollTop}),defaultParent:()=>{if(!mc.current){let e=new pc({});e.mount(window),e.setOptions({layoutScroll:!0}),mc.current=e}return mc.current},resetTransform:(e,t)=>{e.style.transform=t===void 0?`none`:t},checkIsScrollRoot:e=>window.getComputedStyle(e).position===`fixed`}),gc=(0,g.createContext)({transformPagePoint:e=>e,isStatic:!1,reducedMotion:`never`});function _c(e,t){if(typeof e==`function`)return e(t);e!=null&&(e.current=t)}function vc(...e){return t=>{let n=!1,r=e.map(e=>{let r=_c(e,t);return!n&&typeof r==`function`&&(n=!0),r});if(n)return()=>{for(let t=0;t{let{width:e,height:u,top:d,left:f,right:p,bottom:m,direction:h}=c.current;if(t||a===!1||!s.current||!e||!u)return;let g=h===`rtl`,_=n===`left`?g?`right: ${p}`:`left: ${f}`:g?`left: ${f}`:`right: ${p}`,v=r===`bottom`?`bottom: ${m}`:`top: ${d}`;s.current.dataset.motionPopId=o;let y=document.createElement(`style`);l&&(y.nonce=l);let b=i??document.head;return b.appendChild(y),y.sheet&&y.sheet.insertRule(` - [data-motion-pop-id="${o}"] { - position: absolute !important; - width: ${e}px !important; - height: ${u}px !important; - ${_}px !important; - ${v}px !important; - } - `),()=>{s.current?.removeAttribute(`data-motion-pop-id`),b.contains(y)&&b.removeChild(y)}},[t]),(0,z.jsx)(bc,{isPresent:t,childRef:s,sizeRef:c,pop:a,children:a===!1?e:g.cloneElement(e,{ref:u})})}var Sc=({children:e,initial:t,isPresent:n,onExitComplete:r,custom:i,presenceAffectsLayout:a,mode:o,anchorX:s,anchorY:c,root:l})=>{let u=v(Cc),d=(0,g.useId)(),f=!0,p=(0,g.useMemo)(()=>(f=!1,{id:d,initial:t,isPresent:n,custom:i,onExitComplete:e=>{u.set(e,!0);for(let e of u.values())if(!e)return;r&&r()},register:e=>(u.set(e,!1),()=>u.delete(e))}),[n,u,r]);return a&&f&&(p={...p}),(0,g.useMemo)(()=>{u.forEach((e,t)=>u.set(t,!1))},[n]),g.useEffect(()=>{!n&&!u.size&&r&&r()},[n]),e=(0,z.jsx)(xc,{pop:o===`popLayout`,isPresent:n,anchorX:s,anchorY:c,root:l,children:e}),(0,z.jsx)(b.Provider,{value:p,children:e})};function Cc(){return new Map}function wc(e=!0){let t=(0,g.useContext)(b);if(t===null)return[!0,null];let{isPresent:n,onExitComplete:r,register:i}=t,a=(0,g.useId)();(0,g.useEffect)(()=>{if(e)return i(a)},[e]);let o=(0,g.useCallback)(()=>e&&r&&r(a),[a,r,e]);return!n&&r?[!1,o]:[!0]}var Tc=e=>e.key||``;function Ec(e){let t=[];return g.Children.forEach(e,e=>{(0,g.isValidElement)(e)&&t.push(e)}),t}var Dc=({children:e,custom:t,initial:n=!0,onExitComplete:r,presenceAffectsLayout:i=!0,mode:a=`sync`,propagate:o=!1,anchorX:s=`left`,anchorY:c=`top`,root:l})=>{let[u,d]=wc(o),f=(0,g.useMemo)(()=>Ec(e),[e]),p=o&&!u?[]:f.map(Tc),m=(0,g.useRef)(!0),h=(0,g.useRef)(f),b=v(()=>new Map),x=(0,g.useRef)(new Set),[S,C]=(0,g.useState)(f),[w,T]=(0,g.useState)(f);y(()=>{m.current=!1,h.current=f;for(let e=0;e{let g=Tc(e),_=o&&!u?!1:f===w||p.includes(g);return(0,z.jsx)(Sc,{isPresent:_,initial:!m.current||n?void 0:!1,custom:t,presenceAffectsLayout:i,mode:a,root:l,onExitComplete:_?void 0:()=>{if(x.current.has(g))return;if(b.has(g))x.current.add(g),b.set(g,!0);else return;let e=!0;b.forEach(t=>{t||(e=!1)}),e&&(D?.(),T(h.current),o&&d?.(),r&&r())},anchorX:s,anchorY:c,children:e},g)})})},Oc=(0,g.createContext)({strict:!1}),kc={animation:[`animate`,`variants`,`whileHover`,`whileTap`,`exit`,`whileInView`,`whileFocus`,`whileDrag`],exit:[`exit`],drag:[`drag`,`dragControls`],focus:[`whileFocus`],hover:[`whileHover`,`onHoverStart`,`onHoverEnd`],tap:[`whileTap`,`onTap`,`onTapStart`,`onTapCancel`],pan:[`onPan`,`onPanStart`,`onPanSessionStart`,`onPanEnd`],inView:[`whileInView`,`onViewportEnter`,`onViewportLeave`],layout:[`layout`,`layoutId`]},Ac=!1;function jc(){if(Ac)return;let e={};for(let t in kc)e[t]={isEnabled:e=>kc[t].some(t=>!!e[t])};Fa(e),Ac=!0}function Mc(){return jc(),Ia()}function Nc(e){let t=Mc();for(let n in e)t[n]={...t[n],...e[n]};Fa(t)}var Pc=new Set(`animate.exit.variants.initial.style.values.variants.transition.transformTemplate.custom.inherit.onBeforeLayoutMeasure.onAnimationStart.onAnimationComplete.onUpdate.onDragStart.onDrag.onDragEnd.onMeasureDragConstraints.onDirectionLock.onDragTransitionEnd._dragX._dragY.onHoverStart.onHoverEnd.onViewportEnter.onViewportLeave.globalTapTarget.propagate.ignoreStrict.viewport`.split(`.`));function Fc(e){return e.startsWith(`while`)||e.startsWith(`drag`)&&e!==`draggable`||e.startsWith(`layout`)||e.startsWith(`onTap`)||e.startsWith(`onPan`)||e.startsWith(`onLayout`)||Pc.has(e)}var Ic=c({default:()=>Lc}),Lc,Rc=o((()=>{throw Lc={},Error(`Could not resolve "@emotion/is-prop-valid" imported by "framer-motion". Is it installed?`)})),zc=e=>!Fc(e);function Bc(e){typeof e==`function`&&(zc=t=>t.startsWith(`on`)?!Fc(t):e(t))}try{Bc((Rc(),d(Ic)).default)}catch{}function Vc(e,t,n){let r={};for(let i in e)i===`values`&&typeof e.values==`object`||ei(e[i])||(zc(i)||n===!0&&Fc(i)||!t&&!Fc(i)||e.draggable&&i.startsWith(`onDrag`))&&(r[i]=e[i]);return r}function Hc({children:e,isValidProp:t,...n}){t&&Bc(t);let r=(0,g.useContext)(gc);n={...r,...n},n.transition=Nr(n.transition,r.transition),n.isStatic=v(()=>n.isStatic);let i=(0,g.useMemo)(()=>n,[JSON.stringify(n.transition),n.transformPagePoint,n.reducedMotion,n.skipAnimations]);return(0,z.jsx)(gc.Provider,{value:i,children:e})}var Uc=(0,g.createContext)({});function Wc(e,t){if(Ea(e)){let{initial:t,animate:n}=e;return{initial:t===!1||Ca(t)?t:void 0,animate:Ca(n)?n:void 0}}return e.inherit===!1?{}:t}function Gc(e){let{initial:t,animate:n}=Wc(e,(0,g.useContext)(Uc));return(0,g.useMemo)(()=>({initial:t,animate:n}),[Kc(t),Kc(n)])}function Kc(e){return Array.isArray(e)?e.join(` `):e}var qc=()=>({style:{},transform:{},transformOrigin:{},vars:{}});function Jc(e,t,n){for(let r in t)!ei(t[r])&&!go(r,n)&&(e[r]=t[r])}function Yc({transformTemplate:e},t){return(0,g.useMemo)(()=>{let n=qc();return uo(n,t,e),Object.assign({},n.vars,n.style)},[t])}function Xc(e,t){let n=e.style||{},r={};return Jc(r,n,e),Object.assign(r,Yc(e,t)),r}function Zc(e,t){let n={},r=Xc(e,t);return e.drag&&e.dragListener!==!1&&(n.draggable=!1,r.userSelect=r.WebkitUserSelect=r.WebkitTouchCallout=`none`,r.touchAction=e.drag===!0?`none`:`pan-${e.drag===`x`?`y`:`x`}`),e.tabIndex===void 0&&(e.onTap||e.onTapStart||e.whileTap)&&(n.tabIndex=0),n.style=r,n}var Qc=()=>({...qc(),attrs:{}});function $c(e,t,n,r){let i=(0,g.useMemo)(()=>{let n=Qc();return wo(n,t,Eo(r),e.transformTemplate,e.style),{...n.attrs,style:{...n.style}}},[t]);if(e.style){let t={};Jc(t,e.style,e),i.style={...t,...i.style}}return i}var el=[`animate`,`circle`,`defs`,`desc`,`ellipse`,`g`,`image`,`line`,`filter`,`marker`,`mask`,`metadata`,`path`,`pattern`,`polygon`,`polyline`,`rect`,`stop`,`switch`,`symbol`,`svg`,`text`,`tspan`,`use`,`view`];function tl(e){return typeof e!=`string`||e.includes(`-`)?!1:!!(el.indexOf(e)>-1||/[A-Z]/u.test(e))}function nl(e,t,n,{latestValues:r},i,a=!1,o){let s=(o??tl(e)?$c:Zc)(t,r,i,e),c=Vc(t,typeof e==`string`,a),l=e===g.Fragment?{}:{...c,...s,ref:n},{children:u}=t,d=(0,g.useMemo)(()=>ei(u)?u.get():u,[u]);return(0,g.createElement)(e,{...l,children:d})}function rl({scrapeMotionValuesFromProps:e,createRenderState:t},n,r,i){return{latestValues:il(n,r,i,e),renderState:t()}}function il(e,t,n,r){let i={},a=r(e,{});for(let e in a)i[e]=js(a[e]);let{initial:o,animate:s}=e,c=Ea(e),l=Da(e);t&&l&&!c&&e.inherit!==!1&&(o===void 0&&(o=t.initial),s===void 0&&(s=t.animate));let u=n?n.initial===!1:!1;u||=o===!1;let d=u?s:o;if(d&&typeof d!=`boolean`&&!Sa(d)){let t=Array.isArray(d)?d:[d];for(let n=0;n(t,n)=>{let r=(0,g.useContext)(Uc),i=(0,g.useContext)(b),a=()=>rl(e,t,r,i);return n?a():v(a)},ol=al({scrapeMotionValuesFromProps:_o,createRenderState:qc}),sl=al({scrapeMotionValuesFromProps:Oo,createRenderState:Qc}),cl=Symbol.for(`motionComponentSymbol`);function ll(e,t,n){let r=(0,g.useRef)(n);(0,g.useInsertionEffect)(()=>{r.current=n});let i=(0,g.useRef)(null);return(0,g.useCallback)(n=>{n&&e.onMount?.(n),t&&(n?t.mount(n):t.unmount());let a=r.current;if(typeof a==`function`)if(n){let e=a(n);typeof e==`function`&&(i.current=e)}else i.current?(i.current(),i.current=null):a(n);else a&&(a.current=n)},[t])}var ul=(0,g.createContext)({});function dl(e){return e&&typeof e==`object`&&Object.prototype.hasOwnProperty.call(e,`current`)}function fl(e,t,n,r,i,a){let{visualElement:o}=(0,g.useContext)(Uc),s=(0,g.useContext)(Oc),c=(0,g.useContext)(b),l=(0,g.useContext)(gc),u=l.reducedMotion,d=l.skipAnimations,f=(0,g.useRef)(null),p=(0,g.useRef)(!1);r||=s.renderer,!f.current&&r&&(f.current=r(e,{visualState:t,parent:o,props:n,presenceContext:c,blockInitialAnimation:c?c.initial===!1:!1,reducedMotionConfig:u,skipAnimations:d,isSVG:a}),p.current&&f.current&&(f.current.manuallyAnimateOnMount=!0));let m=f.current,h=(0,g.useContext)(ul);m&&!m.projection&&i&&(m.type===`html`||m.type===`svg`)&&pl(f.current,n,i,h);let _=(0,g.useRef)(!1);(0,g.useInsertionEffect)(()=>{m&&_.current&&m.update(n,c)});let v=n[ii],x=(0,g.useRef)(!!v&&typeof window<`u`&&!window.MotionHandoffIsComplete?.(v)&&window.MotionHasOptimisedAnimation?.(v));return y(()=>{p.current=!0,m&&(_.current=!0,window.MotionIsMounted=!0,m.updateFeatures(),m.scheduleRenderMicrotask(),x.current&&m.animationState&&m.animationState.animateChanges())}),(0,g.useEffect)(()=>{m&&(!x.current&&m.animationState&&m.animationState.animateChanges(),x.current&&=(queueMicrotask(()=>{window.MotionHandoffMarkAsComplete?.(v)}),!1),m.enteringChildren=void 0)}),m}function pl(e,t,n,r){let{layoutId:i,layout:a,drag:o,dragConstraints:s,layoutScroll:c,layoutRoot:l,layoutAnchor:u,layoutCrossfade:d}=t;e.projection=new n(e.latestValues,t[`data-framer-portal-id`]?void 0:ml(e.parent)),e.projection.setOptions({layoutId:i,layout:a,alwaysMeasureLayout:!!o||s&&dl(s),visualElement:e,animationType:typeof a==`string`?a:`both`,initialPromotionConfig:r,crossfade:d,layoutScroll:c,layoutRoot:l,layoutAnchor:u})}function ml(e){if(e)return e.options.allowProjection===!1?ml(e.parent):e.projection}function hl(e,{forwardMotionProps:t=!1,type:n}={},r,i){r&&Nc(r);let a=n?n===`svg`:tl(e),o=a?sl:ol;function s(n,s){let c,l={...(0,g.useContext)(gc),...n,layoutId:gl(n)},{isStatic:u}=l,d=Gc(n),f=o(n,u);if(!u&&typeof window<`u`){_l(l,r);let t=vl(l);c=t.MeasureLayout,d.visualElement=fl(e,f,l,i,t.ProjectionNode,a)}return(0,z.jsxs)(Uc.Provider,{value:d,children:[c&&d.visualElement?(0,z.jsx)(c,{visualElement:d.visualElement,...l}):null,nl(e,n,ll(f,d.visualElement,s),f,u,t,a)]})}s.displayName=`motion.${typeof e==`string`?e:`create(${e.displayName??e.name??``})`}`;let c=(0,g.forwardRef)(s);return c[cl]=e,c}function gl({layoutId:e}){let t=(0,g.useContext)(_).id;return t&&e!==void 0?t+`-`+e:e}function _l(e,t){(0,g.useContext)(Oc).strict}function vl(e){let{drag:t,layout:n}=Mc();if(!t&&!n)return{};let r={...t,...n};return{MeasureLayout:t?.isEnabled(e)||n?.isEnabled(e)?r.MeasureLayout:void 0,ProjectionNode:r.ProjectionNode}}function yl(e,t){if(typeof Proxy>`u`)return hl;let n=new Map,r=(n,r)=>hl(n,r,e,t);return new Proxy((e,t)=>r(e,t),{get:(i,a)=>a===`create`?r:(n.has(a)||n.set(a,hl(a,void 0,e,t)),n.get(a))})}var bl=(e,t)=>t.isSVG??tl(e)?new ko(t):new yo(t,{allowProjection:e!==g.Fragment}),xl=class extends za{constructor(e){super(e),e.animationState||=Io(e)}updateAnimationControlsSubscription(){let{animate:e}=this.node.getProps();Sa(e)&&(this.unmountControls=e.subscribe(this.node))}mount(){this.updateAnimationControlsSubscription()}update(){let{animate:e}=this.node.getProps(),{animate:t}=this.node.prevProps||{};e!==t&&this.updateAnimationControlsSubscription()}unmount(){this.node.animationState.reset(),this.unmountControls?.()}},Sl=0,Cl={animation:{Feature:xl},exit:{Feature:class extends za{constructor(){super(...arguments),this.id=Sl++,this.isExitComplete=!1}update(){if(!this.node.presenceContext)return;let{isPresent:e,onExitComplete:t}=this.node.presenceContext,{isPresent:n}=this.node.prevPresenceContext||{};if(!this.node.animationState||e===n)return;if(e&&n===!1){if(this.isExitComplete){let{initial:e,custom:t}=this.node.getProps();if(typeof e==`string`||typeof e==`object`&&e&&!Array.isArray(e)){let n=Jr(this.node,e,t);if(n){let{transition:e,transitionEnd:t,...r}=n;for(let e in r)this.node.getValue(e)?.jump(r[e])}}this.node.animationState.reset(),this.node.animationState.animateChanges()}else this.node.animationState.setActive(`exit`,!1);this.isExitComplete=!1;return}let r=this.node.animationState.setActive(`exit`,!e);t&&!e&&r.then(()=>{this.isExitComplete=!0,t(this.id)})}mount(){let{register:e,onExitComplete:t}=this.node.presenceContext||{};t&&t(this.id),e&&(this.unmount=e(this.id))}unmount(){}}}};function wl(e){return{point:{x:e.pageX,y:e.pageY}}}var Tl=e=>t=>Vi(t)&&e(t,wl(t));function El(e,t,n,r){return Ds(e,t,Tl(n),r)}var Dl=({current:e})=>e?e.ownerDocument.defaultView:null,Ol=(e,t)=>Math.abs(e-t);function kl(e,t){let n=Ol(e.x,t.x),r=Ol(e.y,t.y);return Math.sqrt(n**2+r**2)}var Al=new Set([`auto`,`scroll`]),jl=class{constructor(e,t,{transformPagePoint:n,contextWindow:r=window,dragSnapToOrigin:i=!1,distanceThreshold:a=3,element:o}={}){if(this.startEvent=null,this.lastMoveEvent=null,this.lastMoveEventInfo=null,this.lastRawMoveEventInfo=null,this.handlers={},this.contextWindow=window,this.scrollPositions=new Map,this.removeScrollListeners=null,this.onElementScroll=e=>{this.handleScroll(e.target)},this.onWindowScroll=()=>{this.handleScroll(window)},this.updatePoint=()=>{if(!(this.lastMoveEvent&&this.lastMoveEventInfo))return;this.lastRawMoveEventInfo&&(this.lastMoveEventInfo=Ml(this.lastRawMoveEventInfo,this.transformPagePoint));let e=Pl(this.lastMoveEventInfo,this.history),t=this.startEvent!==null,n=kl(e.offset,{x:0,y:0})>=this.distanceThreshold;if(!t&&!n)return;let{point:r}=e,{timestamp:i}=ke;this.history.push({...r,timestamp:i});let{onStart:a,onMove:o}=this.handlers;t||(a&&a(this.lastMoveEvent,e),this.startEvent=this.lastMoveEvent),o&&o(this.lastMoveEvent,e)},this.handlePointerMove=(e,t)=>{this.lastMoveEvent=e,this.lastRawMoveEventInfo=t,this.lastMoveEventInfo=Ml(t,this.transformPagePoint),De.update(this.updatePoint,!0)},this.handlePointerUp=(e,t)=>{this.end();let{onEnd:n,onSessionEnd:r,resumeAnimation:i}=this.handlers;if((this.dragSnapToOrigin||!this.startEvent)&&i&&i(),!(this.lastMoveEvent&&this.lastMoveEventInfo))return;let a=Pl(e.type===`pointercancel`?this.lastMoveEventInfo:Ml(t,this.transformPagePoint),this.history);this.startEvent&&n&&n(e,a),r&&r(e,a)},!Vi(e))return;this.dragSnapToOrigin=i,this.handlers=t,this.transformPagePoint=n,this.distanceThreshold=a,this.contextWindow=r||window;let s=Ml(wl(e),this.transformPagePoint),{point:c}=s,{timestamp:l}=ke;this.history=[{...c,timestamp:l}];let{onSessionStart:u}=t;u&&u(e,Pl(s,this.history)),this.removeListeners=A(El(this.contextWindow,`pointermove`,this.handlePointerMove),El(this.contextWindow,`pointerup`,this.handlePointerUp),El(this.contextWindow,`pointercancel`,this.handlePointerUp)),o&&this.startScrollTracking(o)}startScrollTracking(e){let t=e.parentElement;for(;t;){let e=getComputedStyle(t);(Al.has(e.overflowX)||Al.has(e.overflowY))&&this.scrollPositions.set(t,{x:t.scrollLeft,y:t.scrollTop}),t=t.parentElement}this.scrollPositions.set(window,{x:window.scrollX,y:window.scrollY}),window.addEventListener(`scroll`,this.onElementScroll,{capture:!0}),window.addEventListener(`scroll`,this.onWindowScroll),this.removeScrollListeners=()=>{window.removeEventListener(`scroll`,this.onElementScroll,{capture:!0}),window.removeEventListener(`scroll`,this.onWindowScroll)}}handleScroll(e){let t=this.scrollPositions.get(e);if(!t)return;let n=e===window,r=n?{x:window.scrollX,y:window.scrollY}:{x:e.scrollLeft,y:e.scrollTop},i={x:r.x-t.x,y:r.y-t.y};i.x===0&&i.y===0||(n?this.lastMoveEventInfo&&(this.lastMoveEventInfo.point.x+=i.x,this.lastMoveEventInfo.point.y+=i.y):this.history.length>0&&(this.history[0].x-=i.x,this.history[0].y-=i.y),this.scrollPositions.set(e,r),De.update(this.updatePoint,!0))}updateHandlers(e){this.handlers=e}end(){this.removeListeners&&this.removeListeners(),this.removeScrollListeners&&this.removeScrollListeners(),this.scrollPositions.clear(),Oe(this.updatePoint)}};function Ml(e,t){return t?{point:t(e.point)}:e}function Nl(e,t){return{x:e.x-t.x,y:e.y-t.y}}function Pl({point:e},t){return{point:e,delta:Nl(e,Il(t)),offset:Nl(e,Fl(t)),velocity:Ll(t,.1)}}function Fl(e){return e[0]}function Il(e){return e[e.length-1]}function Ll(e,t){if(e.length<2)return{x:0,y:0};let n=e.length-1,r=null,i=Il(e);for(;n>=0&&(r=e[n],!(i.timestamp-r.timestamp>N(t)));)n--;if(!r)return{x:0,y:0};r===e[0]&&e.length>2&&i.timestamp-r.timestamp>N(t)*2&&(r=e[1]);let a=P(i.timestamp-r.timestamp);if(a===0)return{x:0,y:0};let o={x:(i.x-r.x)/a,y:(i.y-r.y)/a};return o.x===1/0&&(o.x=0),o.y===1/0&&(o.y=0),o}function Rl(e,{min:t,max:n},r){return t!==void 0&&en&&(e=r?Ot(n,e,r.max):Math.min(e,n)),e}function zl(e,t,n){return{min:t===void 0?void 0:e.min+t,max:n===void 0?void 0:e.max+n-(e.max-e.min)}}function Bl(e,{top:t,left:n,bottom:r,right:i}){return{x:zl(e.x,n,i),y:zl(e.y,t,r)}}function Vl(e,t){let n=t.min-e.min,r=t.max-e.max;return t.max-t.minr?n=j(t.min,t.max-r,e.min):r>i&&(n=j(e.min,e.max-i,t.min)),C(0,1,n)}function Wl(e,t){let n={};return t.min!==void 0&&(n.min=t.min-e.min),t.max!==void 0&&(n.max=t.max-e.min),n}var Gl=.35;function Kl(e=Gl){return e===!1?e=0:e===!0&&(e=Gl),{x:ql(e,`left`,`right`),y:ql(e,`top`,`bottom`)}}function ql(e,t,n){return{min:Jl(e,t),max:Jl(e,n)}}function Jl(e,t){return typeof e==`number`?e:e[t]||0}var Yl=new WeakMap,Xl=class{constructor(e){this.openDragLock=null,this.isDragging=!1,this.currentDirection=null,this.originPoint={x:0,y:0},this.constraints=!1,this.hasMutatedConstraints=!1,this.elastic=ba(),this.latestPointerEvent=null,this.latestPanInfo=null,this.visualElement=e}start(e,{snapToCursor:t=!1,distanceThreshold:n}={}){let{presenceContext:r}=this.visualElement;if(r&&r.isPresent===!1)return;let i=e=>{t&&this.snapToCursor(wl(e).point),this.stopAnimation()},a=(e,t)=>{let{drag:n,dragPropagation:r,onDragStart:i}=this.getProps();if(n&&!r&&(this.openDragLock&&this.openDragLock(),this.openDragLock=Ii(n),!this.openDragLock))return;this.latestPointerEvent=e,this.latestPanInfo=t,this.isDragging=!0,this.currentDirection=null,this.resolveConstraints(),this.visualElement.projection&&(this.visualElement.projection.isAnimationBlocked=!0,this.visualElement.projection.target=void 0),hs(e=>{let t=this.getAxisMotionValue(e).get()||0;if(rt.test(t)){let{projection:n}=this.visualElement;if(n&&n.layout){let r=n.layout.layoutBox[e];r&&(t=qo(r)*(parseFloat(t)/100))}}this.originPoint[e]=t}),i&&De.update(()=>i(e,t),!1,!0),ni(this.visualElement,`transform`);let{animationState:a}=this.visualElement;a&&a.setActive(`whileDrag`,!0)},o=(e,t)=>{this.latestPointerEvent=e,this.latestPanInfo=t;let{dragPropagation:n,dragDirectionLock:r,onDirectionLock:i,onDrag:a}=this.getProps();if(!n&&!this.openDragLock)return;let{offset:o}=t;if(r&&this.currentDirection===null){this.currentDirection=eu(o),this.currentDirection!==null&&i&&i(this.currentDirection);return}this.updateAxis(`x`,t.point,o),this.updateAxis(`y`,t.point,o),this.visualElement.render(),a&&De.update(()=>a(e,t),!1,!0)},s=(e,t)=>{this.latestPointerEvent=e,this.latestPanInfo=t,this.stop(e,t),this.latestPointerEvent=null,this.latestPanInfo=null},c=()=>{let{dragSnapToOrigin:e}=this.getProps();(e||this.constraints)&&this.startAnimation({x:0,y:0})},{dragSnapToOrigin:l}=this.getProps();this.panSession=new jl(e,{onSessionStart:i,onStart:a,onMove:o,onSessionEnd:s,resumeAnimation:c},{transformPagePoint:this.visualElement.getTransformPagePoint(),dragSnapToOrigin:l,distanceThreshold:n,contextWindow:Dl(this.visualElement),element:this.visualElement.current})}stop(e,t){let n=e||this.latestPointerEvent,r=t||this.latestPanInfo,i=this.isDragging;if(this.cancel(),!i||!r||!n)return;let{velocity:a}=r;this.startAnimation(a);let{onDragEnd:o}=this.getProps();o&&De.postRender(()=>o(n,r))}cancel(){this.isDragging=!1;let{projection:e,animationState:t}=this.visualElement;e&&(e.isAnimationBlocked=!1),this.endPanSession();let{dragPropagation:n}=this.getProps();!n&&this.openDragLock&&(this.openDragLock(),this.openDragLock=null),t&&t.setActive(`whileDrag`,!1)}endPanSession(){this.panSession&&this.panSession.end(),this.panSession=void 0}updateAxis(e,t,n){let{drag:r}=this.getProps();if(!n||!$l(e,r,this.currentDirection))return;let i=this.getAxisMotionValue(e),a=this.originPoint[e]+n[e];this.constraints&&this.constraints[e]&&(a=Rl(a,this.constraints[e],this.elastic[e])),i.set(a)}resolveConstraints(){let{dragConstraints:e,dragElastic:t}=this.getProps(),n=this.visualElement.projection&&!this.visualElement.projection.layout?this.visualElement.projection.measure(!1):this.visualElement.projection?.layout,r=this.constraints;e&&dl(e)?this.constraints||=this.resolveRefConstraints():e&&n?this.constraints=Bl(n.layoutBox,e):this.constraints=!1,this.elastic=Kl(t),r!==this.constraints&&!dl(e)&&n&&this.constraints&&!this.hasMutatedConstraints&&hs(e=>{this.constraints!==!1&&this.getAxisMotionValue(e)&&(this.constraints[e]=Wl(n.layoutBox[e],this.constraints[e]))})}resolveRefConstraints(){let{dragConstraints:e,onMeasureDragConstraints:t}=this.getProps();if(!e||!dl(e))return!1;let n=e.current,{projection:r}=this.visualElement;if(!r||!r.layout)return!1;r.root&&(r.root.scroll=void 0,r.root.updateScroll());let i=oo(n,r.root,this.visualElement.getTransformPagePoint()),a=Hl(r.layout.layoutBox,i);if(t){let e=t(Va(a));this.hasMutatedConstraints=!!e,e&&(a=Ba(e))}return a}startAnimation(e){let{drag:t,dragMomentum:n,dragElastic:r,dragTransition:i,dragSnapToOrigin:a,onDragTransitionEnd:o}=this.getProps(),s=this.constraints||{},c=hs(o=>{if(!$l(o,t,this.currentDirection))return;let c=s&&s[o]||{};(a===!0||a===o)&&(c={min:0,max:0});let l=r?200:1e6,u=r?40:1e7,d={type:`inertia`,velocity:n?e[o]:0,bounceStiffness:l,bounceDamping:u,timeConstant:750,restDelta:1,restSpeed:10,...i,...c};return this.startAxisValueAnimation(o,d)});return Promise.all(c).then(o)}startAxisValueAnimation(e,t){let n=this.getAxisMotionValue(e);return ni(this.visualElement,e),n.start(Hr(e,n,0,t,this.visualElement,!1))}stopAnimation(){hs(e=>this.getAxisMotionValue(e).stop())}getAxisMotionValue(e){let t=`_drag${e.toUpperCase()}`;return this.visualElement.getProps()[t]||this.visualElement.getValue(e,this.visualElement.latestValues[e]??0)}snapToCursor(e){hs(t=>{let{drag:n}=this.getProps();if(!$l(t,n,this.currentDirection))return;let{projection:r}=this.visualElement,i=this.getAxisMotionValue(t);if(r&&r.layout){let{min:n,max:a}=r.layout.layoutBox[t],o=i.get()||0;i.set(e[t]-Ot(n,a,.5)+o)}})}scalePositionWithinConstraints(){if(!this.visualElement.current)return;let{drag:e,dragConstraints:t}=this.getProps(),{projection:n}=this.visualElement;if(!dl(t)||!n||!this.constraints)return;this.stopAnimation();let r={x:0,y:0};hs(e=>{let t=this.getAxisMotionValue(e);if(t&&this.constraints!==!1){let n=t.get();r[e]=Ul({min:n,max:n},this.constraints[e])}});let{transformTemplate:i}=this.visualElement.getProps();this.visualElement.current.style.transform=i?i({},``):`none`,n.root&&n.root.updateScroll(),n.updateLayout(),this.constraints=!1,this.resolveConstraints(),hs(t=>{if(!$l(t,e,null))return;let n=this.getAxisMotionValue(t),{min:i,max:a}=this.constraints[t];n.set(Ot(i,a,r[t]))}),this.visualElement.render()}addListeners(){if(!this.visualElement.current)return;Yl.set(this.visualElement,this);let e=this.visualElement.current,t=El(e,`pointerdown`,t=>{let{drag:n,dragListener:r=!0}=this.getProps(),i=t.target,a=i!==e&&Gi(i);n&&r&&!a&&this.start(t)}),n,r=()=>{let{dragConstraints:t}=this.getProps();dl(t)&&t.current&&(this.constraints=this.resolveRefConstraints(),n||=Ql(e,t.current,()=>this.scalePositionWithinConstraints()))},{projection:i}=this.visualElement,a=i.addEventListener(`measure`,r);i&&!i.layout&&(i.root&&i.root.updateScroll(),i.updateLayout()),De.read(r);let o=Ds(window,`resize`,()=>this.scalePositionWithinConstraints()),s=i.addEventListener(`didUpdate`,(({delta:e,hasLayoutChanged:t})=>{this.isDragging&&t&&(hs(t=>{let n=this.getAxisMotionValue(t);n&&(this.originPoint[t]+=e[t].translate,n.set(n.get()+e[t].translate))}),this.visualElement.render())}));return()=>{o(),t(),a(),s&&s(),n&&n()}}getProps(){let e=this.visualElement.getProps(),{drag:t=!1,dragDirectionLock:n=!1,dragPropagation:r=!1,dragConstraints:i=!1,dragElastic:a=Gl,dragMomentum:o=!0}=e;return{...e,drag:t,dragDirectionLock:n,dragPropagation:r,dragConstraints:i,dragElastic:a,dragMomentum:o}}};function Zl(e){let t=!0;return()=>{if(t){t=!1;return}e()}}function Ql(e,t,n){let r=pa(e,Zl(n)),i=pa(t,Zl(n));return()=>{r(),i()}}function $l(e,t,n){return(t===!0||t===e)&&(n===null||n===e)}function eu(e,t=10){let n=null;return Math.abs(e.y)>t?n=`y`:Math.abs(e.x)>t&&(n=`x`),n}var tu=class extends za{constructor(e){super(e),this.removeGroupControls=k,this.removeListeners=k,this.controls=new Xl(e)}mount(){let{dragControls:e}=this.node.getProps();e&&(this.removeGroupControls=e.subscribe(this.controls)),this.removeListeners=this.controls.addListeners()||k}update(){let{dragControls:e}=this.node.getProps(),{dragControls:t}=this.node.prevProps||{};e!==t&&(this.removeGroupControls(),e&&(this.removeGroupControls=e.subscribe(this.controls)))}unmount(){this.removeGroupControls(),this.removeListeners(),this.controls.isDragging||this.controls.endPanSession()}},nu=e=>(t,n)=>{e&&De.update(()=>e(t,n),!1,!0)},ru=class extends za{constructor(){super(...arguments),this.removePointerDownListener=k}onPointerDown(e){this.session=new jl(e,this.createPanHandlers(),{transformPagePoint:this.node.getTransformPagePoint(),contextWindow:Dl(this.node)})}createPanHandlers(){let{onPanSessionStart:e,onPanStart:t,onPan:n,onPanEnd:r}=this.node.getProps();return{onSessionStart:nu(e),onStart:nu(t),onMove:nu(n),onEnd:(e,t)=>{delete this.session,r&&De.postRender(()=>r(e,t))}}}mount(){this.removePointerDownListener=El(this.node.current,`pointerdown`,e=>this.onPointerDown(e))}update(){this.session&&this.session.updateHandlers(this.createPanHandlers())}unmount(){this.removePointerDownListener(),this.session&&this.session.end()}},iu=!1,au=class extends g.Component{componentDidMount(){let{visualElement:e,layoutGroup:t,switchLayoutGroup:n,layoutId:r}=this.props,{projection:i}=e;i&&(t.group&&t.group.add(i),n&&n.register&&r&&n.register(i),iu&&i.root.didUpdate(),i.addEventListener(`animationComplete`,()=>{this.safeToRemove()}),i.setOptions({...i.options,layoutDependency:this.props.layoutDependency,onExitComplete:()=>this.safeToRemove()})),Ns.hasEverUpdated=!0}getSnapshotBeforeUpdate(e){let{layoutDependency:t,visualElement:n,drag:r,isPresent:i}=this.props,{projection:a}=n;return a?(a.isPresent=i,e.layoutDependency!==t&&a.setOptions({...a.options,layoutDependency:t}),iu=!0,r||e.layoutDependency!==t||t===void 0||e.isPresent!==i?a.willUpdate():this.safeToRemove(),e.isPresent!==i&&(i?a.promote():a.relegate()||De.postRender(()=>{let e=a.getStack();(!e||!e.members.length)&&this.safeToRemove()})),null):null}componentDidUpdate(){let{visualElement:e,layoutAnchor:t}=this.props,{projection:n}=e;n&&(n.options.layoutAnchor=t,n.root.didUpdate(),Ni.postRender(()=>{!n.currentAnimation&&n.isLead()&&this.safeToRemove()}))}componentWillUnmount(){let{visualElement:e,layoutGroup:t,switchLayoutGroup:n}=this.props,{projection:r}=e;iu=!0,r&&(r.scheduleCheckAfterUnmount(),t&&t.group&&t.group.remove(r),n&&n.deregister&&n.deregister(r))}safeToRemove(){let{safeToRemove:e}=this.props;e&&e()}render(){return null}};function ou(e){let[t,n]=wc(),r=(0,g.useContext)(_);return(0,z.jsx)(au,{...e,layoutGroup:r,switchLayoutGroup:(0,g.useContext)(ul),isPresent:t,safeToRemove:n})}var su={pan:{Feature:ru},drag:{Feature:tu,ProjectionNode:hc,MeasureLayout:ou}};function cu(e,t,n){let{props:r}=e;e.animationState&&r.whileHover&&e.animationState.setActive(`whileHover`,n===`Start`);let i=r[`onHover`+n];i&&De.postRender(()=>i(t,wl(t)))}var lu=class extends za{mount(){let{current:e}=this.node;e&&(this.unmount=zi(e,(e,t)=>(cu(this.node,t,`Start`),e=>cu(this.node,e,`End`))))}unmount(){}},uu=class extends za{constructor(){super(...arguments),this.isActive=!1}onFocus(){let e=!1;try{e=this.node.current.matches(`:focus-visible`)}catch{e=!0}!e||!this.node.animationState||(this.node.animationState.setActive(`whileFocus`,!0),this.isActive=!0)}onBlur(){!this.isActive||!this.node.animationState||(this.node.animationState.setActive(`whileFocus`,!1),this.isActive=!1)}mount(){this.unmount=A(Ds(this.node.current,`focus`,()=>this.onFocus()),Ds(this.node.current,`blur`,()=>this.onBlur()))}unmount(){}};function du(e,t,n){let{props:r}=e;if(e.current instanceof HTMLButtonElement&&e.current.disabled)return;e.animationState&&r.whileTap&&e.animationState.setActive(`whileTap`,n===`Start`);let i=r[`onTap`+(n===`End`?``:n)];i&&De.postRender(()=>i(t,wl(t)))}var fu=class extends za{mount(){let{current:e}=this.node;if(!e)return;let{globalTapTarget:t,propagate:n}=this.node.props;this.unmount=Qi(e,(e,t)=>(du(this.node,t,`Start`),(e,{success:t})=>du(this.node,e,t?`End`:`Cancel`)),{useGlobalTarget:t,stopPropagation:n?.tap===!1})}unmount(){}},pu=new WeakMap,mu=new WeakMap,hu=e=>{let t=pu.get(e.target);t&&t(e)},gu=e=>{e.forEach(hu)};function _u({root:e,...t}){let n=e||document;mu.has(n)||mu.set(n,{});let r=mu.get(n),i=JSON.stringify(t);return r[i]||(r[i]=new IntersectionObserver(gu,{root:e,...t})),r[i]}function vu(e,t,n){let r=_u(t);return pu.set(e,n),r.observe(e),()=>{pu.delete(e),r.unobserve(e)}}var yu={some:0,all:1},bu=class extends za{constructor(){super(...arguments),this.hasEnteredView=!1,this.isInView=!1}startObserver(){this.stopObserver?.();let{viewport:e={}}=this.node.getProps(),{root:t,margin:n,amount:r=`some`,once:i}=e,a={root:t?t.current:void 0,rootMargin:n,threshold:typeof r==`number`?r:yu[r]},o=e=>{let{isIntersecting:t}=e;if(this.isInView===t||(this.isInView=t,i&&!t&&this.hasEnteredView))return;t&&(this.hasEnteredView=!0),this.node.animationState&&this.node.animationState.setActive(`whileInView`,t);let{onViewportEnter:n,onViewportLeave:r}=this.node.getProps(),a=t?n:r;a&&a(e)};this.stopObserver=vu(this.node.current,a,o)}mount(){this.startObserver()}update(){if(typeof IntersectionObserver>`u`)return;let{props:e,prevProps:t}=this.node;[`amount`,`margin`,`root`].some(xu(e,t))&&this.startObserver()}unmount(){this.stopObserver?.(),this.hasEnteredView=!1,this.isInView=!1}};function xu({viewport:e={}},{viewport:t={}}={}){return n=>e[n]!==t[n]}var Su={inView:{Feature:bu},tap:{Feature:fu},focus:{Feature:uu},hover:{Feature:lu}},Cu={layout:{ProjectionNode:hc,MeasureLayout:ou}},B=yl({...Cl,...Su,...su,...Cu},bl),wu=s((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,O());else{var t=n(l);t!==null&&j(x,t.startTime-e)}}var S=!1,C=-1,w=5,T=-1;function E(){return g?!0:!(e.unstable_now()-Tt&&E());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&j(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?O():S=!1}}}var O;if(typeof y==`function`)O=function(){y(D)};else if(typeof MessageChannel<`u`){var k=new MessageChannel,A=k.port2;k.port1.onmessage=D,O=function(){A.postMessage(null)}}else O=function(){_(D,0)};function j(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,j(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,O()))),r},e.unstable_shouldYield=E,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),Tu=s(((e,t)=>{t.exports=wu()})),Eu=s((e=>{var t=h();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=Eu()})),Ou=s((e=>{var t=Tu(),n=h(),r=Du();function i(e){var t=`https://react.dev/errors/`+e;if(1ne||(e.current=te[ne],te[ne]=null,ne--)}function ae(e,t){ne++,te[ne]=e.current,e.current=t}var oe=re(null),se=re(null),ce=re(null),le=re(null);function ue(e,t){switch(ae(ce,t),ae(se,e),ae(oe,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Zd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Zd(t),e=Qd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}ie(oe),ae(oe,e)}function de(){ie(oe),ie(se),ie(ce)}function fe(e){e.memoizedState!==null&&ae(le,e);var t=oe.current,n=Qd(t,e.type);t!==n&&(ae(se,e),ae(oe,n))}function pe(e){se.current===e&&(ie(oe),ie(se)),le.current===e&&(ie(le),cp._currentValue=ee)}var me,he;function ge(e){if(me===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);me=t&&t[1]||``,he=-1)`:-1i||c[r]!==l[i]){var u=` -`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{_e=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?ge(n):``}function ye(e,t){switch(e.tag){case 26:case 27:case 5:return ge(e.type);case 16:return ge(`Lazy`);case 13:return e.child!==t&&t!==null?ge(`Suspense Fallback`):ge(`Suspense`);case 19:return ge(`SuspenseList`);case 0:case 15:return ve(e.type,!1);case 11:return ve(e.type.render,!1);case 1:return ve(e.type,!0);case 31:return ge(`Activity`);default:return``}}function be(e){try{var t=``,n=null;do t+=ye(e,n),n=e,e=e.return;while(e);return t}catch(e){return` -Error generating stack: `+e.message+` -`+e.stack}}var xe=Object.prototype.hasOwnProperty,Se=t.unstable_scheduleCallback,Ce=t.unstable_cancelCallback,we=t.unstable_shouldYield,Te=t.unstable_requestPaint,Ee=t.unstable_now,De=t.unstable_getCurrentPriorityLevel,Oe=t.unstable_ImmediatePriority,ke=t.unstable_UserBlockingPriority,Ae=t.unstable_NormalPriority,je=t.unstable_LowPriority,Me=t.unstable_IdlePriority,Ne=t.log,Pe=t.unstable_setDisableYieldValue,Fe=null,Ie=null;function Le(e){if(typeof Ne==`function`&&Pe(e),Ie&&typeof Ie.setStrictMode==`function`)try{Ie.setStrictMode(Fe,e)}catch{}}var Re=Math.clz32?Math.clz32:Ve,ze=Math.log,Be=Math.LN2;function Ve(e){return e>>>=0,e===0?32:31-(ze(e)/Be|0)|0}var He=256,Ue=262144,We=4194304;function Ge(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Ke(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ge(n))):i=Ge(o):i=Ge(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ge(n))):i=Ge(o)):i=Ge(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function qe(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Je(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ye(){var e=We;return We<<=1,!(We&62914560)&&(We=4194304),e}function Xe(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Ze(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Qe(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),un=!1;if(ln)try{var dn={};Object.defineProperty(dn,"passive",{get:function(){un=!0}}),window.addEventListener(`test`,dn,dn),window.removeEventListener(`test`,dn,dn)}catch{un=!1}var fn=null,pn=null,mn=null;function hn(){if(mn)return mn;var e,t=pn,n=t.length,r,i=`value`in fn?fn.value:fn.textContent,a=i.length;for(e=0;e=qn),Xn=` `,Zn=!1;function Qn(e,t){switch(e){case`keyup`:return Gn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function $n(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var er=!1;function tr(e,t){switch(e){case`compositionend`:return $n(t);case`keypress`:return t.which===32?(Zn=!0,Xn):null;case`textInput`:return e=t.data,e===Xn&&Zn?null:e;default:return null}}function nr(e,t){if(er)return e===`compositionend`||!Kn&&Qn(e,t)?(e=hn(),mn=pn=fn=null,er=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=wr(n)}}function Er(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Er(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Dr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=It(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=It(e.document)}return t}function Or(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var kr=ln&&`documentMode`in document&&11>=document.documentMode,Ar=null,jr=null,Mr=null,Nr=!1;function Pr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Nr||Ar==null||Ar!==It(r)||(r=Ar,`selectionStart`in r&&Or(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Mr&&Cr(Mr,r)||(Mr=r,r=Fd(jr,`onSelect`),0>=o,i-=o,Ei=1<<32-Re(t)+i|n<m?(g=d,d=null):g=d.sibling;var _=p(i,d,s[m],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,m),u===null?l=_:u.sibling=_,u=_,d=g}if(m===s.length)return n(i,d),L&&Oi(i,m),l;if(d===null){for(;mg?(_=m,m=null):_=m.sibling;var y=p(a,m,v.value,l);if(y===null){m===null&&(m=_);break}e&&m&&y.alternate===null&&t(a,m),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,m=_}if(v.done)return n(a,m),L&&Oi(a,g),u;if(m===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return L&&Oi(a,g),u}for(m=r(m);!v.done;g++,v=c.next())v=h(m,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&m.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&m.forEach(function(e){return t(a,e)}),L&&Oi(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===_&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case m:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===_){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===E&&Oa(l)===r.type){n(e,r.sibling),c=a(r,o.props),Fa(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===_?(c=pi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=fi(o.type,o.key,o.props,null,e.mode,c),Fa(c,o),c.return=e,e=c)}return s(e);case g:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=gi(o,e.mode,c),c.return=e,e=c}return s(e);case E:return o=Oa(o),b(e,r,o,c)}if(N(o))return v(e,r,o,c);if(A(o)){if(l=A(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),y(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,Pa(o),c);if(o.$$typeof===x)return b(e,r,na(e,o),c);Ia(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=mi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Na=0;var i=b(e,t,n,r);return Ma=null,i}catch(t){if(t===Sa||t===wa)throw t;var a=ci(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ra=La(!0),za=La(!1),Ba=!1;function Va(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ha(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ua(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Wa(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,Ul&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=ai(e),ii(e,null,n),t}return ti(e,r,t,n),ai(e)}function Ga(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,et(e,n)}}function Ka(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var qa=!1;function Ja(){if(qa){var e=pa;if(e!==null)throw e}}function Ya(e,t,n,r){qa=!1;var i=e.updateQueue;Ba=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var p=s.lane&-536870913,m=p!==s.lane;if(m?(Kl&p)===p:(r&p)===p){p!==0&&p===fa&&(qa=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;p=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,p);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,p=typeof h==`function`?h.call(_,d,p):h,p==null)break a;d=f({},d,p);break a;case 2:Ba=!0}}p=s.callback,p!==null&&(e.flags|=64,m&&(e.flags|=8192),m=i.callbacks,m===null?i.callbacks=[p]:m.push(p))}else m={lane:p,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=m,c=d):u=u.next=m,o|=p;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;m=s,s=m.next,m.next=null,i.lastBaseUpdate=m,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),eu|=o,e.lanes=o,e.memoizedState=d}}function Xa(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function Za(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=P.T,s={};P.T=s,Ls(e,!1,t,n);try{var c=i(),l=P.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Is(e,t,ga(c,r),Su(e)):Is(e,t,r,Su(e))}catch(n){Is(e,t,{then:function(){},status:`rejected`,reason:n},Su())}finally{F.p=a,o!==null&&s.types!==null&&(o.types=s.types),P.T=o}}function Es(){}function Ds(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Os(e).queue;Ts(e,a,t,ee,n===null?Es:function(){return ks(e),n(r)})}function Os(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:ee,baseState:ee,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ro,lastRenderedState:ee},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ro,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function ks(e){var t=Os(e);t.next===null&&(t=e.alternate.memoizedState),Is(e,t.next.queue,{},Su())}function As(){return ta(cp)}function js(){return No().memoizedState}function Ms(){return No().memoizedState}function Ns(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=Su();e=Ua(n);var r=Wa(t,e,n);r!==null&&(B(r,t,n),Ga(r,t,n)),t={cache:ca()},e.payload=t;return}t=t.return}}function Ps(e,t,n){var r=Su();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Rs(e)?zs(t,n):(n=ni(e,t,n,r),n!==null&&(B(n,e,r),Bs(n,t,r)))}function Fs(e,t,n){Is(e,t,n,Su())}function Is(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Rs(e))zs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Sr(s,o))return ti(e,t,i,0),Wl===null&&ei(),!1}catch{}if(n=ni(e,t,i,r),n!==null)return B(n,e,r),Bs(n,t,r),!0}return!1}function Ls(e,t,n,r){if(r={lane:2,revertLane:Sd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Rs(e)){if(t)throw Error(i(479))}else t=ni(e,n,r,2),t!==null&&B(t,e,2)}function Rs(e){var t=e.alternate;return e===R||t!==null&&t===R}function zs(e,t){_o=go=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Bs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,et(e,n)}}var Vs={readContext:ta,use:Io,useCallback:Co,useContext:Co,useEffect:Co,useImperativeHandle:Co,useLayoutEffect:Co,useInsertionEffect:Co,useMemo:Co,useReducer:Co,useRef:Co,useState:Co,useDebugValue:Co,useDeferredValue:Co,useTransition:Co,useSyncExternalStore:Co,useId:Co,useHostTransitionStatus:Co,useFormState:Co,useActionState:Co,useOptimistic:Co,useMemoCache:Co,useCacheRefresh:Co};Vs.useEffectEvent=Co;var Hs={readContext:ta,use:Io,useCallback:function(e,t){return Mo().memoizedState=[e,t===void 0?null:t],e},useContext:ta,useEffect:fs,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),us(4194308,4,vs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return us(4194308,4,e,t)},useInsertionEffect:function(e,t){us(4,2,e,t)},useMemo:function(e,t){var n=Mo();t=t===void 0?null:t;var r=e();if(vo){Le(!0);try{e()}finally{Le(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Mo();if(n!==void 0){var i=n(t);if(vo){Le(!0);try{n(t)}finally{Le(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ps.bind(null,R,e),[r.memoizedState,e]},useRef:function(e){var t=Mo();return e={current:e},t.memoizedState=e},useState:function(e){e=Jo(e);var t=e.queue,n=Fs.bind(null,R,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:bs,useDeferredValue:function(e,t){return Cs(Mo(),e,t)},useTransition:function(){var e=Jo(!1);return e=Ts.bind(null,R,e.queue,!0,!1),Mo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=R,a=Mo();if(L){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),Wl===null)throw Error(i(349));Kl&127||Uo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,fs(Go.bind(null,r,o,e),[e]),r.flags|=2048,cs(9,{destroy:void 0},Wo.bind(null,r,o,n,t),null),n},useId:function(){var e=Mo(),t=Wl.identifierPrefix;if(L){var n=Di,r=Ei;n=(r&~(1<<32-Re(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=yo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[ot]=t,o[st]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Wd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Fc(t)}}return Bc(t),Ic(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Fc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=ce.current,Vi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=Ni,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[ot]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Vd(e.nodeValue,n)),e||Ri(t,!0)}else e=Xd(e).createTextNode(r),e[ot]=t,t.stateNode=e}return Bc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Vi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[ot]=t}else Hi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Bc(t),e=!1}else n=Ui(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(lo(t),t):(lo(t),null);if(t.flags&128)throw Error(i(558))}return Bc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Vi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[ot]=t}else Hi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Bc(t),a=!1}else a=Ui(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(lo(t),t):(lo(t),null)}return lo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Rc(t,t.updateQueue),Bc(t),null);case 4:return de(),e===null&&jd(t.stateNode.containerInfo),Bc(t),null;case 10:return Yi(t.type),Bc(t),null;case 19:if(ie(uo),r=t.memoizedState,r===null)return Bc(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)zc(r,!1);else{if($l!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=fo(e),o!==null){for(t.flags|=128,zc(r,!1),e=o.updateQueue,t.updateQueue=e,Rc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)di(n,e),n=n.sibling;return ae(uo,uo.current&1|2),L&&Oi(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Ee()>uu&&(t.flags|=128,a=!0,zc(r,!1),t.lanes=4194304)}else{if(!a)if(e=fo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Rc(t,e),zc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!L)return Bc(t),null}else 2*Ee()-r.renderingStartTime>uu&&n!==536870912&&(t.flags|=128,a=!0,zc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(Bc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Ee(),e.sibling=null,n=uo.current,ae(uo,a?n&1|2:n&1),L&&Oi(t,r.treeForkCount),e);case 22:case 23:return lo(t),no(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(Bc(t),t.subtreeFlags&6&&(t.flags|=8192)):Bc(t),n=t.updateQueue,n!==null&&Rc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&ie(va),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Yi(sa),Bc(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Hc(e,t){switch(ji(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Yi(sa),de(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return pe(t),null;case 31:if(t.memoizedState!==null){if(lo(t),t.alternate===null)throw Error(i(340));Hi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(lo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Hi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ie(uo),null;case 4:return de(),null;case 10:return Yi(t.type),null;case 22:case 23:return lo(t),no(),e!==null&&ie(va),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Yi(sa),null;case 25:return null;default:return null}}function Uc(e,t){switch(ji(t),t.tag){case 3:Yi(sa),de();break;case 26:case 27:case 5:pe(t);break;case 4:de();break;case 31:t.memoizedState!==null&&lo(t);break;case 13:lo(t);break;case 19:ie(uo);break;case 10:Yi(t.type);break;case 22:case 23:lo(t),no(),e!==null&&ie(va);break;case 24:Yi(sa)}}function Wc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){td(t,t.return,e)}}function Gc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){td(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){td(t,t.return,e)}}function Kc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{Za(t,n)}catch(t){td(e,e.return,t)}}}function qc(e,t,n){n.props=Ys(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){td(e,t,n)}}function Jc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){td(e,t,n)}}function Yc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){td(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){td(e,t,n)}else n.current=null}function Xc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){td(e,e.return,t)}}function Zc(e,t,n){try{var r=e.stateNode;Gd(r,e.type,n,t),r[st]=t}catch(t){td(e,e.return,t)}}function Qc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&cf(e.type)||e.tag===4}function $c(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Qc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&cf(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function el(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=$t));else if(r!==4&&(r===27&&cf(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(el(e,t,n),e=e.sibling;e!==null;)el(e,t,n),e=e.sibling}function tl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&cf(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(tl(e,t,n),e=e.sibling;e!==null;)tl(e,t,n),e=e.sibling}function nl(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Wd(t,r,n),t[ot]=e,t[st]=n}catch(t){td(e,e.return,t)}}var rl=!1,il=!1,al=!1,ol=typeof WeakSet==`function`?WeakSet:Set,sl=null;function cl(e,t){if(e=e.containerInfo,Jd=W,e=Dr(e),Or(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(Yd={focusedElem:e,selectionRange:n},W=!1,sl=t;sl!==null;)if(t=sl,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,sl=e;else for(;sl!==null;){switch(t=sl,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Wd(o,r,n),o[ot]=e,yt(o),r=o;break a;case`link`:var s=Zf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Tr(s,h),v=Tr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,P.T=null,n=vu,vu=null;var o=mu,s=gu;if(pu=0,hu=mu=null,gu=0,Ul&6)throw Error(i(331));var c=Ul;if(Ul|=4,Rl(o.current),Al(o,o.current,s,n),Ul=c,hd(0,!1),Ie&&typeof Ie.onPostCommitFiberRoot==`function`)try{Ie.onPostCommitFiberRoot(Fe,o)}catch{}return!0}finally{F.p=a,P.T=r,Zu(e,t)}}function ed(e,t,n){t=vi(n,t),t=tc(e.stateNode,t,2),e=Wa(e,t,2),e!==null&&(Ze(e,2),md(e))}function td(e,t,n){if(e.tag===3)ed(e,e,n);else for(;t!==null;){if(t.tag===3){ed(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(fu===null||!fu.has(r))){e=vi(n,e),n=nc(2),r=Wa(t,n,2),r!==null&&(rc(n,r,t,e),Ze(r,2),md(r));break}}t=t.return}}function nd(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Hl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Zl=!0,i.add(n),e=rd.bind(null,e,t,n),t.then(e,e))}function rd(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Wl===e&&(Kl&n)===n&&($l===4||$l===3&&(Kl&62914560)===Kl&&300>Ee()-cu?!(Ul&2)&&Mu(e,0):nu|=n,iu===Kl&&(iu=0)),md(e)}function id(e,t){t===0&&(t=Ye()),e=ri(e,t),e!==null&&(Ze(e,t),md(e))}function ad(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),id(e,n)}function od(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),id(e,n)}function sd(e,t){return Se(e,t)}var cd=null,ld=null,ud=!1,dd=!1,fd=!1,pd=0;function md(e){e!==ld&&e.next===null&&(ld===null?cd=ld=e:ld=ld.next=e),dd=!0,ud||(ud=!0,xd())}function hd(e,t){if(!fd&&dd){fd=!0;do for(var n=!1,r=cd;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-Re(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,bd(r,a))}else a=Kl,a=Ke(r,r===Wl?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||qe(r,a)||(n=!0,bd(r,a));r=r.next}while(n);fd=!1}}function gd(){_d()}function _d(){dd=ud=!1;var e=0;pd!==0&&tf()&&(e=pd);for(var t=Ee(),n=null,r=cd;r!==null;){var i=r.next,a=vd(r,t);a===0?(r.next=null,n===null?cd=i:n.next=i,i===null&&(ld=n)):(n=r,(e!==0||a&3)&&(dd=!0)),r=i}pu!==0&&pu!==5||hd(e,!1),pd!==0&&(pd=0)}function vd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Kd(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function jf(e,t,n){var r=Af;if(r&&typeof t==`string`&&t){var i=Rt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),Tf.has(i)||(Tf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Wd(t,`link`,e),yt(t),r.head.appendChild(t)))}}function Mf(e){Df.D(e),jf(`dns-prefetch`,e,null)}function Nf(e,t){Df.C(e,t),jf(`preconnect`,e,t)}function Pf(e,t,n){Df.L(e,t,n);var r=Af;if(r&&e&&t){var i=`link[rel="preload"][as="`+Rt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Rt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Rt(n.imageSizes)+`"]`)):i+=`[href="`+Rt(e)+`"]`;var a=i;switch(t){case`style`:a=Bf(e);break;case`script`:a=Wf(e)}wf.has(a)||(e=f({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),wf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(Vf(a))||t===`script`&&r.querySelector(Gf(a))||(t=r.createElement(`link`),Wd(t,`link`,e),yt(t),r.head.appendChild(t)))}}function Ff(e,t){Df.m(e,t);var n=Af;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Rt(r)+`"][href="`+Rt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Wf(e)}if(!wf.has(a)&&(e=f({rel:`modulepreload`,href:e},t),wf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Gf(a)))return}r=n.createElement(`link`),Wd(r,`link`,e),yt(r),n.head.appendChild(r)}}}function If(e,t,n){Df.S(e,t,n);var r=Af;if(r&&e){var i=vt(r).hoistableStyles,a=Bf(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(Vf(a)))s.loading=5;else{e=f({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=wf.get(a))&&Jf(e,n);var c=o=r.createElement(`link`);yt(c),Wd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,qf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Lf(e,t){Df.X(e,t);var n=Af;if(n&&e){var r=vt(n).hoistableScripts,i=Wf(e),a=r.get(i);a||(a=n.querySelector(Gf(i)),a||(e=f({src:e,async:!0},t),(t=wf.get(i))&&Yf(e,t),a=n.createElement(`script`),yt(a),Wd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Rf(e,t){Df.M(e,t);var n=Af;if(n&&e){var r=vt(n).hoistableScripts,i=Wf(e),a=r.get(i);a||(a=n.querySelector(Gf(i)),a||(e=f({src:e,async:!0,type:`module`},t),(t=wf.get(i))&&Yf(e,t),a=n.createElement(`script`),yt(a),Wd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function zf(e,t,n,r){var a=(a=ce.current)?Ef(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Bf(n.href),n=vt(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Bf(n.href);var o=vt(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(Vf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),wf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},wf.set(e,n),o||Uf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Wf(n),n=vt(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Bf(e){return`href="`+Rt(e)+`"`}function Vf(e){return`link[rel="stylesheet"][`+e+`]`}function Hf(e){return f({},e,{"data-precedence":e.precedence,precedence:null})}function Uf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Wd(t,`link`,n),yt(t),e.head.appendChild(t))}function Wf(e){return`[src="`+Rt(e)+`"]`}function Gf(e){return`script[async]`+e}function Kf(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Rt(n.href)+`"]`);if(r)return t.instance=r,yt(r),r;var a=f({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),yt(r),Wd(r,`style`,a),qf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Bf(n.href);var o=e.querySelector(Vf(a));if(o)return t.state.loading|=4,t.instance=o,yt(o),o;r=Hf(n),(a=wf.get(a))&&Jf(r,a),o=(e.ownerDocument||e).createElement(`link`),yt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Wd(o,`link`,r),t.state.loading|=4,qf(o,n.precedence,e),t.instance=o;case`script`:return o=Wf(n.src),(a=e.querySelector(Gf(o)))?(t.instance=a,yt(a),a):(r=n,(a=wf.get(o))&&(r=f({},n),Yf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),yt(a),Wd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,qf(r,n.precedence,e));return t.instance}function qf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function $f(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function ep(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function tp(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Bf(r.href),a=t.querySelector(Vf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=ip.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,yt(a);return}a=t.ownerDocument||t,r=Hf(r),(i=wf.get(i))&&Jf(r,i),a=a.createElement(`link`),yt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Wd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=ip.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var np=0;function rp(e,t){return e.stylesheets&&e.count===0&&op(e,e.stylesheets),0np?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function ip(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)op(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var ap=null;function op(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,ap=new Map,t.forEach(sp,e),ap=null,ip.call(e))}function sp(e,t){if(!(t.state.loading&4)){var n=ap.get(e);if(n)var r=n.get(null);else{n=new Map,ap.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=Ou()}))();function Au(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}var ju=e=>typeof e==`object`&&!!e;function Mu(e){return Object.fromEntries(Object.entries(e??{}).filter(([e,t])=>t!==void 0))}var Nu=e=>e===`base`;function Pu(e){return e.slice().filter(e=>!Nu(e))}function Fu(e){return String.fromCharCode(e+(e>25?39:97))}function Iu(e){let t=``,n;for(n=Math.abs(e);n>52;n=n/52|0)t=Fu(n%52)+t;return Fu(n%52)+t}function Lu(e,t){let n=t.length;for(;n;)e=e*33^t.charCodeAt(--n);return e}function Ru(e){return Iu(Lu(5381,e)>>>0)}var zu=/\s*!(important)?/i;function Bu(e){return typeof e==`string`?zu.test(e):!1}function Vu(e){return typeof e==`string`?e.replace(zu,``).trim():e}function Hu(e){return typeof e==`string`?e.replaceAll(` `,`_`):e}var Uu=e=>{let t=new Map;return(...n)=>{let r=JSON.stringify(n);if(t.has(r))return t.get(r);let i=e(...n);return t.set(r,i),i}},Wu=new Set([`__proto__`,`constructor`,`prototype`]);function Gu(...e){return e.reduce((e,t)=>(t&&Object.keys(t).forEach(n=>{if(Wu.has(n))return;let r=e[n],i=t[n];Au(r)&&Au(i)?e[n]=Gu(r,i):e[n]=i}),e),{})}var Ku=e=>e!=null;function qu(e,t,n={}){let{stop:r,getKey:i}=n;function a(e,n=[]){if(ju(e)){let o={};for(let[s,c]of Object.entries(e)){let l=i?.(s,c)??s,u=[...n,l];if(r?.(e,u))return t(e,n);let d=a(c,u);Ku(d)&&(o[l]=d)}return o}return t(e,n)}return a(e)}function Ju(e,t){return e.reduce((e,n,r)=>{let i=t[r];return n!=null&&(e[i]=n),e},{})}function Yu(e,t,n=!0){let{utility:r,conditions:i}=t,{hasShorthand:a,resolveShorthand:o}=r;return qu(e,e=>Array.isArray(e)?Ju(e,i.breakpoints.keys):e,{stop:e=>Array.isArray(e),getKey:n?e=>a?o(e):e:void 0})}var Xu={shift:e=>e,finalize:e=>e,breakpoints:{keys:[]}},Zu=e=>typeof e==`string`?e.replaceAll(/[\n\s]+/g,` `):e;function Qu(e){let{utility:t,hash:n,conditions:r=Xu}=e,i=e=>[t.prefix,e].filter(Boolean).join(`-`),a=(e,a)=>{let o;if(n){let n=[...r.finalize(e),a];o=i(t.toHash(n,Ru))}else o=[...r.finalize(e),i(a)].join(`:`);return o};return Uu(({base:n,...i}={})=>{let o=Yu(Object.assign(i,n),e),s=new Set;return qu(o,(e,n)=>{if(e==null)return;let i=Bu(e),[o,...c]=r.shift(n),l=a(Pu(c),t.transform(o,Vu(Zu(e))).className);i&&(l=`${l}!`),s.add(l)}),Array.from(s).join(` `)})}function $u(...e){return e.flat().filter(e=>Au(e)&&Object.keys(Mu(e)).length>0)}function ed(e){function t(t){let n=$u(...t);return n.length===1?n:n.map(t=>Yu(t,e))}function n(...e){return Gu(...t(e))}function r(...e){return Object.assign({},...t(e))}return{mergeCss:Uu(n),assignCss:r}}var td=/([A-Z])/g,nd=/^ms-/,rd=Uu(e=>e.startsWith(`--`)?e:e.replace(td,`-$1`).replace(nd,`-ms-`).toLowerCase());RegExp(`^(${[`min`,`max`,`clamp`,`calc`].join(`|`)})\\(.*\\)`);var id=`(?:${`cm,mm,Q,in,pc,pt,px,em,ex,ch,rem,lh,rlh,vw,vh,vmin,vmax,vb,vi,svw,svh,lvw,lvh,dvw,dvh,cqw,cqh,cqi,cqb,cqmin,cqmax,%`.split(`,`).join(`|`)})`;RegExp(`^[+-]?[0-9]*.?[0-9]+(?:[eE][+-]?[0-9]+)?${id}$`);function ad(e,...t){let n=Object.getOwnPropertyDescriptors(e),r=Object.keys(n),i=e=>{let t={};for(let r=0;ri(Array.isArray(e)?e:r.filter(e))).concat(i(r))}var od=(...e)=>{let t=e.reduce((e,t)=>(t&&t.forEach(t=>e.add(t)),e),new Set([]));return Array.from(t)},sd=[`htmlSize`,`htmlTranslate`,`htmlWidth`,`htmlHeight`];function cd(e){return sd.includes(e)?e.replace(`html`,``).toLowerCase():e}function ld(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[cd(e),t]))}ld.keys=sd;var ud=new Set(`_hover,_focus,_focusWithin,_focusVisible,_disabled,_active,_visited,_target,_readOnly,_readWrite,_empty,_checked,_enabled,_expanded,_highlighted,_complete,_incomplete,_dragging,_before,_after,_firstLetter,_firstLine,_marker,_selection,_file,_backdrop,_first,_last,_only,_even,_odd,_firstOfType,_lastOfType,_onlyOfType,_peerFocus,_peerHover,_peerActive,_peerFocusWithin,_peerFocusVisible,_peerDisabled,_peerChecked,_peerInvalid,_peerExpanded,_peerPlaceholderShown,_groupFocus,_groupHover,_groupActive,_groupFocusWithin,_groupFocusVisible,_groupDisabled,_groupChecked,_groupExpanded,_groupInvalid,_indeterminate,_required,_valid,_invalid,_autofill,_inRange,_outOfRange,_placeholder,_placeholderShown,_pressed,_selected,_grabbed,_underValue,_overValue,_atValue,_default,_optional,_open,_closed,_fullscreen,_loading,_hidden,_current,_currentPage,_currentStep,_today,_unavailable,_rangeStart,_rangeEnd,_now,_topmost,_motionReduce,_motionSafe,_print,_landscape,_portrait,_dark,_light,_osDark,_osLight,_highContrast,_lessContrast,_moreContrast,_ltr,_rtl,_scrollbar,_scrollbarThumb,_scrollbarTrack,_horizontal,_vertical,_icon,_starting,_noscript,_invertedColors,sm,smOnly,smDown,md,mdOnly,mdDown,lg,lgOnly,lgDown,xl,xlOnly,xlDown,2xl,2xlOnly,2xlDown,smToMd,smToLg,smToXl,smTo2xl,mdToLg,mdToXl,mdTo2xl,lgToXl,lgTo2xl,xlTo2xl,@/xs,@/sm,@/md,@/lg,@/xl,@/2xl,@/3xl,@/4xl,@/5xl,@/6xl,@/7xl,@/8xl,base`.split(`,`)),dd=/^@|&|&$/;function fd(e){return ud.has(e)||dd.test(e)}var pd=/^_/,md=/&|@/;function hd(e){return e.map(e=>ud.has(e)?e.replace(pd,``):md.test(e)?`[${Hu(e.trim())}]`:e)}function gd(e){return e.sort((e,t)=>{let n=fd(e),r=fd(t);return n&&!r?1:!n&&r?-1:0})}var _d=`aspectRatio:asp,boxDecorationBreak:bx-db,zIndex:z,boxSizing:bx-s,objectPosition:obj-p,objectFit:obj-f,overscrollBehavior:ovs-b,overscrollBehaviorX:ovs-bx,overscrollBehaviorY:ovs-by,position:pos/1,top:top,left:left,inset:inset,insetInline:inset-x/insetX,insetBlock:inset-y/insetY,insetBlockEnd:inset-be,insetBlockStart:inset-bs,insetInlineEnd:inset-e/insetEnd/end,insetInlineStart:inset-s/insetStart/start,right:right,bottom:bottom,float:float,visibility:vis,display:d,hideFrom:hide,hideBelow:show,flexBasis:flex-b,flex:flex,flexDirection:flex-d/flexDir,flexGrow:flex-g,flexShrink:flex-sh,gridTemplateColumns:grid-tc,gridTemplateRows:grid-tr,gridColumn:grid-c,gridRow:grid-r,gridColumnStart:grid-cs,gridColumnEnd:grid-ce,gridAutoFlow:grid-af,gridAutoColumns:grid-ac,gridAutoRows:grid-ar,gap:gap,gridGap:grid-g,gridRowGap:grid-rg,gridColumnGap:grid-cg,rowGap:rg,columnGap:cg,justifyContent:jc,alignContent:ac,alignItems:ai,alignSelf:as,padding:p/1,paddingLeft:pl/1,paddingRight:pr/1,paddingTop:pt/1,paddingBottom:pb/1,paddingBlock:py/1/paddingY,paddingBlockEnd:pbe,paddingBlockStart:pbs,paddingInline:px/paddingX/1,paddingInlineEnd:pe/1/paddingEnd,paddingInlineStart:ps/1/paddingStart,marginLeft:ml/1,marginRight:mr/1,marginTop:mt/1,marginBottom:mb/1,margin:m/1,marginBlock:my/1/marginY,marginBlockEnd:mbe,marginBlockStart:mbs,marginInline:mx/1/marginX,marginInlineEnd:me/1/marginEnd,marginInlineStart:ms/1/marginStart,spaceX:sx,spaceY:sy,outlineWidth:ring-w/ringWidth,outlineColor:ring-c/ringColor,outline:ring/1,outlineOffset:ring-o/ringOffset,focusRing:focus-ring,focusVisibleRing:focus-v-ring,focusRingColor:focus-ring-c,focusRingOffset:focus-ring-o,focusRingWidth:focus-ring-w,focusRingStyle:focus-ring-s,divideX:dvd-x,divideY:dvd-y,divideColor:dvd-c,divideStyle:dvd-s,width:w/1,inlineSize:w-is,minWidth:min-w/minW,minInlineSize:min-w-is,maxWidth:max-w/maxW,maxInlineSize:max-w-is,height:h/1,blockSize:h-bs,minHeight:min-h/minH,minBlockSize:min-h-bs,maxHeight:max-h/maxH,maxBlockSize:max-b,boxSize:size,color:c,fontFamily:ff,fontSize:fs,fontSizeAdjust:fs-a,fontPalette:fp,fontKerning:fk,fontFeatureSettings:ff-s,fontWeight:fw,fontSmoothing:fsmt,fontVariant:fv,fontVariantAlternates:fv-alt,fontVariantCaps:fv-caps,fontVariationSettings:fv-s,fontVariantNumeric:fv-num,letterSpacing:ls,lineHeight:lh,textAlign:ta,textDecoration:td,textDecorationColor:td-c,textEmphasisColor:te-c,textDecorationStyle:td-s,textDecorationThickness:td-t,textUnderlineOffset:tu-o,textTransform:tt,textIndent:ti,textShadow:tsh,textShadowColor:tsh-c/textShadowColor,WebkitTextFillColor:wktf-c,textOverflow:tov,verticalAlign:va,wordBreak:wb,textWrap:tw,truncate:trunc,lineClamp:lc,listStyleType:li-t,listStylePosition:li-pos,listStyleImage:li-img,listStyle:li-s,backgroundPosition:bg-p/bgPosition,backgroundPositionX:bg-p-x/bgPositionX,backgroundPositionY:bg-p-y/bgPositionY,backgroundAttachment:bg-a/bgAttachment,backgroundClip:bg-cp/bgClip,background:bg/1,backgroundColor:bg-c/bgColor,backgroundOrigin:bg-o/bgOrigin,backgroundImage:bg-i/bgImage,backgroundRepeat:bg-r/bgRepeat,backgroundBlendMode:bg-bm/bgBlendMode,backgroundSize:bg-s/bgSize,backgroundGradient:bg-grad/bgGradient,backgroundLinear:bg-linear/bgLinear,backgroundRadial:bg-radial/bgRadial,backgroundConic:bg-conic/bgConic,textGradient:txt-grad,gradientFromPosition:grad-from-pos,gradientToPosition:grad-to-pos,gradientFrom:grad-from,gradientTo:grad-to,gradientVia:grad-via,gradientViaPosition:grad-via-pos,borderRadius:bdr/rounded,borderTopLeftRadius:bdr-tl/roundedTopLeft,borderTopRightRadius:bdr-tr/roundedTopRight,borderBottomRightRadius:bdr-br/roundedBottomRight,borderBottomLeftRadius:bdr-bl/roundedBottomLeft,borderTopRadius:bdr-t/roundedTop,borderRightRadius:bdr-r/roundedRight,borderBottomRadius:bdr-b/roundedBottom,borderLeftRadius:bdr-l/roundedLeft,borderStartStartRadius:bdr-ss/roundedStartStart,borderStartEndRadius:bdr-se/roundedStartEnd,borderStartRadius:bdr-s/roundedStart,borderEndStartRadius:bdr-es/roundedEndStart,borderEndEndRadius:bdr-ee/roundedEndEnd,borderEndRadius:bdr-e/roundedEnd,border:bd,borderWidth:bd-w,borderTopWidth:bd-t-w,borderLeftWidth:bd-l-w,borderRightWidth:bd-r-w,borderBottomWidth:bd-b-w,borderBlockStartWidth:bd-bs-w,borderBlockEndWidth:bd-be-w,borderColor:bd-c,borderInline:bd-x/borderX,borderInlineWidth:bd-x-w/borderXWidth,borderInlineColor:bd-x-c/borderXColor,borderBlock:bd-y/borderY,borderBlockWidth:bd-y-w/borderYWidth,borderBlockColor:bd-y-c/borderYColor,borderLeft:bd-l,borderLeftColor:bd-l-c,borderInlineStart:bd-s/borderStart,borderInlineStartWidth:bd-s-w/borderStartWidth,borderInlineStartColor:bd-s-c/borderStartColor,borderRight:bd-r,borderRightColor:bd-r-c,borderInlineEnd:bd-e/borderEnd,borderInlineEndWidth:bd-e-w/borderEndWidth,borderInlineEndColor:bd-e-c/borderEndColor,borderTop:bd-t,borderTopColor:bd-t-c,borderBottom:bd-b,borderBottomColor:bd-b-c,borderBlockEnd:bd-be,borderBlockEndColor:bd-be-c,borderBlockStart:bd-bs,borderBlockStartColor:bd-bs-c,opacity:op,boxShadow:bx-sh/shadow,boxShadowColor:bx-sh-c/shadowColor,mixBlendMode:mix-bm,filter:filter,brightness:brightness,contrast:contrast,grayscale:grayscale,hueRotate:hue-rotate,invert:invert,saturate:saturate,sepia:sepia,dropShadow:drop-shadow,blur:blur,backdropFilter:bkdp,backdropBlur:bkdp-blur,backdropBrightness:bkdp-brightness,backdropContrast:bkdp-contrast,backdropGrayscale:bkdp-grayscale,backdropHueRotate:bkdp-hue-rotate,backdropInvert:bkdp-invert,backdropOpacity:bkdp-opacity,backdropSaturate:bkdp-saturate,backdropSepia:bkdp-sepia,borderCollapse:bd-cl,borderSpacing:bd-sp,borderSpacingX:bd-sx,borderSpacingY:bd-sy,tableLayout:tbl,transitionTimingFunction:trs-tmf,transitionDelay:trs-dly,transitionDuration:trs-dur,transitionProperty:trs-prop,transition:trs,animation:anim,animationName:anim-n,animationTimingFunction:anim-tmf,animationDuration:anim-dur,animationDelay:anim-dly,animationPlayState:anim-ps,animationComposition:anim-comp,animationFillMode:anim-fm,animationDirection:anim-dir,animationIterationCount:anim-ic,animationRange:anim-r,animationState:anim-s,animationRangeStart:anim-rs,animationRangeEnd:anim-re,animationTimeline:anim-tl,transformOrigin:trf-o,transformBox:trf-b,transformStyle:trf-s,transform:trf,rotate:rotate,rotateX:rotate-x,rotateY:rotate-y,rotateZ:rotate-z,scale:scale,scaleX:scale-x,scaleY:scale-y,translate:translate,translateX:translate-x/x,translateY:translate-y/y,translateZ:translate-z/z,accentColor:ac-c,caretColor:ca-c,scrollBehavior:scr-bhv,scrollbar:scr-bar,scrollbarColor:scr-bar-c,scrollbarGutter:scr-bar-g,scrollbarWidth:scr-bar-w,scrollMargin:scr-m,scrollMarginLeft:scr-ml,scrollMarginRight:scr-mr,scrollMarginTop:scr-mt,scrollMarginBottom:scr-mb,scrollMarginBlock:scr-my/scrollMarginY,scrollMarginBlockEnd:scr-mbe,scrollMarginBlockStart:scr-mbt,scrollMarginInline:scr-mx/scrollMarginX,scrollMarginInlineEnd:scr-me,scrollMarginInlineStart:scr-ms,scrollPadding:scr-p,scrollPaddingBlock:scr-py/scrollPaddingY,scrollPaddingBlockStart:scr-pbs,scrollPaddingBlockEnd:scr-pbe,scrollPaddingInline:scr-px/scrollPaddingX,scrollPaddingInlineEnd:scr-pe,scrollPaddingInlineStart:scr-ps,scrollPaddingLeft:scr-pl,scrollPaddingRight:scr-pr,scrollPaddingTop:scr-pt,scrollPaddingBottom:scr-pb,scrollSnapAlign:scr-sa,scrollSnapStop:scrs-s,scrollSnapType:scrs-t,scrollSnapStrictness:scrs-strt,scrollSnapMargin:scrs-m,scrollSnapMarginTop:scrs-mt,scrollSnapMarginBottom:scrs-mb,scrollSnapMarginLeft:scrs-ml,scrollSnapMarginRight:scrs-mr,scrollSnapCoordinate:scrs-c,scrollSnapDestination:scrs-d,scrollSnapPointsX:scrs-px,scrollSnapPointsY:scrs-py,scrollSnapTypeX:scrs-tx,scrollSnapTypeY:scrs-ty,scrollTimeline:scrtl,scrollTimelineAxis:scrtl-a,scrollTimelineName:scrtl-n,touchAction:tch-a,userSelect:us,overflow:ov,overflowWrap:ov-wrap,overflowX:ov-x,overflowY:ov-y,overflowAnchor:ov-a,overflowBlock:ov-b,overflowInline:ov-i,overflowClipBox:ovcp-bx,overflowClipMargin:ovcp-m,overscrollBehaviorBlock:ovs-bb,overscrollBehaviorInline:ovs-bi,fill:fill,stroke:stk,strokeWidth:stk-w,strokeDasharray:stk-dsh,strokeDashoffset:stk-do,strokeLinecap:stk-lc,strokeLinejoin:stk-lj,strokeMiterlimit:stk-ml,strokeOpacity:stk-op,srOnly:sr,debug:debug,appearance:ap,backfaceVisibility:bfv,clipPath:cp-path,hyphens:hy,mask:msk,maskImage:msk-i,maskSize:msk-s,textSizeAdjust:txt-adj,container:cq,containerName:cq-n,containerType:cq-t,cursor:cursor,textStyle:textStyle`,vd=new Map,yd=new Map;_d.split(`,`).forEach(e=>{let[t,n]=e.split(`:`),[r,...i]=n.split(`/`);vd.set(t,r),i.length&&i.forEach(e=>{yd.set(e===`1`?r:e,t)})});var bd=e=>yd.get(e)||e,xd={conditions:{shift:gd,finalize:hd,breakpoints:{keys:[`base`,`sm`,`md`,`lg`,`xl`,`2xl`]}},utility:{transform:(e,t)=>{let n=bd(e);return{className:`${vd.get(n)||rd(n)}_${Hu(t)}`}},hasShorthand:!0,toHash:(e,t)=>t(e.join(`:`)),resolveShorthand:bd}},Sd=Qu(xd),V=(...e)=>Sd(Cd(...e));V.raw=(...e)=>Cd(...e);var{mergeCss:Cd,assignCss:eee}=ed(xd);function wd(){let e=``,t=0,n;for(;t({base:{},variants:{},defaultVariants:{},compoundVariants:[],...e});function H(e){let{base:t,variants:n,defaultVariants:r,compoundVariants:i}=Td(e),a=e=>({...r,...Mu(e)});function o(e={}){let r=a(e),o={...t};for(let[e,t]of Object.entries(r))n[e]?.[t]&&(o=Cd(o,n[e][t]));let s=Ed(i,r);return Cd(o,s)}function s(e){let a=Td(e.config),o=od(e.variantKeys,Object.keys(n));return H({base:Cd(t,a.base),variants:Object.fromEntries(o.map(e=>[e,Cd(n[e],a.variants[e])])),defaultVariants:Gu(r,a.defaultVariants),compoundVariants:[...i,...a.compoundVariants]})}function c(e){return V(o(e))}let l=Object.keys(n);function u(e){return ad(e,l)}let d=Object.fromEntries(Object.entries(n).map(([e,t])=>[e,Object.keys(t)]));return Object.assign(Uu(c),{__cva__:!0,variantMap:d,variantKeys:l,raw:o,config:e,merge:s,splitVariantProps:u,getVariantProps:a})}function Ed(e,t){let n={};return e.forEach(e=>{Object.entries(e).every(([e,n])=>e===`css`?!0:(Array.isArray(n)?n:[n]).some(n=>t[e]===n))&&(n=Cd(n,e.css))}),n}var Dd=[],Od=null,kd=null,Ad=Dd,jd=e=>{let t=e.analytics?.attentionQueue??Dd,n=e.suppressedAttentionIds;return Object.keys(n).length===0?t:t===Od&&n===kd?Ad:(Od=t,kd=n,Ad=t.filter(e=>!n[e.id]),Ad)};function Md(e){return e==null?`—`:e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:e<86400?`${Math.round(e/3600)}h`:`${Math.round(e/86400)}d`}var Nd=new Set([`stopped`,`failed`,`error`,`down`,`unreachable`]),Pd=new Set([`indexing`,`indexing-pending`,`reindexing`,`seeding`]);function Fd(e){return e.ok===!1||Nd.has(e.state)?`down`:Pd.has(e.indexingState)?`indexing`:`nominal`}var Id={code:0,memory:1};function Ld(e){return[...e].sort((e,t)=>(Id[e.role??``]??9)-(Id[t.role??``]??9)||e.id.localeCompare(t.id))}function Rd(e){let t=e.filter(e=>e.scope!==`worktree`),n=new Map;for(let t of e){if(t.scope!==`worktree`)continue;let e=t.worktreeGroup??`(worktree)`,r=n.get(e);r?r.push(t):n.set(e,[t])}let r=[];t.length>0&&r.push({key:`workspace`,scope:`workspace`,repoId:null,engines:Ld(t)});for(let[e,t]of[...n.entries()].sort(([e],[t])=>e.localeCompare(t)))r.push({key:e,scope:`worktree`,repoId:t[0]?.repoId??null,engines:Ld(t)});return r}var zd=[`current`,`drifted`,`missingVerification`,`missing`,`orphaned`,`unsupported`];function Bd(e){let t=e?.counts??{},n=Object.values(t).reduce((e,t)=>e+t,0);return n===0?[]:[...new Set([...zd,...Object.keys(t)])].filter(e=>(t[e]??0)>0).map(e=>({cls:e,count:t[e],pct:Math.round(t[e]/n*100)}))}var Vd=e=>{let t,n=new Set,r=(e,r)=>{let i=typeof e==`function`?e(t):e;if(!Object.is(i,t)){let e=t;t=r??(typeof i!=`object`||!i)?i:Object.assign({},t,i),n.forEach(n=>n(t,e))}},i=()=>t,a={setState:r,getState:i,getInitialState:()=>o,subscribe:e=>(n.add(e),()=>n.delete(e))},o=t=e(r,i,a);return a},Hd=(e=>e?Vd(e):Vd),Ud=e=>e;function Wd(e,t=Ud){let n=g.useSyncExternalStore(e.subscribe,g.useCallback(()=>t(e.getState()),[e,t]),g.useCallback(()=>t(e.getInitialState()),[e,t]));return g.useDebugValue(n),n}var Gd=2e3,Kd=(e,t)=>Object.fromEntries(e.map(e=>[t(e),e])),qd=(e,t,n)=>({...e,[n(t)]:t}),Jd=(e,t)=>{if(!(t in e))return e;let n={...e};return delete n[t],n},Yd=(e,t)=>{let n=Object.keys(e);if(n.length===0)return e;let r=new Set((t?.attentionQueue??[]).map(e=>e.id)),i=n.filter(e=>r.has(e));return i.length===n.length?e:Object.fromEntries(i.map(e=>[e,!0]))};function Xd(e,t,n){switch(t){case`lifecycle`:return{lifecycles:qd(e.lifecycles,n,e=>e.id)};case`lifecycle.removed`:return{lifecycles:Jd(e.lifecycles,n.id)};case`enclosure`:return{enclosures:qd(e.enclosures,n,e=>e.enclosure)};case`enclosure.removed`:return{enclosures:Jd(e.enclosures,n.enclosure)};case`provider`:return{providers:qd(e.providers,n,e=>e.id)};case`provider.removed`:return{providers:Jd(e.providers,n.id)};case`activeWorktreeGroups`:return{activeWorktreeGroups:n.activeWorktreeGroups};case`metrics`:return{metrics:n};case`analytics`:{let t=n;return{analytics:t,suppressedAttentionIds:Yd(e.suppressedAttentionIds,t)}}default:return{}}}var Zd=Hd(e=>({conn:`connecting`,generatedAt:null,gen:0,lifecycles:{},enclosures:{},providers:{},activeWorktreeGroups:[],metrics:null,analytics:null,events:[],eventsHydrated:!1,suppressedAttentionIds:{},setConn:t=>e({conn:t}),applySnapshot:t=>e(e=>({conn:`live`,generatedAt:t.generatedAt,lifecycles:Kd(t.lifecycles,e=>e.id),enclosures:Kd(t.enclosures,e=>e.enclosure),providers:Kd(t.providers,e=>e.id),activeWorktreeGroups:t.activeWorktreeGroups??[],metrics:t.metrics,analytics:t.analytics,suppressedAttentionIds:Yd(e.suppressedAttentionIds,t.analytics)})),applyDelta:(t,n)=>e(e=>Xd(e,t,n)),pushEvent:t=>e(e=>{try{let n=JSON.parse(t),r=[...e.events,n];return{events:r.length>Gd?r.slice(r.length-Gd):r,eventsHydrated:!0}}catch{return{}}}),markEventsHydrated:()=>e({eventsHydrated:!0}),suppressAttention:t=>e(e=>({suppressedAttentionIds:{...e.suppressedAttentionIds,...Object.fromEntries(t.map(e=>[e,!0]))}})),releaseAttention:t=>e(e=>{let n={...e.suppressedAttentionIds};for(let e of t)delete n[e];return{suppressedAttentionIds:n}}),reset:()=>e(e=>({gen:e.gen+1,generatedAt:null,lifecycles:{},enclosures:{},providers:{},activeWorktreeGroups:[],metrics:null,analytics:null,events:[],eventsHydrated:!1,suppressedAttentionIds:{}}))})),Qd=e=>Wd(Zd,e),$d=[`lifecycle`,`lifecycle.removed`,`enclosure`,`enclosure.removed`,`provider`,`provider.removed`,`activeWorktreeGroups`,`metrics`,`analytics`];function ef(e=``){let t=new EventSource(`${e}/api/stream`),n=Zd.getState();t.addEventListener(`snapshot`,e=>{n.applySnapshot(JSON.parse(e.data))});for(let e of $d)t.addEventListener(e,t=>{n.applyDelta(e,JSON.parse(t.data))});return t.addEventListener(`open`,()=>n.setConn(`live`)),t.addEventListener(`error`,()=>n.setConn(`signal-lost`)),()=>t.close()}function tf(e,t=``,n){let r=new EventSource(`${t}/api/events`);return r.addEventListener(`event`,t=>e(t.data)),r.addEventListener(`ready`,()=>n?.()),()=>r.close()}var nf=`taskdoc:`,rf=`series:`,af=`lifecycle:`,of=e=>`${nf}${e}`,sf=e=>`${rf}${e}`,cf=e=>`${af}${e}`;function lf(e,t,n){return e?e.startsWith(nf)?{kind:`taskdoc`,docPath:e.slice(8)}:e.startsWith(rf)?{kind:`series`,seriesId:e.slice(7)}:e.startsWith(af)?{kind:`lifecycle`,lifecycleId:e.slice(10)}:t[e]?{kind:`lifecycle`,lifecycleId:e}:n?.series.some(t=>t.seriesId===e)?{kind:`series`,seriesId:e}:n?.taskDocuments.some(t=>t.docPath===e)?{kind:`taskdoc`,docPath:e}:null:null}function uf(e,t,n){let r=lf(e,t,n);if(r?.kind===`lifecycle`)return r.lifecycleId;if(r?.kind===`taskdoc`)return n?.taskDocuments.find(e=>e.docPath===r.docPath)?.lifecycleId}function df(e){let t=e.docPath.split(`/`).slice(0,-1).filter(Boolean).pop()??``;if(!(!e.repository||!t||!e.id))return`${e.repository}/${t}/${e.id}`}function ff(e,t){return e.find(e=>df(e)===t)?.title}function pf(e){return e.split(`/`).filter(Boolean).pop()??e}var mf=e=>e.docPath.split(`/`).slice(0,-1).filter(Boolean).pop()??``;function hf(e){let t=new Map,n=new Map,r=new Map;for(let i of e){if(i.kind!==`master`)continue;let e=mf(i);if(!e||t.has(e))continue;let a={key:e,title:i.title||e,master:e,children:[]};t.set(e,a),r.set(e,i),i.lifecycleId&&n.set(i.lifecycleId,a)}let i=new Set;for(let[e,a]of t){let t=r.get(e)?.masterLifecycleId,o=t?n.get(t):void 0;o&&o!==a&&(o.children.push(a),i.add(a))}let a=[];for(let r of e){if(r.kind!==`subTask`)continue;let e=df(r);if(!e)continue;let i={key:e,title:r.title||pf(e),leafKey:e,children:[]},o=t.get(mf(r))??(r.masterLifecycleId?n.get(r.masterLifecycleId):void 0);o?o.children.push(i):a.push(i)}return[...[...t.values()].filter(e=>!i.has(e)),...a]}function gf(e,t){for(let n of e){if(n.master===t)return[n];let e=gf(n.children,t);if(e.length)return[n,...e]}return[]}function _f(e,t,n){let r=lf(e,t,n);if(!r)return;let i=n?.taskDocuments??[],a;return r.kind===`taskdoc`?a=i.find(e=>e.docPath===r.docPath):r.kind===`lifecycle`&&(a=i.find(e=>e.lifecycleId===r.lifecycleId)),a&&mf(a)||void 0}function vf(e){let t=new Map;for(let n of e)n.lifecycleId&&t.set(n.lifecycleId,n);return t}function yf(e,t,n){return e.enclosure&&t[e.enclosure]?t[e.enclosure]:n.get(e.id)}function bf(e,t,n){return n?e.id===n.taskId||e.id===n.taskName||t.length>1?n.taskName||n.taskId||Cf(e.id):n.leafId||n.enclosureId||n.taskName||Cf(e.id):Sf(t,Cf(e.id))}function xf(e,t){return t.filter(t=>t.lifecycleId===e.id)}function Sf(e,t){let n=e.find(e=>e.kind===`master`);return n?.title?n.title:e.length===1&&e[0].title?e[0].title:t}function Cf(e){return e.includes(`/`)?e.slice(e.indexOf(`/`)+1):e}function wf(...e){return(...t)=>{for(let n of e)typeof n==`function`&&n(...t)}}var Tf=typeof document<`u`?g.useLayoutEffect:()=>{},Ef={prefix:String(Math.round(Math.random()*1e10)),current:0},Df=g.createContext(Ef),Of=g.createContext(!1);typeof window<`u`&&window.document&&window.document.createElement;var kf=new WeakMap;function Af(e=!1){let t=(0,g.useContext)(Df),n=(0,g.useRef)(null);if(n.current===null&&!e){let e=g.default.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?.ReactCurrentOwner?.current;if(e){let n=kf.get(e);n==null?kf.set(e,{id:t.current,state:e.memoizedState}):e.memoizedState!==n.state&&(t.current=n.id,kf.delete(e))}n.current=++t.current}return n.current}function jf(e){let t=(0,g.useContext)(Df),n=Af(!!e),r=`react-aria${t.prefix}`;return e||`${r}-${n}`}function Mf(e){let t=g.useId(),[n]=(0,g.useState)(Lf()),r=n?`react-aria`:`react-aria${Ef.prefix}`;return e||`${r}-${t}`}var Nf=typeof g.useId==`function`?Mf:jf;function Pf(){return!1}function Ff(){return!0}function If(e){return()=>{}}function Lf(){return typeof g.useSyncExternalStore==`function`?g.useSyncExternalStore(If,Pf,Ff):(0,g.useContext)(Of)}function Rf(e){let[t,n]=(0,g.useState)(e),r=(0,g.useRef)(t),i=(0,g.useRef)(null),a=(0,g.useRef)(()=>{if(!i.current)return;let e=i.current.next();if(e.done){i.current=null;return}r.current===e.value?a.current():n(e.value)});return Tf(()=>{r.current=t,i.current&&a.current()}),[t,(0,g.useCallback)(e=>{i.current=e(r.current),a.current()},[a])]}var zf=!!(typeof window<`u`&&window.document&&window.document.createElement),Bf=new Map,Vf;typeof FinalizationRegistry<`u`&&(Vf=new FinalizationRegistry(e=>{Bf.delete(e)}));function Hf(e){let[t,n]=(0,g.useState)(e),r=(0,g.useRef)(null),i=Nf(t),a=(0,g.useRef)(null);if(Vf&&Vf.register(a,i),zf){let e=Bf.get(i);e&&!e.includes(r)?e.push(r):Bf.set(i,[r])}return Tf(()=>{let e=i;return()=>{Vf&&Vf.unregister(a),Bf.delete(e)}},[i]),(0,g.useEffect)(()=>{let e=r.current;return e&&n(e),()=>{e&&(r.current=null)}}),i}function Uf(e,t){if(e===t)return e;let n=Bf.get(e);if(n)return n.forEach(e=>e.current=t),t;let r=Bf.get(t);return r?(r.forEach(t=>t.current=e),e):t}function Wf(e=[]){let t=Hf(),[n,r]=Rf(t),i=(0,g.useCallback)(()=>{r(function*(){yield t,yield document.getElementById(t)?t:void 0})},[t,r]);return Tf(i,[t,i,...e]),n}function Gf(...e){return e.length===1&&e[0]?e[0]:t=>{let n=!1,r=e.map(e=>{let r=Kf(e,t);return n||=typeof r==`function`,r});if(n)return()=>{r.forEach((t,n)=>{typeof t==`function`?t():Kf(e[n],null)})}}}function Kf(e,t){if(typeof e==`function`)return e(t);e!=null&&(e.current=t)}function qf(e){var t,n,r=``;if(typeof e==`string`||typeof e==`number`)r+=e;else if(typeof e==`object`)if(Array.isArray(e)){var i=e.length;for(t=0;t=65&&e.charCodeAt(2)<=90?t[e]=wf(n,i):(e===`className`||e===`UNSAFE_className`)&&typeof n==`string`&&typeof i==`string`?t[e]=Jf(n,i):e===`id`&&n&&i?t.id=Uf(n,i):e===`ref`&&n&&i?t.ref=Gf(n,i):t[e]=i===void 0?n:i}}return t}function Xf(e){let t=(0,g.useRef)(null),n=(0,g.useRef)(void 0),r=(0,g.useCallback)(t=>{if(typeof e==`function`){let n=e,r=n(t);return()=>{typeof r==`function`?r():n(null)}}else if(e)return e.current=t,()=>{e.current=null}},[e]);return(0,g.useMemo)(()=>({get current(){return t.current},set current(e){t.current=e,n.current&&=(n.current(),void 0),e!=null&&(n.current=r(e))}}),[r])}var Zf=Symbol(`default`);function Qf({values:e,children:t}){for(let[n,r]of e)t=g.createElement(n.Provider,{value:r},t);return t}function $f(e){let{className:t,style:n,children:r,defaultClassName:i,defaultChildren:a,defaultStyle:o,values:s,render:c}=e;return(0,g.useMemo)(()=>{let e,l,u;return e=typeof t==`function`?t({...s,defaultClassName:i}):t,l=typeof n==`function`?n({...s,defaultStyle:o||{}}):n,u=typeof r==`function`?r({...s,defaultChildren:a}):r??a,{className:e??i,style:l||o?{...o,...l}:void 0,children:u??a,"data-rac":``,render:c?e=>c(e,s):void 0}},[t,n,r,i,a,o,s,c])}function ep(e,t){let n=(0,g.useContext)(e);if(t===null)return null;if(n&&typeof n==`object`&&`slots`in n&&n.slots){let e=t||Zf;if(!n.slots[e]){let e=new Intl.ListFormat().format(Object.keys(n.slots).map(e=>`"${e}"`)),r=t?`Invalid slot "${t}".`:`A slot prop is required.`;throw Error(`${r} Valid slot names are ${e}.`)}return n.slots[e]}return n}function tp(e,t,n){let{ref:r,...i}=ep(n,e.slot)||{},a=Xf((0,g.useMemo)(()=>Gf(t,r),[t,r])),o=Yf(i,e);return`style`in i&&i.style&&`style`in e&&e.style&&(typeof i.style==`function`||typeof e.style==`function`?o.style=t=>{let n=typeof i.style==`function`?i.style(t):i.style,r={...t.defaultStyle,...n},a=typeof e.style==`function`?e.style({...t,defaultStyle:r}):e.style;return{...r,...a}}:o.style={...i.style,...e.style}),[o,a]}function np(e=!0){let[t,n]=(0,g.useState)(e),r=(0,g.useRef)(!1),i=(0,g.useCallback)(e=>{r.current=!0,n(!!e)},[]);return Tf(()=>{r.current||n(!1)},[]),[i,t]}function rp(e){let t=/^(data-.*)$/,n={};for(let r in e)t.test(r)||(n[r]=e[r]);return n}function ip(e,t,n){let{render:r,...i}=t,a=(0,g.useRef)(null),o=(0,g.useMemo)(()=>Gf(n,a),[n,a]);Tf(()=>{},[e,r]);let s={...i,ref:o};return r?r(s,void 0):g.createElement(e,s)}var ap={},op=new Proxy({},{get(e,t){if(typeof t!=`string`)return;let n=ap[t];return n||(n=(0,g.forwardRef)(ip.bind(null,t)),ap[t]=n),n}}),sp=`react-aria-clear-focus`,cp=`react-aria-focus`,lp=e=>e?.ownerDocument??document,up=e=>e&&`window`in e&&e.window===e?e:lp(e).defaultView||window;function dp(e){return typeof e==`object`&&!!e&&`nodeType`in e&&typeof e.nodeType==`number`}function fp(e){return dp(e)&&e.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&`host`in e}var pp=!1;function mp(){return pp}function U(e,t){if(!mp())return t&&e?e.contains(t):!1;if(!e||!t)return!1;let n=t;for(;n!==null;){if(n===e)return!0;n=n.tagName===`SLOT`&&n.assignedSlot?n.assignedSlot.parentNode:fp(n)?n.host:n.parentNode}return!1}var hp=(e=document)=>{if(!mp())return e.activeElement;let t=e.activeElement;for(;t&&`shadowRoot`in t&&t.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t};function W(e){if(mp()&&e.target instanceof Element&&e.target.shadowRoot){if(`composedPath`in e)return e.composedPath()[0]??null;if(`composedPath`in e.nativeEvent)return e.nativeEvent.composedPath()[0]??null}return e.target}function gp(e){if(!e)return!1;let t=e.getRootNode(),n=up(e);if(!(t instanceof n.Document||t instanceof n.ShadowRoot))return!1;let r=t.activeElement;return r!=null&&e.contains(r)}function _p(e){let t=bp(lp(e));t!==e&&(t&&vp(t,e),e&&yp(e,t))}function vp(e,t){e.dispatchEvent(new FocusEvent(`blur`,{relatedTarget:t})),e.dispatchEvent(new FocusEvent(`focusout`,{bubbles:!0,relatedTarget:t}))}function yp(e,t){e.dispatchEvent(new FocusEvent(`focus`,{relatedTarget:t})),e.dispatchEvent(new FocusEvent(`focusin`,{bubbles:!0,relatedTarget:t}))}function bp(e){let t=hp(e),n=t?.getAttribute(`aria-activedescendant`);return n&&e.getElementById(n)||t}function xp(e){if(Cp())e.focus({preventScroll:!0});else{let t=wp(e);e.focus(),Tp(t)}}var Sp=null;function Cp(){if(Sp==null){Sp=!1;try{document.createElement(`div`).focus({get preventScroll(){return Sp=!0,!0}})}catch{}}return Sp}function wp(e){let t=e.parentNode,n=[],r=document.scrollingElement||document.documentElement;for(;t instanceof HTMLElement&&t!==r;)(t.offsetHeightt.defaultPrevented,t.isPropagationStopped=()=>t.cancelBubble,t.persist=()=>{},t}function Lp(e,t){Object.defineProperty(e,"target",{value:t}),Object.defineProperty(e,"currentTarget",{value:t})}function Rp(e){let t=(0,g.useRef)({isFocused:!1,observer:null});return Tf(()=>{let e=t.current;return()=>{e.observer&&=(e.observer.disconnect(),null)}},[]),(0,g.useCallback)(n=>{let r=W(n);if(r instanceof HTMLButtonElement||r instanceof HTMLInputElement||r instanceof HTMLTextAreaElement||r instanceof HTMLSelectElement){t.current.isFocused=!0;let n=r;n.addEventListener(`focusout`,r=>{if(t.current.isFocused=!1,n.disabled){let t=Ip(r);e?.(t)}t.current.observer&&(t.current.observer.disconnect(),t.current.observer=null)},{once:!0}),t.current.observer=new MutationObserver(()=>{if(t.current.isFocused&&n.disabled){t.current.observer?.disconnect();let e=n===hp()?null:hp();n.dispatchEvent(new FocusEvent(`blur`,{relatedTarget:e})),n.dispatchEvent(new FocusEvent(`focusout`,{bubbles:!0,relatedTarget:e}))}}),t.current.observer.observe(n,{attributes:!0,attributeFilter:[`disabled`]})}},[e])}var zp=!1;function Bp(e){for(;e&&!Np(e,{skipVisibilityCheck:!0});)e=e.parentElement;let t=up(e),n=t.document.activeElement;if(!n||n===e)return;zp=!0;let r=!1,i=e=>{(W(e)===n||r)&&e.stopImmediatePropagation()},a=t=>{(W(t)===n||r)&&(t.stopImmediatePropagation(),!e&&!r&&(r=!0,xp(n),c()))},o=t=>{(W(t)===e||r)&&t.stopImmediatePropagation()},s=t=>{(W(t)===e||r)&&(t.stopImmediatePropagation(),r||(r=!0,xp(n),c()))};t.addEventListener(`blur`,i,!0),t.addEventListener(`focusout`,a,!0),t.addEventListener(`focusin`,s,!0),t.addEventListener(`focus`,o,!0);let c=()=>{cancelAnimationFrame(l),t.removeEventListener(`blur`,i,!0),t.removeEventListener(`focusout`,a,!0),t.removeEventListener(`focusin`,s,!0),t.removeEventListener(`focus`,o,!0),zp=!1,r=!1},l=requestAnimationFrame(c);return c}function Vp(e){if(typeof window>`u`||window.navigator==null)return!1;let t=window.navigator.userAgentData?.brands;return Array.isArray(t)&&t.some(t=>e.test(t.brand))||e.test(window.navigator.userAgent)}function Hp(e){return typeof window<`u`&&window.navigator!=null?e.test(window.navigator.userAgentData?.platform||window.navigator.platform):!1}function Up(e){let t=null;return()=>(t??=e(),t)}var Wp=Up(function(){return Hp(/^Mac/i)}),Gp=Up(function(){return Hp(/^iPhone/i)}),Kp=Up(function(){return Hp(/^iPad/i)||Wp()&&navigator.maxTouchPoints>1}),qp=Up(function(){return Gp()||Kp()}),Jp=Up(function(){return Wp()||qp()}),Yp=Up(function(){return Vp(/AppleWebKit/i)&&!Xp()}),Xp=Up(function(){return Vp(/Chrome/i)}),Zp=Up(function(){return Vp(/Android/i)}),Qp=Up(function(){return Vp(/Firefox/i)});function $p(e){return e.pointerType===``&&e.isTrusted?!0:Zp()&&e.pointerType?e.type===`click`&&e.buttons===1:e.detail===0&&!e.pointerType}function em(e){return!Zp()&&e.width===0&&e.height===0||e.width===1&&e.height===1&&e.pressure===0&&e.detail===0&&e.pointerType===`mouse`}var tm=(0,g.createContext)({isNative:!0,open:am,useHref:e=>e});function nm(){return(0,g.useContext)(tm)}function rm(e,t,n=!0){let{metaKey:r,ctrlKey:i,altKey:a,shiftKey:o}=t;Qp()&&window.event?.type?.startsWith(`key`)&&e.target===`_blank`&&(Wp()?r=!0:i=!0);let s=Yp()&&Wp()&&!Kp()?new KeyboardEvent(`keydown`,{keyIdentifier:`Enter`,metaKey:r,ctrlKey:i,altKey:a,shiftKey:o}):new MouseEvent(`click`,{metaKey:r,ctrlKey:i,altKey:a,shiftKey:o,detail:1,bubbles:!0,cancelable:!0});rm.isOpening=n,xp(e),e.dispatchEvent(s),rm.isOpening=!1}rm.isOpening=!1;function im(e,t){if(e instanceof HTMLAnchorElement)t(e);else if(e.hasAttribute(`data-href`)){let n=document.createElement(`a`);n.href=e.getAttribute(`data-href`),e.hasAttribute(`data-target`)&&(n.target=e.getAttribute(`data-target`)),e.hasAttribute(`data-rel`)&&(n.rel=e.getAttribute(`data-rel`)),e.hasAttribute(`data-download`)&&(n.download=e.getAttribute(`data-download`)),e.hasAttribute(`data-ping`)&&(n.ping=e.getAttribute(`data-ping`)),e.hasAttribute(`data-referrer-policy`)&&(n.referrerPolicy=e.getAttribute(`data-referrer-policy`)),e.appendChild(n),t(n),e.removeChild(n)}}function am(e,t){im(e,e=>rm(e,t))}function om(e){let t=nm().useHref(e.href??``);return{"data-href":e.href?t:void 0,"data-target":e.target,"data-rel":e.rel,"data-download":e.download,"data-ping":e.ping,"data-referrer-policy":e.referrerPolicy}}function sm(e){let t=nm().useHref(e?.href??``),n={};if(e)for(let r of[`href`,`target`,`rel`,`download`,`ping`,`referrerPolicy`])r in e&&(n[r]=r===`href`?t:e[r]);return n}var cm=null,lm=new Set,um=new Map,dm=!1,fm=!1,pm={Tab:!0,Escape:!0};function mm(e,t){for(let n of lm)n(e,t)}function hm(e){return!(e.metaKey||!Wp()&&e.altKey||e.ctrlKey||e.key===`Control`||e.key===`Shift`||e.key===`Meta`)}function gm(e){dm=!0,!rm.isOpening&&hm(e)&&(cm=`keyboard`,mm(`keyboard`,e))}function _m(e){cm=`pointer`,`pointerType`in e&&e.pointerType,(e.type===`mousedown`||e.type===`pointerdown`)&&(dm=!0,mm(`pointer`,e))}function vm(e){!rm.isOpening&&$p(e)&&(dm=!0,cm=`virtual`)}function ym(e){let t=up(W(e)),n=lp(W(e));W(e)===t||W(e)===n||zp||!e.isTrusted||(!dm&&!fm&&(cm=`virtual`,mm(`virtual`,e)),dm=!1,fm=!1)}function bm(){zp||(dm=!1,fm=!0)}function xm(e){if(typeof window>`u`||typeof document>`u`)return;let t=up(e),n=lp(e);if(um.get(t))return;let r=t.HTMLElement.prototype.focus;t.HTMLElement.prototype.focus=function(){dm=!0,r.apply(this,arguments)},n.addEventListener(`keydown`,gm,!0),n.addEventListener(`keyup`,gm,!0),n.addEventListener(`click`,vm,!0),t.addEventListener(`focus`,ym,!0),t.addEventListener(`blur`,bm,!1),typeof PointerEvent<`u`&&(n.addEventListener(`pointerdown`,_m,!0),n.addEventListener(`pointermove`,_m,!0),n.addEventListener(`pointerup`,_m,!0)),t.addEventListener(`beforeunload`,()=>{Sm(e)},{once:!0}),um.set(t,{focus:r})}var Sm=(e,t)=>{let n=up(e),r=lp(e);t&&r.removeEventListener(`DOMContentLoaded`,t),um.has(n)&&(n.HTMLElement.prototype.focus=um.get(n).focus,r.removeEventListener(`keydown`,gm,!0),r.removeEventListener(`keyup`,gm,!0),r.removeEventListener(`click`,vm,!0),n.removeEventListener(`focus`,ym,!0),n.removeEventListener(`blur`,bm,!1),typeof PointerEvent<`u`&&(r.removeEventListener(`pointerdown`,_m,!0),r.removeEventListener(`pointermove`,_m,!0),r.removeEventListener(`pointerup`,_m,!0)),um.delete(n))};function Cm(e){let t=lp(e),n;return t.readyState===`loading`?(n=()=>{xm(e)},t.addEventListener(`DOMContentLoaded`,n)):xm(e),()=>Sm(e,n)}typeof document<`u`&&Cm();function wm(){return cm!==`pointer`}function Tm(){return cm}function Em(e){cm=e,mm(e,null)}function Dm(){xm();let[e,t]=(0,g.useState)(cm);return(0,g.useEffect)(()=>{let e=()=>{t(cm)};return lm.add(e),()=>{lm.delete(e)}},[]),Lf()?null:e}var Om=new Set([`checkbox`,`radio`,`range`,`color`,`file`,`image`,`button`,`submit`,`reset`]);function km(e,t,n){let r=n?W(n):void 0,i=lp(r),a=up(r),o=a===void 0?HTMLInputElement:a.HTMLInputElement,s=a===void 0?HTMLTextAreaElement:a.HTMLTextAreaElement,c=a===void 0?HTMLElement:a.HTMLElement,l=a===void 0?KeyboardEvent:a.KeyboardEvent,u=hp(i);return e=e||u instanceof o&&!Om.has(u.type)||u instanceof s||u instanceof c&&u.isContentEditable,!(e&&t===`keyboard`&&n instanceof l&&!pm[n.key])}function Am(e,t,n){xm(),(0,g.useEffect)(()=>{if(n?.enabled===!1)return;let t=(t,r)=>{km(!!n?.isTextInput,t,r)&&e(wm())};return lm.add(t),()=>{lm.delete(t)}},t)}function jm(e){return Wp()?e.metaKey:e.ctrlKey}var Mm=new Set([`checkbox`,`radio`,`range`,`color`,`file`,`image`,`button`,`submit`,`reset`]);function Nm(e){return e instanceof HTMLInputElement&&!Mm.has(e.type)||e instanceof HTMLTextAreaElement||e instanceof HTMLElement&&e.isContentEditable}var tee=g.useInsertionEffect??Tf;function Pm(e){let t=(0,g.useRef)(null);return tee(()=>{t.current=e},[e]),(0,g.useCallback)((...e)=>{let n=t.current;return n?.(...e)},[])}function Fm(e,t,n,r){let i=Pm(n),a=n==null;(0,g.useEffect)(()=>{if(a||!e.current)return;let n=e.current;return n.addEventListener(t,i,r),()=>{n.removeEventListener(t,i,r)}},[e,t,r,a])}function Im(e,t){let{id:n,"aria-label":r,"aria-labelledby":i}=e;return n=Hf(n),i&&r?i=[...new Set([n,...i.trim().split(/\s+/)])].join(` `):i&&=i.trim().split(/\s+/).join(` `),!r&&!i&&t&&(r=t),{id:n,"aria-label":r,"aria-labelledby":i}}var nee=new Set([`Arab`,`Syrc`,`Samr`,`Mand`,`Thaa`,`Mend`,`Nkoo`,`Adlm`,`Rohg`,`Hebr`]),ree=new Set([`ae`,`ar`,`arc`,`bcc`,`bqi`,`ckb`,`dv`,`fa`,`glk`,`he`,`ku`,`mzn`,`nqo`,`pnb`,`ps`,`sd`,`ug`,`ur`,`yi`]);function iee(e){if(Intl.Locale){let t=new Intl.Locale(e).maximize(),n=typeof t.getTextInfo==`function`?t.getTextInfo():t.textInfo;if(n)return n.direction===`rtl`;if(t.script)return nee.has(t.script)}let t=e.split(`-`)[0];return ree.has(t)}var Lm=Symbol.for(`react-aria.i18n.locale`);function Rm(){let e=typeof window<`u`&&window[Lm]||typeof navigator<`u`&&(navigator.language||navigator.userLanguage)||`en-US`;try{Intl.DateTimeFormat.supportedLocalesOf([e])}catch{e=`en-US`}return{locale:e,direction:iee(e)?`rtl`:`ltr`}}var zm=Rm(),Bm=new Set;function Vm(){zm=Rm();for(let e of Bm)e(zm)}function Hm(){let e=Lf(),[t,n]=(0,g.useState)(zm);return(0,g.useEffect)(()=>(Bm.size===0&&window.addEventListener(`languagechange`,Vm),Bm.add(n),()=>{Bm.delete(n),Bm.size===0&&window.removeEventListener(`languagechange`,Vm)}),[]),e?{locale:typeof window<`u`&&window[Lm]||`en-US`,direction:`ltr`}:t}var Um=g.createContext(null);function Wm(){let e=Hm();return(0,g.useContext)(Um)||e}var Gm=Symbol.for(`react-aria.i18n.locale`),Km=Symbol.for(`react-aria.i18n.strings`),qm=void 0,Jm=class e{constructor(e,t=`en-US`){this.strings=Object.fromEntries(Object.entries(e).filter(([,e])=>e)),this.defaultLocale=t}getStringForLocale(e,t){let n=this.getStringsForLocale(t)[e];if(!n)throw Error(`Could not find intl message ${e} in ${t} locale`);return n}getStringsForLocale(e){let t=this.strings[e];return t||(t=Ym(e,this.strings,this.defaultLocale),this.strings[e]=t),t}static getGlobalDictionaryForPackage(t){if(typeof window>`u`)return null;let n=window[Gm];if(qm===void 0){let t=window[Km];if(!t)return null;qm={};for(let r in t)qm[r]=new e({[n]:t[r]},n)}let r=qm?.[t];if(!r)throw Error(`Strings for package "${t}" were not included by LocalizedStringProvider. Please add it to the list passed to createLocalizedStringDictionary.`);return r}};function Ym(e,t,n=`en-US`){if(t[e])return t[e];let r=Xm(e);if(t[r])return t[r];for(let e in t)if(e.startsWith(r+`-`))return t[e];return t[n]}function Xm(e){return Intl.Locale?new Intl.Locale(e).language:e.split(`-`)[0]}var Zm=new Map,Qm=new Map,$m=class{constructor(e,t){this.locale=e,this.strings=t}format(e,t){let n=this.strings.getStringForLocale(e,this.locale);return typeof n==`function`?n(t,this):n}plural(e,t,n=`cardinal`){let r=t[`=`+e];if(r)return typeof r==`function`?r():r;let i=this.locale+`:`+n,a=Zm.get(i);return a||(a=new Intl.PluralRules(this.locale,{type:n}),Zm.set(i,a)),r=t[a.select(e)]||t.other,typeof r==`function`?r():r}number(e){let t=Qm.get(this.locale);return t||(t=new Intl.NumberFormat(this.locale),Qm.set(this.locale,t)),t.format(e)}select(e,t){let n=e[t]||e.other;return typeof n==`function`?n():n}},eh=new WeakMap;function th(e){let t=eh.get(e);return t||(t=new Jm(e),eh.set(e,t)),t}function nh(e,t){return t&&Jm.getGlobalDictionaryForPackage(t)||th(e)}function rh(e,t){let{locale:n}=Wm(),r=nh(e,t);return(0,g.useMemo)(()=>new $m(n,r),[n,r])}var ih=typeof document<`u`?g.useInsertionEffect??g.useLayoutEffect:()=>{};function ah(e,t,n){let[r,i]=(0,g.useState)(e||t),a=(0,g.useRef)(r),o=(0,g.useRef)(e!==void 0),s=e!==void 0;(0,g.useEffect)(()=>{o.current,o.current=s},[s]);let c=s?e:r;ih(()=>{a.current=c});let[,l]=(0,g.useReducer)(()=>({}),{});return[c,(0,g.useCallback)((e,...t)=>{let r=typeof e==`function`?e(a.current):e;Object.is(a.current,r)||(a.current=r,i(r),l(),n?.(r,...t))},[n])]}var oh=(0,g.createContext)(null),sh=(0,g.createContext)(null),ch=class{constructor(e){this.value=null,this.level=0,this.hasChildNodes=!1,this.rendered=null,this.textValue=``,this[`aria-label`]=void 0,this.index=0,this.parentKey=null,this.prevKey=null,this.nextKey=null,this.firstChildKey=null,this.lastChildKey=null,this.props={},this.colSpan=null,this.colIndex=null,this.type=this.constructor.type,this.key=e}get childNodes(){throw Error(`childNodes is not supported`)}clone(){let e=new this.constructor(this.key);return e.value=this.value,e.level=this.level,e.hasChildNodes=this.hasChildNodes,e.rendered=this.rendered,e.textValue=this.textValue,e[`aria-label`]=this[`aria-label`],e.index=this.index,e.parentKey=this.parentKey,e.prevKey=this.prevKey,e.nextKey=this.nextKey,e.firstChildKey=this.firstChildKey,e.lastChildKey=this.lastChildKey,e.props=this.props,e.render=this.render,e.colSpan=this.colSpan,e.colIndex=this.colIndex,e}filter(e,t,n){let r=this.clone();return t.addDescendants(r,e),r}},lh=class extends ch{filter(e,t,n){let[r,i]=mh(e,t,this.firstChildKey,n),a=this.clone();return a.firstChildKey=r,a.lastChildKey=i,a}},aee=class extends ch{static{this.type=`header`}},uh=class extends ch{static{this.type=`loader`}},dh=class extends lh{static{this.type=`item`}filter(e,t,n){if(n(this.textValue,this)){let n=this.clone();return t.addDescendants(n,e),n}return null}},fh=class extends lh{static{this.type=`section`}filter(e,t,n){let r=super.filter(e,t,n);if(r&&r.lastChildKey!==null){let t=e.getItem(r.lastChildKey);if(t&&t.type!==`header`)return r}return null}},ph=class{get size(){return this.itemCount}getKeys(){return this.keyMap.keys()}*[Symbol.iterator](){let e=this.firstKey==null?void 0:this.keyMap.get(this.firstKey);for(;e;)yield e,e=e.nextKey==null?void 0:this.keyMap.get(e.nextKey)}getChildren(e){let t=this.keyMap;return{*[Symbol.iterator](){let n=t.get(e),r=n?.firstChildKey==null?null:t.get(n.firstChildKey);for(;r;)yield r,r=r.nextKey==null?void 0:t.get(r.nextKey)}}}getKeyBefore(e){let t=this.keyMap.get(e);if(!t)return null;if(t.prevKey!=null){for(t=this.keyMap.get(t.prevKey);t&&t.type!==`item`&&t.lastChildKey!=null;)t=this.keyMap.get(t.lastChildKey);return t?.key??null}return t.parentKey}getKeyAfter(e){let t=this.keyMap.get(e);if(!t)return null;if(t.type!==`item`&&t.firstChildKey!=null)return t.firstChildKey;for(;t;){if(t.nextKey!=null)return t.nextKey;if(t.parentKey!=null)t=this.keyMap.get(t.parentKey);else return null}return null}getFirstKey(){return this.firstKey}getLastKey(){let e=this.lastKey==null?null:this.keyMap.get(this.lastKey);for(;e?.lastChildKey!=null;)e=this.keyMap.get(e.lastChildKey);return e?.key??null}getItem(e){return this.keyMap.get(e)??null}at(){throw Error(`Not implemented`)}clone(){let e=this.constructor,t=new e;return t.keyMap=new Map(this.keyMap),t.firstKey=this.firstKey,t.lastKey=this.lastKey,t.itemCount=this.itemCount,t}addNode(e){if(this.frozen)throw Error(`Cannot add a node to a frozen collection`);e.type===`item`&&this.keyMap.get(e.key)==null&&this.itemCount++,this.keyMap.set(e.key,e)}addDescendants(e,t){this.addNode(e);let n=t.getChildren(e.key);for(let e of n)this.addDescendants(e,t)}removeNode(e){if(this.frozen)throw Error(`Cannot remove a node to a frozen collection`);let t=this.keyMap.get(e);t!=null&&t.type===`item`&&this.itemCount--,this.keyMap.delete(e)}commit(e,t,n=!1){if(this.frozen)throw Error(`Cannot commit a frozen collection`);this.firstKey=e,this.lastKey=t,this.frozen=!n}filter(e){let t=new this.constructor,[n,r]=mh(this,t,this.firstKey,e);return t?.commit(n,r),t}constructor(){this.keyMap=new Map,this.firstKey=null,this.lastKey=null,this.frozen=!1,this.itemCount=0}};function mh(e,t,n,r){if(n==null)return[null,null];let i=null,a=null,o=e.getItem(n);for(;o!=null;){let n=o.filter(e,t,r);n!=null&&(n.nextKey=null,a&&(n.prevKey=a.key,a.nextKey=n.key),i??=n,t.addNode(n),a=n),o=o.nextKey==null?null:e.getItem(o.nextKey)}if(a&&a.type===`separator`){let e=a.prevKey;t.removeNode(a.key),e==null?a=null:(a=t.getItem(e),a.nextKey=null)}return[i?.key??null,a?.key??null]}var hh=class{constructor(e){this._firstChild=null,this._lastChild=null,this._previousSibling=null,this._nextSibling=null,this._parentNode=null,this._minInvalidChildIndex=null,this.ownerDocument=e}*[Symbol.iterator](){let e=this.firstChild;for(;e;)yield e,e=e.nextSibling}get firstChild(){return this._firstChild}set firstChild(e){this._firstChild=e,this.ownerDocument.markDirty(this)}get lastChild(){return this._lastChild}set lastChild(e){this._lastChild=e,this.ownerDocument.markDirty(this)}get previousSibling(){return this._previousSibling}set previousSibling(e){this._previousSibling=e,this.ownerDocument.markDirty(this)}get nextSibling(){return this._nextSibling}set nextSibling(e){this._nextSibling=e,this.ownerDocument.markDirty(this)}get parentNode(){return this._parentNode}set parentNode(e){this._parentNode=e,this.ownerDocument.markDirty(this)}get isConnected(){return this.parentNode?.isConnected||!1}invalidateChildIndices(e){(this._minInvalidChildIndex==null||!this._minInvalidChildIndex.isConnected||e.indexthis.subscriptions.delete(e)}resetAfterSSR(){this.isSSR&&(this.isSSR=!1,this.firstChild=null,this.lastChild=null,this.nodeId=0)}};function vh(e){let{children:t,items:n,idScope:r,addIdAndValue:i,dependencies:a=[]}=e,o=(0,g.useMemo)(()=>void 0,[t]),s=(0,g.useMemo)(()=>new WeakMap,[...a,o]);return(0,g.useMemo)(()=>{if(n&&typeof t==`function`){let e=[];for(let a of n){let n=yh(a)?a:null,o=n?s.get(n):null;if(!o){o=t(a);let c=o.props.id??a?.key??a?.id;r!=null&&o.props.id==null&&c!=null&&(c=r+`:`+c);let l=c??e.length;o=(0,g.cloneElement)(o,i?{key:l,id:c,value:a}:{key:l}),n&&s.set(n,o)}e.push(o)}return e}else if(typeof t!=`function`)return t},[t,n,s,r,i])}function yh(e){switch(typeof e){case`object`:return e!=null;case`function`:case`symbol`:return!0;default:return!1}}var bh=new Map,xh=new Set;function Sh(){if(typeof window>`u`)return;function e(e){return`propertyName`in e}let t=t=>{let r=W(t);if(!e(t)||!r)return;let i=bh.get(r);i||(i=new Set,bh.set(r,i),r.addEventListener(`transitioncancel`,n,{once:!0})),i.add(t.propertyName)},n=t=>{let r=W(t);if(!e(t)||!r)return;let i=bh.get(r);if(i&&(i.delete(t.propertyName),i.size===0&&(r.removeEventListener(`transitioncancel`,n),bh.delete(r)),bh.size===0)){for(let e of xh)e();xh.clear()}};document.body.addEventListener(`transitionrun`,t),document.body.addEventListener(`transitionend`,n)}typeof document<`u`&&(document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,Sh):Sh());function Ch(){for(let[e]of bh)`isConnected`in e&&!e.isConnected&&bh.delete(e)}function wh(e){requestAnimationFrame(()=>{Ch(),bh.size===0?e():xh.add(e)})}function Th(e){if(!e.isConnected)return;let t=lp(e);if(Tm()===`virtual`){let n=hp(t);wh(()=>{let r=hp(t);(r===n||r===t.body)&&e.isConnected&&xp(e)})}else xp(e)}function Eh(e){let{isDisabled:t,onFocus:n,onBlur:r,onFocusChange:i}=e,a=(0,g.useCallback)(e=>{if(W(e)===e.currentTarget)return r&&r(e),i&&i(!1),!0},[r,i]),o=Rp(a),s=(0,g.useCallback)(e=>{let t=W(e),r=lp(t),a=r?hp(r):hp();t===e.currentTarget&&t===a&&(n&&n(e),i&&i(!0),o(e))},[i,n,o]);return{focusProps:{onFocus:!t&&(n||i||r)?s:void 0,onBlur:!t&&(r||i)?a:void 0}}}function Dh(e){if(!e)return;let t=!0;return n=>{e({...n,preventDefault(){n.preventDefault()},isDefaultPrevented(){return n.isDefaultPrevented()},stopPropagation(){t=!0},continuePropagation(){t=!1},isPropagationStopped(){return t}}),t&&n.stopPropagation()}}function Oh(e){return{keyboardProps:e.isDisabled?{}:{onKeyDown:Dh(e.onKeyDown),onKeyUp:Dh(e.onKeyUp)}}}function kh(e,t){Tf(()=>{if(e&&e.ref&&t)return e.ref.current=t.current,()=>{e.ref&&(e.ref.current=null)}})}var Ah=g.createContext(null);function oee(e){let t=(0,g.useContext)(Ah)||{};kh(t,e);let{ref:n,...r}=t;return r}function jh(e,t){let{focusProps:n}=Eh(e),{keyboardProps:r}=Oh(e),i=Yf(n,r),a=oee(t),o=e.isDisabled?{}:a,s=(0,g.useRef)(e.autoFocus);(0,g.useEffect)(()=>{s.current&&t.current&&Th(t.current),s.current=!1},[t]);let c=e.excludeFromTabOrder?-1:0;return e.isDisabled&&(c=void 0),{focusableProps:Yf({...i,tabIndex:c},o)}}typeof HTMLTemplateElement<`u`&&(Object.defineProperty(HTMLTemplateElement.prototype,"firstChild",{configurable:!0,enumerable:!0,get:function(){return this.content.firstChild}}),Object.defineProperty(HTMLTemplateElement.prototype,"appendChild",{configurable:!0,enumerable:!0,value:function(e){return this.content.appendChild(e)}}),Object.defineProperty(HTMLTemplateElement.prototype,"removeChild",{configurable:!0,enumerable:!0,value:function(e){return this.content.removeChild(e)}}),Object.defineProperty(HTMLTemplateElement.prototype,"insertBefore",{configurable:!0,enumerable:!0,value:function(e,t){return this.content.insertBefore(e,t)}}));var Mh=(0,g.createContext)(!1);function see(e){if((0,g.useContext)(Mh))return g.createElement(g.Fragment,null,e.children);let t=g.createElement(Mh.Provider,{value:!0},e.children);return g.createElement(`template`,null,t)}function Nh(e){let t=(t,n)=>(0,g.useContext)(Mh)?null:e(t,n);return t.displayName=e.displayName||e.name,(0,g.forwardRef)(t)}function cee(){return(0,g.useContext)(Mh)}var lee=s((e=>{var t=h();function n(e,t){return e===t&&(e!==0||1/e==1/t)||e!==e&&t!==t}var r=typeof Object.is==`function`?Object.is:n,i=t.useState,a=t.useEffect,o=t.useLayoutEffect,s=t.useDebugValue;function c(e,t){var n=t(),r=i({inst:{value:n,getSnapshot:t}}),c=r[0].inst,u=r[1];return o(function(){c.value=n,c.getSnapshot=t,l(c)&&u({inst:c})},[e,n,t]),a(function(){return l(c)&&u({inst:c}),e(function(){l(c)&&u({inst:c})})},[e]),s(n),n}function l(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!r(e,n)}catch{return!0}}function u(e,t){return t()}var d=typeof window>`u`||window.document===void 0||window.document.createElement===void 0?u:c;e.useSyncExternalStore=t.useSyncExternalStore===void 0?d:t.useSyncExternalStore})),uee=s(((e,t)=>{t.exports=lee()})),Ph=u(Du(),1),dee=uee(),Fh=(0,g.createContext)(!1),Ih=(0,g.createContext)(null);function Lh(e){if((0,g.useContext)(Ih))return e.content;let{collection:t,document:n}=zh(e.createCollection);return g.createElement(g.Fragment,null,g.createElement(see,null,g.createElement(Ih.Provider,{value:n},e.content)),g.createElement(fee,{render:e.children,collection:t}))}function fee({collection:e,render:t}){return t(e)}function pee(e,t,n){let r=Lf(),i=(0,g.useRef)(r);return i.current=r,(0,dee.useSyncExternalStore)(e,(0,g.useCallback)(()=>i.current?n():t(),[t,n]))}var Rh=typeof g.useSyncExternalStore==`function`?g.useSyncExternalStore:pee;function zh(e){let[t]=(0,g.useState)(()=>new _h(e?.()||new ph));return{collection:Rh((0,g.useCallback)(e=>t.subscribe(e),[t]),(0,g.useCallback)(()=>{let e=t.getCollection();return t.isSSR&&t.resetAfterSSR(),e},[t]),(0,g.useCallback)(()=>(t.isSSR=!0,t.getCollection()),[t])),document:t}}var Bh=(0,g.createContext)(null);function Vh(e){return class extends ch{static{this.type=e}}}function Hh(e,t,n,r,i,a){typeof e==`string`&&(e=Vh(e));let o=(0,g.useCallback)(i=>{i?.setProps(t,n,e,r,a)},[t,n,r,a,e]),s=(0,g.useContext)(Bh);if(s){let o=s.ownerDocument.nodesByProps.get(t);return o||(o=s.ownerDocument.createElement(e.type),o.setProps(t,n,e,r,a),s.appendChild(o),s.ownerDocument.updateCollection(),s.ownerDocument.nodesByProps.set(t,o)),i?g.createElement(Bh.Provider,{value:o},i):null}return g.createElement(e.type,{ref:o},i)}function Uh(e,t){let n=({node:e})=>t(e.props,e.props.ref,e),r=(0,g.forwardRef)((r,i)=>{let a=(0,g.useContext)(Ah);if(!(0,g.useContext)(Fh)){if(t.length>=3)throw Error(t.name+` cannot be rendered outside a collection.`);return t(r,i)}return Hh(e,r,i,`children`in r?r.children:null,null,e=>g.createElement(Ah.Provider,{value:a},g.createElement(n,{node:e})))});return r.displayName=t.name,r}function Wh(e,t,n=Gh){let r=({node:e})=>t(e.props,e.props.ref,e),i=(0,g.forwardRef)((t,i)=>Hh(e,t,i,null,n(t),e=>g.createElement(r,{node:e}))??g.createElement(g.Fragment,null));return i.displayName=t.name,i}function Gh(e){return vh({...e,addIdAndValue:!0})}var Kh=(0,g.createContext)(null);function qh(e){let t=(0,g.useContext)(Kh),n=(t?.dependencies||[]).concat(e.dependencies),r=e.idScope??t?.idScope,i=Gh({...e,idScope:r,dependencies:n});return(0,g.useContext)(Ih)&&(i=g.createElement(Jh,null,i)),t=(0,g.useMemo)(()=>({dependencies:n,idScope:r}),[r,...n]),g.createElement(Kh.Provider,{value:t},i)}function Jh({children:e}){let t=(0,g.useContext)(Ih),n=(0,g.useMemo)(()=>g.createElement(Ih.Provider,{value:null},g.createElement(Fh.Provider,{value:!0},e)),[e]);return Lf()?g.createElement(Bh.Provider,{value:t},n):(0,Ph.createPortal)(n,t)}var Yh=(0,g.createContext)(null),Xh={CollectionRoot({collection:e,renderDropIndicator:t}){return Zh(e,null,t)},CollectionBranch({collection:e,parent:t,renderDropIndicator:n}){return Zh(e,t,n)}};function Zh(e,t,n){return vh({items:t?e.getChildren(t.key):e,dependencies:[n],children(t){if(t.type===`content`)return g.createElement(g.Fragment,null);let r=t.render(t);return!n||t.type!==`item`?r:g.createElement(g.Fragment,null,n({type:`item`,key:t.key,dropPosition:`before`}),r,Qh(e,t,n))}})}function Qh(e,t,n){let r=t.key,i=e.getKeyAfter(r),a=i==null?null:e.getItem(i);for(;a!=null&&a.type!==`item`;)i=e.getKeyAfter(a.key),a=i==null?null:e.getItem(i);let o=t.nextKey==null?null:e.getItem(t.nextKey);for(;o!=null&&o.type!==`item`;)o=o.nextKey==null?null:e.getItem(o.nextKey);let s=[];if(o==null){let r=t;for(;r?.type===`item`&&(!a||r.parentKey!==a.parentKey&&a.level{wh(()=>{if(sg===`restoring`){let t=lp(e);t.documentElement.style.webkitUserSelect===`none`&&(t.documentElement.style.webkitUserSelect=cg||``),cg=``,sg=`default`}})},300)}else if((e instanceof HTMLElement||e instanceof SVGElement)&&e&&lg.has(e)){let t=lg.get(e),n=`userSelect`in e.style?`userSelect`:`webkitUserSelect`;e.style[n]===`none`&&(e.style[n]=t),e.getAttribute(`style`)===``&&e.removeAttribute(`style`),lg.delete(e)}}function fg(e){return e?.defaultView?.__webpack_nonce__||globalThis.__webpack_nonce__||void 0}var pg=new WeakMap;function mg(e){let t=e??(typeof document<`u`?document:void 0);if(!t)return fg(t);if(pg.has(t))return pg.get(t);let n=t.querySelector(`meta[property="csp-nonce"]`),r=n&&n instanceof up(n).HTMLMetaElement&&(n.nonce||n.content)||fg(t)||void 0;return r!==void 0&&pg.set(t,r),r}var hg=g.createContext({register:()=>{}});hg.displayName=`PressResponderContext`;function gg(){let e=(0,g.useRef)(new Map),t=(0,g.useCallback)((t,n,r,i)=>{let a=i?.once?(...t)=>{e.current.delete(r),r(...t)}:r;e.current.set(r,{type:n,eventTarget:t,fn:a,options:i}),t.addEventListener(n,a,i)},[]),n=(0,g.useCallback)((t,n,r,i)=>{let a=e.current.get(r)?.fn||r;t.removeEventListener(n,a,i),e.current.delete(r)},[]),r=(0,g.useCallback)(()=>{e.current.forEach((e,t)=>{n(e.eventTarget,e.type,t,e.options)})},[n]);return(0,g.useEffect)(()=>r,[r]),{addGlobalListener:t,removeGlobalListener:n,removeAllGlobalListeners:r}}function _g(e){let t=(0,g.useContext)(hg);if(t){let{register:n,ref:r,...i}=t;e=Yf(i,e),n()}return kh(t,e.ref),e}var vg=class{#e;constructor(e,t,n,r){this.#e=!0;let i=(r?.target??n.currentTarget)?.getBoundingClientRect(),a,o=0,s,c=null;n.clientX!=null&&n.clientY!=null&&(s=n.clientX,c=n.clientY),i&&(s!=null&&c!=null?(a=s-i.left,o=c-i.top):(a=i.width/2,o=i.height/2)),this.type=e,this.pointerType=t,this.target=n.currentTarget,this.shiftKey=n.shiftKey,this.metaKey=n.metaKey,this.ctrlKey=n.ctrlKey,this.altKey=n.altKey,this.x=a,this.y=o,this.key=n.key}continuePropagation(){this.#e=!1}get shouldStopPropagation(){return this.#e}},yg=Symbol(`linkClicked`),bg=`react-aria-pressable-style`,xg=`data-react-aria-pressable`;function Sg(e){let{onPress:t,onPressChange:n,onPressStart:r,onPressEnd:i,onPressUp:a,onClick:o,isDisabled:s,isPressed:c,preventFocusOnPress:l,shouldCancelOnPointerExit:u,allowTextSelectionOnPress:d,ref:f,...p}=_g(e),[m,h]=(0,g.useState)(!1),_=(0,g.useRef)({isPressed:!1,ignoreEmulatedMouseEvents:!1,didFirePressStart:!1,isTriggeringEvent:!1,activePointerId:null,target:null,isOverTarget:!1,pointerType:null,disposables:[]}),{addGlobalListener:v,removeAllGlobalListeners:y}=gg(),b=(0,g.useCallback)((e,t)=>{let i=_.current;if(s||i.didFirePressStart)return!1;let a=!0;if(i.isTriggeringEvent=!0,r){let n=new vg(`pressstart`,t,e);r(n),a=n.shouldStopPropagation}return n&&n(!0),i.isTriggeringEvent=!1,i.didFirePressStart=!0,h(!0),a},[s,r,n]),x=(0,g.useCallback)((e,r,a=!0)=>{let o=_.current;if(!o.didFirePressStart)return!1;o.didFirePressStart=!1,o.isTriggeringEvent=!0;let c=!0;if(i){let t=new vg(`pressend`,r,e);i(t),c=t.shouldStopPropagation}if(n&&n(!1),h(!1),t&&a&&!s){let n=new vg(`press`,r,e);t(n),c&&=n.shouldStopPropagation}return o.isTriggeringEvent=!1,c},[s,i,n,t]),S=Pm(x),C=Pm((0,g.useCallback)((e,t)=>{let n=_.current;if(s)return!1;if(a){n.isTriggeringEvent=!0;let r=new vg(`pressup`,t,e);return a(r),n.isTriggeringEvent=!1,r.shouldStopPropagation}return!0},[s,a])),w=(0,g.useCallback)(e=>{let t=_.current;if(t.isPressed&&t.target){t.didFirePressStart&&t.pointerType!=null&&x(Tg(t.target,e),t.pointerType,!1),t.isPressed=!1,t.isOverTarget=!1,t.activePointerId=null,t.pointerType=null,y(),d||dg(t.target);for(let e of t.disposables)e();t.disposables=[]}},[d,y,x]),T=Pm(w);(0,g.useEffect)(()=>{s&&_.current.isPressed&&T({currentTarget:_.current.target,shiftKey:!1,ctrlKey:!1,metaKey:!1,altKey:!1})},[s]);let E=(0,g.useCallback)(e=>{u&&w(e)},[u,w]),D=(0,g.useCallback)(e=>{s||o?.(e)},[s,o]),O=(0,g.useCallback)((e,t)=>{if(!s&&o){let n=new MouseEvent(`click`,e);Lp(n,t),o(Ip(n))}},[s,o]),k=(0,g.useMemo)(()=>{let e=_.current,t={onKeyDown(t){if(wg(t.nativeEvent,t.currentTarget)&&U(t.currentTarget,W(t))){Dg(W(t),t.key)&&t.preventDefault();let r=!0;!e.isPressed&&!t.repeat&&(e.target=t.currentTarget,e.isPressed=!0,e.pointerType=`keyboard`,r=b(t,`keyboard`));let i=t.currentTarget;v(lp(t.currentTarget),`keyup`,wf(t=>{wg(t,i)&&!t.repeat&&U(i,W(t))&&e.target&&C(Tg(e.target,t),`keyboard`)},n),!0),r&&t.stopPropagation(),t.metaKey&&Wp()&&e.metaKeyEvents?.set(t.key,t.nativeEvent)}else t.key===`Meta`&&(e.metaKeyEvents=new Map)},onClick(t){if(!(t&&!U(t.currentTarget,W(t)))&&t&&t.button===0&&!e.isTriggeringEvent&&!rm.isOpening){let n=!0;if(s&&t.preventDefault(),!e.ignoreEmulatedMouseEvents&&!e.isPressed&&(e.pointerType===`virtual`||$p(t.nativeEvent))){let e=b(t,`virtual`),r=C(t,`virtual`),i=S(t,`virtual`);D(t),n=e&&r&&i}else if(e.isPressed&&e.pointerType!==`keyboard`){let r=e.pointerType||t.nativeEvent.pointerType||`virtual`,i=C(Tg(t.currentTarget,t),r),a=S(Tg(t.currentTarget,t),r,!0);n=i&&a,e.isOverTarget=!1,D(t),T(t)}e.ignoreEmulatedMouseEvents=!1,n&&t.stopPropagation()}}},n=t=>{if(e.isPressed&&e.target&&wg(t,e.target)){Dg(W(t),t.key)&&t.preventDefault();let n=W(t),r=U(e.target,n);S(Tg(e.target,t),`keyboard`,r),r&&O(t,e.target),y(),t.key!==`Enter`&&Cg(e.target)&&U(e.target,n)&&!t[yg]&&(t[yg]=!0,rm(e.target,t,!1)),e.isPressed=!1,e.metaKeyEvents?.delete(t.key)}else if(t.key===`Meta`&&e.metaKeyEvents?.size){let t=e.metaKeyEvents;e.metaKeyEvents=void 0;for(let n of t.values())e.target?.dispatchEvent(new KeyboardEvent(`keyup`,n))}};if(typeof PointerEvent<`u`){t.onPointerDown=t=>{if(t.button!==0||!U(t.currentTarget,W(t)))return;if(em(t.nativeEvent)){e.pointerType=`virtual`;return}e.pointerType=t.pointerType;let i=!0;if(!e.isPressed){e.isPressed=!0,e.isOverTarget=!0,e.activePointerId=t.pointerId,e.target=t.currentTarget,d||ug(e.target),i=b(t,e.pointerType);let a=W(t);`releasePointerCapture`in a&&(`hasPointerCapture`in a?a.hasPointerCapture(t.pointerId)&&a.releasePointerCapture(t.pointerId):a.releasePointerCapture(t.pointerId)),v(lp(t.currentTarget),`pointerup`,n,!1),v(lp(t.currentTarget),`pointercancel`,r,!1)}i&&t.stopPropagation()},t.onMouseDown=t=>{if(U(t.currentTarget,W(t))&&t.button===0){if(l){let n=Bp(t.target);n&&e.disposables.push(n)}t.stopPropagation()}},t.onPointerUp=t=>{!U(t.currentTarget,W(t))||e.pointerType===`virtual`||t.button===0&&!e.isPressed&&C(t,e.pointerType||t.pointerType)},t.onPointerEnter=t=>{t.pointerId===e.activePointerId&&e.target&&!e.isOverTarget&&e.pointerType!=null&&(e.isOverTarget=!0,b(Tg(e.target,t),e.pointerType))},t.onPointerLeave=t=>{t.pointerId===e.activePointerId&&e.target&&e.isOverTarget&&e.pointerType!=null&&(e.isOverTarget=!1,S(Tg(e.target,t),e.pointerType,!1),E(t))};let n=t=>{if(t.pointerId===e.activePointerId&&e.isPressed&&t.button===0&&e.target){if(U(e.target,W(t))&&e.pointerType!=null){let n=!1,r=setTimeout(()=>{e.isPressed&&e.target instanceof HTMLElement&&(n?T(t):(xp(e.target),e.target.click()))},80);v(t.currentTarget,`click`,()=>n=!0,!0),e.disposables.push(()=>clearTimeout(r))}else T(t);e.isOverTarget=!1}},r=e=>{T(e)};t.onDragStart=e=>{U(e.currentTarget,W(e))&&T(e)}}return t},[v,s,l,y,d,E,b,D,O]);return(0,g.useEffect)(()=>{if(!f)return;let e=lp(f.current);if(!e||!e.head||e.getElementById(bg))return;let t=e.createElement(`style`);t.id=bg;let n=mg(e);n&&(t.nonce=n),t.textContent=` -@layer { - [${xg}] { - touch-action: pan-x pan-y pinch-zoom; - } -} - `.trim(),e.head.prepend(t)},[f]),(0,g.useEffect)(()=>{let e=_.current;return()=>{d||dg(e.target??void 0);for(let t of e.disposables)t();e.disposables=[]}},[d]),{isPressed:c||m,pressProps:Yf(p,k,{[xg]:!0})}}function Cg(e){return e.tagName===`A`&&e.hasAttribute(`href`)}function wg(e,t){let{key:n,code:r}=e,i=t,a=i.getAttribute(`role`);return(n===`Enter`||n===` `||n===`Spacebar`||r===`Space`)&&!(i instanceof up(i).HTMLInputElement&&!kg(i,n)||i instanceof up(i).HTMLTextAreaElement||i.isContentEditable)&&!((a===`link`||!a&&Cg(i))&&n!==`Enter`)}function Tg(e,t){let n=t.clientX,r=t.clientY;return{currentTarget:e,shiftKey:t.shiftKey,ctrlKey:t.ctrlKey,metaKey:t.metaKey,altKey:t.altKey,clientX:n,clientY:r,key:t.key}}function Eg(e){return e instanceof HTMLInputElement?!1:e instanceof HTMLButtonElement?e.type!==`submit`&&e.type!==`reset`:!Cg(e)}function Dg(e,t){return e instanceof HTMLInputElement?!kg(e,t):Eg(e)}var Og=new Set([`checkbox`,`radio`,`range`,`color`,`file`,`image`,`button`,`submit`,`reset`]);function kg(e,t){return e.type===`checkbox`||e.type===`radio`?t===` `:Og.has(e.type)}function Ag(e){let{isDisabled:t,onBlurWithin:n,onFocusWithin:r,onFocusWithinChange:i}=e,a=(0,g.useRef)({isFocusWithin:!1}),{addGlobalListener:o,removeAllGlobalListeners:s}=gg(),c=(0,g.useCallback)(e=>{U(e.currentTarget,W(e))&&a.current.isFocusWithin&&!U(e.currentTarget,e.relatedTarget)&&(a.current.isFocusWithin=!1,s(),n&&n(e),i&&i(!1))},[n,i,a,s]),l=Rp(c),u=(0,g.useCallback)(e=>{if(!U(e.currentTarget,W(e)))return;let t=W(e),n=lp(t),s=hp(n);if(!a.current.isFocusWithin&&s===t){r&&r(e),i&&i(!0),a.current.isFocusWithin=!0,l(e);let t=e.currentTarget;o(n,`focus`,e=>{let r=W(e);if(a.current.isFocusWithin&&!U(t,r)){let e=new n.defaultView.FocusEvent(`blur`,{relatedTarget:r});Lp(e,t),c(Ip(e))}},{capture:!0})}},[r,i,l,o,c]);return t?{focusWithinProps:{onFocus:void 0,onBlur:void 0}}:{focusWithinProps:{onFocus:u,onBlur:c}}}function jg(e={}){let{autoFocus:t=!1,isTextInput:n,within:r}=e,i=(0,g.useRef)({isFocused:!1,isFocusVisible:t||wm()}),[a,o]=(0,g.useState)(!1),[s,c]=(0,g.useState)(()=>i.current.isFocused&&i.current.isFocusVisible),l=(0,g.useCallback)(()=>c(i.current.isFocused&&i.current.isFocusVisible),[]),u=(0,g.useCallback)(e=>{i.current.isFocused=e,i.current.isFocusVisible=wm(),o(e),l()},[l]);Am(e=>{i.current.isFocusVisible=e,l()},[n,a],{enabled:a,isTextInput:n});let{focusProps:d}=Eh({isDisabled:r,onFocusChange:u}),{focusWithinProps:f}=Ag({isDisabled:!r,onFocusWithinChange:u});return{isFocused:a,isFocusVisible:s,focusProps:r?f:d}}var Mg=!1,Ng=0;function Pg(){Mg=!0,setTimeout(()=>{Mg=!1},500)}function Fg(e){e.pointerType===`touch`&&Pg()}function Ig(){let e=lp(null);if(e!==void 0)return Ng===0&&typeof PointerEvent<`u`&&e.addEventListener(`pointerup`,Fg),Ng++,()=>{Ng--,!(Ng>0)&&typeof PointerEvent<`u`&&e.removeEventListener(`pointerup`,Fg)}}function Lg(e){let{onHoverStart:t,onHoverChange:n,onHoverEnd:r,isDisabled:i}=e,[a,o]=(0,g.useState)(!1),s=(0,g.useRef)({isHovered:!1,ignoreEmulatedMouseEvents:!1,pointerType:``,target:null}).current;(0,g.useEffect)(Ig,[]);let{addGlobalListener:c,removeAllGlobalListeners:l}=gg(),{hoverProps:u,triggerHoverEnd:d}=(0,g.useMemo)(()=>{let e=(e,r)=>{if(s.pointerType=r,i||r===`touch`||s.isHovered||!U(e.currentTarget,W(e)))return;s.isHovered=!0;let l=e.currentTarget;s.target=l,c(lp(W(e)),`pointerover`,e=>{s.isHovered&&s.target&&!U(s.target,W(e))&&a(e,e.pointerType)},{capture:!0}),t&&t({type:`hoverstart`,target:l,pointerType:r}),n&&n(!0),o(!0)},a=(e,t)=>{let i=s.target;s.pointerType=``,s.target=null,!(t===`touch`||!s.isHovered||!i)&&(s.isHovered=!1,l(),r&&r({type:`hoverend`,target:i,pointerType:t}),n&&n(!1),o(!1))},u={};return typeof PointerEvent<`u`&&(u.onPointerEnter=t=>{Mg&&t.pointerType===`mouse`||e(t,t.pointerType)},u.onPointerLeave=e=>{!i&&U(e.currentTarget,W(e))&&a(e,e.pointerType)}),{hoverProps:u,triggerHoverEnd:a}},[t,n,r,i,s,c,l]);return(0,g.useEffect)(()=>{i&&d({currentTarget:s.target},s.pointerType)},[i]),{hoverProps:u,isHovered:a}}var Rg=(0,g.createContext)({});function zg(e){let{id:t,label:n,"aria-labelledby":r,"aria-label":i,labelElementType:a=`label`}=e;t=Hf(t);let o=Hf(),s={};n&&(r=r?`${o} ${r}`:o,s={id:o,htmlFor:a===`label`?t:void 0});let c=Im({id:t,"aria-label":i,"aria-labelledby":r});return{labelProps:s,fieldProps:c}}function Bg(e,t=-1/0,n=1/0){return Math.min(Math.max(e,t),n)}var Vg=(0,g.createContext)(null),Hg=7e3,Ug=null;function Wg(e,t=`assertive`,n=Hg){Ug?Ug.announce(e,t,n):(Ug=new Gg,(typeof IS_REACT_ACT_ENVIRONMENT==`boolean`?IS_REACT_ACT_ENVIRONMENT:typeof jest<`u`)?Ug.announce(e,t,n):setTimeout(()=>{Ug?.isAttached()&&Ug?.announce(e,t,n)},100))}var Gg=class{constructor(){this.node=null,this.assertiveLog=null,this.politeLog=null,typeof document<`u`&&(this.node=document.createElement(`div`),this.node.dataset.liveAnnouncer=`true`,Object.assign(this.node.style,{border:0,clip:`rect(0 0 0 0)`,clipPath:`inset(50%)`,height:`1px`,margin:`-1px`,overflow:`hidden`,padding:0,position:`absolute`,width:`1px`,whiteSpace:`nowrap`}),this.assertiveLog=this.createLog(`assertive`),this.node.appendChild(this.assertiveLog),this.politeLog=this.createLog(`polite`),this.node.appendChild(this.politeLog),document.body.prepend(this.node))}isAttached(){return this.node?.isConnected}createLog(e){let t=document.createElement(`div`);return t.setAttribute(`role`,`log`),t.setAttribute(`aria-live`,e),t.setAttribute(`aria-relevant`,`additions`),t}destroy(){this.node&&=(document.body.removeChild(this.node),null)}announce(e,t=`assertive`,n=Hg){if(!this.node)return;let r=document.createElement(`div`);typeof e==`object`?(r.setAttribute(`role`,`img`),r.setAttribute(`aria-labelledby`,e[`aria-labelledby`])):r.textContent=e,t===`assertive`?this.assertiveLog?.appendChild(r):this.politeLog?.appendChild(r),e!==``&&setTimeout(()=>{r.remove()},n)}clear(e){this.node&&((!e||e===`assertive`)&&this.assertiveLog&&(this.assertiveLog.innerHTML=``),(!e||e===`polite`)&&this.politeLog&&(this.politeLog.innerHTML=``))}};function Kg(e,t){let{elementType:n=`button`,isDisabled:r,onPress:i,onPressStart:a,onPressEnd:o,onPressUp:s,onPressChange:c,preventFocusOnPress:l,allowFocusWhenDisabled:u,onClick:d,href:f,target:p,rel:m,type:h=`button`}=e,g;g=n===`button`?{type:h,disabled:r,form:e.form,formAction:e.formAction,formEncType:e.formEncType,formMethod:e.formMethod,formNoValidate:e.formNoValidate,formTarget:e.formTarget,name:e.name,value:e.value}:{role:`button`,href:n===`a`&&!r?f:void 0,target:n===`a`?p:void 0,type:n===`input`?h:void 0,disabled:n===`input`?r:void 0,"aria-disabled":!r||n===`input`?void 0:r,rel:n===`a`?m:void 0};let{pressProps:_,isPressed:v}=Sg({onPressStart:a,onPressEnd:o,onPressChange:c,onPress:i,onPressUp:s,onClick:d,isDisabled:r,preventFocusOnPress:l,ref:t}),{focusableProps:y}=jh(e,t);u&&(y.tabIndex=r?-1:y.tabIndex);let b=Yf(y,_,og(e,{labelable:!0}));return{isPressed:v,buttonProps:Yf(g,b,{"aria-haspopup":e[`aria-haspopup`],"aria-expanded":e[`aria-expanded`],"aria-controls":e[`aria-controls`],"aria-pressed":e[`aria-pressed`],"aria-current":e[`aria-current`],"aria-disabled":e[`aria-disabled`]})}}var qg=(0,g.createContext)({}),Jg=Nh(function(e,t){[e,t]=tp(e,t,qg);let n=e,{isPending:r}=n,{buttonProps:i,isPressed:a}=Kg(e,t);i=Xg(i,r);let{focusProps:o,isFocused:s,isFocusVisible:c}=jg(e),{hoverProps:l,isHovered:u}=Lg({...e,isDisabled:e.isDisabled||r}),d={isHovered:u,isPressed:(n.isPressed||a)&&!r,isFocused:s,isFocusVisible:c,isDisabled:e.isDisabled||!1,isPending:r??!1},f=$f({...e,values:d,defaultClassName:`react-aria-Button`}),p=Hf(i.id),m=Hf(),h=i[`aria-labelledby`];r&&(h?h=`${h} ${m}`:i[`aria-label`]&&(h=`${p} ${m}`));let _=(0,g.useRef)(r);(0,g.useEffect)(()=>{let e={"aria-labelledby":h||p};(!_.current&&s&&r||_.current&&s&&!r)&&Wg(e,`assertive`),_.current=r},[r,s,h,p]);let v=og(e,{global:!0});return delete v.onClick,g.createElement(op.button,{...Yf(v,f,i,o,l),type:i.type===`submit`&&r?`button`:i.type,id:p,ref:t,"aria-labelledby":h,slot:e.slot||void 0,"aria-disabled":r?`true`:i[`aria-disabled`],"data-disabled":e.isDisabled||void 0,"data-pressed":d.isPressed||void 0,"data-hovered":u||void 0,"data-focused":s||void 0,"data-pending":r||void 0,"data-focus-visible":c||void 0},g.createElement(Vg.Provider,{value:{id:m}},f.children))}),Yg=/Focus|Blur|Hover|Pointer(Enter|Leave|Over|Out)|Mouse(Enter|Leave|Over|Out)/;function Xg(e,t){if(t){for(let t in e)t.startsWith(`on`)&&!Yg.test(t)&&(e[t]=void 0);e.href=void 0,e.target=void 0}return e}var Zg=(0,g.createContext)({}),Qg=(0,g.createContext)({});function $g(e,t){let n=(0,g.useRef)(!0),r=(0,g.useRef)(null),i=Pm(e);(0,g.useEffect)(()=>(n.current=!0,()=>{n.current=!1}),[]),(0,g.useEffect)(()=>{let e=r.current;n.current?n.current=!1:(!e||t.some((t,n)=>!Object.is(t,e[n])))&&i(),r.current=t},t)}function e_(e,t){if(!e)return!1;let n=window.getComputedStyle(e),r=document.scrollingElement||document.documentElement,i=/(auto|scroll)/.test(n.overflow+n.overflowX+n.overflowY);return e===r&&n.overflow!==`hidden`&&(i=!0),i&&t&&(i=e.scrollHeight!==e.clientHeight||e.scrollWidth!==e.clientWidth),i}function t_(e,t){let n=e;for(e_(n,t)&&(n=n.parentElement);n&&!e_(n,t);)n=n.parentElement;return n||document.scrollingElement||document.documentElement}function n_(e,t){let n=[],r=document.scrollingElement||document.documentElement;for(;e&&(e_(e,t)&&n.push(e),e!==r);)e=e.parentElement;return n}function r_(e,t,n={}){let{block:r=`nearest`,inline:i=`nearest`}=n;if(e===t)return;let a=e.scrollTop,o=e.scrollLeft,s=t.getBoundingClientRect(),c=e.getBoundingClientRect(),l=window.getComputedStyle(t),u=window.getComputedStyle(e),d=document.scrollingElement||document.documentElement,f=e===d,p=e===d?0:c.top,m=e===d?e.clientHeight:c.bottom,h=e===d?0:c.left,g=e===d?e.clientWidth:c.right,_=parseFloat(l.scrollMarginTop)||0,v=parseFloat(l.scrollMarginBottom)||0,y=parseFloat(l.scrollMarginLeft)||0,b=parseFloat(l.scrollMarginRight)||0,x=parseFloat(u.scrollPaddingTop)||0,S=parseFloat(u.scrollPaddingBottom)||0,C=parseFloat(u.scrollPaddingLeft)||0,w=parseFloat(u.scrollPaddingRight)||0,T=parseFloat(u.borderTopWidth)||0,E=parseFloat(u.borderBottomWidth)||0,D=parseFloat(u.borderLeftWidth)||0,O=parseFloat(u.borderRightWidth)||0,k=s.top-_,A=s.bottom+v,j=s.left-y,M=s.right+b,N=e===d?0:D+O,P=e===d?0:T+E,F=e===d?0:e.offsetWidth-e.clientWidth-N,ee=e===d?0:e.offsetHeight-e.clientHeight-P,te=p+(f?0:T)+x,ne=m-(f?0:E)-S-ee,re=h+(f?0:D)+C,ie=g-(f?0:O)-w;u.direction===`rtl`&&!qp()?re+=F:ie-=F;let ae=kne,oe=jie;if(ae&&r===`start`)a+=k-te;else if(ae&&r===`center`)a+=(k+A)/2-(te+ne)/2;else if(ae&&r===`end`)a+=A-ne;else if(ae&&r===`nearest`){let e=k-te,t=A-ne;a+=Math.abs(e)<=Math.abs(t)?e:t}if(oe&&i===`start`)o+=j-re;else if(oe&&i===`center`)o+=(j+M)/2-(re+ie)/2;else if(oe&&i===`end`)o+=M-ie;else if(oe&&i===`nearest`){let e=j-re,t=M-ie;o+=Math.abs(e)<=Math.abs(t)?e:t}e.scrollTo({left:o,top:a})}function i_(e,t={}){let{containingElement:n}=t;if(e&&e.isConnected){let t=document.scrollingElement||document.documentElement;if(window.getComputedStyle(t).overflow!==`hidden`){let{left:t,top:r}=e.getBoundingClientRect();e?.scrollIntoView?.({block:`nearest`});let{left:i,top:a}=e.getBoundingClientRect();(Math.abs(t-i)>1||Math.abs(r-a)>1)&&(n?.scrollIntoView?.({block:`center`,inline:`center`}),e.scrollIntoView?.({block:`nearest`}))}else{let{left:t,top:r}=e.getBoundingClientRect(),i=n_(e,!0);for(let t of i)r_(t,e);let{left:a,top:o}=e.getBoundingClientRect();if(Math.abs(t-a)>1||Math.abs(r-o)>1){i=n?n_(n,!0):[];for(let e of i)r_(e,n,{block:`center`,inline:`center`});for(let t of n_(e,!0))r_(t,e)}}}}var a_=0,o_=new Map;function s_(e){let[t,n]=(0,g.useState)();return Tf(()=>{if(!e)return;let t=o_.get(e);if(t)n(t.element.id);else{let r=`react-aria-description-${a_++}`;n(r);let i=document.createElement(`div`);i.id=r,i.style.display=`none`,i.textContent=e,document.body.appendChild(i),t={refCount:0,element:i},o_.set(e,t)}return t.refCount++,()=>{t&&--t.refCount===0&&(t.element.remove(),o_.delete(e))}},[e]),{"aria-describedby":e?t:void 0}}var c_={border:0,clip:`rect(0 0 0 0)`,clipPath:`inset(50%)`,height:`1px`,margin:`-1px`,overflow:`hidden`,padding:0,position:`absolute`,width:`1px`,whiteSpace:`nowrap`};function l_(e={}){let{style:t,isFocusable:n}=e,[r,i]=(0,g.useState)(!1),{focusWithinProps:a}=Ag({isDisabled:!n,onFocusWithinChange:e=>i(e)}),o=(0,g.useMemo)(()=>r?t:t?{...c_,...t}:c_,[r]);return{visuallyHiddenProps:{...a,style:o}}}function u_(e){let{children:t,elementType:n=`div`,isFocusable:r,style:i,...a}=e,{visuallyHiddenProps:o}=l_(e);return g.createElement(n,Yf(a,o),t)}var d_=(0,g.createContext)(null),f_={badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valueMissing:!1,valid:!0},p_={...f_,customError:!0,valid:!1},m_={isInvalid:!1,validationDetails:f_,validationErrors:[]},mee=(0,g.createContext)({}),h_=`__reactAriaFormValidationState`;function g_(e){if(e.__reactAriaFormValidationState){let{realtimeValidation:t,displayValidation:n,updateValidation:r,resetValidation:i,commitValidation:a}=e[h_];return{realtimeValidation:t,displayValidation:n,updateValidation:r,resetValidation:i,commitValidation:a}}return __(e)}function __(e){let{isInvalid:t,validationState:n,name:r,value:i,builtinValidation:a,validate:o,validationBehavior:s=`aria`}=e;n&&(t||=n===`invalid`);let c=t===void 0?null:{isInvalid:t,validationErrors:[],validationDetails:p_},l=(0,g.useMemo)(()=>!o||i==null?null:b_(y_(o,i)),[o,i]);a?.validationDetails.valid&&(a=void 0);let u=(0,g.useContext)(mee),d=(0,g.useMemo)(()=>r?Array.isArray(r)?r.flatMap(e=>v_(u[e])):v_(u[r]):[],[u,r]),[f,p]=(0,g.useState)(u),[m,h]=(0,g.useState)(!1);u!==f&&(p(u),h(!1));let _=(0,g.useMemo)(()=>b_(m?[]:d),[m,d]),v=(0,g.useRef)(m_),[y,b]=(0,g.useState)(m_),x=(0,g.useRef)(m_),S=()=>{if(!C)return;w(!1);let e=l||a||v.current;x_(e,x.current)||(x.current=e,b(e))},[C,w]=(0,g.useState)(!1);return(0,g.useEffect)(S),{realtimeValidation:c||_||l||a||m_,displayValidation:s===`native`?c||_||y:c||_||l||a||y,updateValidation(e){s===`aria`&&!x_(y,e)?b(e):v.current=e},resetValidation(){let e=m_;x_(e,x.current)||(x.current=e,b(e)),s===`native`&&w(!1),h(!0)},commitValidation(){s===`native`&&w(!0),h(!0)}}}function v_(e){return e?Array.isArray(e)?e:[e]:[]}function y_(e,t){if(typeof e==`function`){let n=e(t);if(n&&typeof n!=`boolean`)return v_(n)}return[]}function b_(e){return e.length?{isInvalid:!0,validationErrors:e,validationDetails:p_}:null}function x_(e,t){return e===t?!0:!!e&&!!t&&e.isInvalid===t.isInvalid&&e.validationErrors.length===t.validationErrors.length&&e.validationErrors.every((e,n)=>e===t.validationErrors[n])&&Object.entries(e.validationDetails).every(([e,n])=>t.validationDetails[e]===n)}var S_=(0,g.createContext)(null);function C_(e){let{description:t,errorMessage:n,isInvalid:r,validationState:i}=e,{labelProps:a,fieldProps:o}=zg(e),s=Wf([!!t,!!n,r,i]),c=Wf([!!t,!!n,r,i]);return o=Yf(o,{"aria-describedby":[s,c,e[`aria-describedby`]].filter(Boolean).join(` `)||void 0}),{labelProps:a,fieldProps:o,descriptionProps:{id:s},errorMessageProps:{id:c}}}function w_(e,t,n){let r=Pm(e=>{n&&!e.defaultPrevented&&n(t)});(0,g.useEffect)(()=>{let t=e?.current?.form;return t?.addEventListener(`reset`,r),()=>{t?.removeEventListener(`reset`,r)}},[e])}function T_(e,t,n){let{validationBehavior:r,focus:i}=e;Tf(()=>{if(r===`native`&&n?.current&&!n.current.disabled){let e=t.realtimeValidation.isInvalid?t.realtimeValidation.validationErrors.join(` `)||`Invalid value.`:``;n.current.setCustomValidity(e),n.current.hasAttribute(`title`)||(n.current.title=``),t.realtimeValidation.isInvalid||t.updateValidation(D_(n.current))}});let a=(0,g.useRef)(!1),o=Pm(()=>{a.current||t.resetValidation()}),s=Pm(e=>{t.displayValidation.isInvalid||t.commitValidation();let r=n?.current?.form;!e.defaultPrevented&&n&&r&&O_(r)===n.current&&(i?i():n.current?.focus(),Em(`keyboard`)),e.preventDefault()}),c=Pm(()=>{t.commitValidation()});(0,g.useEffect)(()=>{let e=n?.current;if(!e)return;let t=e.form,r=t?.reset;return t&&(t.reset=()=>{a.current=!window.event||window.event.type===`message`&&W(window.event)instanceof MessagePort,r?.call(t),a.current=!1}),e.addEventListener(`invalid`,s),e.addEventListener(`change`,c),t?.addEventListener(`reset`,o),()=>{e.removeEventListener(`invalid`,s),e.removeEventListener(`change`,c),t?.removeEventListener(`reset`,o),t&&(t.reset=r)}},[n,r])}function E_(e){let t=e.validity;return{badInput:t.badInput,customError:t.customError,patternMismatch:t.patternMismatch,rangeOverflow:t.rangeOverflow,rangeUnderflow:t.rangeUnderflow,stepMismatch:t.stepMismatch,tooLong:t.tooLong,tooShort:t.tooShort,typeMismatch:t.typeMismatch,valueMissing:t.valueMissing,valid:t.valid}}function D_(e){return{isInvalid:!e.validity.valid,validationDetails:E_(e),validationErrors:e.validationMessage?[e.validationMessage]:[]}}function O_(e){for(let t=0;tl(W(e).value),autoComplete:e.autoComplete,autoCapitalize:e.autoCapitalize,maxLength:e.maxLength,minLength:e.minLength,name:e.name,form:e.form,placeholder:e.placeholder,inputMode:e.inputMode,autoCorrect:e.autoCorrect,spellCheck:e.spellCheck,enterKeyHint:e.enterKeyHint,onCopy:e.onCopy,onCut:e.onCut,onPaste:e.onPaste,onCompositionEnd:e.onCompositionEnd,onCompositionStart:e.onCompositionStart,onCompositionUpdate:e.onCompositionUpdate,onSelect:e.onSelect,onBeforeInput:e.onBeforeInput,onInput:e.onInput,...u,..._}),descriptionProps:v,errorMessageProps:y,isInvalid:f,validationErrors:p,validationDetails:m}}var F_={};F_={colorSwatchPicker:`تغييرات الألوان`,dropzoneLabel:`DropZone`,selectPlaceholder:`حدد عنصرًا`,tableResizer:`أداة تغيير الحجم`};var I_={};I_={colorSwatchPicker:`Цветови мостри`,dropzoneLabel:`DropZone`,selectPlaceholder:`Изберете предмет`,tableResizer:`Преоразмерител`};var L_={};L_={colorSwatchPicker:`Vzorky barev`,dropzoneLabel:`Místo pro přetažení`,selectPlaceholder:`Vyberte položku`,tableResizer:`Změna velikosti`};var R_={};R_={colorSwatchPicker:`Farveprøver`,dropzoneLabel:`DropZone`,selectPlaceholder:`Vælg et element`,tableResizer:`Størrelsesændring`};var z_={};z_={colorSwatchPicker:`Farbfelder`,dropzoneLabel:`Ablegebereich`,selectPlaceholder:`Element wählen`,tableResizer:`Größenanpassung`};var B_={};B_={colorSwatchPicker:`Χρωματικά δείγματα`,dropzoneLabel:`DropZone`,selectPlaceholder:`Επιλέξτε ένα αντικείμενο`,tableResizer:`Αλλαγή μεγέθους`};var V_={};V_={selectPlaceholder:`Select an item`,tableResizer:`Resizer`,dropzoneLabel:`DropZone`,colorSwatchPicker:`Color swatches`};var H_={};H_={colorSwatchPicker:`Muestras de colores`,dropzoneLabel:`DropZone`,selectPlaceholder:`Seleccionar un artículo`,tableResizer:`Cambiador de tamaño`};var U_={};U_={colorSwatchPicker:`Värvinäidised`,dropzoneLabel:`DropZone`,selectPlaceholder:`Valige üksus`,tableResizer:`Suuruse muutja`};var W_={};W_={colorSwatchPicker:`Värimallit`,dropzoneLabel:`DropZone`,selectPlaceholder:`Valitse kohde`,tableResizer:`Koon muuttaja`};var G_={};G_={colorSwatchPicker:`Échantillons de couleurs`,dropzoneLabel:`DropZone`,selectPlaceholder:`Sélectionner un élément`,tableResizer:`Redimensionneur`};var K_={};K_={colorSwatchPicker:`דוגמיות צבע`,dropzoneLabel:`DropZone`,selectPlaceholder:`בחר פריט`,tableResizer:`שינוי גודל`};var q_={};q_={colorSwatchPicker:`Uzorci boja`,dropzoneLabel:`Zona spuštanja`,selectPlaceholder:`Odaberite stavku`,tableResizer:`Promjena veličine`};var J_={};J_={colorSwatchPicker:`Színtárak`,dropzoneLabel:`DropZone`,selectPlaceholder:`Válasszon ki egy elemet`,tableResizer:`Átméretező`};var Y_={};Y_={colorSwatchPicker:`Campioni di colore`,dropzoneLabel:`Zona di rilascio`,selectPlaceholder:`Seleziona un elemento`,tableResizer:`Ridimensionamento`};var X_={};X_={colorSwatchPicker:`カラースウォッチ`,dropzoneLabel:`ドロップゾーン`,selectPlaceholder:`項目を選択`,tableResizer:`サイズ変更ツール`};var Z_={};Z_={colorSwatchPicker:`색상 견본`,dropzoneLabel:`드롭 영역`,selectPlaceholder:`항목 선택`,tableResizer:`크기 조정기`};var Q_={};Q_={colorSwatchPicker:`Spalvų pavyzdžiai`,dropzoneLabel:`„DropZone“`,selectPlaceholder:`Pasirinkite elementą`,tableResizer:`Dydžio keitiklis`};var $_={};$_={colorSwatchPicker:`Krāsu paraugi`,dropzoneLabel:`DropZone`,selectPlaceholder:`Izvēlēties vienumu`,tableResizer:`Izmēra mainītājs`};var ev={};ev={colorSwatchPicker:`Fargekart`,dropzoneLabel:`Droppsone`,selectPlaceholder:`Velg et element`,tableResizer:`Størrelsesendrer`};var tv={};tv={colorSwatchPicker:`kleurstalen`,dropzoneLabel:`DropZone`,selectPlaceholder:`Selecteer een item`,tableResizer:`Resizer`};var nv={};nv={colorSwatchPicker:`Próbki kolorów`,dropzoneLabel:`Strefa upuszczania`,selectPlaceholder:`Wybierz element`,tableResizer:`Zmiana rozmiaru`};var rv={};rv={colorSwatchPicker:`Amostras de cores`,dropzoneLabel:`DropZone`,selectPlaceholder:`Selecione um item`,tableResizer:`Redimensionador`};var iv={};iv={colorSwatchPicker:`Amostras de cores`,dropzoneLabel:`DropZone`,selectPlaceholder:`Selecione um item`,tableResizer:`Redimensionador`};var av={};av={colorSwatchPicker:`Specimene de culoare`,dropzoneLabel:`Zonă de plasare`,selectPlaceholder:`Selectați un element`,tableResizer:`Instrument de redimensionare`};var ov={};ov={colorSwatchPicker:`Цветовые образцы`,dropzoneLabel:`DropZone`,selectPlaceholder:`Выберите элемент`,tableResizer:`Средство изменения размера`};var sv={};sv={colorSwatchPicker:`Vzorkovníky farieb`,dropzoneLabel:`DropZone`,selectPlaceholder:`Vyberte položku`,tableResizer:`Nástroj na zmenu veľkosti`};var cv={};cv={colorSwatchPicker:`Barvne palete`,dropzoneLabel:`DropZone`,selectPlaceholder:`Izberite element`,tableResizer:`Spreminjanje velikosti`};var lv={};lv={colorSwatchPicker:`Uzorci boje`,dropzoneLabel:`DropZone`,selectPlaceholder:`Izaberite stavku`,tableResizer:`Promena veličine`};var uv={};uv={colorSwatchPicker:`Färgrutor`,dropzoneLabel:`DropZone`,selectPlaceholder:`Välj en artikel`,tableResizer:`Storleksändrare`};var dv={};dv={colorSwatchPicker:`Renk örnekleri`,dropzoneLabel:`Bırakma Bölgesi`,selectPlaceholder:`Bir öğe seçin`,tableResizer:`Yeniden boyutlandırıcı`};var fv={};fv={colorSwatchPicker:`Зразки кольорів`,dropzoneLabel:`DropZone`,selectPlaceholder:`Виберіть елемент`,tableResizer:`Засіб змінення розміру`};var pv={};pv={colorSwatchPicker:`颜色色板`,dropzoneLabel:`放置区域`,selectPlaceholder:`选择一个项目`,tableResizer:`尺寸调整器`};var mv={};mv={colorSwatchPicker:`色票`,dropzoneLabel:`放置區`,selectPlaceholder:`選取項目`,tableResizer:`大小調整器`};var hv={};hv={"ar-AE":F_,"bg-BG":I_,"cs-CZ":L_,"da-DK":R_,"de-DE":z_,"el-GR":B_,"en-US":V_,"es-ES":H_,"et-EE":U_,"fi-FI":W_,"fr-FR":G_,"he-IL":K_,"hr-HR":q_,"hu-HU":J_,"it-IT":Y_,"ja-JP":X_,"ko-KR":Z_,"lt-LT":Q_,"lv-LV":$_,"nb-NO":ev,"nl-NL":tv,"pl-PL":nv,"pt-BR":rv,"pt-PT":iv,"ro-RO":av,"ru-RU":ov,"sk-SK":sv,"sl-SI":cv,"sr-SP":lv,"sv-SE":uv,"tr-TR":dv,"uk-UA":fv,"zh-CN":pv,"zh-TW":mv};var gv=(0,g.createContext)({}),_v=(0,g.createContext)(null),vv=(0,g.forwardRef)(function(e,t){let{render:n}=(0,g.useContext)(_v);return g.createElement(g.Fragment,null,n(e,t))});function yv(e,t){let n=e?.renderDropIndicator,r=e?.isVirtualDragging?.(),i=(0,g.useCallback)(e=>{if(r||t?.isDropTarget(e))return n?n(e):g.createElement(vv,{target:e})},[t?.target,r,n]);return e?.useDropIndicator?i:void 0}function bv(e,t,n){let r=e.focusedKey,i=null;if(t?.isVirtualDragging?.()&&n?.target?.type===`item`&&(i=n.target.key,n.target.dropPosition===`after`)){let e=n.collection.getKeyAfter(i),t=null;if(e!=null){let r=n.collection.getItem(i)?.level??0;for(;e!=null;){let i=n.collection.getItem(e);if(!i)break;if(i.type!==`item`){e=n.collection.getKeyAfter(e);continue}if((i.level??0)<=r)break;t=e,e=n.collection.getKeyAfter(e)}}i=e??t??i}return(0,g.useMemo)(()=>new Set([r,i].filter(e=>e!=null)),[r,i])}var xv=(0,g.createContext)({}),Sv=Uh(aee,function(e,t){return[e,t]=tp(e,t,xv),g.createElement(op.header,{className:`react-aria-Header`,...e,ref:t},e.children)}),Cv=(0,g.createContext)(null);function wv(e){let t=(0,g.useRef)({});return g.createElement(Cv.Provider,{value:t},e.children)}var Tv=(0,g.createContext)({isSelected:!1}),Ev=(0,g.createContext)({});(class extends ch{static{this.type=`separator`}filter(e,t){let n=t.getItem(this.prevKey);if(n&&n.type!==`separator`){let n=this.clone();return t.addDescendants(n,e),n}return null}});var Dv=new WeakMap;function Ov(e){return typeof e==`string`?e.replace(/\s*/g,``):``+e}function kv(e,t){let n=Dv.get(e);if(!n)throw Error(`Unknown list`);return`${n.id}-option-${Ov(t)}`}var Av=class{constructor(e,t,n,r){this._walkerStack=[],this._currentSetFor=new Set,this._acceptNode=e=>{if(e.nodeType===Node.ELEMENT_NODE){let t=e.shadowRoot;if(t){let e=this._doc.createTreeWalker(t,this.whatToShow,{acceptNode:this._acceptNode});return this._walkerStack.unshift(e),NodeFilter.FILTER_ACCEPT}else if(typeof this.filter==`function`)return this.filter(e);else if(this.filter?.acceptNode)return this.filter.acceptNode(e);else if(this.filter===null)return NodeFilter.FILTER_ACCEPT}return NodeFilter.FILTER_SKIP},this._doc=e,this.root=t,this.filter=r??null,this.whatToShow=n??NodeFilter.SHOW_ALL,this._currentNode=t,this._walkerStack.unshift(e.createTreeWalker(t,n,this._acceptNode));let i=t.shadowRoot;if(i){let e=this._doc.createTreeWalker(i,this.whatToShow,{acceptNode:this._acceptNode});this._walkerStack.unshift(e)}}get currentNode(){return this._currentNode}set currentNode(e){if(!U(this.root,e))throw Error(`Cannot set currentNode to a node that is not contained by the root node.`);let t=[],n=e,r=e;for(this._currentNode=e;n&&n!==this.root;)if(n.nodeType===Node.DOCUMENT_FRAGMENT_NODE){let e=n,i=this._doc.createTreeWalker(e,this.whatToShow,{acceptNode:this._acceptNode});t.push(i),i.currentNode=r,this._currentSetFor.add(i),n=r=e.host}else n=n.parentNode;let i=this._doc.createTreeWalker(this.root,this.whatToShow,{acceptNode:this._acceptNode});t.push(i),i.currentNode=r,this._currentSetFor.add(i),this._walkerStack=t}get doc(){return this._doc}firstChild(){let e=this.currentNode,t=this.nextNode();return U(e,t)?(t&&(this.currentNode=t),t):(this.currentNode=e,null)}lastChild(){let e=this._walkerStack[0].lastChild();return e&&(this.currentNode=e),e}nextNode(){let e=this._walkerStack[0].nextNode();if(e){if(e.shadowRoot){let t;if(typeof this.filter==`function`?t=this.filter(e):this.filter?.acceptNode&&(t=this.filter.acceptNode(e)),t===NodeFilter.FILTER_ACCEPT)return this.currentNode=e,e;let n=this.nextNode();return n&&(this.currentNode=n),n}return e&&(this.currentNode=e),e}else if(this._walkerStack.length>1){this._walkerStack.shift();let e=this.nextNode();return e&&(this.currentNode=e),e}else return null}previousNode(){let e=this._walkerStack[0];if(e.currentNode===e.root){if(this._currentSetFor.has(e))if(this._currentSetFor.delete(e),this._walkerStack.length>1){this._walkerStack.shift();let e=this.previousNode();return e&&(this.currentNode=e),e}else return null;return null}let t=e.previousNode();if(t){if(t.shadowRoot){let e;if(typeof this.filter==`function`?e=this.filter(t):this.filter?.acceptNode&&(e=this.filter.acceptNode(t)),e===NodeFilter.FILTER_ACCEPT)return t&&(this.currentNode=t),t;let n=this.lastChild();return n&&(this.currentNode=n),n}return t&&(this.currentNode=t),t}else if(this._walkerStack.length>1){this._walkerStack.shift();let e=this.previousNode();return e&&(this.currentNode=e),e}else return null}nextSibling(){return null}previousSibling(){return null}parentNode(){return null}};function jv(e,t,n,r){return mp()?new Av(e,t,n,r):e.createTreeWalker(t,n,r)}var Mv=g.createContext(null),Nv=`react-aria-focus-scope-restore`,Pv=null;function Fv(e){let{children:t,contain:n,restoreFocus:r,autoFocus:i}=e,a=(0,g.useRef)(null),o=(0,g.useRef)(null),s=(0,g.useRef)([]),{parentNode:c}=(0,g.useContext)(Mv)||{},l=(0,g.useMemo)(()=>new ay({scopeRef:s}),[s]);Tf(()=>{let e=c||oy.root;if(oy.getTreeNode(e.scopeRef)&&Pv&&!Kv(Pv,e.scopeRef)){let t=oy.getTreeNode(Pv);t&&(e=t)}e.addChild(l),oy.addNode(l)},[l,c]),Tf(()=>{let e=oy.getTreeNode(s);e&&(e.contain=!!n)},[n]),Tf(()=>{let e=a.current?.nextSibling,t=[],n=e=>e.stopPropagation();for(;e&&e!==o.current;)t.push(e),e.addEventListener(Nv,n),e=e.nextSibling;return s.current=t,()=>{for(let e of t)e.removeEventListener(Nv,n)}},[t]),Zv(s,r,n),Vv(s,n),$v(s,r,n),Xv(s,i),(0,g.useEffect)(()=>{let e=hp(lp(s.current?s.current[0]:void 0)),t=null;if(Uv(e,s.current)){for(let n of oy.traverse())n.scopeRef&&Uv(e,n.scopeRef.current)&&(t=n);t===oy.getTreeNode(s)&&(Pv=t.scopeRef)}},[s]),Tf(()=>()=>{let e=oy.getTreeNode(s)?.parent?.scopeRef??null;(s===Pv||Kv(s,Pv))&&(!e||oy.getTreeNode(e))&&(Pv=e),oy.removeTreeNode(s)},[s]);let u=(0,g.useMemo)(()=>Iv(s),[]),d=(0,g.useMemo)(()=>({focusManager:u,parentNode:l}),[l,u]);return g.createElement(Mv.Provider,{value:d},g.createElement(`span`,{"data-focus-scope-start":!0,hidden:!0,ref:a}),t,g.createElement(`span`,{"data-focus-scope-end":!0,hidden:!0,ref:o}))}function Iv(e){return{focusNext(t={}){let n=e.current,{from:r,tabbable:i,wrap:a,accept:o}=t,s=r||hp(lp(n[0]??void 0)),c=n[0].previousElementSibling,l=ty(Lv(n),{tabbable:i,accept:o},n);l.currentNode=Uv(s,n)?s:c;let u=l.nextNode();return!u&&a&&(l.currentNode=c,u=l.nextNode()),u&&qv(u,!0),u},focusPrevious(t={}){let n=e.current,{from:r,tabbable:i,wrap:a,accept:o}=t,s=r||hp(lp(n[0]??void 0)),c=n[n.length-1].nextElementSibling,l=ty(Lv(n),{tabbable:i,accept:o},n);l.currentNode=Uv(s,n)?s:c;let u=l.previousNode();return!u&&a&&(l.currentNode=c,u=l.previousNode()),u&&qv(u,!0),u},focusFirst(t={}){let n=e.current,{tabbable:r,accept:i}=t,a=ty(Lv(n),{tabbable:r,accept:i},n);a.currentNode=n[0].previousElementSibling;let o=a.nextNode();return o&&qv(o,!0),o},focusLast(t={}){let n=e.current,{tabbable:r,accept:i}=t,a=ty(Lv(n),{tabbable:r,accept:i},n);a.currentNode=n[n.length-1].nextElementSibling;let o=a.previousNode();return o&&qv(o,!0),o}}}function Lv(e){return e[0].parentElement}function Rv(e){let t=oy.getTreeNode(Pv);for(;t&&t.scopeRef!==e;){if(t.contain)return!1;t=t.parent}return!0}function zv(e){if(!e.form)return Array.from(lp(e).querySelectorAll(`input[type="radio"][name="${CSS.escape(e.name)}"]`)).filter(e=>!e.form);let t=e.form.elements.namedItem(e.name),n=up(e);return t instanceof n.RadioNodeList?Array.from(t).filter(e=>e instanceof n.HTMLInputElement):t instanceof n.HTMLInputElement?[t]:[]}function Bv(e){if(e.checked)return!0;let t=zv(e);return t.length>0&&!t.some(e=>e.checked)}function Vv(e,t){let n=(0,g.useRef)(void 0),r=(0,g.useRef)(void 0);Tf(()=>{let i=e.current;if(!t){r.current&&=(cancelAnimationFrame(r.current),void 0);return}let a=lp(i?i[0]:void 0),o=t=>{if(t.key!==`Tab`||t.altKey||t.ctrlKey||t.metaKey||!Rv(e)||t.isComposing)return;let n=hp(a),r=e.current;if(!r||!Uv(n,r))return;let i=ty(Lv(r),{tabbable:!0},r);if(!n)return;i.currentNode=n;let o=t.shiftKey?i.previousNode():i.nextNode();o||=(i.currentNode=t.shiftKey?r[r.length-1].nextElementSibling:r[0].previousElementSibling,t.shiftKey?i.previousNode():i.nextNode()),t.preventDefault(),o&&(qv(o,!0),o instanceof up(o).HTMLInputElement&&o.select())},s=t=>{(!Pv||Kv(Pv,e))&&Uv(W(t),e.current)?(Pv=e,n.current=W(t)):Rv(e)&&!Wv(W(t),e)?n.current?n.current.focus():Pv&&Pv.current&&Yv(Pv.current):Rv(e)&&(n.current=W(t))},c=t=>{r.current&&cancelAnimationFrame(r.current),r.current=requestAnimationFrame(()=>{let r=Tm(),i=(r===`virtual`||r===null)&&Zp()&&Xp(),o=hp(a);if(!i&&o&&Rv(e)&&!Wv(o,e)){Pv=e;let r=W(t);r&&r.isConnected?(n.current=r,n.current?.focus()):Pv.current&&Yv(Pv.current)}})};return a.addEventListener(`keydown`,o,!1),a.addEventListener(`focusin`,s,!1),i?.forEach(e=>e.addEventListener(`focusin`,s,!1)),i?.forEach(e=>e.addEventListener(`focusout`,c,!1)),()=>{a.removeEventListener(`keydown`,o,!1),a.removeEventListener(`focusin`,s,!1),i?.forEach(e=>e.removeEventListener(`focusin`,s,!1)),i?.forEach(e=>e.removeEventListener(`focusout`,c,!1))}},[e,t]),Tf(()=>()=>{r.current&&cancelAnimationFrame(r.current)},[r])}function Hv(e){return Wv(e)}function Uv(e,t){return!e||!t?!1:t.some(t=>U(t,e))}function Wv(e,t=null){if(e instanceof Element&&e.closest(`[data-react-aria-top-layer]`))return!0;for(let{scopeRef:n}of oy.traverse(oy.getTreeNode(t)))if(n&&Uv(e,n.current))return!0;return!1}function Gv(e){return Wv(e,Pv)}function Kv(e,t){let n=oy.getTreeNode(t)?.parent;for(;n;){if(n.scopeRef===e)return!0;n=n.parent}return!1}function qv(e,t=!1){if(e!=null&&!t)try{Th(e)}catch{}else if(e!=null)try{e.focus()}catch{}}function Jv(e,t=!0){let n=e[0].previousElementSibling,r=Lv(e),i=ty(r,{tabbable:t},e);i.currentNode=n;let a=i.nextNode();return t&&!a&&(r=Lv(e),i=ty(r,{tabbable:!1},e),i.currentNode=n,a=i.nextNode()),a}function Yv(e,t=!0){qv(Jv(e,t))}function Xv(e,t){let n=g.useRef(t);(0,g.useEffect)(()=>{n.current&&(Pv=e,!Uv(hp(lp(e.current?e.current[0]:void 0)),Pv.current)&&e.current&&Yv(e.current)),n.current=!1},[e])}function Zv(e,t,n){Tf(()=>{if(t||n)return;let r=e.current,i=lp(r?r[0]:void 0),a=t=>{let n=W(t);Uv(n,e.current)?Pv=e:Hv(n)||(Pv=null)};return i.addEventListener(`focusin`,a,!1),r?.forEach(e=>e.addEventListener(`focusin`,a,!1)),()=>{i.removeEventListener(`focusin`,a,!1),r?.forEach(e=>e.removeEventListener(`focusin`,a,!1))}},[e,t,n])}function Qv(e){let t=oy.getTreeNode(Pv);for(;t&&t.scopeRef!==e;){if(t.nodeToRestore)return!1;t=t.parent}return t?.scopeRef===e}function $v(e,t,n){let r=(0,g.useRef)(typeof document<`u`?hp(lp(e.current?e.current[0]:void 0)):null);Tf(()=>{let r=e.current,i=lp(r?r[0]:void 0);if(!t||n)return;let a=()=>{(!Pv||Kv(Pv,e))&&Uv(hp(i),e.current)&&(Pv=e)};return i.addEventListener(`focusin`,a,!1),r?.forEach(e=>e.addEventListener(`focusin`,a,!1)),()=>{i.removeEventListener(`focusin`,a,!1),r?.forEach(e=>e.removeEventListener(`focusin`,a,!1))}},[e,n]),Tf(()=>{let r=lp(e.current?e.current[0]:void 0);if(!t)return;let i=t=>{if(t.key!==`Tab`||t.altKey||t.ctrlKey||t.metaKey||!Rv(e)||t.isComposing)return;let n=r.activeElement;if(!Wv(n,e)||!Qv(e))return;let i=oy.getTreeNode(e);if(!i)return;let a=i.nodeToRestore,o=ty(r.body,{tabbable:!0});o.currentNode=n;let s=t.shiftKey?o.previousNode():o.nextNode();if((!a||!a.isConnected||a===r.body)&&(a=void 0,i.nodeToRestore=void 0),(!s||!Wv(s,e))&&a){o.currentNode=a;do s=t.shiftKey?o.previousNode():o.nextNode();while(Wv(s,e));t.preventDefault(),t.stopPropagation(),s?qv(s,!0):Hv(a)?qv(a,!0):n.blur()}};return n||r.addEventListener(`keydown`,i,!0),()=>{n||r.removeEventListener(`keydown`,i,!0)}},[e,t,n]),Tf(()=>{let n=lp(e.current?e.current[0]:void 0);if(!t)return;let i=oy.getTreeNode(e);if(i)return i.nodeToRestore=r.current??void 0,()=>{let r=oy.getTreeNode(e);if(!r)return;let i=r.nodeToRestore,a=hp(n);if(t&&i&&(a&&Wv(a,e)||a===n.body&&Qv(e))){let t=oy.clone();requestAnimationFrame(()=>{if(n.activeElement===n.body){let n=t.getTreeNode(e);for(;n;){if(n.nodeToRestore&&n.nodeToRestore.isConnected){ey(n.nodeToRestore);return}n=n.parent}for(n=t.getTreeNode(e);n;){if(n.scopeRef&&n.scopeRef.current&&oy.getTreeNode(n.scopeRef)){ey(Jv(n.scopeRef.current,!0));return}n=n.parent}}})}}},[e,t])}function ey(e){e.dispatchEvent(new CustomEvent(Nv,{bubbles:!0,cancelable:!0}))&&qv(e)}function ty(e,t,n){let r=t?.tabbable?Pp:Np,i=lp(e?.nodeType===Node.ELEMENT_NODE?e:null),a=jv(i,e||i,NodeFilter.SHOW_ELEMENT,{acceptNode(e){return U(t?.from,e)||t?.tabbable&&e.tagName===`INPUT`&&e.getAttribute(`type`)===`radio`&&(!Bv(e)||a.currentNode.tagName===`INPUT`&&a.currentNode.type===`radio`&&a.currentNode.name===e.name)?NodeFilter.FILTER_REJECT:r(e)&&(!n||Uv(e,n))&&(!t?.accept||t.accept(e))?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});return t?.from&&(a.currentNode=t.from),a}function ny(e,t={}){return{focusNext(n={}){let r=e.current;if(!r)return null;let{from:i,tabbable:a=t.tabbable,wrap:o=t.wrap,accept:s=t.accept}=n,c=i||hp(lp(r)),l=ty(r,{tabbable:a,accept:s});U(r,c)&&(l.currentNode=c);let u=l.nextNode();return!u&&o&&(l.currentNode=r,u=l.nextNode()),u&&qv(u,!0),u},focusPrevious(n=t){let r=e.current;if(!r)return null;let{from:i,tabbable:a=t.tabbable,wrap:o=t.wrap,accept:s=t.accept}=n,c=i||hp(lp(r)),l=ty(r,{tabbable:a,accept:s});if(U(r,c))l.currentNode=c;else{let e=ry(l);return e&&qv(e,!0),e??null}let u=l.previousNode();if(!u&&o){l.currentNode=r;let e=ry(l);if(!e)return null;u=e}return u&&qv(u,!0),u??null},focusFirst(n=t){let r=e.current;if(!r)return null;let{tabbable:i=t.tabbable,accept:a=t.accept}=n,o=ty(r,{tabbable:i,accept:a}).nextNode();return o&&qv(o,!0),o},focusLast(n=t){let r=e.current;if(!r)return null;let{tabbable:i=t.tabbable,accept:a=t.accept}=n,o=ry(ty(r,{tabbable:i,accept:a}));return o&&qv(o,!0),o??null}}}function ry(e){let t,n;do n=e.lastChild(),n&&(t=n);while(n);return t}var iy=class e{constructor(){this.fastMap=new Map,this.root=new ay({scopeRef:null}),this.fastMap.set(null,this.root)}get size(){return this.fastMap.size}getTreeNode(e){return this.fastMap.get(e)}addTreeNode(e,t,n){let r=this.fastMap.get(t??null);if(!r)return;let i=new ay({scopeRef:e});r.addChild(i),i.parent=r,this.fastMap.set(e,i),n&&(i.nodeToRestore=n)}addNode(e){this.fastMap.set(e.scopeRef,e)}removeTreeNode(e){if(e===null)return;let t=this.fastMap.get(e);if(!t)return;let n=t.parent;for(let e of this.traverse())e!==t&&t.nodeToRestore&&e.nodeToRestore&&t.scopeRef&&t.scopeRef.current&&Uv(e.nodeToRestore,t.scopeRef.current)&&(e.nodeToRestore=t.nodeToRestore);let r=t.children;n&&(n.removeChild(t),r.size>0&&r.forEach(e=>n&&n.addChild(e))),this.fastMap.delete(t.scopeRef)}*traverse(e=this.root){if(e.scopeRef!=null&&(yield e),e.children.size>0)for(let t of e.children)yield*this.traverse(t)}clone(){let t=new e;for(let e of this.traverse())t.addTreeNode(e.scopeRef,e.parent?.scopeRef??null,e.nodeToRestore);return t}},ay=class{constructor(e){this.children=new Set,this.contain=!1,this.scopeRef=e.scopeRef}addChild(e){this.children.add(e),e.parent=this}removeChild(e){this.children.delete(e),e.parent=void 0}},oy=new iy;function sy(e){return Jp()?e.altKey:e.ctrlKey}function cy(e,t){let n=`[data-key="${CSS.escape(String(t))}"]`,r=e.current?.dataset.collection;return r&&(n=`[data-collection="${CSS.escape(r)}"]${n}`),e.current?.querySelector(n)}var ly=new WeakMap;function uy(e){let t=Hf();return ly.set(e,t),t}function dy(e){return ly.get(e)}var fy=1e3;function py(e){let{keyboardDelegate:t,selectionManager:n,onTypeSelect:r}=e,i=(0,g.useRef)({search:``,timeout:void 0}).current;return{typeSelectProps:{onKeyDownCapture:t.getKeyForSearch?e=>{let a=my(e.key);if(!(!a||e.ctrlKey||e.metaKey||!U(e.currentTarget,W(e))||i.search.length===0&&a===` `)){if(a===` `&&i.search.trim().length>0&&(e.preventDefault(),`continuePropagation`in e||e.stopPropagation()),i.search+=a,t.getKeyForSearch!=null){let e=t.getKeyForSearch(i.search,n.focusedKey);e??=t.getKeyForSearch(i.search),e!=null&&(n.setFocusedKey(e),r&&r(e))}clearTimeout(i.timeout),i.timeout=setTimeout(()=>{i.search=``},fy)}}:void 0}}}function my(e){return e.length===1||!/^[A-Z]/i.test(e)?e:``}function hy(e,t){let n=(0,g.useRef)(!0),r=(0,g.useRef)(null);Tf(()=>(n.current=!0,()=>{n.current=!1}),[]),Tf(()=>{n.current?n.current=!1:(!r.current||t.some((e,t)=>!Object.is(e,r[t])))&&e(),r.current=t},t)}function gy(e){let{selectionManager:t,keyboardDelegate:n,ref:r,autoFocus:i=!1,shouldFocusWrap:a=!1,disallowEmptySelection:o=!1,disallowSelectAll:s=!1,escapeKeyBehavior:c=`clearSelection`,selectOnFocus:l=t.selectionBehavior===`replace`,disallowTypeAhead:u=!1,shouldUseVirtualFocus:d,allowsTabNavigation:f=!1,scrollRef:p=r,linkBehavior:m=`action`}=e,{direction:h}=Wm(),_=nm(),v=e=>{if(e.altKey&&e.key===`Tab`&&e.preventDefault(),!r.current||!U(r.current,W(e)))return;let i=(n,i)=>{if(n!=null){if(t.isLink(n)&&m===`selection`&&l&&!sy(e)){(0,Ph.flushSync)(()=>{t.setFocusedKey(n,i)});let a=cy(r,n),o=t.getItemProps(n);a&&_.open(a,e,o.href,o.routerOptions);return}if(t.setFocusedKey(n,i),t.isLink(n)&&m===`override`)return;e.shiftKey&&t.selectionMode===`multiple`?t.extendSelection(n):l&&!sy(e)&&t.replaceSelection(n)}};switch(e.key){case`ArrowDown`:if(n.getKeyBelow){let r=t.focusedKey==null?n.getFirstKey?.():n.getKeyBelow?.(t.focusedKey);r==null&&a&&(r=n.getFirstKey?.(t.focusedKey)),r!=null&&(e.preventDefault(),i(r))}break;case`ArrowUp`:if(n.getKeyAbove){let r=t.focusedKey==null?n.getLastKey?.():n.getKeyAbove?.(t.focusedKey);r==null&&a&&(r=n.getLastKey?.(t.focusedKey)),r!=null&&(e.preventDefault(),i(r))}break;case`ArrowLeft`:if(n.getKeyLeftOf){let r=t.focusedKey==null?n.getFirstKey?.():n.getKeyLeftOf?.(t.focusedKey);r==null&&a&&(r=h===`rtl`?n.getFirstKey?.(t.focusedKey):n.getLastKey?.(t.focusedKey)),r!=null&&(e.preventDefault(),i(r,h===`rtl`?`first`:`last`))}break;case`ArrowRight`:if(n.getKeyRightOf){let r=t.focusedKey==null?n.getFirstKey?.():n.getKeyRightOf?.(t.focusedKey);r==null&&a&&(r=h===`rtl`?n.getLastKey?.(t.focusedKey):n.getFirstKey?.(t.focusedKey)),r!=null&&(e.preventDefault(),i(r,h===`rtl`?`last`:`first`))}break;case`Home`:if(n.getFirstKey){if(t.focusedKey===null&&e.shiftKey)return;e.preventDefault();let r=n.getFirstKey(t.focusedKey,jm(e));t.setFocusedKey(r),r!=null&&(jm(e)&&e.shiftKey&&t.selectionMode===`multiple`?t.extendSelection(r):l&&t.replaceSelection(r))}break;case`End`:if(n.getLastKey){if(t.focusedKey===null&&e.shiftKey)return;e.preventDefault();let r=n.getLastKey(t.focusedKey,jm(e));t.setFocusedKey(r),r!=null&&(jm(e)&&e.shiftKey&&t.selectionMode===`multiple`?t.extendSelection(r):l&&t.replaceSelection(r))}break;case`PageDown`:if(n.getKeyPageBelow&&t.focusedKey!=null){let r=n.getKeyPageBelow(t.focusedKey);r!=null&&(e.preventDefault(),i(r))}break;case`PageUp`:if(n.getKeyPageAbove&&t.focusedKey!=null){let r=n.getKeyPageAbove(t.focusedKey);r!=null&&(e.preventDefault(),i(r))}break;case`a`:jm(e)&&t.selectionMode===`multiple`&&s!==!0&&(e.preventDefault(),t.selectAll());break;case`Escape`:c===`clearSelection`&&!o&&t.selectedKeys.size!==0&&(e.stopPropagation(),e.preventDefault(),t.clearSelection());break;case`Tab`:if(!f){if(e.shiftKey)r.current.focus();else{let e=ty(r.current,{tabbable:!0}),t,n;do n=e.lastChild(),n&&(t=n);while(n);let i=hp();t&&(!gp(t)||i&&!Pp(i))&&xp(t)}break}}},y=(0,g.useRef)({top:0,left:0});Fm(p,`scroll`,()=>{y.current={top:p.current?.scrollTop??0,left:p.current?.scrollLeft??0}});let b=e=>{if(t.isFocused){U(e.currentTarget,W(e))||t.setFocused(!1);return}if(U(e.currentTarget,W(e))){if(t.setFocused(!0),t.focusedKey==null){let r=e=>{e!=null&&(t.setFocusedKey(e),l&&!t.isSelected(e)&&t.replaceSelection(e))},i=e.relatedTarget;i&&e.currentTarget.compareDocumentPosition(i)&Node.DOCUMENT_POSITION_FOLLOWING?r(t.lastSelectedKey??n.getLastKey?.()):r(t.firstSelectedKey??n.getFirstKey?.())}else p.current&&(p.current.scrollTop=y.current.top,p.current.scrollLeft=y.current.left);if(t.focusedKey!=null&&p.current){let e=cy(r,t.focusedKey);e instanceof HTMLElement&&(!gp(e)&&!d&&xp(e),Tm()===`keyboard`&&i_(e,{containingElement:r.current}))}}},x=e=>{U(e.currentTarget,e.relatedTarget)||t.setFocused(!1)},S=(0,g.useRef)(!1);Fm(r,cp,d?e=>{let{detail:n}=e;e.stopPropagation(),t.setFocused(!0),n?.focusStrategy===`first`&&(S.current=!0)}:void 0),hy(()=>{if(S.current){let e=n.getFirstKey?.()??null;if(e==null){let e=hp();_p(r.current),yp(e,null),t.collection.size>0&&(S.current=!1)}else t.setFocusedKey(e),S.current=!1}},[t.collection]),hy(()=>{t.collection.size>0&&(S.current=!1)},[t.focusedKey]),Fm(r,sp,d?e=>{e.stopPropagation(),t.setFocused(!1),e.detail?.clearFocusKey&&t.setFocusedKey(null)}:void 0);let C=(0,g.useRef)(i),w=(0,g.useRef)(!1);(0,g.useEffect)(()=>{if(C.current){let e=null;i===`first`&&(e=n.getFirstKey?.()??null),i===`last`&&(e=n.getLastKey?.()??null);let a=t.selectedKeys;if(a.size){for(let n of a)if(t.canSelectItem(n)){e=n;break}}t.setFocused(!0),t.setFocusedKey(e),e==null&&!d&&r.current&&Th(r.current),t.collection.size>0&&(C.current=!1,w.current=!0)}});let T=(0,g.useRef)(t.focusedKey),E=(0,g.useRef)(null);(0,g.useEffect)(()=>{if(t.isFocused&&t.focusedKey!=null&&(t.focusedKey!==T.current||w.current)&&p.current&&r.current){let e=Tm(),n=cy(r,t.focusedKey);if(!(n instanceof HTMLElement))return;(e===`keyboard`||w.current)&&(E.current&&cancelAnimationFrame(E.current),E.current=requestAnimationFrame(()=>{p.current&&(r_(p.current,n),e!==`virtual`&&i_(n,{containingElement:r.current}))}))}!d&&t.isFocused&&t.focusedKey==null&&T.current!=null&&r.current&&Th(r.current),T.current=t.focusedKey,w.current=!1}),(0,g.useEffect)(()=>()=>{E.current&&cancelAnimationFrame(E.current)},[]),Fm(r,`react-aria-focus-scope-restore`,e=>{e.preventDefault(),t.setFocused(!0)});let D={onKeyDown:v,onFocus:b,onBlur:x,onMouseDown(e){p.current===W(e)&&e.preventDefault()}},{typeSelectProps:O}=py({keyboardDelegate:n,selectionManager:t});u||(D=Yf(O,D));let k;d||(k=t.focusedKey==null?0:-1);let A=uy(t.collection);return{collectionProps:Yf(D,{tabIndex:k,"data-collection":A})}}var _y=class{constructor(e){this.ref=e}getItemRect(e){let t=this.ref.current;if(!t)return null;let n=e==null?null:cy(this.ref,e);if(!n)return null;let r=t.getBoundingClientRect(),i=n.getBoundingClientRect();return{x:i.left-r.left-t.clientLeft+t.scrollLeft,y:i.top-r.top-t.clientTop+t.scrollTop,width:i.width,height:i.height}}getContentSize(){let e=this.ref.current;return{width:e?.scrollWidth??0,height:e?.scrollHeight??0}}getVisibleRect(){let e=this.ref.current;return{x:e?.scrollLeft??0,y:e?.scrollTop??0,width:e?.clientWidth??0,height:e?.clientHeight??0}}},vy=class{constructor(...e){if(e.length===1){let t=e[0];this.collection=t.collection,this.ref=t.ref,this.collator=t.collator,this.disabledKeys=t.disabledKeys||new Set,this.disabledBehavior=t.disabledBehavior||`all`,this.orientation=t.orientation||`vertical`,this.direction=t.direction,this.layout=t.layout||`stack`,this.layoutDelegate=t.layoutDelegate||new _y(t.ref)}else this.collection=e[0],this.disabledKeys=e[1],this.ref=e[2],this.collator=e[3],this.layout=`stack`,this.orientation=`vertical`,this.disabledBehavior=`all`,this.layoutDelegate=new _y(this.ref);this.layout===`stack`&&this.orientation===`vertical`&&(this.getKeyLeftOf=void 0,this.getKeyRightOf=void 0)}isDisabled(e){return this.disabledBehavior===`all`&&(e.props?.isDisabled||this.disabledKeys.has(e.key))&&e.props?.disabledBehavior!==`selection`}findNextNonDisabled(e,t,n=!1){let r=e;for(;r!=null;){let e=this.collection.getItem(r);if(e?.type===`item`&&(n||!this.isDisabled(e)))return r;r=t(r)}return null}getNextKey(e,t){let n=e;return n=this.collection.getKeyAfter(n),this.findNextNonDisabled(n,e=>this.collection.getKeyAfter(e),t?.includeDisabled)}getPreviousKey(e,t){let n=e;return n=this.collection.getKeyBefore(n),this.findNextNonDisabled(n,e=>this.collection.getKeyBefore(e),t?.includeDisabled)}findKey(e,t,n){let r=e,i=this.layoutDelegate.getItemRect(r);if(!i||r==null)return null;let a=i;do{if(r=t(r),r==null)break;i=this.layoutDelegate.getItemRect(r)}while(i&&n(a,i)&&r!=null);return r}isSameRow(e,t){return e.y===t.y||e.x!==t.x}isSameColumn(e,t){return e.x===t.x||e.y!==t.y}getKeyBelow(e,t){return this.layout===`grid`&&this.orientation===`vertical`?this.findKey(e,e=>this.getNextKey(e,t),this.isSameRow):this.getNextKey(e,t)}getKeyAbove(e,t){return this.layout===`grid`&&this.orientation===`vertical`?this.findKey(e,e=>this.getPreviousKey(e,t),this.isSameRow):this.getPreviousKey(e,t)}getNextColumn(e,t,n){return t?this.getPreviousKey(e,n):this.getNextKey(e,n)}getKeyRightOf(e,t){let n=this.direction===`ltr`?`getKeyRightOf`:`getKeyLeftOf`;return this.layoutDelegate[n]?(e=this.layoutDelegate[n](e),this.findNextNonDisabled(e,e=>this.layoutDelegate[n](e),t?.includeDisabled)):this.layout===`grid`?this.orientation===`vertical`?this.getNextColumn(e,this.direction===`rtl`,t):this.findKey(e,e=>this.getNextColumn(e,this.direction===`rtl`,t),this.isSameColumn):this.orientation===`horizontal`?this.getNextColumn(e,this.direction===`rtl`,t):null}getKeyLeftOf(e,t){let n=this.direction===`ltr`?`getKeyLeftOf`:`getKeyRightOf`;return this.layoutDelegate[n]?(e=this.layoutDelegate[n](e),this.findNextNonDisabled(e,e=>this.layoutDelegate[n](e),t?.includeDisabled)):this.layout===`grid`?this.orientation===`vertical`?this.getNextColumn(e,this.direction===`ltr`,t):this.findKey(e,e=>this.getNextColumn(e,this.direction===`ltr`,t),this.isSameColumn):this.orientation===`horizontal`?this.getNextColumn(e,this.direction===`ltr`,t):null}getFirstKey(){let e=this.collection.getFirstKey();return this.findNextNonDisabled(e,e=>this.collection.getKeyAfter(e))}getLastKey(){let e=this.collection.getLastKey();return this.findNextNonDisabled(e,e=>this.collection.getKeyBefore(e))}getKeyPageAbove(e){let t=this.ref.current,n=this.layoutDelegate.getItemRect(e);if(!n)return null;if(t&&!e_(t))return this.getFirstKey();let r=e;if(this.orientation===`horizontal`){let e=Math.max(0,n.x+n.width-this.layoutDelegate.getVisibleRect().width);for(;n&&n.x>e&&r!=null;)r=this.getKeyAbove(r),n=r==null?null:this.layoutDelegate.getItemRect(r)}else{let e=Math.max(0,n.y+n.height-this.layoutDelegate.getVisibleRect().height);for(;n&&n.y>e&&r!=null;)r=this.getKeyAbove(r),n=r==null?null:this.layoutDelegate.getItemRect(r)}return r??this.getFirstKey()}getKeyPageBelow(e){let t=this.ref.current,n=this.layoutDelegate.getItemRect(e);if(!n)return null;if(t&&!e_(t))return this.getLastKey();let r=e;if(this.orientation===`horizontal`){let e=Math.min(this.layoutDelegate.getContentSize().width,n.x-n.width+this.layoutDelegate.getVisibleRect().width);for(;n&&n.xe[0]a||new vy({collection:n,disabledKeys:r,disabledBehavior:l,ref:i,collator:c,layoutDelegate:o,orientation:s}),[a,o,n,r,i,c,l,s]),{collectionProps:d}=gy({...e,ref:i,selectionManager:t,keyboardDelegate:u});return{listProps:d}}function Sy(e,t,n){let r=og(e,{labelable:!0}),i=e.selectionBehavior||`toggle`,a=e.orientation||`vertical`,o=e.linkBehavior||(i===`replace`?`action`:`override`);i===`toggle`&&o===`action`&&(o=`override`);let{listProps:s}=xy({...e,ref:n,selectionManager:t.selectionManager,collection:t.collection,disabledKeys:t.disabledKeys,linkBehavior:o}),{focusWithinProps:c}=Ag({onFocusWithin:e.onFocus,onBlurWithin:e.onBlur,onFocusWithinChange:e.onFocusChange}),l=Hf(e.id);Dv.set(t,{id:l,shouldUseVirtualFocus:e.shouldUseVirtualFocus,shouldSelectOnPressUp:e.shouldSelectOnPressUp,shouldFocusOnHover:e.shouldFocusOnHover,isVirtualized:e.isVirtualized,onAction:e.onAction,linkBehavior:o,UNSTABLE_itemBehavior:e.UNSTABLE_itemBehavior});let{labelProps:u,fieldProps:d}=zg({...e,id:l,labelElementType:`span`});return{labelProps:u,listBoxProps:Yf(r,c,t.selectionManager.selectionMode===`multiple`?{"aria-multiselectable":`true`}:{},{role:`listbox`,"aria-orientation":a,...Yf(d,s)})}}var Cy=500;function wy(e){let{isDisabled:t,onLongPressStart:n,onLongPressEnd:r,onLongPress:i,threshold:a=Cy,accessibilityDescription:o}=e,s=(0,g.useRef)(void 0),{addGlobalListener:c,removeGlobalListener:l}=gg(),{pressProps:u}=Sg({isDisabled:t,onPressStart(e){if(e.continuePropagation(),(e.pointerType===`mouse`||e.pointerType===`touch`)&&(n&&n({...e,type:`longpressstart`}),s.current=setTimeout(()=>{e.target.dispatchEvent(new PointerEvent(`pointercancel`,{bubbles:!0})),lp(e.target).activeElement!==e.target&&xp(e.target),i&&i({...e,type:`longpress`}),s.current=void 0},a),e.pointerType===`touch`)){let t=e=>{e.preventDefault()},n=up(e.target);c(e.target,`contextmenu`,t,{once:!0}),c(n,`pointerup`,()=>{setTimeout(()=>{l(e.target,`contextmenu`,t)},30)},{once:!0})}},onPressEnd(e){s.current&&clearTimeout(s.current),r&&(e.pointerType===`mouse`||e.pointerType===`touch`)&&r({...e,type:`longpressend`})}});return{longPressProps:Yf(u,s_(i&&!t?o:void 0))}}function Ty(e){let{id:t,selectionManager:n,key:r,ref:i,shouldSelectOnPressUp:a,shouldUseVirtualFocus:o,focus:s,isDisabled:c,onAction:l,allowsDifferentPressOrigin:u,linkBehavior:d=`action`}=e,f=nm();t=Hf(t);let p=e=>{if(e.pointerType===`keyboard`&&sy(e))n.toggleSelection(r);else{if(n.selectionMode===`none`)return;if(n.isLink(r)){if(d===`selection`&&i.current){let t=n.getItemProps(r);f.open(i.current,e,t.href,t.routerOptions),n.setSelectedKeys(n.selectedKeys);return}else if(d===`override`||d===`none`)return}n.selectionMode===`single`?n.isSelected(r)&&!n.disallowEmptySelection?n.toggleSelection(r):n.replaceSelection(r):e&&e.shiftKey?n.extendSelection(r):n.selectionBehavior===`toggle`||e&&(jm(e)||e.pointerType===`touch`||e.pointerType===`virtual`)?n.toggleSelection(r):n.replaceSelection(r)}};(0,g.useEffect)(()=>{r===n.focusedKey&&n.isFocused&&(o?_p(i.current):s?s():hp()!==i.current&&i.current&&Th(i.current))},[i,r,n.focusedKey,n.childFocusStrategy,n.isFocused,o]),c||=n.isDisabled(r);let m={};!o&&!c?m={tabIndex:r===n.focusedKey?0:-1,onFocus(e){W(e)===i.current&&n.setFocusedKey(r)}}:c&&(m.onMouseDown=e=>{e.preventDefault()}),(0,g.useEffect)(()=>{c&&n.focusedKey===r&&n.setFocusedKey(null)},[n,c,r]);let h=n.isLink(r)&&d===`override`,_=l&&e.UNSTABLE_itemBehavior===`action`,v=n.isLink(r)&&d!==`selection`&&d!==`none`,y=!c&&n.canSelectItem(r)&&!h&&!_,b=(l||v)&&!c,x=b&&(n.selectionBehavior===`replace`?!y:!y||n.isEmpty),S=b&&y&&n.selectionBehavior===`replace`,C=x||S,w=(0,g.useRef)(null),T=C&&y,E=(0,g.useRef)(!1),D=(0,g.useRef)(!1),O=n.getItemProps(r),k=e=>{l&&(l(),i.current?.dispatchEvent(new CustomEvent(`react-aria-item-action`,{bubbles:!0}))),v&&i.current&&f.open(i.current,e,O.href,O.routerOptions)},A={ref:i};if(a?(A.onPressStart=e=>{w.current=e.pointerType,E.current=T,e.pointerType===`keyboard`&&(!C||Dy(e.key))&&p(e)},u?(A.onPressUp=x?void 0:e=>{e.pointerType===`mouse`&&y&&p(e)},A.onPress=x?k:e=>{e.pointerType!==`keyboard`&&e.pointerType!==`mouse`&&y&&p(e)}):A.onPress=e=>{if(x||S&&e.pointerType!==`mouse`){if(e.pointerType===`keyboard`&&!Ey(e.key))return;k(e)}else e.pointerType!==`keyboard`&&y&&p(e)}):(A.onPressStart=e=>{w.current=e.pointerType,E.current=T,D.current=x,y&&(e.pointerType===`mouse`&&!x||e.pointerType===`keyboard`&&(!b||Dy(e.key)))&&p(e)},A.onPress=e=>{(e.pointerType===`touch`||e.pointerType===`pen`||e.pointerType===`virtual`||e.pointerType===`keyboard`&&C&&Ey(e.key)||e.pointerType===`mouse`&&D.current)&&(C?k(e):y&&p(e))}),m[`data-collection`]=dy(n.collection),m[`data-key`]=r,A.preventFocusOnPress=o,o&&(A=Yf(A,{onPressStart(e){e.pointerType!==`touch`&&(n.setFocused(!0),n.setFocusedKey(r))},onPress(e){e.pointerType===`touch`&&(n.setFocused(!0),n.setFocusedKey(r))}})),O)for(let e of[`onPressStart`,`onPressEnd`,`onPressChange`,`onPress`,`onPressUp`,`onClick`])O[e]&&(A[e]=wf(A[e],O[e]));let{pressProps:j,isPressed:M}=Sg(A),N=S?e=>{w.current===`mouse`&&(e.stopPropagation(),e.preventDefault(),k(e))}:void 0,{longPressProps:P}=wy({isDisabled:!T,onLongPress(e){e.pointerType===`touch`&&(p(e),n.setSelectionBehavior(`toggle`))}}),F=e=>{w.current===`touch`&&E.current&&e.preventDefault()},ee=d!==`none`&&n.isLink(r)?e=>{rm.isOpening||e.preventDefault()}:void 0;return{itemProps:Yf(m,y||x||o&&!c?j:{},T?P:{},{onDoubleClick:N,onDragStartCapture:F,onClick:ee,id:t},o?{onMouseDown:e=>e.preventDefault()}:void 0),isPressed:M,isSelected:n.isSelected(r),isFocused:n.isFocused&&n.focusedKey===r,isDisabled:c,allowsSelection:y,hasAction:C}}function Ey(e){return e===`Enter`}function Dy(e){return e===` `}function Oy(e,t){return typeof t.getChildren==`function`?t.getChildren(e.key):e.childNodes}function ky(e){return Ay(e,0)}function Ay(e,t){if(t<0)return;let n=0;for(let r of e){if(n===t)return r;n++}}function jy(e,t,n){if(t.parentKey===n.parentKey)return t.index-n.index;let r=[...My(e,t),t],i=[...My(e,n),n],a=r.slice(0,i.length).findIndex((e,t)=>e!==i[t]);return a===-1?r.findIndex(e=>e===n)>=0?1:(i.findIndex(e=>e===t),-1):(t=r[a],n=i[a],t.index-n.index)}function My(e,t){let n=[],r=t;for(;r?.parentKey!=null;)r=e.getItem(r.parentKey),r&&n.unshift(r);return n}var Ny=new WeakMap;function Py(e){let t=Ny.get(e);if(t!=null)return t;let n=0,r=t=>{for(let i of t)i.type===`section`?r(Oy(i,e)):i.type===`item`&&n++};return r(e),Ny.set(e,n),n}function Fy(e,t,n){let{key:r}=e,i=Dv.get(t),a=e.isDisabled??t.selectionManager.isDisabled(r),o=e.isSelected??t.selectionManager.isSelected(r),s=e.shouldSelectOnPressUp??i?.shouldSelectOnPressUp,c=e.shouldFocusOnHover??i?.shouldFocusOnHover,l=e.shouldUseVirtualFocus??i?.shouldUseVirtualFocus,u=e.isVirtualized??i?.isVirtualized,d=Wf(),f=Wf(),p={role:`option`,"aria-disabled":a||void 0,"aria-selected":t.selectionManager.selectionMode===`none`?void 0:o,"aria-label":e[`aria-label`],"aria-labelledby":d,"aria-describedby":f},m=t.collection.getItem(r);if(u){let e=Number(m?.index);p[`aria-posinset`]=Number.isNaN(e)?void 0:e+1,p[`aria-setsize`]=Py(t.collection)}let h=i?.onAction?()=>i?.onAction?.(r):void 0,g=kv(t,r),{itemProps:_,isPressed:v,isFocused:y,hasAction:b,allowsSelection:x}=Ty({selectionManager:t.selectionManager,key:r,ref:n,shouldSelectOnPressUp:s,allowsDifferentPressOrigin:s&&c,isVirtualized:u,shouldUseVirtualFocus:l,isDisabled:a,onAction:h||m?.props?.onAction?wf(m?.props?.onAction,h):void 0,linkBehavior:i?.linkBehavior,UNSTABLE_itemBehavior:i?.UNSTABLE_itemBehavior,id:g}),{hoverProps:S}=Lg({isDisabled:a||!c,onHoverStart(){wm()||(t.selectionManager.setFocused(!0),t.selectionManager.setFocusedKey(r))}}),C=og(m?.props);delete C.id;let w=sm(m?.props);return{optionProps:{...p,...Yf(C,_,S,w),id:g},labelProps:{id:d},descriptionProps:{id:f},isFocused:y,isFocusVisible:y&&t.selectionManager.isFocused&&wm(),isSelected:o,isDisabled:a,isPressed:v,allowsSelection:x,hasAction:b}}function Iy(e){let{heading:t,"aria-label":n}=e,r=Hf();return{itemProps:{role:`presentation`},headingProps:t?{id:r,role:`presentation`,onMouseDown:e=>{e.preventDefault()}}:{},groupProps:{role:`group`,"aria-label":n,"aria-labelledby":t?r:void 0}}}function Ly(e){let t=g.version.split(`.`);return parseInt(t[0],10)>=19?e:e?`true`:void 0}var Ry=class{constructor(e){this.keyMap=new Map,this.firstKey=null,this.lastKey=null,this.iterable=e;let t=e=>{if(this.keyMap.set(e.key,e),e.childNodes&&e.type===`section`)for(let n of e.childNodes)t(n)};for(let n of e)t(n);let n=null,r=0,i=0;for(let[e,t]of this.keyMap)n?(n.nextKey=e,t.prevKey=n.key):(this.firstKey=e,t.prevKey=void 0),t.type===`item`&&(t.index=r++),(t.type===`section`||t.type===`item`)&&i++,n=t,n.nextKey=void 0;this._size=i,this.lastKey=n?.key??null}*[Symbol.iterator](){yield*this.iterable}get size(){return this._size}getKeys(){return this.keyMap.keys()}getKeyBefore(e){let t=this.keyMap.get(e);return t?t.prevKey??null:null}getKeyAfter(e){let t=this.keyMap.get(e);return t?t.nextKey??null:null}getFirstKey(){return this.firstKey}getLastKey(){return this.lastKey}getItem(e){return this.keyMap.get(e)??null}at(e){let t=[...this.getKeys()];return this.getItem(t[e])}getChildren(e){return this.keyMap.get(e)?.childNodes||[]}},zy=class e extends Set{constructor(t,n,r){super(t),t instanceof e?(this.anchorKey=n??t.anchorKey,this.currentKey=r??t.currentKey):(this.anchorKey=n??null,this.currentKey=r??null)}};function By(e,t){if(e.size!==t.size)return!1;for(let n of e)if(!t.has(n))return!1;return!0}function Vy(e){let{selectionMode:t=`none`,disallowEmptySelection:n=!1,allowDuplicateSelectionEvents:r,selectionBehavior:i=`toggle`,disabledBehavior:a=`all`}=e,o=(0,g.useRef)(!1),[,s]=(0,g.useState)(!1),c=(0,g.useRef)(null),l=(0,g.useRef)(null),[,u]=(0,g.useState)(null),[d,f]=ah((0,g.useMemo)(()=>Hy(e.selectedKeys),[e.selectedKeys]),(0,g.useMemo)(()=>Hy(e.defaultSelectedKeys,new zy),[e.defaultSelectedKeys]),e.onSelectionChange),p=(0,g.useMemo)(()=>e.disabledKeys?new Set(e.disabledKeys):new Set,[e.disabledKeys]),[m,h]=(0,g.useState)(i);i===`replace`&&m===`toggle`&&typeof d==`object`&&d.size===0&&h(`replace`);let _=(0,g.useRef)(i);return(0,g.useEffect)(()=>{i!==_.current&&(h(i),_.current=i)},[i]),{selectionMode:t,disallowEmptySelection:n,selectionBehavior:m,setSelectionBehavior:h,get isFocused(){return o.current},setFocused(e){o.current=e,s(e)},get focusedKey(){return c.current},get childFocusStrategy(){return l.current},setFocusedKey(e,t=`first`){c.current=e,l.current=t,u(e)},selectedKeys:d,setSelectedKeys(e){(r||!By(e,d))&&f(e)},disabledKeys:p,disabledBehavior:a}}function Hy(e,t){return e?e===`all`?`all`:new zy(e):t}var hee=class e{constructor(e,t,n){this.collection=e,this.state=t,this.allowsCellSelection=n?.allowsCellSelection??!1,this._isSelectAll=null,this.layoutDelegate=n?.layoutDelegate||null,this.fullCollection=n?.fullCollection||null}get selectionMode(){return this.state.selectionMode}get disallowEmptySelection(){return this.state.disallowEmptySelection}get selectionBehavior(){return this.state.selectionBehavior}setSelectionBehavior(e){this.state.setSelectionBehavior(e)}get isFocused(){return this.state.isFocused}setFocused(e){this.state.setFocused(e)}get focusedKey(){return this.state.focusedKey}get childFocusStrategy(){return this.state.childFocusStrategy}setFocusedKey(e,t){(e==null||this.collection.getItem(e))&&this.state.setFocusedKey(e,t)}get selectedKeys(){return this.state.selectedKeys===`all`?new Set(this.getSelectAllKeys()):this.state.selectedKeys}get rawSelection(){return this.state.selectedKeys}isSelected(e){if(this.state.selectionMode===`none`)return!1;let t=this.getKey(e);return t==null?!1:this.state.selectedKeys===`all`?this.canSelectItem(t):this.state.selectedKeys.has(t)}get isEmpty(){return this.state.selectedKeys!==`all`&&this.state.selectedKeys.size===0}get isSelectAll(){if(this.isEmpty)return!1;if(this.state.selectedKeys===`all`)return!0;if(this._isSelectAll!=null)return this._isSelectAll;let e=this.getSelectAllKeys(),t=this.state.selectedKeys;return this._isSelectAll=e.every(e=>t.has(e)),this._isSelectAll}get firstSelectedKey(){let e=null;for(let t of this.state.selectedKeys){let n=this.collection.getItem(t);(!e||n&&jy(this.collection,n,e)<0)&&(e=n)}return e?.key??null}get lastSelectedKey(){let e=null;for(let t of this.state.selectedKeys){let n=this.collection.getItem(t);(!e||n&&jy(this.collection,n,e)>0)&&(e=n)}return e?.key??null}get disabledKeys(){return this.state.disabledKeys}get disabledBehavior(){return this.state.disabledBehavior}extendSelection(e){if(this.selectionMode===`none`)return;if(this.selectionMode===`single`){this.replaceSelection(e);return}let t=this.getKey(e);if(t==null)return;let n;if(this.state.selectedKeys===`all`)n=new zy([t],t,t);else{let e=this.state.selectedKeys,r=e.anchorKey??t;n=new zy(e,r,t);for(let i of this.getKeyRange(r,e.currentKey??t))n.delete(i);for(let e of this.getKeyRange(t,r))this.canSelectItem(e)&&n.add(e)}this.state.setSelectedKeys(n)}getKeyRange(e,t){let n=this.collection.getItem(e),r=this.collection.getItem(t);return n&&r?jy(this.collection,n,r)<=0?this.getKeyRangeInternal(e,t):this.getKeyRangeInternal(t,e):[]}getKeyRangeInternal(e,t){if(this.layoutDelegate?.getKeyRange)return this.layoutDelegate.getKeyRange(e,t);let n=[],r=e;for(;r!=null;){let e=this.collection.getItem(r);if(e&&(e.type===`item`||e.type===`cell`&&this.allowsCellSelection)&&n.push(r),r===t)return n;r=this.collection.getKeyAfter(r)}return[]}getKey(e){let t=this.collection.getItem(e);if(!t||t.type===`cell`&&this.allowsCellSelection)return e;for(;t&&t.type!==`item`&&t.parentKey!=null;)t=this.collection.getItem(t.parentKey);return!t||t.type!==`item`?null:t.key}toggleSelection(e){if(this.selectionMode===`none`)return;if(this.selectionMode===`single`&&!this.isSelected(e)){this.replaceSelection(e);return}let t=this.getKey(e);if(t==null)return;let n=new zy(this.state.selectedKeys===`all`?this.getSelectAllKeys():this.state.selectedKeys);n.has(t)?n.delete(t):this.canSelectItem(t)&&(n.add(t),n.anchorKey=t,n.currentKey=t),!(this.disallowEmptySelection&&n.size===0)&&this.state.setSelectedKeys(n)}replaceSelection(e){if(this.selectionMode===`none`)return;let t=this.getKey(e);if(t==null)return;let n=this.canSelectItem(t)?new zy([t],t,t):new zy;this.state.setSelectedKeys(n)}setSelectedKeys(e){if(this.selectionMode===`none`)return;let t=new zy;for(let n of e){let e=this.getKey(n);if(e!=null&&(t.add(e),this.selectionMode===`single`))break}this.state.setSelectedKeys(t)}getSelectAllKeys(){let e=this.fullCollection??this.collection,t=[],n=r=>{for(;r!=null;){if(this.canSelectItemIn(r,e)){let i=e.getItem(r);i?.type===`item`&&t.push(r),i?.hasChildNodes&&(this.allowsCellSelection||i.type!==`item`)&&n(ky(Oy(i,e))?.key??null)}r=e.getKeyAfter(r)}};return n(e.getFirstKey()),t}selectAll(){!this.isSelectAll&&this.selectionMode===`multiple`&&this.state.setSelectedKeys(`all`)}clearSelection(){!this.disallowEmptySelection&&(this.state.selectedKeys===`all`||this.state.selectedKeys.size>0)&&this.state.setSelectedKeys(new zy)}toggleSelectAll(){this.isSelectAll?this.clearSelection():this.selectAll()}select(e,t){this.selectionMode!==`none`&&(this.selectionMode===`single`?this.isSelected(e)&&!this.disallowEmptySelection?this.toggleSelection(e):this.replaceSelection(e):this.selectionBehavior===`toggle`||t&&(t.pointerType===`touch`||t.pointerType===`virtual`)?this.toggleSelection(e):this.replaceSelection(e))}isSelectionEqual(e){if(e===this.state.selectedKeys)return!0;let t=this.selectedKeys;if(e.size!==t.size)return!1;for(let n of e)if(!t.has(n))return!1;for(let n of t)if(!e.has(n))return!1;return!0}canSelectItem(e){return this.canSelectItemIn(e,this.collection)}canSelectItemIn(e,t){if(this.state.selectionMode===`none`||this.state.disabledKeys.has(e))return!1;let n=t.getItem(e);return!(!n||n?.props?.isDisabled||n.type===`cell`&&!this.allowsCellSelection)}isDisabled(e){let t=this.collection.getItem(e);return this.state.disabledBehavior===`all`&&(this.state.disabledKeys.has(e)||!!t?.props?.isDisabled)&&t?.props?.disabledBehavior!==`selection`}isLink(e){return!!this.collection.getItem(e)?.props?.href}getItemProps(e){return this.collection.getItem(e)?.props}withCollection(t){return new e(t,this.state,{allowsCellSelection:this.allowsCellSelection,layoutDelegate:this.layoutDelegate||void 0,fullCollection:this.fullCollection??this.collection})}},gee=class{build(e,t){return this.context=t,Uy(()=>this.iterateCollection(e))}*iterateCollection(e){let{children:t,items:n}=e;if(g.isValidElement(t)&&t.type===g.Fragment)yield*this.iterateCollection({children:t.props.children,items:n});else if(typeof t==`function`){if(!n)throw Error(`props.children was a function but props.items is missing`);let e=0;for(let r of n)yield*this.getFullNode({value:r,index:e},{renderer:t}),e++}else{let e=[];g.Children.forEach(t,t=>{t&&e.push(t)});let n=0;for(let t of e){let e=this.getFullNode({element:t,index:n},{});for(let t of e)n++,yield t}}}getKey(e,t,n,r){if(e.key!=null)return e.key;if(t.type===`cell`&&t.key!=null)return`${r}${t.key}`;let i=t.value;if(i!=null){let e=i.key??i.id;if(e==null)throw Error(`No key found for item`);return e}return r?`${r}.${t.index}`:`$.${t.index}`}getChildState(e,t){return{renderer:t.renderer||e.renderer}}*getFullNode(e,t,n,r){if(g.isValidElement(e.element)&&e.element.type===g.Fragment){let i=[];g.Children.forEach(e.element.props.children,e=>{i.push(e)});let a=e.index??0;for(let e of i)yield*this.getFullNode({element:e,index:a++},t,n,r);return}let i=e.element;if(!i&&e.value&&t&&t.renderer){let n=this.cache.get(e.value);if(n&&(!n.shouldInvalidate||!n.shouldInvalidate(this.context))){n.index=e.index,n.parentKey=r?r.key:null,yield n;return}i=t.renderer(e.value)}if(g.isValidElement(i)){let a=i.type;if(typeof a!=`function`&&typeof a.getCollectionNode!=`function`){let e=i.type;throw Error(`Unknown element <${e}> in collection.`)}let o=a.getCollectionNode(i.props,this.context),s=e.index??0,c=o.next();for(;!c.done&&c.value;){let a=c.value;e.index=s;let l=a.key??null;l??=a.element?null:this.getKey(i,e,t,n);let u=[...this.getFullNode({...a,key:l,index:s,wrapper:_ee(e.wrapper,a.wrapper)},this.getChildState(t,a),n?`${n}${i.key}`:i.key,r)];for(let t of u){if(t.value=a.value??e.value??null,t.value&&this.cache.set(t.value,t),e.type&&t.type!==e.type)throw Error(`Unsupported type <${Wy(t.type)}> in <${Wy(r?.type??`unknown parent type`)}>. Only <${Wy(e.type)}> is supported.`);s++,yield t}c=o.next(u)}return}if(e.key==null||e.type==null)return;let a=this,o={type:e.type,props:e.props,key:e.key,parentKey:r?r.key:null,value:e.value??null,level:(r?.level??0)+ +(r?.type===`item`),index:e.index,rendered:e.rendered,textValue:e.textValue??``,"aria-label":e[`aria-label`],wrapper:e.wrapper,shouldInvalidate:e.shouldInvalidate,hasChildNodes:e.hasChildNodes||!1,childNodes:Uy(function*(){if(!e.hasChildNodes||!e.childNodes)return;let n=0;for(let r of e.childNodes()){r.key!=null&&(r.key=`${o.key}${r.key}`);let e=a.getFullNode({...r,index:n},a.getChildState(t,r),o.key,o);for(let t of e)n++,yield t}})};yield o}constructor(){this.cache=new WeakMap}};function Uy(e){let t=[],n=null;return{*[Symbol.iterator](){for(let e of t)yield e;n||=e();for(let e of n)t.push(e),yield e}}}function _ee(e,t){if(e&&t)return n=>e(t(n));if(e)return e;if(t)return t}function Wy(e){return e[0].toUpperCase()+e.slice(1)}function vee(e,t,n){let r=(0,g.useMemo)(()=>new gee,[]),{children:i,items:a,collection:o}=e;return(0,g.useMemo)(()=>o||t(r.build({children:i,items:a},n)),[r,i,a,o,n,t])}function Gy(e){let{filter:t,layoutDelegate:n}=e,r=Vy(e),i=(0,g.useMemo)(()=>e.disabledKeys?new Set(e.disabledKeys):new Set,[e.disabledKeys]),a=vee(e,(0,g.useCallback)(e=>t?new Ry(t(e)):new Ry(e),[t]),(0,g.useMemo)(()=>({suppressTextValueWarning:e.suppressTextValueWarning}),[e.suppressTextValueWarning])),o=(0,g.useMemo)(()=>new hee(a,r,{layoutDelegate:n}),[a,r,n]);return qy(a,o),{collection:a,disabledKeys:i,selectionManager:o}}function Ky(e,t){let n=(0,g.useMemo)(()=>t?e.collection.filter(t):e.collection,[e.collection,t]),r=e.selectionManager.withCollection(n);return qy(n,r),{collection:n,selectionManager:r,disabledKeys:e.disabledKeys}}function qy(e,t){let n=(0,g.useRef)(null);(0,g.useEffect)(()=>{if(t.focusedKey!=null&&!e.getItem(t.focusedKey)&&n.current){let r=n.current.getKeyAfter(t.focusedKey),i=null;for(;r!=null;){let a=e.getItem(r);if(a&&a.type===`item`&&!t.isDisabled(r)){i=r;break}r=n.current.getKeyAfter(r)}if(i==null)for(r=n.current.getKeyBefore(t.focusedKey);r!=null;){let a=e.getItem(r);if(a&&a.type===`item`&&!t.isDisabled(r)){i=r;break}r=n.current.getKeyBefore(r)}t.setFocusedKey(i)}n.current=e},[e,t])}function Jy(e,t){let{collection:n,onLoadMore:r,scrollOffset:i=1}=e,a=(0,g.useRef)(null),o=Pm(e=>{for(let t of e)t.isIntersecting&&r&&r()});Tf(()=>(t.current&&(a.current=new IntersectionObserver(o,{root:t_(t?.current),rootMargin:`0px ${100*i}% ${100*i}% ${100*i}%`}),a.current.observe(t.current)),()=>{a.current&&a.current.disconnect()}),[n,t,i])}var Yy=(0,g.createContext)(null),Xy=(0,g.createContext)(null),Zy=(0,g.forwardRef)(function(e,t){[e,t]=tp(e,t,Yy);let n=(0,g.useContext)(Xy);return n?g.createElement(Qy,{state:n,props:e,listBoxRef:t}):g.createElement(Lh,{content:g.createElement(qh,e)},n=>g.createElement(yee,{props:e,listBoxRef:t,collection:n}))});function yee({props:e,listBoxRef:t,collection:n}){e={...e,collection:n,children:null,items:null};let{layoutDelegate:r}=(0,g.useContext)($h),i=Gy({...e,layoutDelegate:r});return g.createElement(Qy,{state:i,props:e,listBoxRef:t})}function Qy({state:e,props:t,listBoxRef:n}){[t,n]=tp(t,n,oh);let{dragAndDropHooks:r,layout:i=`stack`,orientation:a=`vertical`,filter:o}=t,s=Ky(e,o),{collection:c,selectionManager:l}=s,u=!!r?.useDraggableCollectionState,d=!!r?.useDroppableCollectionState,{direction:f}=Wm(),{disabledBehavior:p,disabledKeys:m}=l,h=by({usage:`search`,sensitivity:`base`}),{isVirtualized:_,layoutDelegate:v,dropTargetDelegate:y,CollectionRoot:b}=(0,g.useContext)($h),x=(0,g.useMemo)(()=>t.keyboardDelegate||new vy({collection:c,collator:h,ref:n,disabledKeys:m,disabledBehavior:p,layout:i,orientation:a,direction:f,layoutDelegate:v}),[c,h,n,p,m,a,f,t.keyboardDelegate,i,v]),{listBoxProps:S}=Sy({...t,shouldSelectOnPressUp:u||t.shouldSelectOnPressUp,keyboardDelegate:x,isVirtualized:_},s,n);(0,g.useRef)(u),(0,g.useRef)(d),(0,g.useEffect)(()=>{},[u,d]);let C,w,T,E=!1,D=null,O=(0,g.useRef)(null);if(u&&r){C=r.useDraggableCollectionState({collection:c,selectionManager:l,preview:r.renderDragPreview?O:void 0}),r.useDraggableCollection({},C,n);let e=r.DragPreview;D=r.renderDragPreview?g.createElement(e,{ref:O},r.renderDragPreview):null}if(d&&r){w=r.useDroppableCollectionState({collection:c,selectionManager:l});let e=r.dropTargetDelegate||y||new r.ListDropTargetDelegate(c,n,{orientation:a,layout:i,direction:f});T=r.useDroppableCollection({keyboardDelegate:x,dropTargetDelegate:e},w,n),E=w.isDropTarget({type:`root`})}let{focusProps:k,isFocused:A,isFocusVisible:j}=jg(),M=s.collection.size===0,N={isDropTarget:E,isEmpty:M,isFocused:A,isFocusVisible:j,layout:t.layout||`stack`,orientation:a,state:s},P=$f({...t,children:void 0,defaultClassName:`react-aria-ListBox`,values:N}),F=null;M&&t.renderEmptyState&&(F=g.createElement(`div`,{role:`option`,style:{display:`contents`}},t.renderEmptyState(N)));let ee=og(t,{global:!0});return g.createElement(Fv,null,g.createElement(op.div,{...Yf(ee,P,S,k,T?.collectionProps),ref:n,slot:t.slot||void 0,onScroll:t.onScroll,"data-drop-target":E||void 0,"data-empty":M||void 0,"data-focused":A||void 0,"data-focus-visible":j||void 0,"data-layout":t.layout||`stack`,"data-orientation":a},g.createElement(Qf,{values:[[Yy,t],[Xy,s],[gv,{dragAndDropHooks:r,dragState:C,dropState:w}],[Ev,{elementType:`div`}],[_v,{render:xee}],[Yh,{name:`ListBoxSection`,render:$y}]]},g.createElement(wv,null,g.createElement(b,{collection:c,scrollRef:n,persistedKeys:bv(l,r,w),renderDropIndicator:yv(r,w)}))),F,D))}function $y(e,t,n,r=`react-aria-ListBoxSection`){let i=(0,g.useContext)(Xy),{dragAndDropHooks:a,dropState:o}=(0,g.useContext)(gv),{CollectionBranch:s}=(0,g.useContext)($h),[c,l]=np(),{headingProps:u,groupProps:d}=Iy({heading:l,"aria-label":e[`aria-label`]??void 0}),f=$f({...e,id:void 0,children:void 0,defaultClassName:r,values:void 0}),p=og(e,{global:!0});return delete p.id,g.createElement(op.section,{...Yf(p,f,d),ref:t},g.createElement(xv.Provider,{value:{...u,ref:c}},g.createElement(s,{collection:i.collection,parent:n,renderDropIndicator:yv(a,o)})))}var bee=Wh(fh,$y),eb=Uh(dh,function(e,t,n){let r=Xf(t),i=(0,g.useContext)(Xy),{dragAndDropHooks:a,dragState:o,dropState:s}=(0,g.useContext)(gv),c=o&&!(o.isDisabled||o.selectionManager.isDisabled(n.key)),{optionProps:l,labelProps:u,descriptionProps:d,...f}=Fy({key:n.key,"aria-label":e?.[`aria-label`]},i,r),{hoverProps:p,isHovered:m}=Lg({isDisabled:!f.allowsSelection&&!f.hasAction&&!c,onHoverStart:n.props.onHoverStart,onHoverChange:n.props.onHoverChange,onHoverEnd:n.props.onHoverEnd}),{keyboardProps:h}=Oh(e),{focusProps:_}=Eh(e),v=null;o&&a&&(v=a.useDraggableItem({key:n.key,hasAction:f.hasAction},o));let y=null;s&&a&&(y=a.useDroppableItem({target:{type:`item`,key:n.key,dropPosition:`on`}},s,r));let b=o&&o.isDragging(n.key),x=$f({...e,id:void 0,children:e.children,defaultClassName:`react-aria-ListBoxItem`,values:{...f,isHovered:m,selectionMode:i.selectionManager.selectionMode,selectionBehavior:i.selectionManager.selectionBehavior,allowsDragging:!!o,isDragging:b,isDropTarget:y?.isDropTarget}});(0,g.useEffect)(()=>{n.textValue},[n.textValue]);let S=e.href?op.a:op.div,C=og(e,{global:!0});return delete C.id,delete C.onClick,e.href&&l.tabIndex==null&&(l.tabIndex=-1),g.createElement(S,{...Yf(C,x,l,p,h,_,v?.dragProps,y?.dropProps),ref:r,"data-allows-dragging":!!o||void 0,"data-selected":f.isSelected||void 0,"data-disabled":f.isDisabled||void 0,"data-hovered":m||void 0,"data-focused":f.isFocused||void 0,"data-focus-visible":f.isFocusVisible||void 0,"data-pressed":f.isPressed||void 0,"data-dragging":b||void 0,"data-drop-target":y?.isDropTarget||void 0,"data-selection-mode":i.selectionManager.selectionMode===`none`?void 0:i.selectionManager.selectionMode},g.createElement(Qf,{values:[[Qg,{slots:{[Zf]:u,label:u,description:d}}],[Tv,{isSelected:f.isSelected}]]},x.children))});function xee(e,t){t=Xf(t);let{dragAndDropHooks:n,dropState:r}=(0,g.useContext)(gv),{dropIndicatorProps:i,isHidden:a,isDropTarget:o}=n.useDropIndicator(e,r,t);return a?null:g.createElement(Cee,{...e,dropIndicatorProps:i,isDropTarget:o,ref:t})}function See(e,t){let{dropIndicatorProps:n,isDropTarget:r,...i}=e,a=$f({...i,defaultClassName:`react-aria-DropIndicator`,values:{isDropTarget:r}});return g.createElement(g.Fragment,null,g.createElement(op.div,{...n,...a,role:`option`,ref:t,"data-drop-target":r||void 0}))}var Cee=(0,g.forwardRef)(See);Uh(uh,function(e,t,n){let r=(0,g.useContext)(Xy),{isLoading:i,onLoadMore:a,scrollOffset:o,...s}=e,c=(0,g.useRef)(null);Jy((0,g.useMemo)(()=>({onLoadMore:a,collection:r?.collection,sentinelRef:c,scrollOffset:o}),[a,o,r?.collection]),c);let l=$f({...s,id:void 0,children:n.rendered,defaultClassName:`react-aria-ListBoxLoadingIndicator`,values:void 0});return g.createElement(g.Fragment,null,g.createElement(`div`,{style:{position:`relative`,width:0,height:0},inert:Ly(!0)},g.createElement(`div`,{"data-testid":`loadMoreSentinel`,ref:c,style:{position:`absolute`,height:1,width:1}})),i&&l.children&&g.createElement(g.Fragment,null,g.createElement(op.div,{...Yf(og(e,{global:!0}),{tabIndex:-1}),...l,role:`option`,ref:t},l.children)))});var wee=(0,g.createContext)({placement:`bottom`}),Tee=typeof HTMLElement<`u`&&`inert`in HTMLElement.prototype;function tb(e){return e.dataset.liveAnnouncer===`true`||e.dataset.reactAriaTopLayer!==void 0}var nb=new WeakMap,rb=[];function Eee(e,t){let n=up(e?.[0]),r=t instanceof n.Element?{root:t}:t,i=r?.root??document.body,a=r?.shouldUseInert&&Tee,o=new Set(e),s=new Set,c=e=>a&&e instanceof n.HTMLElement?e.inert:e.getAttribute(`aria-hidden`)===`true`,l=(e,t)=>{a&&e instanceof n.HTMLElement?e.inert=t:t?e.setAttribute(`aria-hidden`,`true`):(e.removeAttribute(`aria-hidden`),e instanceof n.HTMLElement&&(e.inert=!1))},u=new Set;if(mp())for(let t of e){let e=t;for(;e&&e!==i;){let t=e.getRootNode();`shadowRoot`in t&&u.add(t.shadowRoot),e=t.parentNode}}let d=e=>{for(let t of e.querySelectorAll(`[data-live-announcer], [data-react-aria-top-layer]`))o.add(t);let t=e=>{if(s.has(e)||o.has(e)||e.parentElement&&s.has(e.parentElement)&&e.parentElement.getAttribute(`role`)!==`row`)return NodeFilter.FILTER_REJECT;for(let t of o)if(U(e,t))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_ACCEPT},n=jv(lp(e),e,NodeFilter.SHOW_ELEMENT,{acceptNode:t}),r=t(e);if(r===NodeFilter.FILTER_ACCEPT&&f(e),r!==NodeFilter.FILTER_REJECT){let e=n.nextNode();for(;e!=null;)f(e),e=n.nextNode()}},f=e=>{let t=nb.get(e)??0;c(e)&&t===0||(t===0&&l(e,!0),s.add(e),nb.set(e,t+1))};rb.length&&rb[rb.length-1].disconnect(),d(i);let p=new MutationObserver(e=>{for(let t of e)if(t.type===`childList`){if(t.target.isConnected&&![...o,...s].some(e=>U(e,t.target)))for(let e of t.addedNodes)(e instanceof HTMLElement||e instanceof SVGElement)&&tb(e)?o.add(e):e instanceof Element&&d(e);if(mp()){for(let e of u)if(!e.isConnected){p.disconnect();break}}}});p.observe(i,{childList:!0,subtree:!0});let m=new Set;if(mp())for(let e of u){let t=new MutationObserver(e=>{for(let t of e)if(t.type===`childList`){if(t.target.isConnected&&![...o,...s].some(e=>U(e,t.target)))for(let e of t.addedNodes)(e instanceof HTMLElement||e instanceof SVGElement)&&tb(e)?o.add(e):e instanceof Element&&d(e);if(mp()){for(let e of u)if(!e.isConnected){p.disconnect();break}}}});t.observe(e,{childList:!0,subtree:!0}),m.add(t)}let h={visibleNodes:o,hiddenNodes:s,observe(){p.observe(i,{childList:!0,subtree:!0})},disconnect(){p.disconnect()}};return rb.push(h),()=>{if(p.disconnect(),mp())for(let e of m)e.disconnect();for(let e of s){let t=nb.get(e);t!=null&&(t===1?(l(e,!1),nb.delete(e)):nb.set(e,t-1))}h===rb[rb.length-1]?(rb.pop(),rb.length&&rb[rb.length-1].observe()):rb.splice(rb.indexOf(h),1)}}function Dee(e){let t=rb[rb.length-1];if(t&&!t.visibleNodes.has(e))return t.visibleNodes.add(e),()=>{t.visibleNodes.delete(e)}}var ib={top:`top`,bottom:`top`,left:`left`,right:`left`},ab={top:`bottom`,bottom:`top`,left:`right`,right:`left`},Oee={top:`left`,left:`top`},ob={top:`height`,left:`width`},sb={width:`totalWidth`,height:`totalHeight`},cb={},lb=()=>typeof document<`u`?window.visualViewport:null;function ub(e,t){let n=0,r=0,i=0,a=0,o=0,s=0,c={},l=(t?.scale??1)>1;if(e.tagName===`BODY`||e.tagName===`HTML`){let l=document.documentElement;i=l.clientWidth,a=l.clientHeight,n=t?.width??i,r=t?.height??a,c.top=l.scrollTop||e.scrollTop,c.left=l.scrollLeft||e.scrollLeft,t&&(o=t.offsetTop,s=t.offsetLeft)}else ({width:n,height:r,top:o,left:s}=xb(e,!1)),c.top=e.scrollTop,c.left=e.scrollLeft,i=n,a=r;return Yp()&&(e.tagName===`BODY`||e.tagName===`HTML`)&&l&&(c.top=0,c.left=0,o=t?.pageTop??0,s=t?.pageLeft??0),{width:n,height:r,totalWidth:i,totalHeight:a,scroll:c,top:o,left:s}}function db(e){return{top:e.scrollTop,left:e.scrollLeft,width:e.scrollWidth,height:e.scrollHeight}}function fb(e,t,n,r,i,a,o){let s=i.scroll[e]??0,c=r[ob[e]],l=o[e]+r.scroll[ib[e]]+a,u=o[e]+r.scroll[ib[e]]+c-a,d=t-s+r.scroll[ib[e]]+o[e]-r[ib[e]],f=t-s+n+r.scroll[ib[e]]+o[e]-r[ib[e]];return du?Math.max(u-f,l-d):0}function pb(e){let t=window.getComputedStyle(e);return{top:parseInt(t.marginTop,10)||0,bottom:parseInt(t.marginBottom,10)||0,left:parseInt(t.marginLeft,10)||0,right:parseInt(t.marginRight,10)||0}}function mb(e){if(cb[e])return cb[e];let[t,n]=e.split(` `),r=ib[t]||`right`,i=Oee[r];ib[n]||(n=`center`);let a=ob[r],o=ob[i];return cb[e]={placement:t,crossPlacement:n,axis:r,crossAxis:i,size:a,crossSize:o},cb[e]}function hb(e,t,n,r,i,a,o,s,c,l,u){let{placement:d,crossPlacement:f,axis:p,crossAxis:m,size:h,crossSize:g}=r,_={};_[m]=e[m]??0,f===`center`?_[m]+=((e[g]??0)-(n[g]??0))/2:f!==m&&(_[m]+=(e[g]??0)-(n[g]??0)),_[m]+=a;let v=e[m]-n[g]+c+l,y=e[m]+e[g]-c-l;if(_[m]=Bg(_[m],v,y),d===p){let t=s?u[h]:u[sb[h]];_[ab[p]]=Math.floor(t-e[p]+i)}else _[p]=Math.floor(e[p]+e[h]+i);return _}function gb(e,t,n,r,i,a,o,s,c,l,u){let d=(e.top==null?c[sb.height]-(e.bottom??0)-o:e.top)-(c.scroll.top??0),f=l?n.top:0,p={top:Math.max(t.top+f,(u?.offsetTop??t.top)+f),bottom:Math.min(t.top+t.height+f,(u?.offsetTop??0)+(u?.height??0))};return s===`top`?Math.max(0,d+o-p.top-((i.top??0)+(i.bottom??0)+a)):Math.max(0,p.bottom-d-((i.top??0)+(i.bottom??0)+a))}function _b(e,t,n,r,i,a,o,s){let{placement:c,axis:l,size:u}=a;return c===l?Math.max(0,n[l]-(o.scroll[l]??0)-(e[l]+(s?t[l]:0))-(r[l]??0)-r[ab[l]]-i):Math.max(0,e[u]+e[l]+(s?t[l]:0)-n[l]-n[u]+(o.scroll[l]??0)-(r[l]??0)-r[ab[l]]-i)}function vb(e,t,n,r,i,a,o,s,c,l,u,d,f,p,m,h,g,_){let v=mb(e),{size:y,crossAxis:b,crossSize:x,placement:S,crossPlacement:C}=v,w=hb(t,s,n,v,u,d,l,f,m,h,c),T=u,E=_b(s,l,t,i,a+u,v,c,g);if(o&&n[y]>E){let e=mb(`${ab[S]} ${C}`),r=hb(t,s,n,e,u,d,l,f,m,h,c);_b(s,l,t,i,a+u,e,c,g)>E&&(v=e,w=r,T=u)}let D=`bottom`;v.axis===`top`?v.placement===`top`?D=`top`:v.placement===`bottom`&&(D=`bottom`):v.crossAxis===`top`&&(v.crossPlacement===`top`?D=`bottom`:v.crossPlacement===`bottom`&&(D=`top`));let O=fb(b,w[b],n[x],s,c,a,l);w[b]+=O;let k=gb(w,s,l,f,i,a,n.height,D,c,g,_);p&&p{if(!n||r===null)return;let e=e=>{let n=W(e);if(!t.current||n instanceof Node&&!U(n,t.current)||n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement)return;let i=r||Tb.get(t.current);i&&i()};return window.addEventListener(`scroll`,e,!0),()=>{window.removeEventListener(`scroll`,e,!0)}},[n,r,t])}function Db(){return window.ResizeObserver!==void 0}function Ob(e){let{ref:t,box:n,onResize:r}=e,i=Pm(r);(0,g.useEffect)(()=>{let e=t?.current;if(e)if(Db()){let t=new window.ResizeObserver(e=>{e.length&&i()});return t.observe(e,{box:n}),()=>{e&&t.unobserve(e)}}else return window.addEventListener(`resize`,i,!1),()=>{window.removeEventListener(`resize`,i,!1)}},[t,n])}var kb=typeof document<`u`?window.visualViewport:null;function Ab(e){let{direction:t}=Wm(),{arrowSize:n,targetRef:r,overlayRef:i,arrowRef:a,scrollRef:o=i,placement:s=`bottom`,containerPadding:c=12,shouldFlip:l=!0,boundaryElement:u=typeof document<`u`?document.body:null,offset:d=0,crossOffset:f=0,shouldUpdatePosition:p=!0,isOpen:m=!0,onClose:h,maxHeight:_,arrowBoundaryOffset:v=0}=e,[y,b]=(0,g.useState)(null),x=[p,s,i.current,r.current,a?.current,o.current,c,l,u,d,f,m,t,_,v,n],S=(0,g.useRef)(kb?.scale);(0,g.useEffect)(()=>{m&&(S.current=kb?.scale)},[m]);let C=(0,g.useCallback)(()=>{if(p===!1||!m||!i.current||!r.current||!u||kb?.scale!==S.current)return;let e=null;if(o.current&&gp(o.current)){let t=hp()?.getBoundingClientRect(),n=o.current.getBoundingClientRect();e={type:`top`,offset:(t?.top??0)-n.top},e.offset>n.height/2&&(e.type=`bottom`,e.offset=(t?.bottom??0)-n.bottom)}let h=i.current;!_&&i.current&&(h.style.top=`0px`,h.style.bottom=``,h.style.maxHeight=(window.visualViewport?.height??window.innerHeight)+`px`);let g=yb({placement:Mb(s,t),overlayNode:i.current,targetNode:r.current,scrollNode:o.current||i.current,padding:c,shouldFlip:l,boundaryElement:u,offset:d,crossOffset:f,maxHeight:_,arrowSize:n??(a?.current?bb(a.current,!0).width:0),arrowBoundaryOffset:v});if(!g.position)return;h.style.top=``,h.style.bottom=``,h.style.left=``,h.style.right=``,Object.keys(g.position).forEach(e=>h.style[e]=g.position[e]+`px`),h.style.maxHeight=g.maxHeight==null?``:g.maxHeight+`px`;let y=hp();if(e&&y&&o.current){let t=y.getBoundingClientRect(),n=o.current.getBoundingClientRect(),r=t[e.type]-n[e.type];o.current.scrollTop+=r-e.offset}b(g)},x);Tf(C,x),jb(C),Ob({ref:i,onResize:C}),Ob({ref:r,onResize:C});let w=(0,g.useRef)(!1);Tf(()=>{let e,t=()=>{w.current=!0,clearTimeout(e),e=setTimeout(()=>{w.current=!1},500),C()},n=()=>{w.current&&t()};return kb?.addEventListener(`resize`,t),kb?.addEventListener(`scroll`,n),()=>{kb?.removeEventListener(`resize`,t),kb?.removeEventListener(`scroll`,n)}},[C]);let T=(0,g.useCallback)(()=>{w.current||h?.()},[h,w]);return Eb({triggerRef:r,isOpen:m,onClose:h&&T}),{overlayProps:{style:{position:y?`absolute`:`fixed`,top:y?void 0:0,left:y?void 0:0,zIndex:1e5,...y?.position,maxHeight:y?.maxHeight??`100vh`}},placement:y?.placement??null,triggerAnchorPoint:y?.triggerAnchorPoint??null,arrowProps:{"aria-hidden":`true`,role:`presentation`,style:{left:y?.arrowOffsetLeft,top:y?.arrowOffsetTop}},updatePosition:C}}function jb(e){Tf(()=>(window.addEventListener(`resize`,e,!1),()=>{window.removeEventListener(`resize`,e,!1)}),[e])}function Mb(e,t){return t===`rtl`?e.replace(`start`,`right`).replace(`end`,`left`):e.replace(`start`,`left`).replace(`end`,`right`)}function Nb(e){let{ref:t,onInteractOutside:n,isDisabled:r,onInteractOutsideStart:i}=e,a=(0,g.useRef)({isPointerDown:!1,ignoreEmulatedMouseEvents:!1}),o=Pm(e=>{n&&Pb(e,t)&&(i&&i(e),a.current.isPointerDown=!0)}),s=Pm(e=>{n&&n(e)});(0,g.useEffect)(()=>{let e=a.current;if(r)return;let n=t.current,i=lp(n);if(typeof PointerEvent<`u`){let n=n=>{e.isPointerDown&&Pb(n,t)&&s(n),e.isPointerDown=!1};return i.addEventListener(`pointerdown`,o,!0),i.addEventListener(`click`,n,!0),()=>{i.removeEventListener(`pointerdown`,o,!0),i.removeEventListener(`click`,n,!0)}}},[t,r])}function Pb(e,t){if(e.button>0)return!1;let n=W(e);if(n){let e=n.ownerDocument;if(!e||!U(e.documentElement,n)||n.closest(`[data-react-aria-top-layer]`))return!1}return t.current?!e.composedPath().includes(t.current):!1}var Fb=[];function Ib(e,t){let{onClose:n,shouldCloseOnBlur:r,isOpen:i,isDismissable:a=!1,isKeyboardDismissDisabled:o=!1,shouldCloseOnInteractOutside:s}=e,c=(0,g.useRef)(void 0);(0,g.useEffect)(()=>{if(i&&!Fb.includes(t))return Fb.push(t),()=>{let e=Fb.indexOf(t);e>=0&&Fb.splice(e,1)}},[i,t]);let l=()=>{Fb[Fb.length-1]===t&&n&&n()},u=e=>{let n=Fb[Fb.length-1];c.current=n,(!s||s(W(e)))&&n===t&&e.stopPropagation()},d=e=>{(!s||s(W(e)))&&(Fb[Fb.length-1]===t&&e.stopPropagation(),c.current===t&&l()),c.current=void 0},f=e=>{e.key===`Escape`&&!o&&!e.nativeEvent.isComposing&&(e.stopPropagation(),e.preventDefault(),l())};Nb({ref:t,onInteractOutside:a&&i?d:void 0,onInteractOutsideStart:u});let{focusWithinProps:p}=Ag({isDisabled:!r,onBlurWithin:e=>{!e.relatedTarget||Gv(e.relatedTarget)||(!s||s(e.relatedTarget))&&n?.()}});return{overlayProps:{onKeyDown:f,...p},underlayProps:{}}}var Lb=typeof document<`u`&&window.visualViewport,Rb=0,zb;function Bb(e={}){let{isDisabled:t}=e;Tf(()=>{if(!t)return Rb++,Rb===1&&(zb=qp()?Hb():Vb()),()=>{Rb--,Rb===0&&zb()}},[t])}function Vb(){let e=window.innerWidth-document.documentElement.clientWidth;return wf(e>0&&(`scrollbarGutter`in document.documentElement.style?Ub(document.documentElement,`scrollbarGutter`,`stable`):Ub(document.documentElement,`paddingRight`,`${e}px`)),Ub(document.documentElement,`overflow`,`hidden`))}function Hb(){let e=Ub(document.documentElement,`overflow`,`hidden`),t,n=!1,r=e=>{let r=W(e);t=e_(r)?r:t_(r,!0),n=!1;let i=r.ownerDocument.defaultView.getSelection();i&&!i.isCollapsed&&i.containsNode(r,!0)&&(n=!0),e.composedPath().some(e=>e instanceof HTMLInputElement&&e.type===`range`)&&(n=!0),`selectionStart`in r&&`selectionEnd`in r&&r.selectionStart{if(!(e.touches.length===2||n)){if(!t||t===document.documentElement||t===document.body){e.preventDefault();return}t.scrollHeight===t.clientHeight&&t.scrollWidth===t.clientWidth&&e.preventDefault()}},s=e=>{let t=W(e),n=e.relatedTarget;n&&Nm(n)?(n.focus({preventScroll:!0}),Gb(n,Nm(t))):n||(t.parentElement?.closest(`[tabindex]`))?.focus({preventScroll:!0})},c=HTMLElement.prototype.focus;HTMLElement.prototype.focus=function(e){let t=hp(),n=t!=null&&Nm(t);c.call(this,{...e,preventScroll:!0}),(!e||!e.preventScroll)&&Gb(this,n)};let l=wf(Wb(document,`touchstart`,r,{passive:!1,capture:!0}),Wb(document,`touchmove`,o,{passive:!1,capture:!0}),Wb(document,`blur`,s,!0));return()=>{e(),l(),i.remove(),HTMLElement.prototype.focus=c}}function Ub(e,t,n){let r=e.style[t];return e.style[t]=n,()=>{e.style[t]=r}}function Wb(e,t,n,r){return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}}function Gb(e,t){t||!Lb?Kb(e):Lb.addEventListener(`resize`,()=>Kb(e),{once:!0})}function Kb(e){let t=document.scrollingElement||document.documentElement,n=e;for(;n&&n!==t;){let e=t_(n);if(e!==document.documentElement&&e!==document.body&&e!==n){let t=e.getBoundingClientRect(),r=n.getBoundingClientRect();if(r.topt.top+n.clientHeight){let n=t.bottom;Lb&&(n=Math.min(n,Lb.offsetTop+Lb.height));let i=r.top-t.top-((n-t.top)/2-r.height/2);e.scrollTo({top:Math.max(0,Math.min(e.scrollHeight-e.clientHeight,e.scrollTop+i)),behavior:`smooth`})}}n=e.parentElement}}function qb(e,t){let{triggerRef:n,popoverRef:r,groupRef:i,isNonModal:a,isKeyboardDismissDisabled:o,shouldCloseOnInteractOutside:s,...c}=e,l=c.trigger===`SubmenuTrigger`,{overlayProps:u,underlayProps:d}=Ib({isOpen:t.isOpen,onClose:t.close,shouldCloseOnBlur:!0,isDismissable:!a||l,isKeyboardDismissDisabled:o,shouldCloseOnInteractOutside:s},i??r),{overlayProps:f,arrowProps:p,placement:m,triggerAnchorPoint:h}=Ab({...c,targetRef:n,overlayRef:r,isOpen:t.isOpen,onClose:a&&!l?t.close:null});return Bb({isDisabled:a||!t.isOpen}),(0,g.useEffect)(()=>{if(t.isOpen&&r.current)return a?Dee(i?.current??r.current):Eee([i?.current??r.current],{shouldUseInert:!0})},[a,t.isOpen,r,i]),{popoverProps:Yf(u,f),arrowProps:p,underlayProps:d,placement:m,triggerAnchorPoint:h}}var Jb={};Jb={dismiss:`تجاهل`};var Yb={};Yb={dismiss:`Отхвърляне`};var Xb={};Xb={dismiss:`Odstranit`};var Zb={};Zb={dismiss:`Luk`};var Qb={};Qb={dismiss:`Schließen`};var $b={};$b={dismiss:`Απόρριψη`};var ex={};ex={dismiss:`Dismiss`};var tx={};tx={dismiss:`Descartar`};var nx={};nx={dismiss:`Lõpeta`};var rx={};rx={dismiss:`Hylkää`};var ix={};ix={dismiss:`Rejeter`};var ax={};ax={dismiss:`התעלם`};var ox={};ox={dismiss:`Odbaci`};var sx={};sx={dismiss:`Elutasítás`};var cx={};cx={dismiss:`Ignora`};var lx={};lx={dismiss:`閉じる`};var ux={};ux={dismiss:`무시`};var dx={};dx={dismiss:`Atmesti`};var fx={};fx={dismiss:`Nerādīt`};var px={};px={dismiss:`Lukk`};var mx={};mx={dismiss:`Negeren`};var hx={};hx={dismiss:`Zignoruj`};var gx={};gx={dismiss:`Descartar`};var _x={};_x={dismiss:`Dispensar`};var vx={};vx={dismiss:`Revocare`};var yx={};yx={dismiss:`Пропустить`};var bx={};bx={dismiss:`Zrušiť`};var xx={};xx={dismiss:`Opusti`};var Sx={};Sx={dismiss:`Odbaci`};var Cx={};Cx={dismiss:`Avvisa`};var wx={};wx={dismiss:`Kapat`};var Tx={};Tx={dismiss:`Скасувати`};var Ex={};Ex={dismiss:`取消`};var Dx={};Dx={dismiss:`關閉`};var Ox={};Ox={"ar-AE":Jb,"bg-BG":Yb,"cs-CZ":Xb,"da-DK":Zb,"de-DE":Qb,"el-GR":$b,"en-US":ex,"es-ES":tx,"et-EE":nx,"fi-FI":rx,"fr-FR":ix,"he-IL":ax,"hr-HR":ox,"hu-HU":sx,"it-IT":cx,"ja-JP":lx,"ko-KR":ux,"lt-LT":dx,"lv-LV":fx,"nb-NO":px,"nl-NL":mx,"pl-PL":hx,"pt-BR":gx,"pt-PT":_x,"ro-RO":vx,"ru-RU":yx,"sk-SK":bx,"sl-SI":xx,"sr-SP":Sx,"sv-SE":Cx,"tr-TR":wx,"uk-UA":Tx,"zh-CN":Ex,"zh-TW":Dx};function kx(e){return e&&e.__esModule?e.default:e}function Ax(e){let{onDismiss:t,...n}=e,r=Im(n,rh(kx(Ox),`@react-aria/overlays`).format(`dismiss`)),i=()=>{t&&t()};return g.createElement(u_,null,g.createElement(`button`,{...r,tabIndex:-1,onClick:i,style:{width:1,height:1}}))}function jx({children:e}){let t=(0,g.useMemo)(()=>({register:()=>{}}),[]);return g.createElement(hg.Provider,{value:t},e)}var Mx=(0,g.createContext)({});function Nx(){return(0,g.useContext)(Mx)??{}}var Px=g.createContext(null);function Fx(e){let t=Lf(),{portalContainer:n=t?null:document.body,isExiting:r}=e,[i,a]=(0,g.useState)(!1),o=(0,g.useMemo)(()=>({contain:i,setContain:a}),[i,a]),{getContainer:s}=Nx();if(!e.portalContainer&&s&&(n=s()),!n)return null;let c=e.children;return e.disableFocusManagement||(c=g.createElement(Fv,{restoreFocus:!0,contain:(e.shouldContainFocus||i)&&!r},c)),c=g.createElement(Px.Provider,{value:o},g.createElement(jx,null,c)),Ph.createPortal(c,n)}function Ix(){let e=(0,g.useContext)(Px)?.setContain;Tf(()=>{e?.(!0)},[e])}function Lx(e){let[t,n]=ah(e.isOpen,e.defaultOpen||!1,e.onOpenChange);return{isOpen:t,setOpen:n,open:(0,g.useCallback)(()=>{n(!0)},[n]),close:(0,g.useCallback)(()=>{n(!1)},[n]),toggle:(0,g.useCallback)(()=>{n(!t)},[n,t])}}function Rx(e,t=!0){let[n,r]=(0,g.useState)(!0),i=n&&t;return Tf(()=>{if(i&&e.current&&`getAnimations`in e.current)for(let t of e.current.getAnimations())t instanceof CSSTransition&&t.cancel()},[e,i]),Bx(e,i,(0,g.useCallback)(()=>r(!1),[])),i}function zx(e,t){let[n,r]=(0,g.useState)(t?`open`:`closed`);switch(n){case`open`:t||r(`exiting`);break;case`closed`:case`exiting`:t&&r(`open`);break}let i=n===`exiting`;return Bx(e,i,(0,g.useCallback)(()=>{r(e=>e===`exiting`?`closed`:e)},[])),i}function Bx(e,t,n){Tf(()=>{if(t&&e.current){if(!(`getAnimations`in e.current)){n();return}let t=e.current.getAnimations();if(t.length===0){n();return}let r=!1;return Promise.allSettled(t.map(e=>e.finished)).then(()=>{r||(0,Ph.flushSync)(()=>{n()})}),()=>{r=!0}}},[e,t,n])}var Vx=(0,g.createContext)(null),Hx=(0,g.createContext)(null),Ux=(0,g.forwardRef)(function(e,t){[e,t]=tp(e,t,Vx);let n=(0,g.useContext)(jS),r=Lx(e),i=e.isOpen!=null||e.defaultOpen!=null||!n?r:n,a=zx(t,i.isOpen)||e.isExiting||!1,o=cee(),{direction:s}=Wm();if(o){let t=e.children;return typeof t==`function`&&(t=t({trigger:e.trigger||null,placement:`bottom`,isEntering:!1,isExiting:!1,defaultChildren:null})),g.createElement(g.Fragment,null,t)}return i&&!i.isOpen&&!a?null:g.createElement(Wx,{...e,triggerRef:e.triggerRef,state:i,popoverRef:t,isExiting:a,dir:s})});function Wx({state:e,isExiting:t,UNSTABLE_portalContainer:n,clearContexts:r,...i}){let a=(0,g.useRef)(null),o=(0,g.useRef)(null),s=(0,g.useContext)(Hx),c=s&&i.trigger===`SubmenuTrigger`,{popoverProps:l,underlayProps:u,arrowProps:d,placement:f,triggerAnchorPoint:p}=qb({...i,offset:i.offset??8,arrowRef:a,groupRef:c?s:o},e),m=i.popoverRef,h=Rx(m,!!f)||i.isEntering||!1,_=$f({...i,defaultClassName:`react-aria-Popover`,values:{trigger:i.trigger||null,placement:f,isEntering:h,isExiting:t}}),v=!i.isNonModal||i.trigger===`SubmenuTrigger`,[y,b]=(0,g.useState)(!1);Tf(()=>{m.current&&b(v&&!m.current.querySelector(`[role=dialog]`))},[m,v]),(0,g.useEffect)(()=>{y&&(i.trigger!==`SubmenuTrigger`||Tm()!==`pointer`)&&m.current&&!gp(m.current)&&Th(m.current)},[y,m,i.trigger]);let x=(0,g.useMemo)(()=>{let e=_.children;if(r)for(let t of r)e=g.createElement(t.Provider,{value:null},e);return e},[_.children,r]),[S,C]=(0,g.useState)(null),w=(0,g.useCallback)(()=>{i.triggerRef.current&&C(i.triggerRef.current.getBoundingClientRect().width+`px`)},[i.triggerRef]);Tf(w,[w]),Ob({ref:_.style?.[`--trigger-width`]?void 0:i.triggerRef,onResize:w});let T={...l.style,"--trigger-anchor-point":p?`${p.x}px ${p.y}px`:void 0,..._.style,"--trigger-width":_.style?.[`--trigger-width`]||S},E=g.createElement(op.div,{...Yf(og(i,{global:!0}),l),..._,role:y?`dialog`:void 0,tabIndex:y?-1:void 0,"aria-label":i[`aria-label`],"aria-labelledby":i[`aria-labelledby`],ref:m,slot:i.slot||void 0,style:T,dir:i.dir,"data-trigger":i.trigger,"data-placement":f,"data-entering":h||void 0,"data-exiting":t||void 0},!i.isNonModal&&g.createElement(Ax,{onDismiss:e.close}),g.createElement(wee.Provider,{value:{...d,placement:f,ref:a}},x),g.createElement(Ax,{onDismiss:e.close}));return c?g.createElement(Fx,{...i,shouldContainFocus:y,isExiting:t,portalContainer:n??s?.current??void 0},E):g.createElement(Fx,{...i,shouldContainFocus:y,isExiting:t,portalContainer:n},!i.isNonModal&&e.isOpen&&g.createElement(`div`,{"data-testid":`underlay`,...u,style:{position:`fixed`,inset:0}}),g.createElement(`div`,{ref:o,style:{display:`contents`}},g.createElement(Hx.Provider,{value:o},E)))}var Gx={};Gx={longPressMessage:`اضغط مطولاً أو اضغط على Alt + السهم لأسفل لفتح القائمة`};var Kx={};Kx={longPressMessage:`Натиснете продължително или натиснете Alt+ стрелка надолу, за да отворите менюто`};var qx={};qx={longPressMessage:`Dlouhým stiskem nebo stisknutím kláves Alt + šipka dolů otevřete nabídku`};var Jx={};Jx={longPressMessage:`Langt tryk eller tryk på Alt + pil ned for at åbne menuen`};var Yx={};Yx={longPressMessage:`Drücken Sie lange oder drücken Sie Alt + Nach-unten, um das Menü zu öffnen`};var Xx={};Xx={longPressMessage:`Πιέστε παρατεταμένα ή πατήστε Alt + κάτω βέλος για να ανοίξετε το μενού`};var Zx={};Zx={longPressMessage:`Long press or press Alt + ArrowDown to open menu`};var Qx={};Qx={longPressMessage:`Mantenga pulsado o pulse Alt + flecha abajo para abrir el menú`};var $x={};$x={longPressMessage:`Menüü avamiseks vajutage pikalt või vajutage klahve Alt + allanool`};var eS={};eS={longPressMessage:`Avaa valikko painamalla pohjassa tai näppäinyhdistelmällä Alt + Alanuoli`};var tS={};tS={longPressMessage:`Appuyez de manière prolongée ou appuyez sur Alt\xA0+\xA0Flèche vers le bas pour ouvrir le menu.`};var nS={};nS={longPressMessage:`לחץ לחיצה ארוכה או הקש Alt + ArrowDown כדי לפתוח את התפריט`};var rS={};rS={longPressMessage:`Dugo pritisnite ili pritisnite Alt + strelicu prema dolje za otvaranje izbornika`};var iS={};iS={longPressMessage:`Nyomja meg hosszan, vagy nyomja meg az Alt + lefele nyíl gombot a menü megnyitásához`};var aS={};aS={longPressMessage:`Premi a lungo o premi Alt + Freccia giù per aprire il menu`};var oS={};oS={longPressMessage:`長押しまたは Alt+下矢印キーでメニューを開く`};var sS={};sS={longPressMessage:`길게 누르거나 Alt + 아래쪽 화살표를 눌러 메뉴 열기`};var cS={};cS={longPressMessage:`Norėdami atidaryti meniu, nuspaudę palaikykite arba paspauskite „Alt + ArrowDown“.`};var lS={};lS={longPressMessage:`Lai atvērtu izvēlni, turiet nospiestu vai nospiediet taustiņu kombināciju Alt + lejupvērstā bultiņa`};var uS={};uS={longPressMessage:`Langt trykk eller trykk Alt + PilNed for å åpne menyen`};var dS={};dS={longPressMessage:`Druk lang op Alt + pijl-omlaag of druk op Alt om het menu te openen`};var fS={};fS={longPressMessage:`Naciśnij i przytrzymaj lub naciśnij klawisze Alt + Strzałka w dół, aby otworzyć menu`};var pS={};pS={longPressMessage:`Pressione e segure ou pressione Alt + Seta para baixo para abrir o menu`};var mS={};mS={longPressMessage:`Prima continuamente ou prima Alt + Seta Para Baixo para abrir o menu`};var hS={};hS={longPressMessage:`Apăsați lung sau apăsați pe Alt + săgeată în jos pentru a deschide meniul`};var gS={};gS={longPressMessage:`Нажмите и удерживайте или нажмите Alt + Стрелка вниз, чтобы открыть меню`};var _S={};_S={longPressMessage:`Ponuku otvoríte dlhým stlačením alebo stlačením klávesu Alt + klávesu so šípkou nadol`};var vS={};vS={longPressMessage:`Za odprtje menija pritisnite in držite gumb ali pritisnite Alt+puščica navzdol`};var yS={};yS={longPressMessage:`Dugo pritisnite ili pritisnite Alt + strelicu prema dole da otvorite meni`};var bS={};bS={longPressMessage:`Håll nedtryckt eller tryck på Alt + pil nedåt för att öppna menyn`};var xS={};xS={longPressMessage:`Menüyü açmak için uzun basın veya Alt + Aşağı Ok tuşuna basın`};var SS={};SS={longPressMessage:`Довго або звичайно натисніть комбінацію клавіш Alt і стрілка вниз, щоб відкрити меню`};var CS={};CS={longPressMessage:`长按或按 Alt + 向下方向键以打开菜单`};var wS={};wS={longPressMessage:`長按或按 Alt+向下鍵以開啟功能表`};var TS={};TS={"ar-AE":Gx,"bg-BG":Kx,"cs-CZ":qx,"da-DK":Jx,"de-DE":Yx,"el-GR":Xx,"en-US":Zx,"es-ES":Qx,"et-EE":$x,"fi-FI":eS,"fr-FR":tS,"he-IL":nS,"hr-HR":rS,"hu-HU":iS,"it-IT":aS,"ja-JP":oS,"ko-KR":sS,"lt-LT":cS,"lv-LV":lS,"nb-NO":uS,"nl-NL":dS,"pl-PL":fS,"pt-BR":pS,"pt-PT":mS,"ro-RO":hS,"ru-RU":gS,"sk-SK":_S,"sl-SI":vS,"sr-SP":yS,"sv-SE":bS,"tr-TR":xS,"uk-UA":SS,"zh-CN":CS,"zh-TW":wS};function ES(e,t,n){let{type:r}=e,{isOpen:i}=t;(0,g.useEffect)(()=>{n&&n.current&&Tb.set(n.current,t.close)});let a;r===`menu`?a=!0:r===`listbox`&&(a=`listbox`);let o=Hf();return{triggerProps:{"aria-haspopup":a,"aria-expanded":i,"aria-controls":i?o:void 0,onPress:t.toggle},overlayProps:{id:o}}}function DS(e){return e&&e.__esModule?e.default:e}function OS(e,t,n){let{type:r=`menu`,isDisabled:i,trigger:a=`press`}=e,o=Hf(),{triggerProps:s,overlayProps:c}=ES({type:r},t,n),l=e=>{if(!i&&!(a===`longPress`&&!e.altKey)&&n&&n.current)switch(e.key){case`Enter`:case` `:if(a===`longPress`||e.isDefaultPrevented())return;case`ArrowDown`:`continuePropagation`in e||e.stopPropagation(),e.preventDefault(),t.toggle(`first`);break;case`ArrowUp`:`continuePropagation`in e||e.stopPropagation(),e.preventDefault(),t.toggle(`last`);break;default:`continuePropagation`in e&&e.continuePropagation()}},u=rh(DS(TS),`@react-aria/menu`),{longPressProps:d}=wy({isDisabled:i||a!==`longPress`,accessibilityDescription:u.format(`longPressMessage`),onLongPressStart(){t.close()},onLongPress(){t.open(`first`)}}),f={preventFocusOnPress:!0,onPressStart(e){e.pointerType!==`touch`&&e.pointerType!==`keyboard`&&!i&&(xp(e.target),t.open(e.pointerType===`virtual`?`first`:null))},onPress(e){e.pointerType===`touch`&&!i&&(xp(e.target),t.toggle())}};return delete s.onPress,{menuTriggerProps:{...s,...a===`press`?f:d,id:o,onKeyDown:l},menuProps:{...c,"aria-labelledby":o,autoFocus:t.focusStrategy||!0,onClose:t.close}}}function kS(e,t){let{role:n=`dialog`}=e,r=Wf();r=e[`aria-label`]?void 0:r;let i=(0,g.useRef)(!1);return(0,g.useEffect)(()=>{if(t.current&&!gp(t.current)){Th(t.current);let e=setTimeout(()=>{(hp()===t.current||hp()===document.body)&&(i.current=!0,t.current&&(t.current.blur(),Th(t.current)),i.current=!1)},500);return()=>{clearTimeout(e)}}},[t]),Ix(),(0,g.useRef)(!1),(0,g.useEffect)(()=>{}),{dialogProps:{...og(e,{labelable:!0}),role:n,tabIndex:-1,"aria-labelledby":e[`aria-labelledby`]||r,onBlur:e=>{i.current&&e.stopPropagation()}},titleProps:{id:r}}}var AS=(0,g.createContext)(null),jS=(0,g.createContext)(null),MS=(0,g.forwardRef)(function(e,t){let n=e[`aria-labelledby`];[e,t]=tp(e,t,AS);let{dialogProps:r,titleProps:i}=kS({...e,"aria-labelledby":n},t),a=(0,g.useContext)(jS);!r[`aria-label`]&&!r[`aria-labelledby`]&&e[`aria-labelledby`]&&(r[`aria-labelledby`]=e[`aria-labelledby`]);let o=$f({defaultClassName:`react-aria-Dialog`,className:e.className,style:e.style,children:e.children,values:{close:a?.close||(()=>{})}}),s=og(e,{global:!0});return g.createElement(op.section,{...Yf(s,o,r),render:e.render,ref:t,slot:e.slot||void 0},g.createElement(Qf,{values:[[Zg,{slots:{[Zf]:{},title:{...i,level:2}}}],[qg,{slots:{[Zf]:{},close:{onPress:()=>a?.close()}}}]]},o.children))});function NS(e={}){let{locale:t}=Wm();return(0,g.useMemo)(()=>new Intl.ListFormat(t,e),[t,e])}var PS=new WeakMap;function FS(e,t){let{id:n}=PS.get(e)??{};if(!n)throw Error(`Unknown list`);return`${n}-${IS(t)}`}function IS(e){return typeof e==`string`?e.replace(/\s*/g,``):``+e}var LS={};LS={deselectedItem:e=>`${e.item} \u{63A}\u{64A}\u{631} \u{627}\u{644}\u{645}\u{62D}\u{62F}\u{62F}`,longPressToSelect:`اضغط مطولًا للدخول إلى وضع التحديد.`,select:`تحديد`,selectedAll:`جميع العناصر المحددة.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`لم يتم تحديد عناصر`,one:()=>`${t.number(e.count)} \u{639}\u{646}\u{635}\u{631} \u{645}\u{62D}\u{62F}\u{62F}`,other:()=>`${t.number(e.count)} \u{639}\u{646}\u{635}\u{631} \u{645}\u{62D}\u{62F}\u{62F}`})}.`,selectedItem:e=>`${e.item} \u{627}\u{644}\u{645}\u{62D}\u{62F}\u{62F}`};var RS={};RS={deselectedItem:e=>`${e.item} \u{43D}\u{435} \u{435} \u{438}\u{437}\u{431}\u{440}\u{430}\u{43D}.`,longPressToSelect:`Натиснете и задръжте за да влезете в избирателен режим.`,select:`Изберете`,selectedAll:`Всички елементи са избрани.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Няма избрани елементи`,one:()=>`${t.number(e.count)} \u{438}\u{437}\u{431}\u{440}\u{430}\u{43D} \u{435}\u{43B}\u{435}\u{43C}\u{435}\u{43D}\u{442}`,other:()=>`${t.number(e.count)} \u{438}\u{437}\u{431}\u{440}\u{430}\u{43D}\u{438} \u{435}\u{43B}\u{435}\u{43C}\u{435}\u{43D}\u{442}\u{438}`})}.`,selectedItem:e=>`${e.item} \u{438}\u{437}\u{431}\u{440}\u{430}\u{43D}.`};var zS={};zS={deselectedItem:e=>`Polo\u{17E}ka ${e.item} nen\xed vybr\xe1na.`,longPressToSelect:`Dlouhým stisknutím přejdete do režimu výběru.`,select:`Vybrat`,selectedAll:`Vybrány všechny položky.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nevybrány žádné položky`,one:()=>`Vybr\xe1na ${t.number(e.count)} polo\u{17E}ka`,other:()=>`Vybr\xe1no ${t.number(e.count)} polo\u{17E}ek`})}.`,selectedItem:e=>`Vybr\xe1na polo\u{17E}ka ${e.item}.`};var BS={};BS={deselectedItem:e=>`${e.item} ikke valgt.`,longPressToSelect:`Lav et langt tryk for at aktivere valgtilstand.`,select:`Vælg`,selectedAll:`Alle elementer valgt.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Ingen elementer valgt`,one:()=>`${t.number(e.count)} element valgt`,other:()=>`${t.number(e.count)} elementer valgt`})}.`,selectedItem:e=>`${e.item} valgt.`};var VS={};VS={deselectedItem:e=>`${e.item} nicht ausgew\xe4hlt.`,longPressToSelect:`Gedrückt halten, um Auswahlmodus zu öffnen.`,select:`Auswählen`,selectedAll:`Alle Elemente ausgewählt.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Keine Elemente ausgewählt`,one:()=>`${t.number(e.count)} Element ausgew\xe4hlt`,other:()=>`${t.number(e.count)} Elemente ausgew\xe4hlt`})}.`,selectedItem:e=>`${e.item} ausgew\xe4hlt.`};var HS={};HS={deselectedItem:e=>`\u{394}\u{3B5}\u{3BD} \u{3B5}\u{3C0}\u{3B9}\u{3BB}\u{3AD}\u{3C7}\u{3B8}\u{3B7}\u{3BA}\u{3B5} \u{3C4}\u{3BF} \u{3C3}\u{3C4}\u{3BF}\u{3B9}\u{3C7}\u{3B5}\u{3AF}\u{3BF} ${e.item}.`,longPressToSelect:`Πατήστε παρατεταμένα για να μπείτε σε λειτουργία επιλογής.`,select:`Επιλογή`,selectedAll:`Επιλέχθηκαν όλα τα στοιχεία.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Δεν επιλέχθηκαν στοιχεία`,one:()=>`\u{395}\u{3C0}\u{3B9}\u{3BB}\u{3AD}\u{3C7}\u{3B8}\u{3B7}\u{3BA}\u{3B5} ${t.number(e.count)} \u{3C3}\u{3C4}\u{3BF}\u{3B9}\u{3C7}\u{3B5}\u{3AF}\u{3BF}`,other:()=>`\u{395}\u{3C0}\u{3B9}\u{3BB}\u{3AD}\u{3C7}\u{3B8}\u{3B7}\u{3BA}\u{3B1}\u{3BD} ${t.number(e.count)} \u{3C3}\u{3C4}\u{3BF}\u{3B9}\u{3C7}\u{3B5}\u{3AF}\u{3B1}`})}.`,selectedItem:e=>`\u{395}\u{3C0}\u{3B9}\u{3BB}\u{3AD}\u{3C7}\u{3B8}\u{3B7}\u{3BA}\u{3B5} \u{3C4}\u{3BF} \u{3C3}\u{3C4}\u{3BF}\u{3B9}\u{3C7}\u{3B5}\u{3AF}\u{3BF} ${e.item}.`};var US={};US={deselectedItem:e=>`${e.item} not selected.`,select:`Select`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`No items selected`,one:()=>`${t.number(e.count)} item selected`,other:()=>`${t.number(e.count)} items selected`})}.`,selectedAll:`All items selected.`,selectedItem:e=>`${e.item} selected.`,longPressToSelect:`Long press to enter selection mode.`};var WS={};WS={deselectedItem:e=>`${e.item} no seleccionado.`,longPressToSelect:`Mantenga pulsado para abrir el modo de selección.`,select:`Seleccionar`,selectedAll:`Todos los elementos seleccionados.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Ningún elemento seleccionado`,one:()=>`${t.number(e.count)} elemento seleccionado`,other:()=>`${t.number(e.count)} elementos seleccionados`})}.`,selectedItem:e=>`${e.item} seleccionado.`};var GS={};GS={deselectedItem:e=>`${e.item} pole valitud.`,longPressToSelect:`Valikurežiimi sisenemiseks vajutage pikalt.`,select:`Vali`,selectedAll:`Kõik üksused valitud.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Üksusi pole valitud`,one:()=>`${t.number(e.count)} \xfcksus valitud`,other:()=>`${t.number(e.count)} \xfcksust valitud`})}.`,selectedItem:e=>`${e.item} valitud.`};var KS={};KS={deselectedItem:e=>`Kohdetta ${e.item} ei valittu.`,longPressToSelect:`Siirry valintatilaan painamalla pitkään.`,select:`Valitse`,selectedAll:`Kaikki kohteet valittu.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Ei yhtään kohdetta valittu`,one:()=>`${t.number(e.count)} kohde valittu`,other:()=>`${t.number(e.count)} kohdetta valittu`})}.`,selectedItem:e=>`${e.item} valittu.`};var qS={};qS={deselectedItem:e=>`${e.item} non s\xe9lectionn\xe9.`,longPressToSelect:`Appuyez de manière prolongée pour passer en mode de sélection.`,select:`Sélectionner`,selectedAll:`Tous les éléments sélectionnés.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Aucun élément sélectionné`,one:()=>`${t.number(e.count)} \xe9l\xe9ment s\xe9lectionn\xe9`,other:()=>`${t.number(e.count)} \xe9l\xe9ments s\xe9lectionn\xe9s`})}.`,selectedItem:e=>`${e.item} s\xe9lectionn\xe9.`};var JS={};JS={deselectedItem:e=>`${e.item} \u{5DC}\u{5D0} \u{5E0}\u{5D1}\u{5D7}\u{5E8}.`,longPressToSelect:`הקשה ארוכה לכניסה למצב בחירה.`,select:`בחר`,selectedAll:`כל הפריטים נבחרו.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`לא נבחרו פריטים`,one:()=>`\u{5E4}\u{5E8}\u{5D9}\u{5D8} ${t.number(e.count)} \u{5E0}\u{5D1}\u{5D7}\u{5E8}`,other:()=>`${t.number(e.count)} \u{5E4}\u{5E8}\u{5D9}\u{5D8}\u{5D9}\u{5DD} \u{5E0}\u{5D1}\u{5D7}\u{5E8}\u{5D5}`})}.`,selectedItem:e=>`${e.item} \u{5E0}\u{5D1}\u{5D7}\u{5E8}.`};var YS={};YS={deselectedItem:e=>`Stavka ${e.item} nije odabrana.`,longPressToSelect:`Dugo pritisnite za ulazak u način odabira.`,select:`Odaberite`,selectedAll:`Odabrane su sve stavke.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nije odabrana nijedna stavka`,one:()=>`Odabrana je ${t.number(e.count)} stavka`,other:()=>`Odabrano je ${t.number(e.count)} stavki`})}.`,selectedItem:e=>`Stavka ${e.item} je odabrana.`};var XS={};XS={deselectedItem:e=>`${e.item} nincs kijel\xf6lve.`,longPressToSelect:`Nyomja hosszan a kijelöléshez.`,select:`Kijelölés`,selectedAll:`Az összes elem kijelölve.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Egy elem sincs kijelölve`,one:()=>`${t.number(e.count)} elem kijel\xf6lve`,other:()=>`${t.number(e.count)} elem kijel\xf6lve`})}.`,selectedItem:e=>`${e.item} kijel\xf6lve.`};var ZS={};ZS={deselectedItem:e=>`${e.item} non selezionato.`,longPressToSelect:`Premi a lungo per passare alla modalità di selezione.`,select:`Seleziona`,selectedAll:`Tutti gli elementi selezionati.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nessun elemento selezionato`,one:()=>`${t.number(e.count)} elemento selezionato`,other:()=>`${t.number(e.count)} elementi selezionati`})}.`,selectedItem:e=>`${e.item} selezionato.`};var QS={};QS={deselectedItem:e=>`${e.item} \u{304C}\u{9078}\u{629E}\u{3055}\u{308C}\u{3066}\u{3044}\u{307E}\u{305B}\u{3093}\u{3002}`,longPressToSelect:`長押しして選択モードを開きます。`,select:`選択`,selectedAll:`すべての項目を選択しました。`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`項目が選択されていません`,one:()=>`${t.number(e.count)} \u{9805}\u{76EE}\u{3092}\u{9078}\u{629E}\u{3057}\u{307E}\u{3057}\u{305F}`,other:()=>`${t.number(e.count)} \u{9805}\u{76EE}\u{3092}\u{9078}\u{629E}\u{3057}\u{307E}\u{3057}\u{305F}`})}\u{3002}`,selectedItem:e=>`${e.item} \u{3092}\u{9078}\u{629E}\u{3057}\u{307E}\u{3057}\u{305F}\u{3002}`};var $S={};$S={deselectedItem:e=>`${e.item}\u{C774}(\u{AC00}) \u{C120}\u{D0DD}\u{B418}\u{C9C0} \u{C54A}\u{C558}\u{C2B5}\u{B2C8}\u{B2E4}.`,longPressToSelect:`선택 모드로 들어가려면 길게 누르십시오.`,select:`선택`,selectedAll:`모든 항목이 선택되었습니다.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`선택된 항목이 없습니다`,one:()=>`${t.number(e.count)}\u{AC1C} \u{D56D}\u{BAA9}\u{C774} \u{C120}\u{D0DD}\u{B418}\u{C5C8}\u{C2B5}\u{B2C8}\u{B2E4}`,other:()=>`${t.number(e.count)}\u{AC1C} \u{D56D}\u{BAA9}\u{C774} \u{C120}\u{D0DD}\u{B418}\u{C5C8}\u{C2B5}\u{B2C8}\u{B2E4}`})}.`,selectedItem:e=>`${e.item}\u{C774}(\u{AC00}) \u{C120}\u{D0DD}\u{B418}\u{C5C8}\u{C2B5}\u{B2C8}\u{B2E4}.`};var eC={};eC={deselectedItem:e=>`${e.item} nepasirinkta.`,longPressToSelect:`Norėdami įjungti pasirinkimo režimą, paspauskite ir palaikykite.`,select:`Pasirinkti`,selectedAll:`Pasirinkti visi elementai.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nepasirinktas nė vienas elementas`,one:()=>`Pasirinktas ${t.number(e.count)} elementas`,other:()=>`Pasirinkta element\u{173}: ${t.number(e.count)}`})}.`,selectedItem:e=>`Pasirinkta: ${e.item}.`};var tC={};tC={deselectedItem:e=>`Vienums ${e.item} nav atlas\u{12B}ts.`,longPressToSelect:`Ilgi turiet nospiestu. lai ieslēgtu atlases režīmu.`,select:`Atlasīt`,selectedAll:`Atlasīti visi vienumi.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nav atlasīts neviens vienums`,one:()=>`Atlas\u{12B}to vienumu skaits: ${t.number(e.count)}`,other:()=>`Atlas\u{12B}to vienumu skaits: ${t.number(e.count)}`})}.`,selectedItem:e=>`Atlas\u{12B}ts vienums ${e.item}.`};var nC={};nC={deselectedItem:e=>`${e.item} er ikke valgt.`,longPressToSelect:`Bruk et langt trykk for å gå inn i valgmodus.`,select:`Velg`,selectedAll:`Alle elementer er valgt.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Ingen elementer er valgt`,one:()=>`${t.number(e.count)} element er valgt`,other:()=>`${t.number(e.count)} elementer er valgt`})}.`,selectedItem:e=>`${e.item} er valgt.`};var rC={};rC={deselectedItem:e=>`${e.item} niet geselecteerd.`,longPressToSelect:`Druk lang om de selectiemodus te openen.`,select:`Selecteren`,selectedAll:`Alle items geselecteerd.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Geen items geselecteerd`,one:()=>`${t.number(e.count)} item geselecteerd`,other:()=>`${t.number(e.count)} items geselecteerd`})}.`,selectedItem:e=>`${e.item} geselecteerd.`};var iC={};iC={deselectedItem:e=>`Nie zaznaczono ${e.item}.`,longPressToSelect:`Naciśnij i przytrzymaj, aby wejść do trybu wyboru.`,select:`Zaznacz`,selectedAll:`Wszystkie zaznaczone elementy.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nie zaznaczono żadnych elementów`,one:()=>`${t.number(e.count)} zaznaczony element`,other:()=>`${t.number(e.count)} zaznaczonych element\xf3w`})}.`,selectedItem:e=>`Zaznaczono ${e.item}.`};var aC={};aC={deselectedItem:e=>`${e.item} n\xe3o selecionado.`,longPressToSelect:`Mantenha pressionado para entrar no modo de seleção.`,select:`Selecionar`,selectedAll:`Todos os itens selecionados.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nenhum item selecionado`,one:()=>`${t.number(e.count)} item selecionado`,other:()=>`${t.number(e.count)} itens selecionados`})}.`,selectedItem:e=>`${e.item} selecionado.`};var oC={};oC={deselectedItem:e=>`${e.item} n\xe3o selecionado.`,longPressToSelect:`Prima continuamente para entrar no modo de seleção.`,select:`Selecionar`,selectedAll:`Todos os itens selecionados.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nenhum item selecionado`,one:()=>`${t.number(e.count)} item selecionado`,other:()=>`${t.number(e.count)} itens selecionados`})}.`,selectedItem:e=>`${e.item} selecionado.`};var sC={};sC={deselectedItem:e=>`${e.item} neselectat.`,longPressToSelect:`Apăsați lung pentru a intra în modul de selectare.`,select:`Selectare`,selectedAll:`Toate elementele selectate.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Niciun element selectat`,one:()=>`${t.number(e.count)} element selectat`,other:()=>`${t.number(e.count)} elemente selectate`})}.`,selectedItem:e=>`${e.item} selectat.`};var cC={};cC={deselectedItem:e=>`${e.item} \u{43D}\u{435} \u{432}\u{44B}\u{431}\u{440}\u{430}\u{43D}\u{43E}.`,longPressToSelect:`Нажмите и удерживайте для входа в режим выбора.`,select:`Выбрать`,selectedAll:`Выбраны все элементы.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Нет выбранных элементов`,one:()=>`${t.number(e.count)} \u{44D}\u{43B}\u{435}\u{43C}\u{435}\u{43D}\u{442} \u{432}\u{44B}\u{431}\u{440}\u{430}\u{43D}`,other:()=>`${t.number(e.count)} \u{44D}\u{43B}\u{435}\u{43C}\u{435}\u{43D}\u{442}\u{43E}\u{432} \u{432}\u{44B}\u{431}\u{440}\u{430}\u{43D}\u{43E}`})}.`,selectedItem:e=>`${e.item} \u{432}\u{44B}\u{431}\u{440}\u{430}\u{43D}\u{43E}.`};var lC={};lC={deselectedItem:e=>`Nevybrat\xe9 polo\u{17E}ky: ${e.item}.`,longPressToSelect:`Dlhším stlačením prejdite do režimu výberu.`,select:`Vybrať`,selectedAll:`Všetky vybraté položky.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Žiadne vybraté položky`,one:()=>`${t.number(e.count)} vybrat\xe1 polo\u{17E}ka`,other:()=>`Po\u{10D}et vybrat\xfdch polo\u{17E}iek:${t.number(e.count)}`})}.`,selectedItem:e=>`Vybrat\xe9 polo\u{17E}ky: ${e.item}.`};var uC={};uC={deselectedItem:e=>`Element ${e.item} ni izbran.`,longPressToSelect:`Za izbirni način pritisnite in dlje časa držite.`,select:`Izberite`,selectedAll:`Vsi elementi so izbrani.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Noben element ni izbran`,one:()=>`${t.number(e.count)} element je izbran`,other:()=>`${t.number(e.count)} elementov je izbranih`})}.`,selectedItem:e=>`Element ${e.item} je izbran.`};var dC={};dC={deselectedItem:e=>`${e.item} nije izabrano.`,longPressToSelect:`Dugo pritisnite za ulazak u režim biranja.`,select:`Izaberite`,selectedAll:`Izabrane su sve stavke.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Nije izabrana nijedna stavka`,one:()=>`Izabrana je ${t.number(e.count)} stavka`,other:()=>`Izabrano je ${t.number(e.count)} stavki`})}.`,selectedItem:e=>`${e.item} je izabrano.`};var fC={};fC={deselectedItem:e=>`${e.item} ej markerat.`,longPressToSelect:`Tryck länge när du vill öppna väljarläge.`,select:`Markera`,selectedAll:`Alla markerade objekt.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Inga markerade objekt`,one:()=>`${t.number(e.count)} markerat objekt`,other:()=>`${t.number(e.count)} markerade objekt`})}.`,selectedItem:e=>`${e.item} markerat.`};var pC={};pC={deselectedItem:e=>`${e.item} se\xe7ilmedi.`,longPressToSelect:`Seçim moduna girmek için uzun basın.`,select:`Seç`,selectedAll:`Tüm ögeler seçildi.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Hiçbir öge seçilmedi`,one:()=>`${t.number(e.count)} \xf6ge se\xe7ildi`,other:()=>`${t.number(e.count)} \xf6ge se\xe7ildi`})}.`,selectedItem:e=>`${e.item} se\xe7ildi.`};var mC={};mC={deselectedItem:e=>`${e.item} \u{43D}\u{435} \u{432}\u{438}\u{431}\u{440}\u{430}\u{43D}\u{43E}.`,longPressToSelect:`Виконайте довге натиснення, щоб перейти в режим вибору.`,select:`Вибрати`,selectedAll:`Усі елементи вибрано.`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`Жодних елементів не вибрано`,one:()=>`${t.number(e.count)} \u{435}\u{43B}\u{435}\u{43C}\u{435}\u{43D}\u{442} \u{432}\u{438}\u{431}\u{440}\u{430}\u{43D}\u{43E}`,other:()=>`\u{412}\u{438}\u{431}\u{440}\u{430}\u{43D}\u{43E} \u{435}\u{43B}\u{435}\u{43C}\u{435}\u{43D}\u{442}\u{456}\u{432}: ${t.number(e.count)}`})}.`,selectedItem:e=>`${e.item} \u{432}\u{438}\u{431}\u{440}\u{430}\u{43D}\u{43E}.`};var hC={};hC={deselectedItem:e=>`\u{672A}\u{9009}\u{62E9} ${e.item}\u{3002}`,longPressToSelect:`长按以进入选择模式。`,select:`选择`,selectedAll:`已选择所有项目。`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`未选择项目`,one:()=>`\u{5DF2}\u{9009}\u{62E9} ${t.number(e.count)} \u{4E2A}\u{9879}\u{76EE}`,other:()=>`\u{5DF2}\u{9009}\u{62E9} ${t.number(e.count)} \u{4E2A}\u{9879}\u{76EE}`})}\u{3002}`,selectedItem:e=>`\u{5DF2}\u{9009}\u{62E9} ${e.item}\u{3002}`};var gC={};gC={deselectedItem:e=>`\u{672A}\u{9078}\u{53D6}\u{300C}${e.item}\u{300D}\u{3002}`,longPressToSelect:`長按以進入選擇模式。`,select:`選取`,selectedAll:`已選取所有項目。`,selectedCount:(e,t)=>`${t.plural(e.count,{"=0":`未選取任何項目`,one:()=>`\u{5DF2}\u{9078}\u{53D6} ${t.number(e.count)} \u{500B}\u{9805}\u{76EE}`,other:()=>`\u{5DF2}\u{9078}\u{53D6} ${t.number(e.count)} \u{500B}\u{9805}\u{76EE}`})}\u{3002}`,selectedItem:e=>`\u{5DF2}\u{9078}\u{53D6}\u{300C}${e.item}\u{300D}\u{3002}`};var _C={};_C={"ar-AE":LS,"bg-BG":RS,"cs-CZ":zS,"da-DK":BS,"de-DE":VS,"el-GR":HS,"en-US":US,"es-ES":WS,"et-EE":GS,"fi-FI":KS,"fr-FR":qS,"he-IL":JS,"hr-HR":YS,"hu-HU":XS,"it-IT":ZS,"ja-JP":QS,"ko-KR":$S,"lt-LT":eC,"lv-LV":tC,"nb-NO":nC,"nl-NL":rC,"pl-PL":iC,"pt-BR":aC,"pt-PT":oC,"ro-RO":sC,"ru-RU":cC,"sk-SK":lC,"sl-SI":uC,"sr-SP":dC,"sv-SE":fC,"tr-TR":pC,"uk-UA":mC,"zh-CN":hC,"zh-TW":gC};function vC(e){return e&&e.__esModule?e.default:e}function yC(e,t){let{getRowText:n=e=>t.collection.getTextValue?.(e)??t.collection.getItem(e)?.textValue}=e,r=rh(vC(_C),`@react-aria/grid`),i=t.selectionManager.rawSelection,a=(0,g.useRef)(i),o=(0,g.useCallback)(()=>{if(!t.selectionManager.isFocused||i===a.current){a.current=i;return}let e=bC(i,a.current),o=bC(a.current,i),s=t.selectionManager.selectionBehavior===`replace`,c=[];if(t.selectionManager.selectedKeys.size===1&&s){let e=t.selectionManager.selectedKeys.keys().next().value;if(e!=null&&t.collection.getItem(e)){let t=n(e);t&&c.push(r.format(`selectedItem`,{item:t}))}}else if(e.size===1&&o.size===0){let t=e.keys().next().value;if(t!=null){let e=n(t);e&&c.push(r.format(`selectedItem`,{item:e}))}}else if(o.size===1&&e.size===0){let e=o.keys().next().value;if(e!=null&&t.collection.getItem(e)){let t=n(e);t&&c.push(r.format(`deselectedItem`,{item:t}))}}t.selectionManager.selectionMode===`multiple`&&(c.length===0||i===`all`||i.size>1||a.current===`all`||a.current?.size>1)&&c.push(i===`all`?r.format(`selectedAll`):r.format(`selectedCount`,{count:i.size})),c.length>0&&Wg(c.join(` `)),a.current=i},[i,t.selectionManager.selectedKeys,t.selectionManager.isFocused,t.selectionManager.selectionBehavior,t.selectionManager.selectionMode,t.collection,n,r]);$g(()=>{if(t.selectionManager.isFocused)o();else{let e=requestAnimationFrame(o);return()=>cancelAnimationFrame(e)}},[i,t.selectionManager.isFocused])}function bC(e,t){let n=new Set;if(e===`all`||t===`all`)return n;for(let r of e.keys())t.has(r)||n.add(r);return n}function xC(e,t){let n=t?.isDisabled,[r,i]=(0,g.useState)(!1);return Tf(()=>{if(e?.current&&!n){let t=()=>{e.current&&i(!!ty(e.current,{tabbable:!0}).nextNode())};t();let n=new MutationObserver(t);return n.observe(e.current,{subtree:!0,childList:!0,attributes:!0,attributeFilter:[`tabIndex`,`disabled`]}),()=>{n.disconnect()}}}),n?!1:r}function SC(e){return e&&e.__esModule?e.default:e}function CC(e){let t=rh(SC(_C),`@react-aria/grid`),n=Dm(),r=(n===`pointer`||n===`virtual`||n==null)&&typeof window<`u`&&`ontouchstart`in window;return s_((0,g.useMemo)(()=>{let n=e.selectionManager.selectionMode,i=e.selectionManager.selectionBehavior,a;return r&&(a=t.format(`longPressToSelect`)),i===`replace`&&n!==`none`&&e.hasItemActions?a:void 0},[e.selectionManager.selectionMode,e.selectionManager.selectionBehavior,e.hasItemActions,t,r]))}function wC(e,t,n){let{isVirtualized:r,keyboardDelegate:i,layoutDelegate:a,onAction:o,disallowTypeAhead:s,linkBehavior:c=`action`,keyboardNavigationBehavior:l=`arrow`,escapeKeyBehavior:u=`clearSelection`,shouldSelectOnPressUp:d}=e;!e[`aria-label`]&&!e[`aria-labelledby`]&&console.warn(`An aria-label or aria-labelledby prop is required for accessibility.`);let{listProps:f}=xy({selectionManager:t.selectionManager,collection:t.collection,disabledKeys:t.disabledKeys,ref:n,keyboardDelegate:i,layoutDelegate:a,isVirtualized:r,selectOnFocus:t.selectionManager.selectionBehavior===`replace`,shouldFocusWrap:e.shouldFocusWrap,linkBehavior:c,disallowTypeAhead:s,autoFocus:e.autoFocus,escapeKeyBehavior:u}),p=Hf(e.id);PS.set(t,{id:p,onAction:o,linkBehavior:c,keyboardNavigationBehavior:l,shouldSelectOnPressUp:d});let m=CC({selectionManager:t.selectionManager,hasItemActions:!!o}),h=xC(n,{isDisabled:t.collection.size!==0}),g=Yf(og(e,{labelable:!0}),{role:`grid`,id:p,"aria-multiselectable":t.selectionManager.selectionMode===`multiple`?`true`:void 0},t.collection.size===0?{tabIndex:h?-1:0}:f,m);return r&&(g[`aria-rowcount`]=t.collection.size,g[`aria-colcount`]=1),yC({},t),{gridProps:g}}var TC={expand:{ltr:`ArrowRight`,rtl:`ArrowLeft`},collapse:{ltr:`ArrowLeft`,rtl:`ArrowRight`}};function EC(e,t,n){let{node:r,isVirtualized:i}=e,{direction:a}=Wm(),{onAction:o,linkBehavior:s,keyboardNavigationBehavior:c,shouldSelectOnPressUp:l}=PS.get(t),u=Wf(),d=(0,g.useRef)(null),f=()=>{n.current!==null&&(d.current!=null&&r.key!==d.current||!gp(n.current))&&Th(n.current)},p={},m=e.hasChildItems,h=t.selectionManager.isLink(r.key);if(r!=null&&`expandedKeys`in t){let e=t.collection.getChildren?.(r.key);m||=[...e??[]].length>1,o==null&&!h&&t.selectionManager.selectionMode===`none`&&m&&(o=()=>t.toggleKey(r.key));let n=m?t.expandedKeys.has(r.key):void 0,i=1,a=r.index;if(r.level>=0&&r?.parentKey!=null){let e=t.collection.getItem(r.parentKey);if(e){let n=OC(e,t.collection);i=[...n].filter(e=>e.type===`item`).length,a>0&&n[0].type!==`item`&&--a}}else i=[...t.collection].filter(e=>e.level===0&&e.type===`item`).length;p={"aria-expanded":n,"aria-level":r.level+1,"aria-posinset":a+1,"aria-setsize":i}}let{itemProps:_,...v}=Ty({selectionManager:t.selectionManager,key:r.key,ref:n,isVirtualized:i,shouldSelectOnPressUp:e.shouldSelectOnPressUp||l,onAction:o||r.props?.onAction?wf(r.props?.onAction,o?()=>o(r.key):void 0):void 0,focus:f,linkBehavior:s}),y=e=>{let i=hp();if(!U(e.currentTarget,W(e))||!n.current||!i)return;let o=ty(n.current);if(o.currentNode=i,`expandedKeys`in t&&i===n.current){if(e.key===TC.expand[a]&&t.selectionManager.focusedKey===r.key&&m&&!t.expandedKeys.has(r.key)){t.toggleKey(r.key),e.stopPropagation();return}else if(e.key===TC.collapse[a]&&t.selectionManager.focusedKey===r.key){if(m&&t.expandedKeys.has(r.key)){t.toggleKey(r.key),e.stopPropagation();return}else if(!t.expandedKeys.has(r.key)&&r.parentKey&&t.collection.getItem(r.parentKey)?.type===`item`){t.selectionManager.setFocusedKey(r.parentKey),e.stopPropagation();return}}}switch(e.key){case`ArrowLeft`:if(c===`arrow`){let t=a===`rtl`?o.nextNode():o.previousNode();if(t)e.preventDefault(),e.stopPropagation(),Th(t),i_(t,{containingElement:t_(n.current)});else if(e.preventDefault(),e.stopPropagation(),a===`rtl`)Th(n.current),i_(n.current,{containingElement:t_(n.current)});else{o.currentNode=n.current;let e=DC(o);e&&(Th(e),i_(e,{containingElement:t_(n.current)}))}}break;case`ArrowRight`:if(c===`arrow`){let t=a===`rtl`?o.previousNode():o.nextNode();if(t)e.preventDefault(),e.stopPropagation(),Th(t),i_(t,{containingElement:t_(n.current)});else if(e.preventDefault(),e.stopPropagation(),a===`ltr`)Th(n.current),i_(n.current,{containingElement:t_(n.current)});else{o.currentNode=n.current;let e=DC(o);e&&(Th(e),i_(e,{containingElement:t_(n.current)}))}}break;case`ArrowUp`:case`ArrowDown`:!e.altKey&&U(n.current,W(e))&&(e.stopPropagation(),e.preventDefault(),n.current.parentElement?.dispatchEvent(new KeyboardEvent(e.nativeEvent.type,e.nativeEvent)));break}},b=e=>{if(d.current=r.key,W(e)!==n.current){wm()||t.selectionManager.setFocusedKey(r.key);return}},x=e=>{let t=hp();if(!(!U(e.currentTarget,W(e))||!n.current||!t))switch(e.key){case`Tab`:if(c===`tab`){let r=ty(n.current,{tabbable:!0});r.currentNode=t,(e.shiftKey?r.previousNode():r.nextNode())&&e.stopPropagation()}}},S=om(r.props),C=Yf(_,v.hasAction?S:{},{role:`row`,onKeyDownCapture:y,onKeyDown:x,onFocus:b,"aria-label":r[`aria-label`]||r.textValue||void 0,"aria-selected":t.selectionManager.canSelectItem(r.key)?t.selectionManager.isSelected(r.key):void 0,"aria-disabled":t.selectionManager.isDisabled(r.key)||void 0,"aria-labelledby":u&&(r[`aria-label`]||r.textValue)?`${FS(t,r.key)} ${u}`:void 0,id:FS(t,r.key)});if(i){let{collection:e}=t;C[`aria-rowindex`]=[...e].find(e=>e.type===`section`)?[...e.getKeys()].filter(t=>e.getItem(t)?.type!==`section`).findIndex(e=>e===r.key)+1:r.index+1}let w={role:`gridcell`,"aria-colindex":1};return{rowProps:{...Yf(C,p)},gridCellProps:w,descriptionProps:{id:u},...v}}function DC(e){let t=null,n=null;do n=e.lastChild(),n&&(t=n);while(n);return t}function OC(e,t){let n=t.getChildren?.(e.key),r=n?Array.from(n):[],i=r.length>0?r[0]:null,a=[];for(;i;)a.push(i),i=i.nextKey==null?null:t.getItem(i.nextKey);return a}function kC(e){return e&&e.__esModule?e.default:e}function AC(e,t){let{key:n}=e,r=t.selectionManager,i=Hf(),a=!t.selectionManager.canSelectItem(n),o=t.selectionManager.isSelected(n);return{checkboxProps:{id:i,"aria-label":rh(kC(_C),`@react-aria/grid`).format(`select`),isSelected:o,isDisabled:a,onChange:()=>r.toggleSelection(n)}}}function jC(e,t){let{key:n}=e,{checkboxProps:r}=AC(e,t);return{checkboxProps:{...r,"aria-labelledby":`${r.id} ${FS(t,n)}`}}}var MC=(0,g.createContext)(null),NC=(0,g.forwardRef)(function(e,t){return[e,t]=tp(e,t,MC),g.createElement(Lh,{content:g.createElement(qh,e)},n=>g.createElement(PC,{props:e,collection:n,gridListRef:t}))});function PC({props:e,collection:t,gridListRef:n}){[e,n]=tp(e,n,oh);let{shouldUseVirtualFocus:r,filter:i,disallowTypeAhead:a,...o}=e,{dragAndDropHooks:s,keyboardNavigationBehavior:c=`arrow`,layout:l=`stack`,orientation:u=`vertical`}=e,{CollectionRoot:d,isVirtualized:f,layoutDelegate:p,dropTargetDelegate:m}=(0,g.useContext)($h),h=Ky(Gy({...o,collection:t,children:void 0,layoutDelegate:p}),i),_=by({usage:`search`,sensitivity:`base`}),{disabledBehavior:v,disabledKeys:y}=h.selectionManager,{direction:b}=Wm(),x=(0,g.useMemo)(()=>new vy({collection:h.collection,collator:_,ref:n,disabledKeys:y,disabledBehavior:v,layoutDelegate:p,layout:l,orientation:u,direction:b}),[h.collection,n,l,u,y,v,p,_,b]),{gridProps:S}=wC({...o,keyboardDelegate:x,keyboardNavigationBehavior:l===`grid`?`tab`:c,isVirtualized:f,shouldSelectOnPressUp:e.shouldSelectOnPressUp,disallowTypeAhead:a},h,n),C=h.selectionManager,w=!!s?.useDraggableCollectionState,T=!!s?.useDroppableCollectionState;(0,g.useRef)(w),(0,g.useRef)(T),(0,g.useEffect)(()=>{},[w,T]);let E,D,O,k=!1,A=null,j=(0,g.useRef)(null);if(w&&s){E=s.useDraggableCollectionState({collection:h.collection,selectionManager:C,preview:s.renderDragPreview?j:void 0}),s.useDraggableCollection({},E,n);let e=s.DragPreview;A=s.renderDragPreview?g.createElement(e,{ref:j},s.renderDragPreview):null}if(T&&s){D=s.useDroppableCollectionState({collection:h.collection,selectionManager:C});let e=s.dropTargetDelegate||m||new s.ListDropTargetDelegate(t,n,{layout:l,direction:b,orientation:u});O=s.useDroppableCollection({keyboardDelegate:x,dropTargetDelegate:e},D,n),k=D.isDropTarget({type:`root`})}let{focusProps:M,isFocused:N,isFocusVisible:P}=jg(),F=h.collection.size===0,ee={isDropTarget:k,orientation:u,isEmpty:F,isFocused:N,isFocusVisible:P,layout:l,state:h},te=$f({...e,children:void 0,defaultClassName:`react-aria-GridList`,values:ee}),ne=null;if(F&&e.renderEmptyState){let t=e.renderEmptyState(ee);ne=g.createElement(`div`,{role:`row`,"aria-rowindex":1,style:{display:`contents`}},g.createElement(`div`,{role:`gridcell`,style:{display:`contents`}},t))}let re=og(e,{global:!0});return g.createElement(Fv,null,g.createElement(op.div,{...Yf(re,te,S,M,O?.collectionProps,null),ref:n,slot:e.slot||void 0,onScroll:e.onScroll,"data-drop-target":k||void 0,"data-empty":F||void 0,"data-focused":N||void 0,"data-focus-visible":P||void 0,"data-layout":l,"data-orientation":u},g.createElement(Qf,{values:[[Xy,h],[gv,{dragAndDropHooks:s,dragState:E,dropState:D}],[_v,{render:IC}]]},T&&g.createElement(zC,null),g.createElement(wv,null,g.createElement(d,{collection:h.collection,scrollRef:n,persistedKeys:bv(C,s,D),renderDropIndicator:yv(s,D)}))),ne,A))}var FC=Uh(dh,function(e,t,n){let r=(0,g.useContext)(Xy),{dragAndDropHooks:i,dragState:a,dropState:o}=(0,g.useContext)(gv),s=Xf(t),{isVirtualized:c}=(0,g.useContext)($h),l=a&&!(a.isDisabled||a.selectionManager.isDisabled(n.key)),{rowProps:u,gridCellProps:d,descriptionProps:f,...p}=EC({node:n,shouldSelectOnPressUp:!!a,isVirtualized:c},r,s),{hoverProps:m,isHovered:h}=Lg({isDisabled:!p.allowsSelection&&!p.hasAction&&!l,onHoverStart:n.props.onHoverStart,onHoverChange:n.props.onHoverChange,onHoverEnd:n.props.onHoverEnd}),{isFocusVisible:_,focusProps:v}=jg(),{isFocusVisible:y,focusProps:b}=jg({within:!0}),{checkboxProps:x}=jC({key:n.key},r),S=r.selectionManager.disabledBehavior===`all`&&p.isDisabled?{isDisabled:!0}:{},C=null;a&&i&&(C=i.useDraggableItem({key:n.key,hasDragButton:!0},a));let w=null,T=(0,g.useRef)(null),{visuallyHiddenProps:E}=l_();o&&i&&(w=i.useDropIndicator({target:{type:`item`,key:n.key,dropPosition:`on`}},o,T));let D=a&&a.isDragging(n.key),O=$f({...e,id:void 0,children:n.rendered,defaultClassName:`react-aria-GridListItem`,values:{...p,isHovered:h,isFocusVisible:_,isFocusVisibleWithin:y,selectionMode:r.selectionManager.selectionMode,selectionBehavior:r.selectionManager.selectionBehavior,allowsDragging:!!a,isDragging:D,isDropTarget:w?.isDropTarget,id:n.key,state:r}}),k=(0,g.useRef)(null);(0,g.useEffect)(()=>{a&&!k.current&&console.warn(`Draggable items in a GridList must contain a