From 5d7e68e53c069df3e5748f6a649db6603598de31 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Mon, 6 Jul 2026 11:53:13 +0200 Subject: [PATCH 01/40] =?UTF-8?q?chore(design):=20bootstrap=20dashboard=20?= =?UTF-8?q?design-prototype=20run=20=E2=80=94=20plan=20+=20design=20checkp?= =?UTF-8?q?oint=20locked?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run feat-dashboard-design-prototype--design: supervisor identity, four-lane research (seed corpus, board, fresh-ui surface, eis-chat + Claude Design), locked plan LD-1..LD-7, 8-slice design checkpoint. Supersedes-in-execution #425 (DDX-15) scope; no framework source. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Dgu7TfPnzpXUii84FSybbg --- .../context-pack.md | 75 +++++++++ .../drift.md | 32 ++++ .../plan.md | 154 ++++++++++++++++++ .../research.md | 56 +++++++ .../supervisor.md | 51 ++++++ .../worklog.md | 128 +++++++++++++++ 6 files changed, 496 insertions(+) create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/context-pack.md create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/drift.md create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/plan.md create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/research.md create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/supervisor.md create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/worklog.md diff --git a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md new file mode 100644 index 000000000..faa8c3a76 --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md @@ -0,0 +1,75 @@ +# Context Pack: Dev Dashboard E2E Claude Design prototype + design-sync system + +## Run Metadata + +| Field | Value | +| -------------- | ----------------------------------------- | +| Run ID | `feat-dashboard-design-prototype--design` | +| Branch | `feat/dashboard-design-prototype` | +| Current phase | `plan` (awaiting PLAN-EVAL) | +| Archetype | N/A (repo tooling + design artifacts) | +| Scope overlays | none | + +## Current State + +Run bootstrapped 2026-07-06 in worktree `.llm/tmp/design-proto-wt` @ `317e4b50` (beta.5 cut). +Four-lane research complete and condensed into research.md. Plan locked with the owner in-session +(LD-1…LD-7): full E2E Claude Design prototype of the beta.6 Dev Dashboard on a NEW design system +synced at 100% parity from today's fresh-ui, via a production-grade reusable `tools/design-sync/` +system; fully-agentic canvas lane over the Claude Design MCP with owner steering; #425 (DDX-15) +superseded-in-execution; new issue to file in Backlog / Triage. This run is fully decoupled from +the beta.6 implementation supervisor. + +## Completed + +- Research (four parallel lanes: seed-corpus mining, GitHub board sweep, fresh-ui inventory, + eis-chat + Claude Design capabilities). +- Plan + Design checkpoint (worklog.md § Design, 8 slices). +- Run dir scaffolding (supervisor.md first). + +## In Progress + +- Bootstrap tail: commit + push branch, open draft PR, file new issue + board comments, dispatch + PLAN-EVAL. + +## Next Steps + +1. Commit run dir; push `feat/dashboard-design-prototype` (explicit refspec); open draft PR (WSL gh). +2. File new issue (Backlog / Triage, `Part of #400`); supersession comments on #425/#400. +3. Dispatch PLAN-EVAL (OpenHands minimax-M3, separate session). **Hard stop before slice 1.** +4. Owner: `claude mcp add … claude-design …` + `/design-login`; then slice 0 canvas smoke. + +## Key Decisions + +| Decision | Source | Notes | +| -------- | ------ | ----- | +| LD-1…LD-7 | plan.md § Locked Decisions | owner-ratified in session 2026-07-06 | + +## Files Changed + +| Path | Status | Notes | +| ---- | ------ | ----- | +| `.llm/runs/feat-dashboard-design-prototype--design/*` | new | run artifacts (6 files) | + +## Gates + +| Gate family | Current status | Evidence | +| ----------- | -------------- | -------- | +| Static | NOT_RUN | after slice 1 | +| Fitness | NOT_RUN | idempotence/parity/traps defined in plan.md | +| Runtime | NOT_RUN | slice 0 MCP smoke blocked on owner login | +| Consumer | N/A | no package surface | + +## Open Questions + +- OQ-1 MCP viability (slice 0 gate) · OQ-2 synthetic pkg name · OQ-3 shots in-repo · OQ-4 closure + build source — see research.md. + +## Drift and Debt + +- Drift: DDX-15 scope expansion + DDX-0 inversion; Tier-A lane override (see drift.md). +- Debt: none created; DataTable grid-collapse verification noted in plan.md. + +## Commits + +- See the draft PR's commit list + per-slice PR comments (V3 retired `commits.md`). diff --git a/.llm/runs/feat-dashboard-design-prototype--design/drift.md b/.llm/runs/feat-dashboard-design-prototype--design/drift.md new file mode 100644 index 000000000..da50a8bf3 --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/drift.md @@ -0,0 +1,32 @@ +# Drift Log: Dev Dashboard E2E Claude Design prototype + design-sync system + +Drift is append-only. Record facts that diverge from the plan, RFC, doctrine, or current-state +documentation. + +## 2026-07-06 — DDX-15 scope expansion + DDX-0 dependency inversion + +- **What:** Owner expanded the design pre-step from DDX-15's filed scope (design-sync artifact + + Fresh panel-shell prototype) to a full E2E Claude Design prototype + production-grade reusable + sync system, and inverted the filed DDX-0→DDX-15 edge: prototype pass 1 now validates/amends the + DDX-0 L3 promote-set **before** DDX-0 is implemented (the eis-chat two-pass loop). +- **Source:** owner directives in session 2026-07-06 (five forks answered; see plan.md LD-1…LD-7). +- **Expected:** `.llm/runs/plan-roadmap-expansion--seed/design/A-dashboard/epic-and-issues.md` — + DDX-15 depends on DDX-0, blocks DDX-5 + panels. +- **Actual:** This run supersedes #425 in execution; #425 stays open as the beta.6 tracking point + and is closed by this run's PR when the artifacts land. New issue filed in Backlog / Triage. +- **Severity:** significant +- **Action:** rescope (owner-ratified); board comments on #400/#425 at bootstrap. +- **Evidence:** research.md F1/F11; session decision log. + +## 2026-07-06 — Lane override: Tier-A implements repo tooling + drives the canvas + +- **What:** Tier-A (Fable 5 supervisor) implements `tools/design-sync/` and orchestrates the + Claude Design canvas via MCP, instead of routing implementation to Tier-D. +- **Source:** owner fork answers (fully-agentic canvas; sync home = tools/); supervisor.md + § Recorded lane/eval overrides. +- **Expected:** lane-policy default — source slices → Tier D. +- **Actual:** deliverable is repo tooling (not `packages/`/`plugins/`) + a Claude-native cloud + surface only Claude can drive; boundary not crossed. +- **Severity:** minor +- **Action:** accept (recorded). +- **Evidence:** supervisor.md lane table; AGENTS.md tooling tiers. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/plan.md b/.llm/runs/feat-dashboard-design-prototype--design/plan.md new file mode 100644 index 000000000..85a92416d --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/plan.md @@ -0,0 +1,154 @@ +# Plan: Dev Dashboard E2E Claude Design prototype + production design-sync system + +## Run Metadata + +| Field | Value | +| -------------- | -------------------------------------------- | +| Run ID | `feat-dashboard-design-prototype--design` | +| Branch | `feat/dashboard-design-prototype` | +| Phase | `plan` | +| Target | repo tooling (`tools/design-sync/`) + design artifacts (`resources/design/dashboard/`) | +| Archetype | N/A — no `packages/`/`plugins/` surface changes | +| Scope overlays | none (design/tooling run; SCOPE-frontend informs vocabulary only) | + +## Archetype + +N/A with justification: the run's code deliverable is product-facing repo tooling under `tools/` +(AGENTS.md tooling tier 2), not a workspace package. The design artifacts describe the future +`plugins/dashboard` (ARCHETYPE-5 + `plugin-dashboard-core`), but this run does not create them — +that is DDX-2/DDX-4 (WSL Codex, beta.6 supervisor). + +## Current Doctrine Verdict + +N/A for the tooling deliverable. The design deliverable must stay consistent with the ratified +dashboard proposal (`.llm/runs/plan-roadmap-expansion--seed/design/A-dashboard/proposal.md`) — +panel IA, `DashboardPanelContribution` seam vocabulary, per-capability create→configure→monitor +loops — so downstream implementation slices inherit zero design/doctrine conflicts. + +## Axioms in Play + +| Axiom | Why it matters | +| ----- | -------------- | +| Wrap, don't reinvent | The sync system wraps fresh-ui's existing machine-consumable registry (`registry.generated.ts`, manifest, JSDoc headers) — no parallel component catalog. | +| Contract first | `config.json` + `conventions.md` are the sync contract; the converter implements them. | +| Drift is explicit | The DDX-0↔DDX-15 inversion and the #425 supersession are recorded in `drift.md` and on the board. | + +## Goal + +A complete, fully-agentic E2E Claude Design prototype of the NetScript Dev Dashboard (shell + 7 +panels + 4 per-capability sections, light/dark) on a **new** Claude Design project seeded at 100% +component parity from today's fresh-ui — plus a **production-grade, reusable design-sync system** +(`tools/design-sync/`) and a sync-back spec that makes every new/changed component +implementation-ready for fresh-ui. + +## Scope + +- `tools/design-sync/` — registry→synthetic-React-package converter + compiled CSS closure + + conventions header + preview cards; idempotent re-sync; the six eis-chat traps encoded as checks; + `deno task design:sync` entry. +- `resources/design/dashboard/` — CLAUDE-DESIGN-BRIEF.md, PROPOSED-COMPONENTS.md (DDX-0 promote-set + + new components in NS One idiom), NS-ONE-ADDITIONS-equivalent sync-back spec, prototype-shots/, + DECISIONS.md. +- New Claude Design project (cloud) seeded via the sync system + brief. +- Board: file the new issue (Backlog / Triage, `Part of #400`); supersession-in-execution comments + on #425 and #400. + +## Non-Scope + +- **No `packages/` or `plugins/` source changes.** fresh-ui implementation of prototyped components + = downstream WSL Codex lanes fed by the sync-back spec (DDX-0 amendment + new issues as needed). +- No `plugins/dashboard/.design-sync/` placement yet — the plugin doesn't exist until DDX-2/4; this + run's artifacts live in `resources/design/dashboard/` and migrate when the plugin lands (handoff + note). +- No CLI `ui:design-sync` command — filed separately as a future framework issue (owner: the sync + mechanism may later be offered to NetScript devs for their own Claude-Design-designed projects). +- No telemetry/AI/beta.6 implementation work — that supervisor runs elsewhere. + +## Hidden Scope + +- Compiled Tailwind CSS closure needs a real Fresh build; may require a kitchen-sink page so the + closure contains every registry class (OQ-4). +- Token-closure completeness check (trap b) needs the DTCG source as ground truth — compare + `tokens.css` var set vs compiled closure var set. +- Preview cards for ~55–60 units is authored content, not just codegen — budget agent time; carry + eis-chat's 29 as prior art where components overlap. +- Board comments must respect netscript-pr taxonomy; new issue takes `Part of #400`, **no closing + keyword anywhere** (umbrella discipline). + +## Locked Decisions + +| ID | Decision | Rationale | +| -- | -------- | --------- | +| LD-1 | Full E2E prototype breadth (shell + 7 panels + 4 capability sections, light/dark), staged in two passes | Owner fork 1 (2026-07-06); showcase + decision-locking is the point; pass 1 gates the promote-set before capability sections burn canvas turns | +| LD-2 | New Claude Design project synced from today's fresh-ui at 100% fidelity/parity; stale project abandoned | Owner fork 2; evidence: near-total divergence (research F6) | +| LD-3 | Fully agentic canvas lane via Claude Design MCP; owner steers/iterates from the canvas UI; recorded fallback = owner relays if endpoint persistently 404s | Owner fork 3; flakiness gate at slice 0 | +| LD-4 | Sync system = `tools/design-sync/`, production-grade, idempotent; future promotion path = `netscript ui:design-sync` CLI feature for NetScript devs (separate issue, framework lane) | Owner fork 4 + follow-up note | +| LD-5 | Run fully decoupled from beta.6 supervisor; #425 superseded-in-execution (stays open as beta.6 tracking point, closed by this run's PR when artifacts land); new issue filed in Backlog / Triage | Owner fork 5 | +| LD-6 | Two-pass loop inverts DDX-0→DDX-15: prototype pass 1 validates/amends the DDX-0 promote-set before DDX-0 implementation | eis-chat proven loop (research F11); recorded as drift vs filed DAG | +| LD-7 | Design artifacts follow the eis-chat idiom (brief → proposed-components → prototype-shots → sync-back spec) with the six traps encoded as tooling checks | research F8/F9 | + +## Open-Decision Sweep + +| Decision | Status | Notes | +| -------- | ------ | ----- | +| MCP round-trip viability (OQ-1) | **must resolve now** (slice 0 gate, before slice 3) | Fallback recorded in supervisor.md; does not block slices 1–2 | +| Synthetic package name (OQ-2) | safe to defer | Default `@netscript/ns-one`, global `NSOne`; decide at `config.json` authoring | +| Prototype-shots in-repo (OQ-3) | safe to defer | Default: commit under `resources/design/dashboard/prototype-shots/` | +| CSS-closure build source (OQ-4) | safe to defer | Default `apps/dashboard` build; add kitchen-sink page if closure is incomplete | + +## Risk Register + +| Risk | Mitigation | +| ---- | ---------- | +| Claude Design MCP 404/401 flakiness | Slice 0 hard gate + recorded owner-relay fallback; retry with `/design-login` re-auth | +| Plan-token burn (canvas shares the plan pool) | Brief front-loads everything (system, IA, conventions, inspiration); batch canvas turns; owner steers interactively rather than agent trial-and-error | +| Registry→React conversion edge cases (signals-heavy islands, `chat-render` parser, `f-client-nav`) | Type-only-Preact trick covers components; islands get React-shim previews; `f-client-nav` attr is inert in React — documented in conventions.md; chat-render excluded from parity set (AI collection optional for dashboard) | +| Compiled closure missing classes/tokens (traps a+b) | Tooling checks: var-set diff vs DTCG source; `:root:not([data-theme])` default block appended by the converter | +| Canvas invents off-system UI | conventions.md as readmeHeader + token rule ("no raw hex") + per-panel previews with real content (no `[RENDER_BLANK]`) | +| Prototype drifts from ratified IA | Brief embeds proposal §IA verbatim; supervisor slice review compares shots vs IA before accepting a pass | +| Collision with beta.6 supervisor | Separate branch/worktree/PR; board comments declare the dependency; no shared files except future merge of `tools/` | + +## Anti-Patterns to Resolve or Avoid + +| AP | Status | Plan | +| -- | ------ | ---- | +| Hand-flattened CSS subset (eis-chat trap) | risk | Avoid: converter only ships compiled closure | +| Speculative seams (files to satisfy folder shape) | risk | Avoid: every tools/ file traces to the Design section | +| Self-certifying canvas output | risk | Avoid: supervisor slice review of shots vs IA + owner steering; IMPL-EVAL independent | + +## Fitness Gates + +| Gate | Required | Expected evidence | +| ---- | -------- | ----------------- | +| Sync idempotence | yes | re-run `design:sync` on unchanged registry → zero diff in output bundle | +| Parity checklist | yes | converter report: registry manifest units vs synthetic package exports vs preview cards | +| Trap checks (a–f) | yes | converter check output committed with slice 5 | + +## Arch-Debt Implications + +| Entry | Action | Notes | +| ----- | ------ | ----- | +| DataTable grid-template collapse (eis-chat finding) | verify/none | Check whether fresh-ui's current `data-table` block carries the bug; if yes → downstream fix issue, not this run | + +## Validation Plan + +| Order | Gate | Command or check | Expected result | +| ----- | ---- | ---------------- | --------------- | +| 1 | Static (tools) | `.llm/tools/run-deno-check.ts --root tools/design-sync --ext ts,tsx` (+ lint, fmt wrappers) | PASS | +| 2 | Sync self-test | `deno task design:sync -- --check` on fresh-ui registry | bundle built; parity + trap checks green | +| 3 | Canvas smoke (slice 0) | MCP create/read scratch design | round-trip OK or fallback recorded | +| 4 | Pass review (slices 4/6) | supervisor shot-vs-IA review + owner steering sign-off | decisions logged in DECISIONS.md | +| 5 | IMPL-EVAL | OpenHands qwen-3.7-max, separate session | PASS | + +## Dependencies + +- Claude Design MCP availability (`https://api.anthropic.com/v1/design/mcp`) + owner `/design-login`. +- fresh-ui `0.0.1-beta.4` registry surface (in-repo, baseline `317e4b50`). +- eis-chat `.design-sync/` recipe (extracted in seed run `analysis/A-dashboard/02`). +- Seed-run corpus for the brief (proposal, teardowns, voice rules). + +## Drift Watch + +- fresh-ui registry changes on main during the run (re-sync before pass 2 anyway). +- #425/#400 body edits by the beta.6 supervisor. +- Claude Design product changes (MCP endpoint, design-system import behavior). diff --git a/.llm/runs/feat-dashboard-design-prototype--design/research.md b/.llm/runs/feat-dashboard-design-prototype--design/research.md new file mode 100644 index 000000000..e2368c031 --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/research.md @@ -0,0 +1,56 @@ +# Research — feat-dashboard-design-prototype--design + +Four parallel research lanes ran 2026-07-06 (seed-run corpus mining, GitHub board sweep, fresh-ui +surface inventory, eis-chat prior art + Claude Design capability research). Findings below are the +load-bearing subset; each cites its source. + +## Re-baseline + +- Carried-in source: `.llm/runs/plan-roadmap-expansion--seed/` (the ratified roadmap-expansion seed + run) + the filed beta.6 board (#399/#400 + DDX/T issues). +- Re-derived against `main` @ `317e4b50` (2026-07-06, beta.5 cut). +- What changed vs the carried-in version: + - The seed run planned DDX-15 as "Claude design-sync artifact + panel prototype" **depending on + DDX-0**; owner (2026-07-06, this session) expanded the scope to a **full E2E Claude Design + prototype** and inverted the edge (prototype pass 1 validates the DDX-0 promote-set). + - fresh-ui at planning time vs now: version marched `0.0.1-alpha.6` → `beta.4`; the seed-run + inventory (`analysis/A-dashboard/01`) remains directionally correct but the AI/chat collection, + `DataGrid`, `Icon`, and the DTCG token pipeline all landed after it. + +## Findings + +| # | Finding | How to verify | +| - | ------- | ------------- | +| 1 | The dashboard epic is **#400** (beta.6, 23 slices DDX-0…19); design lane is **#425 (DDX-15)**: `plugins/dashboard/.design-sync/` + Fresh panel-shell prototype, depends on DDX-0, blocks DDX-5 + all panels. It does NOT cover a full E2E canvas prototype. | `gh issue view 400 / 425 --repo rickylabs/netscript` (WSL) | +| 2 | Design research is already done: competitor teardowns with distilled IA vocabulary (Encore Flow/API Explorer, Temporal event-history All/Compact/JSON, Inngest two-panel + rerun-from-step, Trigger.dev OTel inspector; Appwrite create→configure→monitor, Directus Panel contract, Strapi codegen-from-UI). | `.llm/runs/plan-roadmap-expansion--seed/research/A-dashboard/03-competitor-dev-console-teardown.md`, `04-baas-admin-console-teardown.md` | +| 3 | The locked panel IA (7 cross-cutting panels + per-capability sections) and the full design proposal exist. | `.llm/runs/plan-roadmap-expansion--seed/design/A-dashboard/proposal.md` §0–9 | +| 4 | **NS One (eis-chat DS) L0–L2 is byte-identical to fresh-ui's copy-source output** — NS One *is* fresh-ui output; the ratified gap is the missing L3 `blocks/` layer (DDX-0 promote-set: breadcrumbs, context-rail, plugin-gated-view, activity-feed, connector, entity-rail, tree-nav). | `.llm/runs/plan-roadmap-expansion--seed/analysis/A-dashboard/03-fresh-ui-vs-nsone-gap-inventory.md` | +| 5 | fresh-ui today: ~55–60 units (31 registry components, 11 blocks, 3 islands, 8 runtime compounds, L0 primitives), 4-tier DTCG token pipeline (`tokens/*.tokens.json` → `tokens.css` → Tailwind v4 bridge), machine-consumable registry (`registry.generated.ts` 290KB embeds all source; structured `@component/@layer/@depends` JSDoc). | `packages/fresh-ui/{deno.json,registry.manifest.ts,registry.generated.ts,tokens/}` | +| 6 | **Near-total divergence, not drift**: all current fresh-ui architecture (src/ restructure, token pipeline, AI/chat collection, DataGrid, Icon) landed 2026-06-14 → 07-05. The ~6-month-old Claude Design project predates all of it — patching is not viable. | `git log --oneline -- packages/fresh-ui` (50 commits, earliest 2026-06-14) | +| 7 | Styling is class/CSS-driven: `--ns-*` vars + semantic `ns-*` classes + layout objects (~25KB hand-authored CSS) port to React **verbatim**; only JSX/hooks (Preact signals, Fresh islands, `f-client-nav`, native ``) need conversion. | `packages/fresh-ui/registry/{theme/tokens.css,styles/layouts.css}`; `src/runtime/*` | +| 8 | The React-port recipe is **written**: eis-chat `.design-sync/NOTES.md` — synthetic npm package, **type-only Preact imports compile as genuine React under React JSX**, CSS must be the compiled Tailwind closure (~80KB `_fresh` output, NOT a hand-flattened subset), fonts via Google-Fonts `@import`. | eis-chat `resources/design/` + `.design-sync/` (private repo, WSL `gh`); extraction: seed run `analysis/A-dashboard/02-eis-chat-design-sync-full-extraction.md` | +| 9 | Six recorded parity traps: (a) canvas defaults to no theme → append `:root:not([data-theme])` block; (b) missing spacing tokens silently zero gaps; (c) prototype found a real source bug (DataTable grid-template collapse); (d) weak synthetic `.d.ts` → conventions.md is the prop-contract source; (e) `[RENDER_BLANK]` unauthored previews; (f) raw-hex leakage → mandate token-driven charts. | eis-chat `.design-sync/NOTES.md`; seed run `analysis/A-dashboard/02` | +| 10 | Claude Design (July 2026): design-system import is first-class (GitHub repo / files / `/design-sync` from Claude Code); canvas runtime is React; MCP server `https://api.anthropic.com/v1/design/mcp` enables agent-driven import/export; known 404/401 flakiness (anthropics/claude-code #69310/#69313/#69324/#69325); usage draws from the shared plan pool; exports incl. Claude Code handoff bundle. | https://support.claude.com/en/articles/14604397 · https://support.claude.com/en/articles/14604416 · claude-code issues above | +| 11 | eis-chat prototype = the proven template: brief + inspiration shots + DS import → 6 screens × light/dark + shell details (22 prototype-shots) → `NS-ONE-ADDITIONS.md` sync-back spec (181 CSS selectors / 51 `ns-*` bases) → stacked implementation PRs. Loop was **two-pass**: discovery pass → author components at source → re-sync → refine on real components. | eis-chat `resources/design/{CLAUDE-DESIGN-BRIEF.md,PROPOSED-COMPONENTS.md,NS-ONE-ADDITIONS.md,prototype-shots/}` | +| 12 | Voice/brand constraints binding on dashboard copy: dark-default with "warm cream light theme" brand look; factual comparison tone; **no "honesty/candor" framing**; no unshipped-capability claims; no invented metrics. | seed run `specs/01-ratified-decisions.md:40-48`; `analysis/D-positioning/current-docs-audit.md` §4–5 | +| 13 | Compiled-CSS-closure source: `apps/dashboard` (the scaffolded showcase app) is the natural Fresh build from which to compile the Tailwind closure for the synthetic package. | `apps/dashboard/` (referenced as the worked showcase in `docs/site/capabilities/fresh-ui.md`) | +| 14 | Beta.6 board context: 41 open issues; telemetry T3–T8 co-land with dashboard DDX; #505 is the only `status:impl` item (beta.5 e2e-cli-prod red). This run must not collide with that supervisor's lanes. | GitHub milestone `0.0.1-beta.6` sweep, 2026-07-06 | + +## jsr-audit surface scan (package/plugin waves) + +N/A — this run ships repo tooling (`tools/design-sync/`) + design artifacts; no `packages/` or +`plugins/` surface changes. The fresh-ui implementation of prototyped components is downstream +(WSL Codex lanes fed by the sync-back spec) and will carry its own jsr-audit there. + +## Open questions + +- OQ-1 (**must resolve at slice 0**): does the Claude Design MCP round-trip work from this + environment (create/read/export), given the known 404/401 reports? Fallback recorded in + `supervisor.md` if not. +- OQ-2 (safe to defer to slice 1): synthetic package naming — DDX-15 spec says + `@netscript/dashboard-ns-one` / global `NSOne`; since this sync covers all of fresh-ui (not a + dashboard subset), `@netscript/ns-one` may be truer. Decide when writing `config.json`. +- OQ-3 (safe to defer to slice 7): where prototype-shots live long-term (repo size vs + `resources/design/dashboard/prototype-shots/` following eis-chat). Default: commit them. +- OQ-4 (safe to defer): whether the compiled CSS closure builds from `apps/dashboard` as-is or + needs a dedicated kitchen-sink page to pull all registry classes into the closure. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/supervisor.md b/.llm/runs/feat-dashboard-design-prototype--design/supervisor.md new file mode 100644 index 000000000..891717342 --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/supervisor.md @@ -0,0 +1,51 @@ +# Supervisor Identity — feat-dashboard-design-prototype--design + +Written at run start per `workflow/lane-policy.md` § Supervisor identity. A run dir without this +file is not activated. Other supervisors cross-peek a run by reading this file — it is how a run's +operating identity is discoverable without chat memory. + +| Field | Value | +| --- | --- | +| Model | Claude Fable 5 (`claude-fable-5[1m]`) | +| Session | https://claude.ai/code/session_01Dgu7TfPnzpXUii84FSybbg | +| Host | Windows 11 Home 10.0.26200, user `chaut` | +| Checkout | `C:\Dev\repos\netscript-framework` | +| Worktree | `C:\Dev\repos\netscript-framework\.llm\tmp\design-proto-wt` | +| Branch | `feat/dashboard-design-prototype` | +| Baseline | `317e4b50` (origin/main, 2026-07-06, beta.5 cut) | +| Run ID | `feat-dashboard-design-prototype--design` | + +## Run charter (one paragraph) + +Deliver the beta.6 Dev Dashboard's missing design pre-step as a self-contained run, fully decoupled +from the beta.6 implementation supervisor: (1) a **production-grade reusable design-sync system** +(`tools/design-sync/`) that converts the current `@netscript/fresh-ui` copy-source registry into a +Claude Design-consumable design system (synthetic React package + compiled CSS closure) with +idempotent re-sync; (2) a **new Claude Design project** seeded at 100% component parity; (3) a +**full E2E prototype** of the dashboard (shell + 7 panels + 4 per-capability sections, light/dark), +driven agentically via the Claude Design MCP with the owner steering from the canvas UI; (4) a +**sync-back spec** making every new/changed component implementation-ready for fresh-ui (downstream +lanes, not this run). Supersedes-in-execution #425 (DDX-15); inverts the DDX-0→DDX-15 edge into the +eis-chat two-pass loop (prototype pass 1 validates the DDX-0 promote-set before DDX-0 lands). + +## Lane table in force + +| Tier | Binding | Role in this run | +| --- | --- | --- | +| A | Claude Fable 5 (this session) | Supervisor; slice review gate; canvas orchestration via Claude Design MCP; board comments | +| B | Claude Opus sub-agents (internal) | Design-brief prose synthesis from the seed-run corpus; research condensation | +| C | — | Not used | +| D | WSL Codex | **Not used in this run** — fresh-ui implementation of prototyped components is a downstream handoff fed by the sync-back spec | +| E | OpenHands minimax-M3 (PLAN-EVAL) / qwen-3.7-max (IMPL-EVAL) | Separate-session evaluator verdicts | + +## Recorded lane/eval overrides + +- **Tier-A implements `tools/design-sync/`** (repo tooling, not `packages/`/`plugins/` source — the + supervisor-does-not-write-framework-code boundary is not crossed). Authorization: owner directive + in-session (2026-07-06): "fully agentic … we'll start it here as soon as we locked together the + plan", sync-home fork answered `tools/design-sync`. Mirrored in `drift.md`. +- **Canvas lane is Tier-A via Claude Design MCP** (not a Codex/OpenHands lane — Claude Design is a + Claude-native surface). Owner steers/iterates directly from the Claude Design dashboard. + Fallback if the MCP endpoint is persistently 404/401 (known June-2026 flakiness): Tier-A prepares + brief + design system + per-turn instructions; owner relays through the canvas UI. Slice 0 gates + this. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/worklog.md b/.llm/runs/feat-dashboard-design-prototype--design/worklog.md new file mode 100644 index 000000000..614fe8a0f --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/worklog.md @@ -0,0 +1,128 @@ +# Worklog: Dev Dashboard E2E Claude Design prototype + design-sync system + +## Run Metadata + +| Field | Value | +| -------------- | ----------------------------------------- | +| Run ID | `feat-dashboard-design-prototype--design` | +| Branch | `feat/dashboard-design-prototype` | +| Archetype | N/A (repo tooling + design artifacts) | +| Scope overlays | none | + +## Design + +### Public Surface + +- `deno task design:sync` — root task delegating to `tools/design-sync/mod.ts` (build | check | + clean subcommands). +- `tools/design-sync/mod.ts` — CLI entry: reads `resources/design/dashboard/.design-sync/config.json`, + emits the synthetic package bundle to a gitignored scratch dir, prints a parity + trap-check + report. +- `resources/design/dashboard/` — the design artifact set (brief, proposed components, sync-back + spec, shots, decisions). + +### Domain Vocabulary + +- `SyncConfig` — parsed `config.json` (projectId, pkg, globalName, srcMap, cssEntry, readmeHeader). +- `RegistryUnit` — one manifest item (kind: component | block | island | lib | support | style | + theme) joined with its embedded source from `registry.generated.ts`. +- `ConversionResult` — per-unit outcome: emitted React source, skipped-with-reason, or shimmed + (islands). +- `ParityReport` — manifest units vs emitted exports vs preview cards; the fitness-gate artifact. +- `TrapCheck` — one of the six encoded eis-chat traps (theme-default, token-closure, compiled-css, + weak-dts, render-blank, raw-hex) with PASS/FAIL + evidence. + +### Ports + +- `RegistrySource` — reads fresh-ui's manifest + generated source (seam so the tool later works + against any NetScript app's copied registry — the CLI-promotion path). +- `ClosureBuilder` — produces the compiled Tailwind CSS closure from a Fresh build (default: + `apps/dashboard`); seam for the kitchen-sink fallback (OQ-4). + +### Constants + +- `TRAP_IDS` — `theme-default | token-closure | compiled-css | weak-dts | render-blank | raw-hex`. +- `UNIT_KINDS` — mirrors `registry.schema.ts` kinds; imported (type-only) not restated. +- `PARITY_EXCLUSIONS` — units excluded from the canvas parity set with reasons (e.g. `chat-render` + parser internals; `f-client-nav` behavior noted inert). + +### Commit Slices + +| # | Slice | Gate | Files | +| - | ----- | ---- | ----- | +| 0 | Canvas pre-flight: MCP connect + round-trip smoke | manual: create/read scratch design; evidence in worklog | run dir only | +| 1 | design-sync v1: converter + closure + conventions + previews + trap checks + idempotence | wrappers (check/lint/fmt) + `design:sync --check` self-test | `tools/design-sync/**`, root `deno.json` task, `.gitignore` scratch entry | +| 2 | Dashboard design brief + proposed components distilled from seed corpus | supervisor review vs proposal §IA + voice rules | `resources/design/dashboard/{CLAUDE-DESIGN-BRIEF.md,PROPOSED-COMPONENTS.md}` | +| 3 | New Claude Design project seeded (design system + brief imported) | ParityReport green; canvas renders seeded system | `.design-sync/config.json` (+ run-dir evidence) | +| 4 | Prototype pass 1: shell + Stack Map + Flow/Trace Waterfall + Service Catalog/API Explorer + Run Inspector ×light/dark | shot-vs-IA review + owner steering; DDX-0 promote-set verdict | `resources/design/dashboard/prototype-shots/`, `DECISIONS.md` | +| 5 | Re-sync checkpoint: pass-1 components fed back; idempotence + trap checks re-run | `design:sync --check` green on updated inputs | sync-back deltas + run dir | +| 6 | Prototype pass 2: Plugin Control, Logs, Resource Control + workers/sagas/triggers/streams sections | shot-vs-IA review + owner steering | shots + `DECISIONS.md` | +| 7 | Sync-back spec + final shots + board comments (#400/#425) + handoff notes | IMPL-EVAL (separate session) | `resources/design/dashboard/NS-ONE-ADDITIONS.md`, run dir | + +### Deferred Scope + +- fresh-ui implementation of prototyped components — downstream WSL Codex lanes (DDX-0 amendment + + new issues from the sync-back spec). +- `netscript ui:design-sync` CLI productization — separate framework issue. +- `plugins/dashboard/.design-sync/` placement — migrates when DDX-2/4 create the plugin. +- AI/chat collection parity on the canvas — not needed for dashboard surfaces. + +### Contributor Path + +A developer re-syncing after registry changes runs `deno task design:sync`, reads the printed +ParityReport + TrapCheck table, and re-imports the bundle into the Claude Design project (or lets +the MCP lane do it). To add a new prototyped component to source, they read one sync-back spec +entry (class contract + props + CSS) and implement it in fresh-ui following an existing registry +unit of the same kind. + +## Progress Log + +| Time | Slice | Step | Notes | +| ---- | ----- | ---- | ----- | +| 2026-07-06 | — | Bootstrap | Worktree `.llm/tmp/design-proto-wt` @ `317e4b50`; run dir scaffolded; four-lane research complete (see research.md) | + +## Decisions + +| Decision | Reason | Source | +| -------- | ------ | ------ | +| LD-1…LD-7 | see plan.md § Locked Decisions | owner (session 2026-07-06) + research | + +## Drift + +| Drift | Severity | Logged in drift.md | +| ----- | -------- | ------------------ | +| DDX-0↔DDX-15 dependency inversion | significant | yes | +| #425 superseded-in-execution | significant | yes | + +## Gate Results + +### Static Gates + +| Gate | Command or check | Result | Notes | +| ---- | ---------------- | ------ | ----- | +| check/lint/fmt (tools) | scoped wrappers | NOT_RUN | after slice 1 | + +### Fitness Gates + +| Gate | Result | Evidence | Notes | +| ---- | ------ | -------- | ----- | +| Sync idempotence | NOT_RUN | — | slice 1/5 | +| Parity checklist | NOT_RUN | — | slice 3 | +| Trap checks a–f | NOT_RUN | — | slice 1/5 | + +### Runtime Gates + +| Gate | Result | Evidence | Notes | +| ---- | ------ | -------- | ----- | +| Canvas MCP smoke | NOT_RUN | — | slice 0; blocked on owner `/design-login` | + +### Consumer Gates + +| Consumer | Result | Evidence | Notes | +| -------- | ------ | -------- | ----- | +| N/A | — | — | no package surface changes | + +## Handoff Notes + +- Evaluator: start with plan.md § Locked Decisions + research.md findings F4–F11, then the + ParityReport/TrapCheck evidence, then DECISIONS.md vs the ratified proposal IA. From da3c04002ce93aa123233ce667aa95c7fbc264c9 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Mon, 6 Jul 2026 12:00:41 +0200 Subject: [PATCH 02/40] chore(design): board filed (#506/#507, comments on #425/#400) + lane-policy addendum (Fable 5 = design lane, WSL = chores only) Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Dgu7TfPnzpXUii84FSybbg --- .../board/comment-400.md | 9 ++++ .../board/comment-425.md | 11 +++++ .../board/issue-body.md | 25 +++++++++++ .../pr-body.md | 44 +++++++++++++++++++ .../supervisor.md | 8 ++-- 5 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/board/comment-400.md create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/board/comment-425.md create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/board/issue-body.md create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/pr-body.md diff --git a/.llm/runs/feat-dashboard-design-prototype--design/board/comment-400.md b/.llm/runs/feat-dashboard-design-prototype--design/board/comment-400.md new file mode 100644 index 000000000..5ddceb916 --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/board/comment-400.md @@ -0,0 +1,9 @@ +**Design pre-step update** (owner-ratified, 2026-07-06). + +DDX-15 (#425) is superseded-in-execution by a dedicated design run (tracking issue #507; branch `feat/dashboard-design-prototype`). Three epic-level consequences: + +1. **Sequencing:** DDX-5 (#415) and all panel slices (#416–#422, #427–#431) are blocked on the design run's delivery — a full E2E Claude Design prototype + `tools/design-sync/` system + sync-back spec — not on the narrower DDX-15 as filed. +2. **DDX-0 (#410) edge inverted:** the prototype's pass 1 validates/amends the L3 promote-set (breadcrumbs, context-rail, plugin-gated-view, activity-feed, connector, entity-rail, tree-nav) *before* DDX-0 implementation. DDX-0 implementers should treat the run's sync-back spec as the authoritative promote-set input. +3. **No board restructuring:** all DDX issue numbers, milestones, and the telemetry co-land contract are unchanged. GitHub remains the source of truth; this is an execution-lane note, not a re-plan. + +Run dir: `.llm/runs/feat-dashboard-design-prototype--design/` on the run branch. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/board/comment-425.md b/.llm/runs/feat-dashboard-design-prototype--design/board/comment-425.md new file mode 100644 index 000000000..58c2a64bc --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/board/comment-425.md @@ -0,0 +1,11 @@ +**Superseded-in-execution** (owner-ratified, 2026-07-06). + +This slice's scope has been expanded and is being executed by a dedicated design run — see tracking issue #507 (Backlog / Triage) and draft PR branch `feat/dashboard-design-prototype` (run dir `.llm/runs/feat-dashboard-design-prototype--design/`). + +Scope changes vs the filed DDX-15: + +- Expanded from ".design-sync artifact + Fresh panel-shell prototype" to a **full E2E Claude Design prototype** (shell + 7 panels + 4 capability sections, light/dark) on a **new** design system synced at 100% parity from current fresh-ui, plus a **production-grade reusable sync system** at `tools/design-sync/`. +- The DDX-0 → DDX-15 dependency is **inverted**: prototype pass 1 validates/amends the DDX-0 L3 promote-set before DDX-0 is implemented (eis-chat two-pass loop). +- Artifacts land at `resources/design/dashboard/` and migrate to `plugins/dashboard/.design-sync/` when DDX-2/DDX-4 create the plugin. + +This issue stays open as the beta.6 tracking point; the run's PR carries `Closes #425` and resolves it on merge. **DDX-5 (#415) and all panel slices are blocked on that delivery.** diff --git a/.llm/runs/feat-dashboard-design-prototype--design/board/issue-body.md b/.llm/runs/feat-dashboard-design-prototype--design/board/issue-body.md new file mode 100644 index 000000000..c4597a816 --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/board/issue-body.md @@ -0,0 +1,25 @@ +Part of #400 + +## What + +The beta.6 Dev Dashboard's design pre-step, executed as a dedicated agentic run fully decoupled from the beta.6 implementation supervisor: + +1. **`tools/design-sync/`** — a production-grade, reusable design-sync system converting the `@netscript/fresh-ui` copy-source registry into a Claude Design-consumable design system (synthetic React package via type-only-Preact compilation + compiled Tailwind CSS closure + conventions header + preview cards). Idempotent re-sync so the system survives registry evolution; the six eis-chat parity traps (theme-default, token-closure, compiled-css, weak-dts, render-blank, raw-hex) encoded as automated checks. +2. **A new Claude Design project** seeded at 100% component parity from today's fresh-ui — replacing the stale eis-chat-era design system (near-total divergence since 2026-06-14). +3. **A full E2E Claude Design prototype** of the dashboard: shell + all 7 panels (Stack Map, Service Catalog + API Explorer, Flow/Trace Waterfall, Run Inspector, Plugin Control, Logs, Resource Control) + the 4 per-capability sections (workers/sagas/triggers/streams), light + dark — used to showcase, iterate, and lock design decisions before implementation. +4. **A sync-back spec** (`NS-ONE-ADDITIONS` idiom) making every new/changed component implementation-ready for downstream fresh-ui lanes (DDX-0 promote-set amendment + follow-up issues). + +## Relationship to the filed board + +- **Supersedes-in-execution #425 (DDX-15).** #425 stays open as the beta.6 tracking point; the run's PR carries `Closes #425` and resolves its expanded scope on merge. DDX-5 (#415) and all panel slices are blocked on this run's delivery. +- **Inverts the DDX-0→DDX-15 edge** (owner-ratified): prototype pass 1 validates/amends the DDX-0 L3 promote-set *before* DDX-0 is implemented — the proven eis-chat two-pass loop. +- **No `packages/`/`plugins/` source changes here.** Component implementation stays on downstream WSL Codex lanes fed by the sync-back spec. + +## Future promotion (recorded, not in scope) + +The sync mechanism is a candidate for a `netscript ui:design-sync` CLI feature — offering NetScript devs the same fresh-ui ⇄ Claude Design loop for their own projects. To be filed separately as a framework issue when this run's tool stabilizes. + +## Run + +- Run dir: `.llm/runs/feat-dashboard-design-prototype--design/` (branch `feat/dashboard-design-prototype`) +- Supervisor: Claude Fable 5; canvas lane: Claude Design MCP with owner steering; PLAN-EVAL (minimax-M3) gates implementation; IMPL-EVAL (qwen-3.7-max) gates merge. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/pr-body.md b/.llm/runs/feat-dashboard-design-prototype--design/pr-body.md new file mode 100644 index 000000000..b7573645e --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/pr-body.md @@ -0,0 +1,44 @@ +# Plan & Design — READY FOR REVIEW + +**Run:** `feat-dashboard-design-prototype--design` · **Supervisor:** Claude Fable 5 (session-linked in `supervisor.md`) · **Baseline:** `317e4b50` (beta.5 cut) + +> **Do not merge until the Plan-Gate (PLAN-EVAL) and the final evaluator pass (IMPL-EVAL) are complete.** + +## What this run delivers + +The beta.6 Dev Dashboard's missing design pre-step, fully decoupled from the beta.6 implementation supervisor: + +1. **`tools/design-sync/`** — production-grade, reusable converter: fresh-ui copy-source registry → Claude Design-consumable design system (synthetic React package via the type-only-Preact trick + compiled Tailwind CSS closure + conventions header + preview cards). Idempotent re-sync; the six eis-chat parity traps encoded as checks. Future promotion path: `netscript ui:design-sync` for NetScript devs (separate framework issue). +2. **New Claude Design project** seeded at 100% component parity from today's fresh-ui (`0.0.1-beta.4`) — the stale eis-chat-era design system is abandoned (near-total divergence, not drift). +3. **Full E2E prototype** — shell + 7 panels + 4 per-capability sections, light/dark, driven agentically via the Claude Design MCP with owner steering from the canvas. +4. **Sync-back spec** (`NS-ONE-ADDITIONS` idiom) making every new/changed component implementation-ready for downstream fresh-ui lanes. + +## Key findings (research.md) + +- NS One L0–L2 is byte-identical to fresh-ui output; the ratified gap is the L3 `blocks/` layer (DDX-0). All current fresh-ui architecture landed 2026-06-14→07-05 — the old canvas project predates it entirely. +- fresh-ui CSS (~25KB `--ns-*` tokens + semantic classes) ports to React verbatim; only JSX/hooks need conversion, and eis-chat's `.design-sync/NOTES.md` recipe makes that mechanical. +- The seed-run corpus already holds the design research (competitor teardowns, 7-panel IA, voice rules) — this run distills, it does not re-research. + +## Locked decisions + +LD-1 full E2E breadth (two staged passes) · LD-2 new design system at 100% parity · LD-3 fully-agentic MCP canvas lane, owner steers, recorded fallback · LD-4 sync home `tools/design-sync/` · LD-5 decoupled run; #425 superseded-in-execution; new backlog issue · LD-6 DDX-0↔DDX-15 inversion (prototype pass 1 validates the promote-set) · LD-7 eis-chat artifact idiom + traps-as-checks. Full rationale in `plan.md`. + +## Commit slices + +0 canvas MCP pre-flight → 1 design-sync v1 → 2 design brief → 3 project seeding (parity gate) → 4 prototype pass 1 (flagship surfaces) → 5 re-sync checkpoint → 6 prototype pass 2 (control panels + capability sections) → 7 sync-back spec + shots + board comments. + +## Risk register (top) + +Claude Design MCP 404/401 flakiness (slice-0 hard gate + owner-relay fallback) · plan-token burn (brief front-loads everything; batch canvas turns) · conversion edge cases (islands/signals; exclusion list with reasons) · closure completeness (var-set diff vs DTCG source) · off-system canvas invention (conventions header + no-raw-hex rule + real-content previews). + +## Gates + +Static: scoped wrappers over `tools/design-sync`. Fitness: sync idempotence, parity checklist, trap checks a–f. Runtime: canvas MCP smoke. Consumer/jsr-audit: N/A — **no `packages/`/`plugins/` source changes in this run.** + +## Board linkage + +Part of #400 (epic: dev-dashboard, no closing keyword — umbrella). Supersedes-in-execution #425 (DDX-15): #425 stays open as the beta.6 tracking point while this run executes, and this PR resolves its (expanded) scope on merge — Closes #425. + +🤖 Generated with [Claude Code](https://claude.com/claude-code) + +https://claude.ai/code/session_01Dgu7TfPnzpXUii84FSybbg diff --git a/.llm/runs/feat-dashboard-design-prototype--design/supervisor.md b/.llm/runs/feat-dashboard-design-prototype--design/supervisor.md index 891717342..cd7829696 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/supervisor.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/supervisor.md @@ -32,10 +32,10 @@ eis-chat two-pass loop (prototype pass 1 validates the DDX-0 promote-set before | Tier | Binding | Role in this run | | --- | --- | --- | -| A | Claude Fable 5 (this session) | Supervisor; slice review gate; canvas orchestration via Claude Design MCP; board comments | -| B | Claude Opus sub-agents (internal) | Design-brief prose synthesis from the seed-run corpus; research condensation | -| C | — | Not used | -| D | WSL Codex | **Not used in this run** — fresh-ui implementation of prototyped components is a downstream handoff fed by the sync-back spec | +| A | Claude Fable 5 (this session) | Supervisor; **all design/creativity work** (canvas orchestration via Claude Design MCP, brief authoring, design decisions, shot review); slice review gate; board comments. Owner directive 2026-07-06: Fable 5 is THE design lane — "it outsmarts by far all others in creativity and design consistency" | +| B | Claude Opus 4.8 sub-agents (internal) | Everything that is neither design nor a chore: research condensation, mechanical doc assembly, code scaffolding support | +| C | Claude Workflow (Sonnet 5 stages) | Only if a batch fan-out is ever justified; **never Fable 5 in a workflow** | +| D | WSL Codex | **Chores and easy well-scoped tasks only — never design-related work** (owner directive 2026-07-06). In this run: gh board filing chores. fresh-ui implementation of prototyped components is a downstream handoff fed by the sync-back spec | | E | OpenHands minimax-M3 (PLAN-EVAL) / qwen-3.7-max (IMPL-EVAL) | Separate-session evaluator verdicts | ## Recorded lane/eval overrides From d69af1bebae5717c90f3c15a83a7a05ff2a301e7 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Mon, 6 Jul 2026 12:04:46 +0200 Subject: [PATCH 03/40] =?UTF-8?q?chore(design):=20PLAN-EVAL=20dispatched?= =?UTF-8?q?=20on=20PR=20#506=20=E2=80=94=20context=20pack=20at=20plan-eval?= =?UTF-8?q?=20phase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Dgu7TfPnzpXUii84FSybbg --- .../context-pack.md | 22 +++++++++---- .../plan-eval-dispatch.md | 33 +++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/plan-eval-dispatch.md diff --git a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md index faa8c3a76..7e332ee06 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md @@ -6,7 +6,7 @@ | -------------- | ----------------------------------------- | | Run ID | `feat-dashboard-design-prototype--design` | | Branch | `feat/dashboard-design-prototype` | -| Current phase | `plan` (awaiting PLAN-EVAL) | +| Current phase | `plan-eval` (dispatched, awaiting verdict) | | Archetype | N/A (repo tooling + design artifacts) | | Scope overlays | none | @@ -29,15 +29,23 @@ the beta.6 implementation supervisor. ## In Progress -- Bootstrap tail: commit + push branch, open draft PR, file new issue + board comments, dispatch - PLAN-EVAL. +- PLAN-EVAL (OpenHands minimax-M3, PR-comment lane) dispatched 2026-07-06 on draft PR **#506** + (comment 4891516954). Supervisor watching via `gh-watch.ts --pr 506` background. **Hard stop + before slice 1 until PASS.** + +## Board state (filed) + +- Draft PR **#506** (`Closes #425`, Part of #400) — the commit trail. +- New tracking issue **#507** (Backlog / Triage; type:feat, epic:dev-dashboard, area:fresh-ui, + area:tooling, priority:p1, status:plan). +- Supersession comments posted on #425 (4891488892) and #400 (4891489240). ## Next Steps -1. Commit run dir; push `feat/dashboard-design-prototype` (explicit refspec); open draft PR (WSL gh). -2. File new issue (Backlog / Triage, `Part of #400`); supersession comments on #425/#400. -3. Dispatch PLAN-EVAL (OpenHands minimax-M3, separate session). **Hard stop before slice 1.** -4. Owner: `claude mcp add … claude-design …` + `/design-login`; then slice 0 canvas smoke. +1. PLAN-EVAL verdict → PASS: proceed to slice 0; FAIL_PLAN: fix plan boxes (max 2 cycles). +2. Owner: `claude mcp add … claude-design …` + `/design-login`; then slice 0 canvas smoke. +3. Owner lane directive 2026-07-06 (in force, also in memory): Fable 5 = all design/creativity + work; WSL Codex = chores only, never design; Opus 4.8 = the rest; Sonnet 5 = workflow stages. ## Key Decisions diff --git a/.llm/runs/feat-dashboard-design-prototype--design/plan-eval-dispatch.md b/.llm/runs/feat-dashboard-design-prototype--design/plan-eval-dispatch.md new file mode 100644 index 000000000..3e9e328cd --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/plan-eval-dispatch.md @@ -0,0 +1,33 @@ +use harness + +Run PLAN-EVAL for this PR (run `feat-dashboard-design-prototype--design`). You are the Plan-Gate evaluator — a separate session from the generator. Judge the PLAN, not code; no implementation slices exist yet by design. + +## SKILL + +Read these before evaluating (repo-relative): + +- `.agents/skills/netscript-harness/SKILL.md` — harness protocol; you are the PLAN-EVAL lane. +- `.llm/harness/evaluator/plan-protocol.md` — your procedure. Follow it exactly. +- `.llm/harness/gates/plan-gate.md` — the checklist you enforce, box by box. +- `.llm/harness/evaluator/verdict-definitions.md` — PASS / FAIL_PLAN meanings. +- `.agents/skills/netscript-pr/SKILL.md` — comment conventions. + +## Inputs (run dir: `.llm/runs/feat-dashboard-design-prototype--design/`) + +1. `research.md` — 14 findings F1–F14; verify the re-baseline against `317e4b50` (origin/main, beta.5 cut) and spot-check at least one load-bearing finding against the tree (e.g. F-claims about `packages/fresh-ui/registry.generated.ts` / `registry.manifest.ts` and the DTCG token pipeline under `packages/fresh-ui/tokens/`). +2. `plan.md` — locked decisions LD-1..LD-7, scope/non-scope, fitness gates, validation plan. +3. `worklog.md` `## Design` section — domain vocabulary, ports (RegistrySource, ClosureBuilder), constants (TRAP_IDS, UNIT_KINDS, PARITY_EXCLUSIONS), 8 commit slices (0–7). +4. `supervisor.md` + `drift.md` — recorded lane overrides (Tier-A implements `tools/design-sync/`; canvas lane = Tier-A via Claude Design MCP with owner-relay fallback; owner directive 2026-07-06: Fable 5 = design lane, WSL Codex = chores only) and the DDX-0↔DDX-15 dependency inversion (owner-ratified). +5. `.llm/harness/debt/arch-debt.md` for relevant open debt. + +## Run-specific context + +- Deliverables: `tools/design-sync/` (repo tooling — NOT `packages/`/`plugins/` source), a new Claude Design project at 100% fresh-ui parity, a full E2E dashboard prototype (7 panels + 4 capability sections, light/dark), and a sync-back spec. Archetype gates for packages/plugins are N/A; the plan's fitness gates (sync idempotence, parity checklist, trap checks a–f, canvas MCP smoke) replace them — verify the plan states this explicitly. +- Board linkage: PR carries `Closes #425`; new tracking issue #507; epic #400. Verify plan/PR consistency on this. +- Slice 0 is a canvas MCP pre-flight hard gate with a recorded fallback; verify the plan treats MCP flakiness as a first-class risk with an owner-authorized fallback lane, not an unstated assumption. + +## Procedure and output + +Follow `plan-protocol.md`: walk `plan-gate.md` box by box citing plan locations; run the open-decision sweep yourself (any unflagged rework-forcing open decision = unchecked box); confirm the 8 slices are ordered, sized, and each names its proving gate and files. + +Write your full verdict as a PR comment. Also write `plan-eval.md` in the run dir from `templates/plan-eval.md` and commit it to this PR branch ONLY (no other file changes; preserve lock hygiene — do not commit `deno.lock`). Emit exactly one verdict: PASS or FAIL_PLAN (with each unchecked box and the specific fix). From dfd9d8caf0acb8117d591f4257aae376c1e3f011 Mon Sep 17 00:00:00 2001 From: openhands Date: Mon, 6 Jul 2026 10:14:41 +0000 Subject: [PATCH 04/40] =?UTF-8?q?chore(plan-eval):=20PASS=20=E2=80=94=20pl?= =?UTF-8?q?an-gate=20checklist=20satisfied=20for=20feat-dashboard-design-p?= =?UTF-8?q?rototype--design?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eight Plan-Gate boxes walked. Research re-baselined against 317e4b50 and spot-checked against fresh-ui registry / DTCG token pipeline. Open-decision sweep is clean (4 OQs flagged, no unflagged rework-forcing decisions). Eight commit slices (0-7) ordered, sized, each names its gate and files. Risk register and gate set both explicit. Archetype N/A (no packages/plugins surface) and the plan states it. Verdict: PASS. Co-authored-by: openhands --- .../plan-eval.md | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/plan-eval.md diff --git a/.llm/runs/feat-dashboard-design-prototype--design/plan-eval.md b/.llm/runs/feat-dashboard-design-prototype--design/plan-eval.md new file mode 100644 index 000000000..7db3823c1 --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/plan-eval.md @@ -0,0 +1,47 @@ +# PLAN-EVAL — feat-dashboard-design-prototype--design + +- Plan evaluator session: openhands / minimax-m3 / 2026-07-06 +- Run: `feat-dashboard-design-prototype--design` +- Surface / archetype: N/A (repo tooling `tools/design-sync/` + design artifacts `resources/design/dashboard/`) +- Scope overlays: none +- Baseline: `317e4b50` (origin/main, `v0.0.1-beta.5` cut) +- Branch: `feat/dashboard-design-prototype` (PR #506) +- Board linkage verified: `Closes #425` · `Part of #400` (no closing keyword on epic) · new tracking issue #507 filed in Backlog / Triage + +## Checklist results + +| Plan-Gate item | Result | Evidence / location | +| --------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Research present and current | PASS | `research.md` exists with 14 findings F1–F14; explicitly re-baselined against `main` @ `317e4b50` (F1 footer + carried-in seed `plan-roadmap-expansion--seed` re-derived). Spot-checked: `packages/fresh-ui/registry.generated.ts` present (297 KB), `registry.manifest.ts` present (40 KB), DTCG token pipeline exists at `packages/fresh-ui/tokens/`, `packages/fresh-ui/styles/{styles.css, theme-bridge.css, tokens.css, tokens.json}` all present, fresh-ui `deno.json` version is `0.0.1-beta.5` at baseline. | +| Decisions locked | PASS | `plan.md` § Locked Decisions LD-1..LD-7 each carry rationale. `worklog.md` § Design § Decisions mirrors with checkmarks. Drift log records LD-3/4/5/6 overrides explicitly. | +| Open-decision sweep | PASS | `plan.md` § Open-Decision Sweep enumerates OQ-1..OQ-4 with "must resolve now" / "safe to defer" status. Evaluator-run sweep: no additional unflagged rework-forcing open decisions found. Slice-0 MCP gate resolves OQ-1; slice-1/3/7 resolve OQ-2/3/4 without forcing prior-slice rework. | +| Commit slices (< 30, gate + files each) | PASS | 8 slices (0..7), ordered, all small. `worklog.md` § Design § Slices table cites for each: a gate (manual / wrappers / supervisor review / `design:sync --check` / ParityReport / shot-vs-IA / IMPL-EVAL), files touched (`tools/design-sync/**`, `resources/design/dashboard/*`, `.design-sync/config.json`, run dir). | +| Risk register | PASS | `plan.md` § Risk Register lists 7 risks (MCP flakiness, plan-token burn, conversion edge cases, closure completeness, canvas invention, prototype drift, beta.6 collision) each with mitigation + owner. Top risk (MCP flakiness) is treated as first-class: hard gate at slice 0 + recorded owner-relay fallback (LD-3, supervisor.md). | +| Gate set selected | PASS | Archetype gates N/A — no `packages/` or `plugins/` surface. Plan § Fitness Gates defines 4 fitness gates (sync idempotence, parity checklist, traps a–f, canvas MCP smoke); pr-body § Gates table states "Archetype gates: N/A — tooling + design artifacts only" explicitly. `archetype-gate-matrix.md` consulted. | +| Deferred scope explicit | PASS | `plan.md` § Non-Scope: 5 explicit non-scope items (no `packages/`/`plugins/` source, no `plugins/dashboard/.design-sync/`, no `netscript ui:design-sync` CLI, no telemetry/AI/beta.6 implementation, no AI/chat parity). § Hidden Scope: 3 call-outs (closure completeness, preview-card authoring effort, board comments). | +| jsr-audit surface scan (pkg/plugin) | PASS (N/A) | Plan delivers `tools/design-sync/` (repo tooling) + design artifacts — no `packages/` or `plugins/` source surface. N/A per `archetype-gate-matrix.md` non-package rule; `research.md` § jsr-audit surface scan records the N/A decision. | + +## Open-decision sweep (evaluator-run) + +The plan's own sweep is the four OQs in `plan.md`. I ran the sweep independently and find: + +- **OQ-1 (MCP round-trip viability)** — flagged "must resolve now" with slice 0 hard gate. The gate is the right size (a scratch design round-trip), the fallback (owner-relay) is recorded in `supervisor.md`, and the gate fires before any slice that depends on the MCP (slice 3 onward). No rework risk; if it fails, owner-relay keeps the run going. **OK as planned.** +- **OQ-2 (synthetic package name)** — safe to defer to slice 1. The name only lives in `.design-sync/config.json` + `resources/design/dashboard/CLAUDE-DESIGN-BRIEF.md`; changing it is a config edit, not a code rewrite. **No rework risk.** +- **OQ-3 (prototype-shots location)** — safe to defer to slice 7. Shots are author-time content; in-repo is a directory choice that doesn't bind a future refactor. **No rework risk.** +- **OQ-4 (CSS closure build source)** — safe to defer; default is `apps/dashboard` build, fallback is a kitchen-sink page under the same `tools/design-sync/` tree. The kitchen-sink page is an addition, not a replacement, so it doesn't force rework if needed. **No rework risk.** + +No additional unflagged open decisions found. The plan is not deferring any decision whose answer would force a rewrite of a prior slice. + +## Verdict + +`PASS` + +All eight Plan-Gate boxes satisfied. Implementation may begin on PLAN-EVAL PASS. + +## Notes + +- **Version-label drift, not a soundness issue.** Plan line 146 and pr-body line 12 say "fresh-ui `0.0.1-beta.4`"; the actual `packages/fresh-ui/deno.json` at baseline `317e4b50` reads `0.0.1-beta.5`. The content the design-sync system reads (`registry.generated.ts`, `registry.manifest.ts`, DTCG tokens, theme CSS) is at the baseline regardless of the version label, and the parity claim is about content parity, not version-string parity. Worth tightening in a follow-up edit (e.g. `fresh-ui at baseline 317e4b50`) but **not** a `FAIL_PLAN` — it doesn't force a rewrite of any slice. +- **Lane override correctness.** `drift.md` records Tier-A (Fable 5) implementing `tools/design-sync/`; canvas lane = Tier-A via Claude Design MCP with owner-relay fallback; owner directive 2026-07-06: Fable 5 = design lane, WSL Codex = chores only. The slice review gate (A1) is preserved because the supervisor (Fable 5) is not the implementer of every slice — the WSL Codex `chores` work (board comments, gh commands) is separate from the agentic work. Lane-policy addendum is recorded in supervisor.md. +- **DDX-0↔DDX-15 inversion (LD-6, owner-ratified).** Plan records that prototype pass 1 will validate the promote-set normally written by DDX-0; DDX-15 expands scope to all of fresh-ui (not just dashboard). This is the load-bearing plan decision and the supervisor's `drift.md` entry covers it. +- **Board hygiene.** pr-body uses `Closes #425` (correct, #425 is the issue this run resolves), `Part of #400` (no closing keyword — umbrella, correct), new issue #507 in Backlog / Triage. Consistent with `netscript-pr` taxonomy and with the trigger comment's "new tracking issue #507". +- **Archetype is genuinely N/A.** The deliverables are `tools/design-sync/` (repo tooling) and `resources/design/dashboard/` (design artifacts). Neither lives under `packages/` or `plugins/`, so the jsr-audit surface scan is N/A per the archetype-gate-matrix. The plan and pr-body both state this explicitly. From 45b9eb48c3d1b21f21e30b6ae57ee3a77ac94e64 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Mon, 6 Jul 2026 12:18:22 +0200 Subject: [PATCH 05/40] =?UTF-8?q?chore(design):=20slice-0=20pre-flight=20r?= =?UTF-8?q?ead=20smoke=20PASS=20=E2=80=94=20native=20DesignSync=20tool=20s?= =?UTF-8?q?upersedes=20raw=20MCP=20(OQ-1=20green)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Dgu7TfPnzpXUii84FSybbg --- .../context-pack.md | 6 ++++-- .../drift.md | 17 +++++++++++++++++ .../worklog.md | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md index 7e332ee06..5aa215416 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md @@ -70,8 +70,10 @@ the beta.6 implementation supervisor. ## Open Questions -- OQ-1 MCP viability (slice 0 gate) · OQ-2 synthetic pkg name · OQ-3 shots in-repo · OQ-4 closure - build source — see research.md. +- **OQ-1 RESOLVED GREEN 2026-07-06:** canvas lane runs on the native `DesignSync` tool + (claude.ai-login authorized; read smoke PASS; stale project `ea3fa1b9-…` visible and left + untouched per LD-2). See drift.md latest entry. +- OQ-2 synthetic pkg name · OQ-3 shots in-repo · OQ-4 closure build source — see research.md. ## Drift and Debt diff --git a/.llm/runs/feat-dashboard-design-prototype--design/drift.md b/.llm/runs/feat-dashboard-design-prototype--design/drift.md index da50a8bf3..2c5288624 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/drift.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/drift.md @@ -30,3 +30,20 @@ documentation. - **Severity:** minor - **Action:** accept (recorded). - **Evidence:** supervisor.md lane table; AGENTS.md tooling tiers. + +## 2026-07-06 — Canvas sync mechanism: native DesignSync tool, not raw MCP + +- **What:** The sync lane runs on Claude Code's native `DesignSync` tool (+ `/design-sync` skill) + instead of the raw `claude-design` MCP endpoint the plan assumed. +- **Expected:** plan/research OQ-1 assumed MCP tools (`mcp__claude-design__*`) with known 404/401 + flakiness and an owner-relay fallback. +- **Actual:** `DesignSync` is first-class in the harness: claude.ai-login auth (owner ran + `/design-login`), read smoke PASS (`list_projects` → stale `eis-chat — NS One` visible, + `ea3fa1b9-…`), `localPath` disk uploads that keep the 290KB registry / ~80KB CSS closure out of + model context, and a finalize_plan write boundary. Strictly better; the MCP server stays + registered as a secondary surface for canvas-driving if needed. +- **Severity:** minor (favorable; de-risks the top risk-register entry) +- **Action:** accept; slice 0 write half (`create_project` + round-trip) still gates after + PLAN-EVAL PASS. Slice 1 targets the DesignSync bundle shape (`@dsCard` preview markers, + 256-file batches). +- **Evidence:** worklog.md § Runtime Gates. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/worklog.md b/.llm/runs/feat-dashboard-design-prototype--design/worklog.md index 614fe8a0f..430f683be 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/worklog.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/worklog.md @@ -114,7 +114,7 @@ unit of the same kind. | Gate | Result | Evidence | Notes | | ---- | ------ | -------- | ----- | -| Canvas MCP smoke | NOT_RUN | — | slice 0; blocked on owner `/design-login` | +| Canvas connectivity smoke (read half) | **PASS** 2026-07-06 | `DesignSync list_projects` returned the writable set: 1 project, the stale `eis-chat — NS One` (`ea3fa1b9-906c-4b8a-8ef7-421b460e5c15`), after owner ran `claude mcp add claude-design …` + `/design-login` | OQ-1 resolved GREEN — via a better mechanism than planned: Claude Code's **native `DesignSync` tool** (localPath disk uploads that bypass model context, plan-boundary enforcement, claude.ai-login auth) rather than the raw MCP. Write half (`create_project` + round-trip) runs in slice 0 proper, after PLAN-EVAL PASS | ### Consumer Gates From 9a881908000f93418693635d25aa0a1fba56897f Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Mon, 6 Jul 2026 12:21:44 +0200 Subject: [PATCH 06/40] =?UTF-8?q?feat(design):=20slice=200=20=E2=80=94=20c?= =?UTF-8?q?anvas=20round-trip=20PASS;=20project=20'NetScript=20=E2=80=94?= =?UTF-8?q?=20NS=20One'=20created=20(ec262e10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Dgu7TfPnzpXUii84FSybbg --- .../context-pack.md | 14 ++++++++++---- .../plan.md | 2 +- .../pr-body.md | 2 +- .../worklog.md | 1 + 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md index 5aa215416..e0e079e9a 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md @@ -6,7 +6,7 @@ | -------------- | ----------------------------------------- | | Run ID | `feat-dashboard-design-prototype--design` | | Branch | `feat/dashboard-design-prototype` | -| Current phase | `plan-eval` (dispatched, awaiting verdict) | +| Current phase | `implement` (PLAN-EVAL **PASS** 2026-07-06, `plan-eval.md` @ dfd9d8ca; slice 0 complete) | | Archetype | N/A (repo tooling + design artifacts) | | Scope overlays | none | @@ -29,9 +29,15 @@ the beta.6 implementation supervisor. ## In Progress -- PLAN-EVAL (OpenHands minimax-M3, PR-comment lane) dispatched 2026-07-06 on draft PR **#506** - (comment 4891516954). Supervisor watching via `gh-watch.ts --pr 506` background. **Hard stop - before slice 1 until PASS.** +- **Slice 1**: `tools/design-sync/` v1 (converter + closure + conventions + previews + trap + checks + idempotence). Canvas target locked: project **`NetScript — NS One`** + (`ec262e10-d4ad-451f-9aeb-e51955db3634`) — goes into `.design-sync/config.json`. + +## Done gates + +- PLAN-EVAL **PASS** (minimax-M3, `plan-eval.md` committed dfd9d8ca; version-label note fixed in + plan.md/pr-body.md). Slice 0 canvas round-trip **PASS** (create/finalize/write/read/delete via + native `DesignSync` tool). ## Board state (filed) diff --git a/.llm/runs/feat-dashboard-design-prototype--design/plan.md b/.llm/runs/feat-dashboard-design-prototype--design/plan.md index 85a92416d..ed89278d1 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/plan.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/plan.md @@ -143,7 +143,7 @@ implementation-ready for fresh-ui. ## Dependencies - Claude Design MCP availability (`https://api.anthropic.com/v1/design/mcp`) + owner `/design-login`. -- fresh-ui `0.0.1-beta.4` registry surface (in-repo, baseline `317e4b50`). +- fresh-ui registry surface at baseline `317e4b50` (in-repo; `packages/fresh-ui/deno.json` reads `0.0.1-beta.5` — parity claim is content parity, not version-string parity; PLAN-EVAL note). - eis-chat `.design-sync/` recipe (extracted in seed run `analysis/A-dashboard/02`). - Seed-run corpus for the brief (proposal, teardowns, voice rules). diff --git a/.llm/runs/feat-dashboard-design-prototype--design/pr-body.md b/.llm/runs/feat-dashboard-design-prototype--design/pr-body.md index b7573645e..c19d81687 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/pr-body.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/pr-body.md @@ -9,7 +9,7 @@ The beta.6 Dev Dashboard's missing design pre-step, fully decoupled from the beta.6 implementation supervisor: 1. **`tools/design-sync/`** — production-grade, reusable converter: fresh-ui copy-source registry → Claude Design-consumable design system (synthetic React package via the type-only-Preact trick + compiled Tailwind CSS closure + conventions header + preview cards). Idempotent re-sync; the six eis-chat parity traps encoded as checks. Future promotion path: `netscript ui:design-sync` for NetScript devs (separate framework issue). -2. **New Claude Design project** seeded at 100% component parity from today's fresh-ui (`0.0.1-beta.4`) — the stale eis-chat-era design system is abandoned (near-total divergence, not drift). +2. **New Claude Design project** seeded at 100% component parity from today's fresh-ui at baseline `317e4b50` — the stale eis-chat-era design system is abandoned (near-total divergence, not drift). 3. **Full E2E prototype** — shell + 7 panels + 4 per-capability sections, light/dark, driven agentically via the Claude Design MCP with owner steering from the canvas. 4. **Sync-back spec** (`NS-ONE-ADDITIONS` idiom) making every new/changed component implementation-ready for downstream fresh-ui lanes. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/worklog.md b/.llm/runs/feat-dashboard-design-prototype--design/worklog.md index 430f683be..77ce590d3 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/worklog.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/worklog.md @@ -115,6 +115,7 @@ unit of the same kind. | Gate | Result | Evidence | Notes | | ---- | ------ | -------- | ----- | | Canvas connectivity smoke (read half) | **PASS** 2026-07-06 | `DesignSync list_projects` returned the writable set: 1 project, the stale `eis-chat — NS One` (`ea3fa1b9-906c-4b8a-8ef7-421b460e5c15`), after owner ran `claude mcp add claude-design …` + `/design-login` | OQ-1 resolved GREEN — via a better mechanism than planned: Claude Code's **native `DesignSync` tool** (localPath disk uploads that bypass model context, plan-boundary enforcement, claude.ai-login auth) rather than the raw MCP. Write half (`create_project` + round-trip) runs in slice 0 proper, after PLAN-EVAL PASS | +| Canvas round-trip smoke (write half, slice 0) | **PASS** 2026-07-06 (post PLAN-EVAL PASS) | `create_project` → **`NetScript — NS One`**, projectId `ec262e10-d4ad-451f-9aeb-e51955db3634` · `finalize_plan` (`_smoke/roundtrip.html`, localDir = worktree) → `write_files` (inline, `@dsCard` marker) → `get_file` read back **byte-identical** → `delete_files` cleanup. Full CRUD cycle green | Slice 0 complete. New project is empty by design until slice 3 seeding. Stale eis-chat project untouched (LD-2). `projectId` is the slice-3 target and belongs in `.design-sync/config.json` at slice 1 | ### Consumer Gates From 4b31f44be96cd79916f20a2e6c30cf908dff6f68 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Mon, 6 Jul 2026 12:58:01 +0200 Subject: [PATCH 07/40] feat(design-sync): registry-to-canvas sync proves 100% fresh-ui parity with green traps and idempotence Slice 1 of the dashboard design-prototype run: tools/design-sync/ v1 converts the fresh-ui registry (Preact) into a synthetic React package, concat-builds the CSS closure (registry has zero Tailwind utilities), bundles via native deno bundle, emits 44 preview cards + prompt.md contracts, and gates on ParityReport + six eis-chat traps + double-build idempotence. Interactive primitives fold in via the subpaths module-graph loader; markdown (template-sourced chat stack) is a recorded exclusion. Gate: deno task design:sync check = PASS (parity 44/44, idempotence dfac420b48f8, traps 4xPASS/2 by-design WARN); scoped check/lint/fmt clean. Refs #507, part of #400. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Dgu7TfPnzpXUii84FSybbg --- .gitignore | 4 + .../board/pr-comment-slice0.md | 10 + .../context-pack.md | 33 +- .../drift.md | 13 + .../worklog.md | 13 +- deno.json | 1 + .../design/dashboard/.design-sync/config.json | 35 ++ tools/design-sync/mod.ts | Bin 0 -> 5966 bytes tools/design-sync/src/bundle.ts | 141 +++++++ tools/design-sync/src/closure.ts | 106 ++++++ tools/design-sync/src/config.ts | 96 +++++ tools/design-sync/src/convert.ts | 359 ++++++++++++++++++ tools/design-sync/src/parity.ts | 60 +++ tools/design-sync/src/previews.ts | 136 +++++++ tools/design-sync/src/registry-source.ts | 112 ++++++ tools/design-sync/src/report.ts | 50 +++ tools/design-sync/src/traps.ts | 128 +++++++ tools/design-sync/src/types.ts | 140 +++++++ tools/design-sync/templates/card.html | 88 +++++ tools/design-sync/templates/conventions.md | 47 +++ 20 files changed, 1559 insertions(+), 13 deletions(-) create mode 100644 .llm/runs/feat-dashboard-design-prototype--design/board/pr-comment-slice0.md create mode 100644 resources/design/dashboard/.design-sync/config.json create mode 100644 tools/design-sync/mod.ts create mode 100644 tools/design-sync/src/bundle.ts create mode 100644 tools/design-sync/src/closure.ts create mode 100644 tools/design-sync/src/config.ts create mode 100644 tools/design-sync/src/convert.ts create mode 100644 tools/design-sync/src/parity.ts create mode 100644 tools/design-sync/src/previews.ts create mode 100644 tools/design-sync/src/registry-source.ts create mode 100644 tools/design-sync/src/report.ts create mode 100644 tools/design-sync/src/traps.ts create mode 100644 tools/design-sync/src/types.ts create mode 100644 tools/design-sync/templates/card.html create mode 100644 tools/design-sync/templates/conventions.md diff --git a/.gitignore b/.gitignore index 179d43c4e..56fa69a83 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,7 @@ dist/ # CI output land here and embed machine-local absolute paths. Never commit it. # If a specific artifact ever needs to be durable, re-add it with a `!` negation. .llm/tmp/ + +# design-sync scratch output (synthetic React package + canvas bundle); +# rebuild with `deno task design:sync`, never commit. +.ds-sync/ diff --git a/.llm/runs/feat-dashboard-design-prototype--design/board/pr-comment-slice0.md b/.llm/runs/feat-dashboard-design-prototype--design/board/pr-comment-slice0.md new file mode 100644 index 000000000..ebf060c9f --- /dev/null +++ b/.llm/runs/feat-dashboard-design-prototype--design/board/pr-comment-slice0.md @@ -0,0 +1,10 @@ +## Slice 0 — canvas pre-flight: PASS ✅ (commit 9a881908) + +**Gate:** manual round-trip smoke against the Claude Design surface (worklog § Runtime Gates). + +- PLAN-EVAL **PASS** landed first (`plan-eval.md` @ dfd9d8ca, minimax-M3) — implementation began only after the Plan-Gate cleared. +- Mechanism upgrade (recorded in `drift.md`): the canvas lane runs on Claude Code's **native `DesignSync` tool** (claude.ai-login auth, `localPath` disk uploads that bypass model context, `finalize_plan` write boundary) instead of the raw `claude-design` MCP the plan assumed. This retires the top risk-register entry (MCP 404/401 flakiness). +- Round-trip evidence: `create_project` → new project **`NetScript — NS One`** (`ec262e10-d4ad-451f-9aeb-e51955db3634`) → `finalize_plan` → `write_files` (smoke card with `@dsCard` marker) → `get_file` read back **byte-identical** → `delete_files` cleanup. Project left empty by design until slice 3 seeding; the stale `eis-chat — NS One` project is untouched (LD-2). +- PLAN-EVAL's non-blocking note fixed: plan.md/pr-body now say "fresh-ui at baseline `317e4b50`" instead of the stale `0.0.1-beta.4` label. + +**Next:** slice 1 — `tools/design-sync/` v1 (converter + CSS closure + conventions + previews + trap checks + idempotence), gated by scoped check/lint/fmt wrappers + `design:sync --check` self-test. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md index e0e079e9a..92f1dfc79 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/context-pack.md @@ -29,15 +29,23 @@ the beta.6 implementation supervisor. ## In Progress -- **Slice 1**: `tools/design-sync/` v1 (converter + closure + conventions + previews + trap - checks + idempotence). Canvas target locked: project **`NetScript — NS One`** - (`ec262e10-d4ad-451f-9aeb-e51955db3634`) — goes into `.design-sync/config.json`. +- **Slice 2**: dashboard design brief + proposed components (`resources/design/dashboard/`). + Delegation split per owner directive: Fable 5 keeps the tricky design/creativity core; Opus 4.8 + sub-agent authors the 26 pending preview stories (`tools/design-sync/previews/.preview.js`, + read by `emitCards`) + mechanical doc polish; WSL Codex = chores only. ## Done gates - PLAN-EVAL **PASS** (minimax-M3, `plan-eval.md` committed dfd9d8ca; version-label note fixed in plan.md/pr-body.md). Slice 0 canvas round-trip **PASS** (create/finalize/write/read/delete via native `DesignSync` tool). +- **Slice 1 COMPLETE**: `tools/design-sync/` v1 (11 modules + card/conventions templates + + config.json + `design:sync` task + `.ds-sync/` gitignore). `design:sync check` **PASS** — + parity 44/44 cards, idempotence `dfac420b48f8`, traps 4×PASS/2 by-design WARN; scoped + check/lint/fmt clean. Key mechanics: zero-Tailwind registry ⇒ concat closure (no Fresh build); + cn shim drops clsx/tailwind-merge (React = only npm dep); `subpaths` graph fold-in gives the + canvas the 8 interactive primitives; `markdown` excluded (template-sourced chat stack). See + drift.md D3. ## Board state (filed) @@ -48,10 +56,14 @@ the beta.6 implementation supervisor. ## Next Steps -1. PLAN-EVAL verdict → PASS: proceed to slice 0; FAIL_PLAN: fix plan boxes (max 2 cycles). -2. Owner: `claude mcp add … claude-design …` + `/design-login`; then slice 0 canvas smoke. +1. Slice 2: design brief + proposed components (Fable 5); in parallel delegate the 26 preview + stories (`tools/design-sync/previews/*.preview.js`) + doc polish to an Opus 4.8 sub-agent. +2. Slice 3: re-run `design:sync`, seed project `ec262e10-d4ad-451f-9aeb-e51955db3634` via + DesignSync `finalize_plan` + `write_files` (localPath from `.ds-sync/bundle/`). 3. Owner lane directive 2026-07-06 (in force, also in memory): Fable 5 = all design/creativity work; WSL Codex = chores only, never design; Opus 4.8 = the rest; Sonnet 5 = workflow stages. +4. OQ-2 RESOLVED: pkg `@netscript/ns-one` / global `NSOne`. OQ-4 RESOLVED-MOOT: concat closure, + no Fresh build (drift.md D3). ## Key Decisions @@ -63,15 +75,18 @@ the beta.6 implementation supervisor. | Path | Status | Notes | | ---- | ------ | ----- | -| `.llm/runs/feat-dashboard-design-prototype--design/*` | new | run artifacts (6 files) | +| `.llm/runs/feat-dashboard-design-prototype--design/*` | new | run artifacts | +| `tools/design-sync/**` (11 src + 2 templates) | new | slice 1 | +| `resources/design/dashboard/.design-sync/config.json` | new | projectId + subpaths + exclusions | +| `deno.json` (`design:sync` task), `.gitignore` (`.ds-sync/`) | modified | slice 1 | ## Gates | Gate family | Current status | Evidence | | ----------- | -------------- | -------- | -| Static | NOT_RUN | after slice 1 | -| Fitness | NOT_RUN | idempotence/parity/traps defined in plan.md | -| Runtime | NOT_RUN | slice 0 MCP smoke blocked on owner login | +| Static | **PASS** (slice-1 scope) | scoped wrappers, 11 files clean | +| Fitness | **PASS** (build-side) | idempotence + parity + traps green; canvas-side at slice 3 | +| Runtime | **PASS** (slice 0) | canvas round-trip CRUD green | | Consumer | N/A | no package surface | ## Open Questions diff --git a/.llm/runs/feat-dashboard-design-prototype--design/drift.md b/.llm/runs/feat-dashboard-design-prototype--design/drift.md index 2c5288624..60ce262a0 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/drift.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/drift.md @@ -47,3 +47,16 @@ documentation. PLAN-EVAL PASS. Slice 1 targets the DesignSync bundle shape (`@dsCard` preview markers, 256-file batches). - **Evidence:** worklog.md § Runtime Gates. + +## D3 — 2026-07-06 — slice 1 implementation vs Design-section wording (minor) + +- Plan Design § said `RegistryUnit` joins manifest items with source embedded in + `registry.generated.ts`; implementation reads `files[].source` from disk via + `registry.manifest.ts` (cheaper, identical content, keeps the RegistrySource port). +- Plan Design § said `ClosureBuilder` compiles the Tailwind closure from a Fresh build + (`apps/dashboard`, OQ-4). Verified the registry carries ZERO Tailwind utility classes, so the + shipped builder is `RegistryConcatClosureBuilder` (deterministic concat: fonts → tokens → base → + layouts → per-unit CSS). OQ-4 is moot; no Fresh build in the loop. +- Added beyond plan wording: `subpaths` module-graph fold-in for `@netscript/fresh-ui/interactive` + (command-palette dependency; also surfaces the 8 interactive primitives on the canvas global). +- Severity: minor — same contract names/ports as the locked Design; mechanisms simplified. diff --git a/.llm/runs/feat-dashboard-design-prototype--design/worklog.md b/.llm/runs/feat-dashboard-design-prototype--design/worklog.md index 77ce590d3..1a019b367 100644 --- a/.llm/runs/feat-dashboard-design-prototype--design/worklog.md +++ b/.llm/runs/feat-dashboard-design-prototype--design/worklog.md @@ -80,12 +80,17 @@ unit of the same kind. | Time | Slice | Step | Notes | | ---- | ----- | ---- | ----- | | 2026-07-06 | — | Bootstrap | Worktree `.llm/tmp/design-proto-wt` @ `317e4b50`; run dir scaffolded; four-lane research complete (see research.md) | +| 2026-07-06 | 1 | `tools/design-sync/` v1 | 11 TS modules + 2 templates + `.design-sync/config.json` + root `design:sync` task + `.ds-sync/` gitignore. Gate `design:sync check` **PASS**: parity green (44/44 cards = 30 components + 11 blocks + 3 islands), idempotence PASS (`dfac420b48f8`), 180-file bundle, traps 4×PASS + 2 by-design WARN (weak-dts: theme-toggle; render-blank: 26 floor cards pending authored stories → slice 2/3). Scoped check/lint/fmt clean | ## Decisions | Decision | Reason | Source | | -------- | ------ | ------ | | LD-1…LD-7 | see plan.md § Locked Decisions | owner (session 2026-07-06) + research | +| Closure = deterministic registry concat, no Fresh build | registry has ZERO Tailwind utility classes (verified) — closure is fonts→tokens→base→layouts→per-unit CSS; kills OQ-4 dependency on building apps/dashboard | slice-1 verification | +| `cn` shim drops clsx + tailwind-merge | no Tailwind utils ⇒ merge is a no-op; React becomes the ONLY npm dep of the synthetic package | slice-1 | +| `subpaths` module-graph fold-in | `command-palette` imports `@netscript/fresh-ui/interactive`; loader walks the 35-file `src/runtime` graph into the pkg and exposes Dialog/Tabs/Popover/Drawer/Sheet/Combobox/Accordion/Tooltip on the canvas global — interactive primitives now first-class on canvas | slice-1 | +| `markdown` unit excluded | template-sourced (`.tsx.template`) chat renderer on the npm remark/rehype stack — belongs to the deferred AI/chat collection | slice-1 | ## Drift @@ -100,15 +105,15 @@ unit of the same kind. | Gate | Command or check | Result | Notes | | ---- | ---------------- | ------ | ----- | -| check/lint/fmt (tools) | scoped wrappers | NOT_RUN | after slice 1 | +| check/lint/fmt (tools) | scoped wrappers `--root tools/design-sync --ext ts` | **PASS** 2026-07-06 | 11 files, 0 findings each | ### Fitness Gates | Gate | Result | Evidence | Notes | | ---- | ------ | -------- | ----- | -| Sync idempotence | NOT_RUN | — | slice 1/5 | -| Parity checklist | NOT_RUN | — | slice 3 | -| Trap checks a–f | NOT_RUN | — | slice 1/5 | +| Sync idempotence | **PASS** 2026-07-06 | `design:sync check` double-build tree hash `dfac420b48f8` stable | slice 1 (re-run at slice 5) | +| Parity checklist | **PASS** (build-side) 2026-07-06 | ParityReport green: 44/44 card-bearing units emitted (30 component + 11 block + 3 island); 2 recorded exclusions (markdown, chat-render); style/theme/support/lib all consumed | canvas-side re-verify at slice 3 | +| Trap checks a–f | **PASS** 2026-07-06 | theme-default PASS (`:root` light + `[data-theme='dark']` in closure) · token-closure PASS (160 defined; fallback-less refs all resolved incl. runtime inline-style tokens) · compiled-css PASS (37 parts, 88 KiB) · weak-dts WARN (theme-toggle only) · render-blank WARN (26 floor cards, by design pre-authoring) · raw-hex PASS (0 hex anywhere) | WARNs feed slice 2/3 story authoring | ### Runtime Gates diff --git a/deno.json b/deno.json index 2107d2125..eb3b6ef36 100644 --- a/deno.json +++ b/deno.json @@ -51,6 +51,7 @@ "agentic:sync-claude": "deno run --no-lock --allow-read --allow-write .llm/tools/agentic/sync-claude-skills.ts --pretty", "agentic:sync-claude:check": "deno run --no-lock --allow-read .llm/tools/agentic/sync-claude-skills.ts --check --pretty", "agentic:check-claude": "deno run --no-lock --allow-read --allow-run .llm/tools/agentic/validate-claude-surface.ts --pretty", + "design:sync": "deno run --no-lock --allow-read --allow-write --allow-run --allow-env tools/design-sync/mod.ts", "docs:links": "deno run --no-lock --allow-read .llm/tools/validation/check-internal-doc-links.ts --pretty", "docs:maintenance": "deno task docs:links && deno task agentic:sync-claude:check && deno task agentic:check-claude", "agentic:smoke-claude-remote": "deno run --no-lock --allow-read --allow-run .llm/tools/agentic/claude-remote-smoke.ts --env-aware --pretty", diff --git a/resources/design/dashboard/.design-sync/config.json b/resources/design/dashboard/.design-sync/config.json new file mode 100644 index 000000000..f0513811b --- /dev/null +++ b/resources/design/dashboard/.design-sync/config.json @@ -0,0 +1,35 @@ +{ + "projectId": "ec262e10-d4ad-451f-9aeb-e51955db3634", + "projectName": "NetScript — NS One", + "pkg": "@netscript/ns-one", + "globalName": "NSOne", + "shape": "package", + "registry": { + "root": "packages/fresh-ui", + "manifest": "registry.manifest.ts" + }, + "scratchDir": ".ds-sync", + "fontImport": "@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600;9..40,700&display=swap');", + "exclude": [ + { + "pattern": "^src/", + "reason": "AI/chat collection deferred — not needed for dashboard surfaces (plan § Deferred Scope)" + }, + { + "pattern": "\\.template$", + "reason": "template-sourced chat markdown renderer (react-markdown/remark/rehype npm stack) — deferred with the AI/chat collection" + } + ], + "subpaths": { + "@netscript/fresh-ui/interactive": "interactive.ts" + }, + "groups": { + "component": "general", + "block": "blocks", + "island": "islands" + }, + "react": { + "version": "19.2.0", + "domVersion": "19.2.0" + } +} diff --git a/tools/design-sync/mod.ts b/tools/design-sync/mod.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe0734d3318a4daf040680ba5b4e1b287337d86d GIT binary patch literal 5966 zcma)A+iu%P5}jv%MP(*4BC|3T8`!}@i5)nOlW{gT#0mDnV?-^oB{8N*qPykGY6R>@ z>=(|L%&9I?BxTvV1`J7L_vz}YQ>UtX@Z`x3J)uO~beiwl+dQT}|MOq+U))U7#ArL) zU8EEj&vbk#aBHyZG}c2(6Fn~rr*mxeZ{&M*6sL<-$>>ZVPZd9~cD z)Eo{*l~c>h>A+hCXTonTjp?&ivBTElOCJmXUuolXLK11-x1FVP{^XEE-))h{p=>~+ z3qUfgRu%hq%KqDoycS!|pMbYvP}&+(#zJl}q7uq2n1-+7(6Cr%_hKD*FV#j;Mr} zCTXU_XMn(h$L~%l*VsH*mt9)SV51m4*Y3J7mox^uktQ_q+!RwsJxh5xuiQA%pd9ZV z)Jj6;`CumnlZ>M!@qUgav@2v4NZ*SF*2Dt|X5?(|Su^@Ir`^}|bCqakl6T#Sbrx1x zxq(oH@@t+tOWldptBncuS}-zJ?l>##!swTrWN^v`fV|uQ(DT$CbKEyZR~)b#!+rj~ z^a}BIb4taOu20M&|KfA8YmCp&ZP=f@+-w>n8q`HD4MgKJGzgLEg0nCg*Fkr;rA9oN zS8x?lwNGr;v6qwXY#!R(b~RZ{+qzj`CVQS>&-xi(GU(h$quw z%cmh0L5`$WKkwRl=#3S}a8@%qTrzsR1VY5&;wP&CzpLHjoiSpQWL{Op4v^Z{v^CS% zoUoa&@JVz)>RP3cVDI~g6FO)O(l>B}B&vl)cgCJA#w_W!J!i=lL3At}0Y!vB`v8E1 z2h|(r6PWGkL)($deQGa+_1D{)A^s=E6o!{?;YO28IYcxF;*bswDUP%s70vmX_RrXV z5#z6h^mwUPqtNdxolwxgMw!m1ZWj6wh%<{!3tG@?RwTh6_B;mBq%crL&t*-;gc`)q zN2CE65k0EbXYYe7blIl{uqX}z)H>Wi#vf2f`ZZ+>=y{aOhw*Su=-z_ExrMt;J<776w_Lt?_wnV?yKf(k-k+>i>>OA>&5E(gKB&14H%5Q@=bQB?kSt{M zcF6QiiC#x1$JRo3q1Fc?1l|Y^5=1=+7Cwz1Eh2prXK2O~^i}w4a^DZ|&xjULRX^6# zt)FgTnsoNuBt<$;?7vbs3wk~hVJM2RZLF+TuUXkticMu?9UCrC^$G*@R&zb*iO`5T zFl)Wubp@=u(^|x)rdX8p%P*{FH(aH?b7iboHW?T!y}O1O#yZf4`dE~f5>@UcY6P0~ zAdb*bmi9$t)OAR!wne_O!J4}F09r-$n!-Mp8tInQLoTlO!h*dK!IjSu*|XGCEa5dr zD(n3j&ZxGPnfC~^fJVh7a3?CW`i=xNb+e^_tASA8*GfL$ExkKM6RVWs15F^q7^9C? z$mn>15_W~7lQRnq4|?&23%DN^jKKiywm~=Jw+Yx4{#%9N+-P*@a0!lG?t-gCD+}8d z$B`Oy4nP$eD^`QYO8~6A;Z)ULZ}9vQ2d)59BAelG7d-9r{3uh_o#Lo;^KlaNn1uK5 zqXT!16Rci~Igr*i%br`Sk-QFperMSPC>4Q*ZEWq4~#)@qWf zCau*R!Hp)xapi!{qevKog!a#Z@B#v0To9bAi$0x?FMOgZv@|#$>EmJ!V-e(bB8;J5 zz~ZvY+ds+U0_TDt1SWqADrixN^Ac_mP=u*m{Qw1D{V)on??sviy-v<2=~ROjb;A^! z+tL-0U5p)C3wasz&VD=E-T(WqTsL5ccXj1u-W(hC70vBGj*L;aflR_4y$X!|-o}wD z&U`}~?EM->rAp3NlY;#|^`63>wPo8vF;}p<P1=2^GSk}6o^$-$cfggZO{S;G z4et=oqqJsSebSdMsT%4J6fC|Njo{ORC#w7PM{YrFqJ5%4E2S?20d8HhnpS-P*1*M(Voxbj`fr2I*!e8 zmpeb4l6X@H92Q{Bii^s!0~}{!R$-uvQZ%~L$vnAA;r@xsY18P-@8-H=HF_wOo31r0 zrol)+6S@O3kWK(H)lspH>3M;>gM7-D6n+nU)Aaz9cdqc(3*=U3R9>x|A#qe|xB9of zw`GJn&R*wRhuA=Y;e6Kyv5R~OLzesTM5Etx(Isy5K?1oblS7ldpnzYr#4EDtzco&_ z+z&#?s>>JIX!YwfS%o9%i!OY660Tp+`|6w21u*XgI6S1iMkMc&z*CI=_ygQ+aiig$ zutOXorKHx3?M|8Pt-aRLQk0C)oOhDZ1Ly3dtmqP!pg*Zao6{WEOTrYNI%#(t)^5%sLIfLSasJ=ZE8J8AoO{iJ#Em51K2u7F7nH~xX#y9`VnLmR;_-d vpzg<{7a=gt-`(Jog(#HNZ|J)ZlHerDjFsEGXs(??bxHHEYBi)nJlpvT01UA? literal 0 HcmV?d00001 diff --git a/tools/design-sync/src/bundle.ts b/tools/design-sync/src/bundle.ts new file mode 100644 index 000000000..6d239738b --- /dev/null +++ b/tools/design-sync/src/bundle.ts @@ -0,0 +1,141 @@ +/** + * Bundle step: write the synthetic package to scratch, compile the single + * `_ds_bundle.js` with native `deno bundle` (esbuild-backed, zero extra + * deps), and assemble the canvas-ready upload tree. + * + * The scratch package carries its own `deno.jsonc` (classic React JSX + * transform + pinned npm React) and is bundled with `--config` + `--no-lock` + * so the workspace root config, its Preact JSX settings, and the repo lock + * file are never touched. + */ +import type { ConversionResult, SyncConfig } from './types.ts'; +import { fwd } from './config.ts'; + +function scratchDenoJson(cfg: SyncConfig): string { + return JSON.stringify( + { + compilerOptions: { + jsx: 'react', + jsxFactory: 'React.createElement', + jsxFragmentFactory: 'React.Fragment', + lib: ['dom', 'dom.iterable', 'esnext'], + }, + imports: { + react: `npm:react@${cfg.react.version}`, + 'react-dom/client': `npm:react-dom@${cfg.react.domVersion}/client`, + }, + }, + null, + 2, + ) + '\n'; +} + +function bundleEntry(cfg: SyncConfig, conversions: ConversionResult[]): string { + const imports: string[] = [ + `import * as ReactNamespace from 'react';`, + `import * as ReactDOMClient from 'react-dom/client';`, + ]; + const registry: string[] = []; + for (const conv of conversions) { + if (!conv.exportName) continue; + const tsx = conv.files.find((f) => f.endsWith('.tsx')); + if (!tsx) continue; + const spec = `../${tsx}`; + if (conv.defaultExport) imports.push(`import ${conv.exportName} from '${spec}';`); + else imports.push(`import { ${conv.exportName} } from '${spec}';`); + registry.push(conv.exportName); + } + const subNames: string[] = []; + Object.values(cfg.subpaths).forEach((target, i) => { + imports.push(`import * as __sub${i} from '../${target}';`); + subNames.push(`__sub${i}`); + }); + + const unique = [...new Set(registry)]; + return `${imports.join('\n')} + +const surface: Record = {}; +for (const ns of [${subNames.join(', ')}] as Record[]) { + for (const [key, value] of Object.entries(ns)) { + if (/^[A-Z]/.test(key)) surface[key] = value; + } +} +Object.assign(surface, { ${unique.join(', ')} }); + +const globals = globalThis as unknown as Record; +globals.React = ReactNamespace; +globals.ReactDOM = ReactDOMClient; +globals.${cfg.globalName} = surface; +`; +} + +async function writeTree(root: string, files: Map): Promise { + for (const [rel, content] of files) { + const abs = `${root}/${rel}`; + await Deno.mkdir(abs.slice(0, abs.lastIndexOf('/')), { recursive: true }); + await Deno.writeTextFile(abs, content); + } +} + +export interface BundleResult { + bundleJs: string; + scratchRoot: string; +} + +export async function buildBundleJs( + cfg: SyncConfig, + pkgFiles: Map, + conversions: ConversionResult[], +): Promise { + const scratchRoot = fwd(`${cfg.repoRoot}/${cfg.scratchDir}`); + const pkgRoot = `${scratchRoot}/pkg`; + try { + await Deno.remove(pkgRoot, { recursive: true }); + } catch { + // first build + } + + const tree = new Map(pkgFiles); + tree.set('deno.jsonc', scratchDenoJson(cfg)); + tree.set('__ds/bundle-entry.ts', bundleEntry(cfg, conversions)); + await writeTree(pkgRoot, tree); + + const outPath = `${pkgRoot}/__ds/_ds_bundle.js`; + const cmd = new Deno.Command(Deno.execPath(), { + args: [ + 'bundle', + '--quiet', + '--no-lock', + '--platform', + 'browser', + '--config', + `${pkgRoot}/deno.jsonc`, + '-o', + outPath, + `${pkgRoot}/__ds/bundle-entry.ts`, + ], + cwd: pkgRoot, + stdout: 'piped', + stderr: 'piped', + }); + const proc = await cmd.output(); + if (!proc.success) { + const err = new TextDecoder().decode(proc.stderr); + throw new Error(`deno bundle failed:\n${err}`); + } + + let bundleJs = await Deno.readTextFile(outPath); + // The entry exports nothing, so the ESM output is classic-script safe once + // any (empty) export statement is dropped. + bundleJs = bundleJs.replace(/\nexport\s*\{\s*\};?\s*$/, '\n'); + if (/process\.env/.test(bundleJs) && !/var process\s*=/.test(bundleJs)) { + bundleJs = `var process = { env: { NODE_ENV: "production" } };\n${bundleJs}`; + } + const head = bundleJs.slice(0, 4000); + if (/^import\s/.test(bundleJs) || /^export\s/m.test(head)) { + throw new Error( + 'bundle output still contains module syntax; cards load it as a classic script', + ); + } + return { bundleJs, scratchRoot }; +} diff --git a/tools/design-sync/src/closure.ts b/tools/design-sync/src/closure.ts new file mode 100644 index 000000000..bcd06530b --- /dev/null +++ b/tools/design-sync/src/closure.ts @@ -0,0 +1,106 @@ +/** + * ClosureBuilder port: produce the full CSS closure the canvas needs. + * + * eis-chat's hard-won rule was "ship the compiled Tailwind closure, never a + * hand-flattened subset" — because its components referenced Tailwind + * `*-ns-*` utilities that only exist after a build. Today's fresh-ui + * registry has **zero Tailwind utility classes** (verified: semantic `ns-*` + * classes with paired per-component CSS only), so the complete closure is a + * deterministic concatenation: + * + * fonts → tokens.css → base rules → layouts.css → per-unit component CSS + * + * The only Tailwind-entangled file is `theme/styles.css` (an `@import + * 'tailwindcss'` entry with `@apply` rules); its `@layer base` intent is + * re-expressed below as plain CSS against `--ns-*` vars. `theme-bridge.css` + * (a Tailwind v4 `@theme inline` bridge for consumer apps) is deliberately + * omitted — it defines utilities-facing aliases, not rendered styles. + */ +import type { RegistryUnit, SyncConfig } from './types.ts'; +import { fwd } from './config.ts'; + +/** + * `theme/styles.css` `@layer base`, hand-mapped from `@apply` to vars. + * Kept intentionally small: html/body ground, heading rhythm, media reset. + */ +const BASE_RULES = `/* base rules (mapped from fresh-ui theme/styles.css @layer base) */ +html { + background: var(--ns-bg); + color: var(--ns-fg); + min-height: 100%; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +body { + margin: 0; + background: var(--ns-bg); + color: var(--ns-fg); + font-family: var(--ns-font-sans); + font-size: var(--ns-text-base, 1rem); + line-height: var(--ns-leading-normal, 1.5); + min-height: 100vh; + transition: background-color 0.2s ease, color 0.2s ease; +} +a, button { touch-action: manipulation; } +h1, h2, h3, h4 { + letter-spacing: -0.02em; + line-height: 1.25; + text-wrap: balance; +} +code, pre, kbd, samp { font-family: var(--ns-font-mono); } +img, svg, video { max-width: 100%; height: auto; } +`; + +export interface ClosureResult { + /** the full `_ds_bundle.css` content */ + css: string; + /** ordered registry paths folded into the closure */ + parts: string[]; +} + +export interface ClosureBuilder { + build(units: RegistryUnit[]): Promise; +} + +export class RegistryConcatClosureBuilder implements ClosureBuilder { + constructor(private readonly cfg: SyncConfig) {} + + async build(units: RegistryUnit[]): Promise { + const root = `${this.cfg.repoRoot}/${fwd(this.cfg.registry.root)}`; + const parts: string[] = []; + const chunks: string[] = [ + '/* NS One canvas closure — generated by tools/design-sync (do not edit) */', + ]; + + const tokensPath = 'registry/theme/tokens.css'; + chunks.push(`/* == ${tokensPath} == */`, await Deno.readTextFile(`${root}/${tokensPath}`)); + parts.push(tokensPath); + + chunks.push('/* == base == */', BASE_RULES); + + const layoutsPath = 'registry/styles/layouts.css'; + chunks.push(`/* == ${layoutsPath} == */`, await Deno.readTextFile(`${root}/${layoutsPath}`)); + parts.push(layoutsPath); + + const seen = new Set([tokensPath, layoutsPath]); + for (const unit of units) { + if (unit.excluded) continue; + for (const src of unit.sources) { + if (!src.registryPath.endsWith('.css') || seen.has(src.registryPath)) continue; + // theme entries handled above; the Tailwind entry + bridge are omitted by design + if ( + src.registryPath === 'registry/theme/styles.css' || + src.registryPath === 'registry/theme/theme-bridge.css' + ) { + seen.add(src.registryPath); + continue; + } + seen.add(src.registryPath); + chunks.push(`/* == ${src.registryPath} (${unit.item.name}) == */`, src.content); + parts.push(src.registryPath); + } + } + + return { css: `${chunks.join('\n\n')}\n`, parts }; + } +} diff --git a/tools/design-sync/src/config.ts b/tools/design-sync/src/config.ts new file mode 100644 index 000000000..212374c36 --- /dev/null +++ b/tools/design-sync/src/config.ts @@ -0,0 +1,96 @@ +/** + * SyncConfig loading + validation. + * + * The config file is the single machine-readable manifest of a sync target + * (Claude Design project id, synthetic package identity, registry location, + * exclusions). Paths inside it are repo-relative; the repo root is derived + * from the config location (`/resources/design/**` by convention) + * or passed explicitly. + */ +import type { SyncConfig } from './types.ts'; + +const REQUIRED_STRING_FIELDS = [ + 'projectId', + 'projectName', + 'pkg', + 'globalName', + 'shape', + 'scratchDir', + 'fontImport', +] as const; + +function fail(msg: string): never { + throw new Error(`design-sync config: ${msg}`); +} + +/** Normalize to forward slashes so path handling is uniform on Windows. */ +export function fwd(path: string): string { + return path.replaceAll('\\', '/'); +} + +export function dirOf(path: string): string { + const p = fwd(path); + const i = p.lastIndexOf('/'); + return i < 0 ? '.' : p.slice(0, i); +} + +/** Walk up from `start` until a directory containing `deno.json` with a workspace is found. */ +async function findRepoRoot(start: string): Promise { + let dir = fwd(start); + for (let hops = 0; hops < 12; hops++) { + try { + const raw = await Deno.readTextFile(`${dir}/deno.json`); + if (JSON.parse(raw).workspace) return dir; + } catch { + // keep walking + } + const parent = dirOf(dir); + if (parent === dir) break; + dir = parent; + } + fail(`could not locate repo root (deno.json with workspace) above ${start}`); +} + +export async function loadConfig(configPath: string): Promise { + const abs = fwd( + configPath.match(/^([a-zA-Z]:\/|\/)/) ? configPath : `${fwd(Deno.cwd())}/${configPath}`, + ); + let raw: string; + try { + raw = await Deno.readTextFile(abs); + } catch (e) { + fail(`cannot read ${abs}: ${e instanceof Error ? e.message : e}`); + } + const parsed = JSON.parse(raw) as Record; + + for (const field of REQUIRED_STRING_FIELDS) { + if (typeof parsed[field] !== 'string' || !(parsed[field] as string).length) { + fail(`missing or empty string field "${field}" in ${abs}`); + } + } + if (parsed.shape !== 'package') fail(`unsupported shape "${parsed.shape}" (only "package")`); + const registry = parsed.registry as { root?: string; manifest?: string } | undefined; + if (!registry?.root || !registry?.manifest) fail('missing registry.root / registry.manifest'); + const react = parsed.react as { version?: string; domVersion?: string } | undefined; + if (!react?.version || !react?.domVersion) fail('missing react.version / react.domVersion'); + + const repoRoot = await findRepoRoot(dirOf(abs)); + const cfg: SyncConfig = { + ...(parsed as unknown as Omit), + exclude: Array.isArray(parsed.exclude) ? parsed.exclude as SyncConfig['exclude'] : [], + subpaths: (parsed.subpaths ?? {}) as SyncConfig['subpaths'], + groups: (parsed.groups ?? {}) as SyncConfig['groups'], + repoRoot, + configPath: abs, + }; + + try { + const st = await Deno.stat( + `${repoRoot}/${fwd(cfg.registry.root)}/${fwd(cfg.registry.manifest)}`, + ); + if (!st.isFile) fail('registry manifest path is not a file'); + } catch { + fail(`registry manifest not found under ${repoRoot}/${cfg.registry.root}`); + } + return cfg; +} diff --git a/tools/design-sync/src/convert.ts b/tools/design-sync/src/convert.ts new file mode 100644 index 000000000..dcaffca1d --- /dev/null +++ b/tools/design-sync/src/convert.ts @@ -0,0 +1,359 @@ +/** + * Converter: fresh-ui (Preact/Fresh) registry sources → a synthetic React + * package the Claude Design canvas can execute. + * + * The eis-chat recipe applies: Preact appears in registry components as + * type-only imports, so compiling the same source under a classic React JSX + * transform yields genuine React components. The converter therefore only: + * + * 1. rewrites the three Preact specifiers to local shims + * (`preact` → types + Fragment compat, `preact/hooks` → React hooks, + * `@preact/signals` → a useState-backed signal shim), + * 2. replaces `lib/cn.ts` with a dependency-free implementation (registry + * components carry zero Tailwind utility classes, so `tailwind-merge` + * is semantically a no-op here — dropping it removes every npm dep + * except React itself), + * 3. injects the `React` scope import that the classic JSX factory needs. + * + * Everything else (JSX bodies, `class=` props — React ≥16 passes `class` + * through to the DOM, `ns-*` class contracts, CSS) ports verbatim. + */ +import type { + ConversionResult, + PropsSummary, + RegistryUnit, + SourceFile, + SyncConfig, +} from './types.ts'; + +const HOOK_NAMES = [ + 'useState', + 'useEffect', + 'useLayoutEffect', + 'useMemo', + 'useCallback', + 'useRef', + 'useContext', + 'useReducer', + 'useId', + 'useImperativeHandle', +]; + +/** Value exports the preact compat shim knows how to map onto React. */ +const PREACT_VALUE_COMPAT: Record = { + Fragment: 'export const Fragment = React.Fragment;', + createContext: 'export const createContext = React.createContext;', + cloneElement: 'export const cloneElement = React.cloneElement;', + toChildArray: 'export const toChildArray = React.Children.toArray;', +}; + +const SIGNAL_IMPL: Record = { + useSignal: `export function useSignal(initial: T) { + const [value, set] = React.useState(initial); + return { + get value(): T { + return value; + }, + set value(next: T) { + set(next); + }, + peek(): T { + return value; + }, + }; +}`, + useComputed: `export function useComputed(compute: () => T) { + const value = compute(); + return { get value(): T { return value; }, peek(): T { return value; } }; +}`, + useSignalEffect: `export function useSignalEffect(effect: () => void | (() => void)) { + React.useEffect(effect); +}`, +}; + +function relTo(pkgPath: string, target: string): string { + const depth = pkgPath.split('/').length - 1; + return depth === 0 ? `./${target}` : `${'../'.repeat(depth)}${target}`; +} + +function relToDs(pkgPath: string): string { + return relTo(pkgPath, '__ds'); +} + +const CN_SHIM = `/** + * Dependency-free replacement for fresh-ui's clsx + tailwind-merge \`cn\`. + * Registry components use semantic \`ns-*\` classes only (no Tailwind + * utilities), so merge semantics reduce to flatten + join. + */ +export type ClassValue = + | string + | number + | bigint + | null + | undefined + | false + | ClassValue[] + | Record; + +export const cn = (...inputs: ClassValue[]): string => { + const out: string[] = []; + const visit = (input: ClassValue): void => { + if (!input && input !== 0) return; + if (Array.isArray(input)) { + input.forEach(visit); + } else if (typeof input === 'object') { + for (const [key, on] of Object.entries(input)) { + if (on) out.push(key); + } + } else { + out.push(String(input)); + } + }; + inputs.forEach(visit); + return out.join(' '); +}; +`; + +export interface ConvertOutput { + conversions: ConversionResult[]; + /** pkg-relative path → content for the synthetic package tree */ + pkgFiles: Map; + /** JSX.* members + top-level preact type names seen across all sources */ + shims: { + jsxMembers: Set; + typeNames: Set; + valueNames: Set; + signalNames: Set; + }; +} + +function pascal(unitName: string): string { + return unitName.split(/[-_]/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(''); +} + +function extractProps(source: string): PropsSummary | undefined { + const m = source.match(/(?:export )?(?:interface|type) (\w*Props)\b[^{]*\{([\s\S]*?)\n\}/); + if (!m) return undefined; + const raw = `${m[0]}`; + const body = m[2]; + const required: string[] = []; + for (const line of body.split('\n')) { + const field = line.match(/^\s{2}(\w+)(\??):/); + if (field && field[2] !== '?' && field[1] !== 'children') required.push(field[1]); + } + return { raw, hasChildren: /children\??:/.test(body), required }; +} + +function primaryExport(source: string, unitName: string): { name?: string; isDefault: boolean } { + const def = source.match(/export default function ([A-Z]\w*)/); + if (def) return { name: def[1], isDefault: true }; + const wanted = pascal(unitName); + const named = [...source.matchAll(/export (?:function|const) ([A-Z]\w*)/g)].map((m) => m[1]); + if (named.includes(wanted)) return { name: wanted, isDefault: false }; + return { name: named[0], isDefault: false }; +} + +/** Rewrite one source file; mutates the scan-accumulator sets. */ +export function convertSource( + pkgPath: string, + content: string, + scan: ConvertOutput['shims'], + notes: string[], + errors: string[], + subpaths: Record = {}, +): string { + const ds = relToDs(pkgPath); + let out = content; + + for (const [spec, target] of Object.entries(subpaths)) { + if (out.includes(`'${spec}'`)) { + out = out.replaceAll(`'${spec}'`, `'${relTo(pkgPath, target)}'`); + notes.push(`subpath "${spec}" → ${relTo(pkgPath, target)} (${pkgPath})`); + } + } + + for (const m of content.matchAll(/\bJSX\.([A-Za-z]\w*)/g)) scan.jsxMembers.add(m[1]); + + out = out.replace( + /import\s+(type\s+)?\{([^}]*)\}\s+from\s+'(preact|preact\/hooks|@preact\/signals)';?/g, + (_full, typeOnly: string | undefined, names: string, spec: string) => { + const bindings = names.split(',').map((n) => n.trim()).filter(Boolean); + if (spec === 'preact') { + for (const b of bindings) { + const name = b.replace(/^type\s+/, ''); + if (typeOnly || b.startsWith('type ')) scan.typeNames.add(name); + else { + if (!PREACT_VALUE_COMPAT[name]) { + errors.push(`unmapped preact value import "${name}" in ${pkgPath}`); + } + scan.valueNames.add(name); + } + } + return `import ${typeOnly ?? ''}{ ${names.trim()} } from '${ds}/preact-compat.ts';`; + } + if (spec === 'preact/hooks') { + return `import { ${names.trim()} } from '${ds}/hooks.ts';`; + } + for (const b of bindings) { + const name = b.replace(/^type\s+/, ''); + if (!SIGNAL_IMPL[name] && !typeOnly) { + errors.push(`unmapped signal import "${name}" in ${pkgPath}`); + } + scan.signalNames.add(name); + } + return `import { ${names.trim()} } from '${ds}/signals.ts';`; + }, + ); + + // Statement-aware scan: `@example` doc blocks legitimately show imports of + // npm specifiers (e.g. rehype-sanitize), so comment lines don't count. + for (const line of out.split('\n')) { + const t = line.trimStart(); + if (t.startsWith('*') || t.startsWith('//') || t.startsWith('/*')) continue; + const m = t.match(/from\s+'([^'.][^']*)'/); + if (m) errors.push(`unexpected bare specifier "${m[1]}" in ${pkgPath}`); + } + + if (pkgPath.endsWith('.tsx')) { + out = `import { React } from '${ds}/react-scope.ts';\n${out}`; + notes.push(`injected React scope import (${pkgPath})`); + } + return out; +} + +export function convertUnits( + cfg: SyncConfig, + units: RegistryUnit[], + extraSources: SourceFile[] = [], +): ConvertOutput { + const pkgFiles = new Map(); + const conversions: ConversionResult[] = []; + const shims: ConvertOutput['shims'] = { + jsxMembers: new Set(), + typeNames: new Set(), + valueNames: new Set(), + signalNames: new Set(), + }; + + for (const unit of units) { + if (unit.excluded) continue; + const group = cfg.groups[unit.item.kind]; + const result: ConversionResult = { + unit: unit.item.name, + kind: 'emitted', + group, + files: [], + notes: [], + errors: [], + }; + + for (const src of unit.sources) { + if (src.pkgPath === 'lib/cn.ts') { + if (!pkgFiles.has(src.pkgPath)) pkgFiles.set(src.pkgPath, CN_SHIM); + result.kind = 'shimmed'; + result.notes.push('lib/cn.ts replaced with dependency-free implementation'); + result.files.push(src.pkgPath); + continue; + } + if (/\.(ts|tsx)$/.test(src.pkgPath)) { + if (!pkgFiles.has(src.pkgPath)) { + pkgFiles.set( + src.pkgPath, + convertSource( + src.pkgPath, + src.content, + shims, + result.notes, + result.errors, + cfg.subpaths, + ), + ); + } + result.files.push(src.pkgPath); + const code = src.pkgPath.endsWith('.tsx') ? src.content : undefined; + if (code && !result.exportName) { + const exp = primaryExport(code, unit.item.name); + result.exportName = exp.name; + result.defaultExport = exp.isDefault; + result.props = extractProps(code); + if (!exp.name) result.errors.push(`no PascalCase export found in ${src.pkgPath}`); + } + } else { + // css / json assets flow into the closure builder, not the package tree + result.kind = result.files.length ? result.kind : 'skipped'; + result.notes.push(`asset handled by closure: ${src.pkgPath}`); + } + } + if (group && !result.exportName) { + result.errors.push(`card-bearing unit "${unit.item.name}" has no renderable export`); + } + conversions.push(result); + } + + if (extraSources.length) { + const result: ConversionResult = { + unit: '__subpaths', + kind: 'emitted', + files: [], + notes: [], + errors: [], + }; + for (const src of extraSources) { + if (pkgFiles.has(src.pkgPath)) continue; + pkgFiles.set( + src.pkgPath, + convertSource(src.pkgPath, src.content, shims, result.notes, result.errors, cfg.subpaths), + ); + result.files.push(src.pkgPath); + } + conversions.push(result); + } + + emitShims(pkgFiles, shims); + return { conversions, pkgFiles, shims }; +} + +function emitShims(pkgFiles: Map, shims: ConvertOutput['shims']): void { + pkgFiles.set( + '__ds/react-scope.ts', + `import * as ReactNamespace from 'react';\n\n` + + `// Single in-bundle React identity; the classic JSX factory references it.\n` + + `export const React = ReactNamespace;\n`, + ); + + const jsxMembers = [...shims.jsxMembers].sort().map((m) => + ` export type ${m} = Record | A | B;` + ); + const typeNames = [...shims.typeNames].sort() + .filter((n) => n !== 'JSX') + .map((n) => `export type ${n} = unknown | A | B;`); + const valueLines = [...shims.valueNames].sort() + .map((n) => PREACT_VALUE_COMPAT[n]) + .filter((line): line is string => Boolean(line)); + pkgFiles.set( + '__ds/preact-compat.ts', + `/**\n * Parse-only Preact type surface + React-backed value compat.\n` + + ` * Types are erased at bundle time; only names/arity must line up.\n */\n` + + (valueLines.length ? `import { React } from './react-scope.ts';\n\n` : '\n') + + `${typeNames.join('\n')}\n` + + `// deno-lint-ignore no-namespace\n` + + `export namespace JSX {\n${jsxMembers.join('\n')}\n}\n` + + (valueLines.length ? `\n${valueLines.join('\n')}\n` : ''), + ); + + pkgFiles.set( + '__ds/hooks.ts', + `import { React } from './react-scope.ts';\n\n` + + HOOK_NAMES.map((h) => `export const ${h} = React.${h};`).join('\n') + '\n', + ); + + const signalBodies = [...shims.signalNames].sort() + .map((n) => SIGNAL_IMPL[n]) + .filter((body): body is string => Boolean(body)); + if (signalBodies.length) { + pkgFiles.set( + '__ds/signals.ts', + `import { React } from './react-scope.ts';\n\n${signalBodies.join('\n\n')}\n`, + ); + } +} diff --git a/tools/design-sync/src/parity.ts b/tools/design-sync/src/parity.ts new file mode 100644 index 000000000..bcaebdf78 --- /dev/null +++ b/tools/design-sync/src/parity.ts @@ -0,0 +1,60 @@ +/** + * ParityReport: manifest units vs emitted conversions vs preview cards. + * This is the fitness-gate artifact — `ok` means every included unit of a + * card-bearing kind produced both a conversion and a card, and every other + * included unit was at least consumed (emitted, shimmed, or folded into the + * CSS closure). + */ +import type { ConversionResult, ParityReport, RegistryUnit, SyncConfig } from './types.ts'; + +export function buildParity( + cfg: SyncConfig, + units: RegistryUnit[], + conversions: ConversionResult[], + cardFiles: Map, +): ParityReport { + const convByUnit = new Map(conversions.map((c) => [c.unit, c])); + const cardUnits = new Set( + conversions.filter((c) => + c.group && c.exportName && + cardFiles.has(`components/${c.group}/${c.exportName}/${c.exportName}.html`) + ).map((c) => c.unit), + ); + + const kinds = [...new Set(units.map((u) => u.item.kind))].sort(); + const rows = kinds.map((kind) => { + const ofKind = units.filter((u) => u.item.kind === kind); + const included = ofKind.filter((u) => !u.excluded); + return { + kind, + manifest: ofKind.length, + converted: included.filter((u) => convByUnit.has(u.item.name)).length, + cards: included.filter((u) => cardUnits.has(u.item.name)).length, + excluded: ofKind.length - included.length, + }; + }); + + const missing: string[] = []; + for (const unit of units) { + if (unit.excluded) continue; + const conv = convByUnit.get(unit.item.name); + if (!conv) { + missing.push(`${unit.item.name}: no conversion`); + continue; + } + if (conv.errors.length) missing.push(`${unit.item.name}: ${conv.errors.join('; ')}`); + if (cfg.groups[unit.item.kind] && !cardUnits.has(unit.item.name)) { + missing.push(`${unit.item.name}: card-bearing kind "${unit.item.kind}" but no card emitted`); + } + } + + return { + rows, + missing, + excluded: units.filter((u) => u.excluded).map((u) => ({ + unit: u.item.name, + reason: u.excluded as string, + })), + ok: missing.length === 0, + }; +} diff --git a/tools/design-sync/src/previews.ts b/tools/design-sync/src/previews.ts new file mode 100644 index 000000000..5d538e9be --- /dev/null +++ b/tools/design-sync/src/previews.ts @@ -0,0 +1,136 @@ +/** + * Preview-card emitter. + * + * Every card-bearing unit gets, under `components///`: + * - `.html` the canvas card (first line: ``) + * - `.tsx` the converted source, as prop-contract truth + * - `.prompt.md` distilled usage: JSDoc header, props, ns-* classes + * plus `_preview/.js` — the story registry (`window.__dsPreview`). + * + * v1 stories are floor cards (bare render, label children when accepted), + * the fast path eis-chat chose; authored stories drop into + * `tools/design-sync/previews/.preview.js` and replace the floor card + * verbatim on the next build. Trap `render-blank` reports which floor cards + * are predicted blank so authoring effort goes where it matters. + */ +import type { ConversionResult, RegistryUnit, SyncConfig } from './types.ts'; +import { fwd } from './config.ts'; + +export interface CardSet { + /** bundle-relative path → content */ + files: Map; + /** units whose floor card is predicted to render blank/broken */ + predictedBlank: string[]; + /** units using an authored story instead of a floor card */ + authored: string[]; +} + +function cardHtml(template: string, name: string): string { + return template.replaceAll('{{NAME}}', name); +} + +function floorStory(conv: ConversionResult): string { + const props = conv.props; + const children = props?.hasChildren ? `, ${JSON.stringify(conv.exportName)}` : ''; + return `// generated floor card for "${conv.unit}" — author tools/design-sync/previews/${conv.unit}.preview.js to replace +(function () { + var R = window.React; + var NS = window.NSOne || {}; + window.__dsPreview = { + ${conv.exportName}: function () { + return R.createElement(NS.${conv.exportName}, null${children}); + }, + }; +})(); +`; +} + +function promptMd(unit: RegistryUnit, conv: ConversionResult): string { + const source = unit.sources.find((s) => s.pkgPath.endsWith('.tsx'))?.content ?? ''; + const header = source.match(/\/\*\*[\s\S]*?\*\//)?.[0] ?? ''; + const classSet = new Set(); + for (const src of unit.sources) { + for (const m of src.content.matchAll(/\bns-[a-z0-9]+(?:-[a-z0-9]+)*(?:--[a-z0-9-]+)?\b/g)) { + classSet.add(m[0]); + } + } + const lines = [ + `# ${conv.exportName} (\`${unit.item.name}\`, ${unit.item.kind}, layer ${unit.item.layer})`, + '', + unit.item.description, + '', + ]; + if (header) lines.push('## Source header', '', '```ts', header, '```', ''); + if (conv.props?.raw) { + lines.push( + '## Props (real TypeScript contract — authoritative, not a weak `.d.ts`)', + '', + '```ts', + conv.props.raw, + '```', + '', + ); + } + if (classSet.size) { + lines.push( + '## Class contract', + '', + [...classSet].sort().map((c) => `\`${c}\``).join(' · '), + '', + ); + } + if (unit.item.registryDependencies?.length) { + lines.push(`Registry dependencies: ${unit.item.registryDependencies.join(', ')}`, ''); + } + return `${lines.join('\n')}\n`; +} + +export async function emitCards( + cfg: SyncConfig, + units: RegistryUnit[], + conversions: ConversionResult[], + pkgFiles: Map, + cardTemplate: string, +): Promise { + const files = new Map(); + const predictedBlank: string[] = []; + const authored: string[] = []; + const byName = new Map(units.map((u) => [u.item.name, u])); + const toolRoot = `${cfg.repoRoot}/tools/design-sync`; + + for (const conv of conversions) { + if (!conv.group || !conv.exportName) continue; + const unit = byName.get(conv.unit); + if (!unit) continue; + const dir = `components/${conv.group}/${conv.exportName}`; + + files.set( + `${dir}/${conv.exportName}.html`, + `\n${cardHtml(cardTemplate, conv.exportName)}`, + ); + + const tsxPath = conv.files.find((f) => f.endsWith('.tsx')); + if (tsxPath && pkgFiles.has(tsxPath)) { + files.set(`${dir}/${conv.exportName}.tsx`, pkgFiles.get(tsxPath) as string); + } + files.set(`${dir}/${conv.exportName}.prompt.md`, promptMd(unit, conv)); + + let story: string | undefined; + try { + story = await Deno.readTextFile(fwd(`${toolRoot}/previews/${conv.unit}.preview.js`)); + authored.push(conv.unit); + } catch { + story = floorStory(conv); + const required = conv.props?.required ?? []; + if (required.length || (conv.props && !conv.props.hasChildren)) { + predictedBlank.push( + `${conv.unit}${ + required.length ? ` (required props: ${required.join(', ')})` : ' (no children prop)' + }`, + ); + } + } + files.set(`_preview/${conv.exportName}.js`, story); + } + return { files, predictedBlank, authored }; +} diff --git a/tools/design-sync/src/registry-source.ts b/tools/design-sync/src/registry-source.ts new file mode 100644 index 000000000..5cf6bfbf9 --- /dev/null +++ b/tools/design-sync/src/registry-source.ts @@ -0,0 +1,112 @@ +/** + * RegistrySource port: joins the typed registry manifest with the actual + * source files on disk. + * + * The fresh-ui implementation imports `registry.manifest.ts` directly (a + * plain typed module) and reads each `files[].source` from the package + * directory — it never parses the 290KB `registry.generated.ts` embed. The + * port exists so the same converter can later run against any NetScript + * app's copied registry (the `netscript ui:design-sync` promotion path). + */ +import type { + RegistryItemDefinition, + RegistrySource, + RegistryUnit, + SourceFile, + SyncConfig, +} from './types.ts'; +import { fwd } from './config.ts'; + +interface ManifestShape { + items: RegistryItemDefinition[]; +} + +function isManifest(value: unknown): value is ManifestShape { + return typeof value === 'object' && value !== null && + Array.isArray((value as ManifestShape).items); +} + +/** Strip the leading `registry/` segment to get the synthetic-package path. */ +export function toPkgPath(registryPath: string): string { + return registryPath.replace(/^registry\//, ''); +} + +/** Resolve a relative specifier against a package-relative directory. */ +export function joinRel(dir: string, spec: string): string { + const parts = dir ? dir.split('/') : []; + for (const seg of spec.split('/')) { + if (seg === '.' || seg === '') continue; + if (seg === '..') parts.pop(); + else parts.push(seg); + } + return parts.join('/'); +} + +/** Relative `.ts`/`.tsx` specifiers on real import/export statements (not doc comments). */ +export function relativeImports(content: string): string[] { + const specs: string[] = []; + for (const line of content.split('\n')) { + const t = line.trimStart(); + if (t.startsWith('*') || t.startsWith('//') || t.startsWith('/*')) continue; + const m = t.match(/from\s+'(\.\.?\/[^']*\.tsx?)'/); + if (m) specs.push(m[1]); + } + return specs; +} + +export class FreshUiRegistrySource implements RegistrySource { + constructor(private readonly cfg: SyncConfig) {} + + async load(): Promise { + const root = `${this.cfg.repoRoot}/${fwd(this.cfg.registry.root)}`; + const manifestPath = `${root}/${fwd(this.cfg.registry.manifest)}`; + const mod = await import(`file:///${manifestPath.replace(/^\//, '')}`) as Record< + string, + unknown + >; + const manifest = Object.values(mod).find(isManifest); + if (!manifest || manifest.items.length === 0) { + throw new Error(`design-sync: no manifest with items[] exported by ${manifestPath}`); + } + + const rules = this.cfg.exclude.map((r) => ({ re: new RegExp(r.pattern), reason: r.reason })); + const units: RegistryUnit[] = []; + for (const item of manifest.items) { + const excludedBy = rules.find((r) => item.files.some((f) => r.re.test(fwd(f.source)))); + if (excludedBy) { + units.push({ item, sources: [], excluded: excludedBy.reason }); + continue; + } + const sources = []; + for (const file of item.files) { + const registryPath = fwd(file.source); + const content = await Deno.readTextFile(`${root}/${registryPath}`); + sources.push({ registryPath, pkgPath: toPkgPath(registryPath), content }); + } + units.push({ item, sources }); + } + return units; + } + + /** + * Walk each configured subpath entry's relative-import graph. The files + * keep their package-root-relative paths in the synthetic tree (they live + * outside `registry/`), so relative imports inside the graph port verbatim. + */ + async loadSubpaths(): Promise { + const root = `${this.cfg.repoRoot}/${fwd(this.cfg.registry.root)}`; + const seen = new Set(); + const queue = Object.values(this.cfg.subpaths).map(fwd); + const files: SourceFile[] = []; + while (queue.length) { + const rel = queue.shift() as string; + if (seen.has(rel)) continue; + seen.add(rel); + const content = await Deno.readTextFile(`${root}/${rel}`); + files.push({ registryPath: rel, pkgPath: rel, content }); + const dir = rel.includes('/') ? rel.slice(0, rel.lastIndexOf('/')) : ''; + for (const spec of relativeImports(content)) queue.push(joinRel(dir, spec)); + } + return files; + } +} diff --git a/tools/design-sync/src/report.ts b/tools/design-sync/src/report.ts new file mode 100644 index 000000000..de3df38d3 --- /dev/null +++ b/tools/design-sync/src/report.ts @@ -0,0 +1,50 @@ +/** + * Compact terminal report: parity table + trap table + verdict. + */ +import type { ParityReport, TrapCheck } from './types.ts'; + +function pad(s: string | number, w: number): string { + return String(s).padEnd(w); +} + +export function printReport(parity: ParityReport, traps: TrapCheck[], extra: string[]): boolean { + console.log('\nParityReport'); + console.log( + ` ${pad('kind', 12)} ${pad('manifest', 9)} ${pad('converted', 10)} ${ + pad('cards', 6) + } excluded`, + ); + for (const r of parity.rows) { + console.log( + ` ${pad(r.kind, 12)} ${pad(r.manifest, 9)} ${pad(r.converted, 10)} ${ + pad(r.cards, 6) + } ${r.excluded}`, + ); + } + if (parity.excluded.length) { + console.log(' excluded units:'); + for (const e of parity.excluded) console.log(` - ${e.unit}: ${e.reason}`); + } + if (parity.missing.length) { + console.log(' MISSING:'); + for (const m of parity.missing) console.log(` ! ${m}`); + } + + console.log('\nTrapChecks'); + for (const t of traps) { + console.log(` [${t.result}] ${pad(t.id, 14)} ${t.evidence}`); + for (const d of t.details.slice(0, 12)) console.log(` - ${d}`); + if (t.details.length > 12) console.log(` … ${t.details.length - 12} more`); + } + + for (const line of extra) console.log(line); + + const failed = traps.filter((t) => t.result === 'FAIL').map((t) => t.id); + const ok = parity.ok && failed.length === 0; + console.log( + ok + ? '\ndesign-sync: PASS (parity green, no FAIL traps)' + : `\ndesign-sync: FAIL (${[...(parity.ok ? [] : ['parity']), ...failed].join(', ')})`, + ); + return ok; +} diff --git a/tools/design-sync/src/traps.ts b/tools/design-sync/src/traps.ts new file mode 100644 index 000000000..c92e43e8b --- /dev/null +++ b/tools/design-sync/src/traps.ts @@ -0,0 +1,128 @@ +/** + * The six recorded eis-chat parity traps, encoded as deterministic checks + * against the built bundle (research.md F9). Each check states its + * fresh-ui-adapted meaning: + * + * - `theme-default`: eis-chat had to patch a dark-default app so unthemed + * canvas roots fell to the brand light look. fresh-ui tokens are already + * light-default (`:root` = warm cream, `[data-theme='dark']` override), so + * here the check *verifies* both halves exist in the closure. + * - `token-closure`: every `var(--ns-*)` referenced anywhere in the closure + * must be defined in it — missing spacing tokens silently zero gaps. + * - `compiled-css`: the closure must be the full set (tokens + base + + * layout objects + every included unit's CSS), never a partial flatten. + * - `weak-dts`: prop contracts must come from real TypeScript, not + * `{ [key: string]: unknown }` bags — cards ship the converted `.tsx` and + * a props section in `prompt.md`; units without one are listed. + * - `render-blank`: floor cards with required props / no children are + * predicted blank; authoring effort is directed there (WARN, by design). + * - `raw-hex`: raw hex in component CSS/TSX outside the token ramp files — + * inherited source findings WARN (they feed the sync-back spec), hex in + * generated output FAILs. + */ +import type { TrapCheck } from './types.ts'; +import type { CardSet } from './previews.ts'; +import type { ClosureResult } from './closure.ts'; + +export interface TrapInput { + closure: ClosureResult; + bundleFiles: Map; + /** synthetic package sources — inline-style token assignments count as definitions */ + pkgFiles: Map; + cards: CardSet; + cardUnits: { unit: string; hasProps: boolean }[]; + expectedCssParts: string[]; +} + +export function runTraps(input: TrapInput): TrapCheck[] { + const { closure, bundleFiles, cards } = input; + const checks: TrapCheck[] = []; + + const hasRootTheme = /:root\s*\{[^}]*--ns-bg\s*:/s.test(closure.css); + const hasDarkOverride = /\[data-theme='dark'\]/.test(closure.css); + checks.push({ + id: 'theme-default', + result: hasRootTheme && hasDarkOverride ? 'PASS' : 'FAIL', + evidence: `:root token block ${ + hasRootTheme ? 'present' : 'MISSING' + }; [data-theme='dark'] override ${hasDarkOverride ? 'present' : 'MISSING'}`, + details: [], + }); + + const defined = new Set(); + for (const m of closure.css.matchAll(/(--ns-[\w-]+)\s*:/g)) defined.add(m[1]); + // Runtime primitives assign per-instance tokens through inline styles + // (e.g. the popover anchor name) — those are definitions too. + for (const [path, content] of input.pkgFiles) { + if (!/\.(ts|tsx)$/.test(path)) continue; + for (const m of content.matchAll(/'(--ns-[\w-]+)'\s*:/g)) defined.add(m[1]); + } + const missing = new Set(); + // `var(--x, fallback)` is a per-instance override knob, not a gap — only a + // fallback-less reference to an undefined token breaks rendering. + for (const m of closure.css.matchAll(/var\(\s*(--ns-[\w-]+)\s*\)/g)) { + if (!defined.has(m[1])) missing.add(m[1]); + } + checks.push({ + id: 'token-closure', + result: missing.size ? 'FAIL' : 'PASS', + evidence: `${defined.size} tokens defined; ${missing.size} referenced-but-undefined`, + details: [...missing].sort(), + }); + + const absentParts = input.expectedCssParts.filter((p) => !closure.parts.includes(p)); + const hasLayouts = /\.ns-stack\b/.test(closure.css) && /\.ns-cluster\b/.test(closure.css); + checks.push({ + id: 'compiled-css', + result: absentParts.length === 0 && hasLayouts ? 'PASS' : 'FAIL', + evidence: `${closure.parts.length} css parts folded; layout objects ${ + hasLayouts ? 'present' : 'MISSING' + }; ${absentParts.length} expected parts absent (${ + Math.round(closure.css.length / 1024) + } KiB total)`, + details: absentParts, + }); + + const weak = input.cardUnits.filter((u) => !u.hasProps).map((u) => u.unit); + checks.push({ + id: 'weak-dts', + result: weak.length ? 'WARN' : 'PASS', + evidence: `${ + input.cardUnits.length - weak.length + }/${input.cardUnits.length} cards carry a real props contract`, + details: weak, + }); + + checks.push({ + id: 'render-blank', + result: cards.predictedBlank.length ? 'WARN' : 'PASS', + evidence: + `${cards.authored.length} authored stories; ${cards.predictedBlank.length} floor cards predicted blank`, + details: cards.predictedBlank, + }); + + const inherited: string[] = []; + const generated: string[] = []; + const hexRe = /#[0-9a-fA-F]{3,8}\b/; + for (const [path, content] of bundleFiles) { + if (!/\.(css|tsx)$/.test(path)) continue; + for (const [n, line] of content.split('\n').entries()) { + if (!hexRe.test(line)) continue; + // token ramps legitimately carry hex fallbacks next to their oklch values + if (/--ns-[\w-]+\s*:/.test(line)) continue; + const hit = `${path}:${n + 1}`; + // card copies and the concatenated closure carry source-inherited CSS + const fromSource = path.startsWith('components/') || path === '_ds_bundle.css'; + (fromSource ? inherited : generated).push(hit); + } + } + checks.push({ + id: 'raw-hex', + result: generated.length ? 'FAIL' : inherited.length ? 'WARN' : 'PASS', + evidence: + `${generated.length} hex literals in generated files; ${inherited.length} inherited from source (sync-back candidates)`, + details: [...generated, ...inherited].slice(0, 40), + }); + + return checks; +} diff --git a/tools/design-sync/src/types.ts b/tools/design-sync/src/types.ts new file mode 100644 index 000000000..89191bd7e --- /dev/null +++ b/tools/design-sync/src/types.ts @@ -0,0 +1,140 @@ +/** + * Shared contracts for the design-sync system. + * + * Vocabulary is locked by the run plan + * (`.llm/runs/feat-dashboard-design-prototype--design/worklog.md` § Design): + * `SyncConfig`, `RegistryUnit`, `ConversionResult`, `ParityReport`, `TrapCheck`, + * plus the `RegistrySource` / `ClosureBuilder` ports. + */ +import type { + RegistryItemDefinition, + RegistryItemKind, +} from '../../../packages/fresh-ui/registry.schema.ts'; + +export type { RegistryItemDefinition, RegistryItemKind }; + +/** The six recorded eis-chat parity traps, encoded as first-class checks. */ +export const TRAP_IDS = [ + 'theme-default', + 'token-closure', + 'compiled-css', + 'weak-dts', + 'render-blank', + 'raw-hex', +] as const; + +export type TrapId = (typeof TRAP_IDS)[number]; + +export interface ExcludeRule { + /** RegExp source matched against each manifest file `source` path. */ + pattern: string; + reason: string; +} + +export interface SyncConfig { + projectId: string; + projectName: string; + pkg: string; + globalName: string; + shape: 'package'; + registry: { + /** repo-relative package root, e.g. `packages/fresh-ui` */ + root: string; + /** manifest module relative to `root`, e.g. `registry.manifest.ts` */ + manifest: string; + }; + /** repo-relative gitignored scratch dir, e.g. `.ds-sync` */ + scratchDir: string; + /** CSS `@import` line(s) for remote fonts, prepended to `styles.css`. */ + fontImport: string; + exclude: ExcludeRule[]; + /** + * Package-subpath specifiers (e.g. `@netscript/fresh-ui/interactive`) + * mapped to their entry module relative to `registry.root`. The loader + * walks each entry's relative-import graph into the synthetic package and + * the converter rewrites the specifier to a relative path. + */ + subpaths: Record; + /** kind → canvas card group; kinds absent here get no preview card. */ + groups: Partial>; + react: { version: string; domVersion: string }; + /** absolute repo root (resolved at load time, not persisted) */ + repoRoot: string; + /** absolute path of the loaded config file */ + configPath: string; +} + +export interface SourceFile { + /** path as written in the manifest, e.g. `registry/components/ui/badge.tsx` */ + registryPath: string; + /** synthetic-package-relative emit path, e.g. `components/ui/badge.tsx` */ + pkgPath: string; + content: string; +} + +export interface RegistryUnit { + item: RegistryItemDefinition; + sources: SourceFile[]; + /** exclusion reason when the unit is out of the parity set */ + excluded?: string; +} + +export type ConversionKind = 'emitted' | 'shimmed' | 'skipped'; + +export interface PropsSummary { + raw: string; + hasChildren: boolean; + required: string[]; +} + +export interface ConversionResult { + unit: string; + kind: ConversionKind; + /** primary PascalCase export used for the preview card */ + exportName?: string; + defaultExport?: boolean; + /** canvas card group, when the unit's kind maps to one */ + group?: string; + /** synthetic-package-relative emitted paths */ + files: string[]; + notes: string[]; + errors: string[]; + props?: PropsSummary; +} + +export interface TrapCheck { + id: TrapId; + result: 'PASS' | 'WARN' | 'FAIL'; + evidence: string; + details: string[]; +} + +export interface ParityRow { + kind: string; + manifest: number; + converted: number; + cards: number; + excluded: number; +} + +export interface ParityReport { + rows: ParityRow[]; + /** included units missing a conversion or an expected card */ + missing: string[]; + excluded: { unit: string; reason: string }[]; + ok: boolean; +} + +/** Seam: where registry units come from (fresh-ui today; any copied app registry later). */ +export interface RegistrySource { + load(): Promise; +} + +export interface BuildOutput { + units: RegistryUnit[]; + conversions: ConversionResult[]; + /** bundle-dir-relative path → content of every emitted canvas file */ + bundleFiles: Map; + traps: TrapCheck[]; + parity: ParityReport; +} diff --git a/tools/design-sync/templates/card.html b/tools/design-sync/templates/card.html new file mode 100644 index 000000000..71aa86781 --- /dev/null +++ b/tools/design-sync/templates/card.html @@ -0,0 +1,88 @@ + + + + + + + + + +
+ + + + + diff --git a/tools/design-sync/templates/conventions.md b/tools/design-sync/templates/conventions.md new file mode 100644 index 000000000..1eafce55a --- /dev/null +++ b/tools/design-sync/templates/conventions.md @@ -0,0 +1,47 @@ +# NS One — NetScript design system ({{PKG}}) + +This design system is a 1:1 React-compiled sync of `@netscript/fresh-ui`'s copy-source registry. +Every component here exists as real, shipped Preact/Fresh source in the NetScript framework; the +canvas build only swaps the JSX runtime. Treat this document plus each card's `*.prompt.md` and +`*.tsx` as the prop-contract truth. + +## Runtime contract on the canvas + +- `_ds_bundle.js` exposes `window.React`, `window.ReactDOM`, and `window.{{GLOBAL_NAME}}` — every + component is a property of `{{GLOBAL_NAME}}` (e.g. `{{GLOBAL_NAME}}.Badge`). +- Components accept `class` (not `className`) — they are Preact-authored; React passes `class` + through to the DOM. Keep using `class` in prototypes so markup round-trips to Fresh unchanged. +- `_ds_bundle.css` is the full style closure: design tokens, base rules, layout objects, and every + component's CSS. `styles.css` loads the DM Sans / DM Mono fonts. +- Preview stories live in `window.__dsPreview` per card; `?story=` renders one story. + +## Layer ladder (shared with fresh-ui) + +- **L0 tokens** — semantic `--ns-*` custom properties (`--ns-bg/fg/surface/card/border/muted`, + intents `primary/accent/destructive/success/warning`, scales `--ns-space-*`, `--ns-radius-*`, + `--ns-text-*`, fonts `--ns-font-sans` = DM Sans, `--ns-font-mono` = DM Mono). +- **L2 components** — emit semantic `ns-*` classes (BEM-ish variants: `ns-btn--primary`, + `ns-badge--success`, …). Never import another L2 component. +- **L3 blocks** — page-level compositions (sidebar shells, page headers, stats grids). +- Layout objects from `layouts.css`: `.ns-stack`, `.ns-cluster`, `.ns-grid--*`, `.ns-split`, + `.ns-toolbar`, `.ns-switcher`, `.ns-shell`, `.ns-section`, `.ns-sidebar`, `.ns-topbar`. + +## Hard rules for new canvas work + +1. **Theme-blind components**: style only via `--ns-*` vars and `ns-*` classes. Never raw hex, never + a gray-ramp step directly — derive with `color-mix()` if a shade is missing. +2. **Light is the unthemed default** (warm cream brand look); dark is `[data-theme='dark']` on the + root. Every screen must be designed in both. +3. State via `data-part` / `data-state` / `aria-*` attributes, native elements first (`\n \n \n \n {children}\n {description ? {description} : null}\n \n \n );\n}\n"; const template_016 = - '.ns-choice {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: var(--ns-space-3);\r\n cursor: pointer;\r\n}\r\n\r\n.ns-choice--disabled {\r\n cursor: not-allowed;\r\n opacity: 0.72;\r\n}\r\n\r\n.ns-choice__control {\r\n position: relative;\r\n display: inline-flex;\r\n flex-shrink: 0;\r\n}\r\n\r\n.ns-choice__body {\r\n display: flex;\r\n min-width: 0;\r\n flex-direction: column;\r\n gap: var(--ns-space-1);\r\n}\r\n\r\n.ns-choice__label {\r\n font-size: var(--ns-text-sm);\r\n font-weight: 500;\r\n line-height: 1.4;\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-choice__description {\r\n font-size: var(--ns-text-xs);\r\n line-height: 1.5;\r\n color: var(--ns-muted-fg);\r\n}\r\n\r\n.ns-checkbox,\r\n.ns-switch {\r\n position: absolute;\r\n inset: 0;\r\n margin: 0;\r\n opacity: 0;\r\n cursor: inherit;\r\n}\r\n\r\n.ns-checkbox:focus-visible + .ns-checkbox__indicator,\r\n.ns-switch:focus-visible + .ns-switch__track {\r\n outline: 2px solid var(--ns-ring);\r\n outline-offset: 2px;\r\n}\r\n'; + '.ns-choice {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: var(--ns-space-3);\r\n cursor: pointer;\r\n}\r\n\r\n.ns-choice--disabled {\r\n cursor: not-allowed;\r\n opacity: 0.55;\r\n}\r\n\r\n.ns-choice__control {\r\n position: relative;\r\n display: inline-flex;\r\n flex-shrink: 0;\r\n}\r\n\r\n.ns-choice__body {\r\n display: flex;\r\n min-width: 0;\r\n flex-direction: column;\r\n gap: var(--ns-space-1);\r\n}\r\n\r\n.ns-choice__label {\r\n font-size: var(--ns-text-sm);\r\n font-weight: 500;\r\n line-height: 1.4;\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-choice__description {\r\n font-size: var(--ns-text-xs);\r\n line-height: 1.5;\r\n color: var(--ns-muted-fg);\r\n}\r\n\r\n.ns-checkbox,\r\n.ns-switch {\r\n position: absolute;\r\n inset: 0;\r\n margin: 0;\r\n opacity: 0;\r\n cursor: inherit;\r\n}\r\n\r\n.ns-checkbox:focus-visible + .ns-checkbox__indicator,\r\n.ns-switch:focus-visible + .ns-switch__track {\r\n outline: 2px solid var(--ns-ring);\r\n outline-offset: 2px;\r\n}\r\n'; const template_017 = '.ns-citation {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n vertical-align: super;\r\n min-width: var(--ns-space-4);\r\n height: var(--ns-space-4);\r\n padding: 0 var(--ns-space-1);\r\n margin-inline: var(--ns-space-px);\r\n border: 1px solid var(--ns-primary-border);\r\n border-radius: var(--ns-radius-sm);\r\n background: var(--ns-primary-subtle);\r\n color: var(--ns-primary);\r\n font-family: var(--ns-font-mono);\r\n font-size: var(--ns-text-3xs);\r\n font-weight: 600;\r\n line-height: 1;\r\n cursor: pointer;\r\n transition:\r\n background-color var(--ns-ease-fast),\r\n border-color var(--ns-ease-fast),\r\n color var(--ns-ease-fast);\r\n}\r\n\r\n.ns-citation:hover {\r\n background: color-mix(in srgb, var(--ns-primary) 16%, transparent);\r\n border-color: var(--ns-primary);\r\n}\r\n\r\n.ns-citation:focus-visible {\r\n outline: 2px solid var(--ns-ring);\r\n outline-offset: var(--ns-space-px);\r\n}\r\n\r\n.ns-citation.is-active {\r\n background: var(--ns-primary);\r\n border-color: var(--ns-primary);\r\n color: var(--ns-primary-fg);\r\n}\r\n'; const template_018 = "/**\n * @component CitationChip\n * @layer 2\n * @depends theme-seed\n * @description Inline per-claim source marker [n] that pairs with a sources list —\n * the grounded-agent citation UX.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\n\ninterface CitationChipProps\n extends Omit, 'class' | 'onClick'> {\n /** 1-based citation number rendered in the chip. */\n index: number;\n /** Source label, surfaced as the hover title + accessible name. */\n source?: string;\n /** Active when its matching source row is selected. */\n active?: boolean;\n /** Invoked with the citation index on activation. */\n onClick?: (index: number) => void;\n class?: string;\n}\n\n/**\n * Renders a clickable superscript citation chip.\n */\nexport function CitationChip(\n { index, source, active, onClick, class: className, ...props }: CitationChipProps,\n): VNode {\n return (\n onClick?.(index)}\n >\n {index}\n \n );\n}\n"; const template_019 = - ".ns-code {\r\n overflow: hidden;\r\n border: 1px solid var(--ns-border);\r\n border-radius: var(--ns-radius-md);\r\n background: var(--ns-surface);\r\n font-family: var(--ns-font-mono);\r\n}\r\n\r\n.ns-code__head {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--ns-space-2);\r\n padding: var(--ns-space-1-5) var(--ns-space-3);\r\n border-bottom: 1px solid var(--ns-border);\r\n background: var(--ns-surface-raised);\r\n}\r\n\r\n.ns-code__name {\r\n font-size: var(--ns-text-xs);\r\n font-weight: 500;\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-code__lang {\r\n font-size: var(--ns-text-2xs);\r\n text-transform: uppercase;\r\n letter-spacing: var(--ns-label-tracking);\r\n color: var(--ns-muted-fg);\r\n}\r\n\r\n.ns-code__copy {\r\n margin-inline-start: auto;\r\n display: inline-flex;\r\n align-items: center;\r\n gap: var(--ns-space-1);\r\n padding: var(--ns-space-0-5) var(--ns-space-2);\r\n border: 1px solid var(--ns-border);\r\n border-radius: var(--ns-radius-sm);\r\n background: var(--ns-surface);\r\n color: var(--ns-muted-fg);\r\n font-family: var(--ns-font-mono);\r\n font-size: var(--ns-text-2xs);\r\n cursor: pointer;\r\n transition: color var(--ns-ease-fast), border-color var(--ns-ease-fast);\r\n}\r\n\r\n.ns-code__copy:hover {\r\n color: var(--ns-fg);\r\n border-color: var(--ns-border-hover);\r\n}\r\n\r\n.ns-code__copy:focus-visible {\r\n outline: 2px solid var(--ns-ring);\r\n outline-offset: var(--ns-space-px);\r\n}\r\n\r\n.ns-code__copy[data-state='copied'] {\r\n color: var(--ns-success);\r\n border-color: var(--ns-success-border);\r\n}\r\n\r\n.ns-code pre {\r\n margin: 0;\r\n padding: var(--ns-space-3);\r\n overflow-x: auto;\r\n font-size: var(--ns-text-xs);\r\n line-height: var(--ns-leading-normal);\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-code code {\r\n font-family: inherit;\r\n}\r\n"; + ".ns-code {\r\n overflow: hidden;\r\n border: 1px solid var(--ns-border);\r\n border-radius: var(--ns-radius-md);\r\n background: var(--ns-surface);\r\n font-family: var(--ns-font-mono);\r\n}\r\n\r\n.ns-code__head {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--ns-space-2);\r\n padding: var(--ns-space-1-5) var(--ns-space-3);\r\n border-bottom: 1px solid var(--ns-border);\r\n background: var(--ns-surface-raised);\r\n}\r\n\r\n.ns-code__name {\r\n font-size: var(--ns-text-xs);\r\n font-weight: 500;\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-code__lang {\r\n font-size: var(--ns-text-2xs);\r\n text-transform: uppercase;\r\n letter-spacing: var(--ns-label-tracking);\r\n color: var(--ns-muted-fg);\r\n}\r\n\r\n.ns-code__copy {\r\n margin-inline-start: auto;\r\n display: inline-flex;\r\n align-items: center;\r\n gap: var(--ns-space-1);\r\n padding: var(--ns-space-0-5) var(--ns-space-2);\r\n border: 1px solid var(--ns-border);\r\n border-radius: var(--ns-radius-sm);\r\n background: var(--ns-surface);\r\n color: var(--ns-muted-fg);\r\n font-family: var(--ns-font-mono);\r\n font-size: var(--ns-text-2xs);\r\n cursor: pointer;\r\n transition: color var(--ns-ease-fast), border-color var(--ns-ease-fast);\r\n}\r\n\r\n.ns-code__copy:hover {\r\n color: var(--ns-fg);\r\n border-color: var(--ns-border-hover);\r\n}\r\n\r\n.ns-code__copy:focus-visible {\r\n outline: 2px solid var(--ns-ring);\r\n outline-offset: var(--ns-space-px);\r\n}\r\n\r\n.ns-code__copy[data-state='copied'] {\r\n color: var(--ns-success);\r\n border-color: var(--ns-success-border);\r\n}\r\n\r\n.ns-code pre {\r\n margin: 0;\r\n padding: var(--ns-space-3);\r\n overflow-x: auto;\r\n font-size: var(--ns-text-xs);\r\n line-height: var(--ns-leading-normal);\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-code code {\r\n font-family: inherit;\r\n /* Preserve trailing breathing room when long lines scroll horizontally:\r\n an overflow container's right padding collapses visually, so carry it\r\n on the inline-level code box instead. */\r\n display: inline-block;\r\n min-width: 100%;\r\n padding-right: var(--ns-space-3);\r\n box-sizing: border-box;\r\n}\r\n"; const template_020 = "/**\n * @component CodeBlock\n * @layer 2\n * @depends theme-seed\n * @description Fenced code surface with a filename/language header and a copy\n * affordance. Presentational — clipboard + \"Copied\" state are hydrated by an app\n * island (the button exposes data-part='copy' and data-clipboard); syntax\n * highlighting is layered at L4 if desired.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\n\ninterface CodeBlockProps extends Omit, 'class'> {\n /** Raw source to display (and copy). */\n code: string;\n /** Optional filename shown in the header. */\n filename?: string;\n /** Optional language label. */\n lang?: string;\n class?: string;\n}\n\n/**\n * Renders a code surface with header metadata and a copy button.\n */\nexport function CodeBlock(\n { code, filename, lang, class: className, ...props }: CodeBlockProps,\n): VNode {\n return (\n
\n
\n {filename ? {filename} : null}\n {lang ? {lang} : null}\n \n Copy\n \n
\n
{code}
\n
\n );\n}\n"; const template_021 = @@ -50,139 +50,157 @@ const template_022 = const template_023 = "import type { JSX } from 'preact';\n\ninterface ControlPropSource {\n controlProps(overrides?: Record): Record;\n}\n\ninterface InputControlProps {\n readonly id?: string;\n readonly name?: string;\n readonly form?: string;\n readonly type?: JSX.HTMLInputTypeAttribute;\n readonly defaultValue?: string;\n readonly defaultChecked?: boolean;\n readonly 'aria-invalid'?: boolean;\n readonly 'aria-describedby'?: string;\n readonly 'aria-required'?: boolean;\n readonly required?: boolean;\n readonly minLength?: number;\n readonly maxLength?: number;\n readonly min?: number | string;\n readonly max?: number | string;\n readonly pattern?: string;\n readonly step?: number | string;\n readonly multiple?: boolean;\n readonly placeholder?: string;\n readonly autocomplete?: string;\n}\n\ninterface SelectControlProps {\n readonly id?: string;\n readonly name?: string;\n readonly form?: string;\n readonly defaultValue?: string;\n readonly 'aria-invalid'?: boolean;\n readonly 'aria-describedby'?: string;\n readonly 'aria-required'?: boolean;\n readonly required?: boolean;\n readonly multiple?: boolean;\n}\n\ninterface TextareaControlProps {\n readonly id?: string;\n readonly name?: string;\n readonly form?: string;\n readonly defaultValue?: string;\n readonly 'aria-invalid'?: boolean;\n readonly 'aria-describedby'?: string;\n readonly 'aria-required'?: boolean;\n readonly required?: boolean;\n readonly minLength?: number;\n readonly maxLength?: number;\n readonly placeholder?: string;\n readonly rows?: number;\n readonly cols?: number;\n}\n\n/**\n * Narrow descriptor control props for the Input wrapper component.\n */\nexport function getInputProps(\n field: ControlPropSource,\n overrides?: JSX.InputHTMLAttributes,\n): InputControlProps {\n const props = field.controlProps(overrides ? { ...overrides } : undefined);\n\n return {\n id: readString(props.id),\n name: readString(props.name),\n form: readString(props.form),\n type: readInputType(props.type),\n defaultValue: readString(props.defaultValue),\n defaultChecked: readBoolean(props.defaultChecked),\n 'aria-invalid': readBoolean(props['aria-invalid']),\n 'aria-describedby': readString(props['aria-describedby']),\n 'aria-required': readBoolean(props['aria-required']),\n required: readBoolean(props.required),\n minLength: readNumber(props.minLength),\n maxLength: readNumber(props.maxLength),\n min: readNumberish(props.min),\n max: readNumberish(props.max),\n pattern: readString(props.pattern),\n step: readNumberish(props.step),\n multiple: readBoolean(props.multiple),\n placeholder: readString(props.placeholder),\n autocomplete: readString(props.autocomplete),\n };\n}\n\n/**\n * Narrow descriptor control props for the Select wrapper component.\n */\nexport function getSelectProps(\n field: ControlPropSource,\n overrides?: JSX.SelectHTMLAttributes,\n): SelectControlProps {\n const props = field.controlProps(overrides ? { ...overrides } : undefined);\n\n return {\n id: readString(props.id),\n name: readString(props.name),\n form: readString(props.form),\n defaultValue: readString(props.defaultValue),\n 'aria-invalid': readBoolean(props['aria-invalid']),\n 'aria-describedby': readString(props['aria-describedby']),\n 'aria-required': readBoolean(props['aria-required']),\n required: readBoolean(props.required),\n multiple: readBoolean(props.multiple),\n };\n}\n\n/**\n * Narrow descriptor control props for the Textarea wrapper component.\n */\nexport function getTextareaProps(\n field: ControlPropSource,\n overrides?: JSX.TextareaHTMLAttributes,\n): TextareaControlProps {\n const props = field.controlProps(overrides ? { ...overrides } : undefined);\n\n return {\n id: readString(props.id),\n name: readString(props.name),\n form: readString(props.form),\n defaultValue: readString(props.defaultValue),\n 'aria-invalid': readBoolean(props['aria-invalid']),\n 'aria-describedby': readString(props['aria-describedby']),\n 'aria-required': readBoolean(props['aria-required']),\n required: readBoolean(props.required),\n minLength: readNumber(props.minLength),\n maxLength: readNumber(props.maxLength),\n placeholder: readString(props.placeholder),\n rows: readNumber(props.rows),\n cols: readNumber(props.cols),\n };\n}\n\nfunction readBoolean(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction readInputType(value: unknown): JSX.HTMLInputTypeAttribute | undefined {\n return typeof value === 'string' ? value as JSX.HTMLInputTypeAttribute : undefined;\n}\n\nfunction readNumber(value: unknown): number | undefined {\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction readNumberish(value: unknown): number | string | undefined {\n return typeof value === 'number' || typeof value === 'string' ? value : undefined;\n}\n\nfunction readString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n"; const template_024 = - "import type { JSX, VNode } from 'preact';\nimport { Card } from './card.tsx';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface DataTableSectionProps\n extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n}\n\ninterface DataTableProps extends DataTableSectionProps {\n interactive?: boolean;\n}\n\ninterface DataTableRowProps extends DataTableSectionProps {\n /**\n * CSS `grid-template-columns` for this row's cells, e.g. `'2fr 1fr 1fr'` or\n * `'minmax(0, 1fr) auto'`. Without it the row is a single-column grid and\n * cells stack — pass the same template to header and body rows to align them.\n */\n cols?: string;\n}\n\ntype DataTableComponent = ((props: DataTableProps) => VNode) & {\n Header: (props: DataTableSectionProps) => VNode;\n Body: (props: DataTableSectionProps) => VNode;\n Row: (props: DataTableRowProps) => VNode;\n Footer: (props: DataTableSectionProps) => VNode;\n};\n\nfunction DataTableRoot({ children, class: className, ...props }: DataTableProps): VNode {\n return {children};\n}\n\nfunction DataTableHeader({ children, class: className, ...props }: DataTableSectionProps): VNode {\n return (\n \n {children}\n \n );\n}\n\nfunction DataTableBody({ children, class: className, ...props }: DataTableSectionProps): VNode {\n return
{children}
;\n}\n\nfunction DataTableRow(\n { children, class: className, cols, style, ...props }: DataTableRowProps,\n): VNode {\n const gridStyle = cols\n ? { ...(style && typeof style === 'object' ? style : null), gridTemplateColumns: cols }\n : style;\n return (\n
\n {children}\n
\n );\n}\n\nfunction DataTableFooter({ children, class: className, ...props }: DataTableSectionProps): VNode {\n return (\n \n {children}\n \n );\n}\n\n/**\n * Card-backed data table block with shared header, row, and footer seams.\n */\nexport const DataTable: DataTableComponent = Object.assign(DataTableRoot, {\n Header: DataTableHeader,\n Body: DataTableBody,\n Row: DataTableRow,\n Footer: DataTableFooter,\n});\n"; + '/* DataTable block styles. Host-agnostic: every layout rule the block needs\n lives here so it renders identically with or without a utility framework. */\n\n.ns-data-table {\n overflow: hidden;\n}\n\n/* Combines with .ns-card__header, which is a flex column for stacked\n title/description; reset the axis explicitly for the table header rail. */\n.ns-data-table__header {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: flex-end;\n justify-content: space-between;\n gap: var(--ns-space-3) var(--ns-space-4);\n}\n\n.ns-data-table__body > * + * {\n border-top: 1px solid var(--ns-border);\n}\n\n.ns-data-table__row {\n display: grid;\n align-items: center;\n gap: var(--ns-space-4);\n padding: var(--ns-space-4) var(--ns-space-5);\n}\n\n.ns-data-table__footer {\n border-top: 1px solid var(--ns-border);\n padding: var(--ns-space-4) var(--ns-space-5);\n}\n'; const template_025 = - "import type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface DetailLayoutSectionProps\n extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n}\n\ntype DetailLayoutComponent = ((props: DetailLayoutSectionProps) => VNode) & {\n Main: (props: DetailLayoutSectionProps) => VNode;\n Aside: (props: DetailLayoutSectionProps) => VNode;\n};\n\nfunction DetailLayoutRoot(\n { children, class: className, ...props }: DetailLayoutSectionProps,\n): VNode {\n return (\n \n {children}\n \n );\n}\n\nfunction DetailLayoutMain(\n { children, class: className, ...props }: DetailLayoutSectionProps,\n): VNode {\n return
{children}
;\n}\n\nfunction DetailLayoutAside(\n { children, class: className, ...props }: DetailLayoutSectionProps,\n): VNode {\n return
{children}
;\n}\n\n/**\n * Two-column detail-page layout with main and aside regions.\n */\nexport const DetailLayout: DetailLayoutComponent = Object.assign(DetailLayoutRoot, {\n Main: DetailLayoutMain,\n Aside: DetailLayoutAside,\n});\n"; + "import type { JSX, VNode } from 'preact';\nimport { Card } from './card.tsx';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface DataTableSectionProps\n extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n}\n\ninterface DataTableProps extends DataTableSectionProps {\n interactive?: boolean;\n}\n\ninterface DataTableRowProps extends DataTableSectionProps {\n /**\n * CSS `grid-template-columns` for this row's cells, e.g. `'2fr 1fr 1fr'` or\n * `'minmax(0, 1fr) auto'`. Without it the row is a single-column grid and\n * cells stack — pass the same template to header and body rows to align them.\n */\n cols?: string;\n}\n\ntype DataTableComponent = ((props: DataTableProps) => VNode) & {\n Header: (props: DataTableSectionProps) => VNode;\n Body: (props: DataTableSectionProps) => VNode;\n Row: (props: DataTableRowProps) => VNode;\n Footer: (props: DataTableSectionProps) => VNode;\n};\n\nfunction DataTableRoot({ children, class: className, ...props }: DataTableProps): VNode {\n return {children};\n}\n\nfunction DataTableHeader({ children, class: className, ...props }: DataTableSectionProps): VNode {\n return (\n \n {children}\n \n );\n}\n\nfunction DataTableBody({ children, class: className, ...props }: DataTableSectionProps): VNode {\n return
{children}
;\n}\n\nfunction DataTableRow(\n { children, class: className, cols, style, ...props }: DataTableRowProps,\n): VNode {\n const gridStyle = cols\n ? { ...(style && typeof style === 'object' ? style : null), gridTemplateColumns: cols }\n : style;\n return (\n
\n {children}\n
\n );\n}\n\nfunction DataTableFooter({ children, class: className, ...props }: DataTableSectionProps): VNode {\n return (\n
\n {children}\n
\n );\n}\n\n/**\n * Card-backed data table block with shared header, row, and footer seams.\n */\nexport const DataTable: DataTableComponent = Object.assign(DataTableRoot, {\n Header: DataTableHeader,\n Body: DataTableBody,\n Row: DataTableRow,\n Footer: DataTableFooter,\n});\n"; const template_026 = - ".ns-donut {\r\n display: grid;\r\n grid-template-columns: auto minmax(0, 1fr);\r\n grid-template-areas: 'chart legend';\r\n align-items: center;\r\n gap: var(--ns-space-4);\r\n}\r\n\r\n.ns-donut__svg {\r\n grid-area: chart;\r\n width: var(--ns-space-24);\r\n height: var(--ns-space-24);\r\n}\r\n\r\n.ns-donut__ring {\r\n stroke: var(--ns-primary);\r\n transition: stroke-dasharray var(--ns-ease-normal);\r\n}\r\n\r\n.ns-donut__ring[data-tone='success'] {\r\n stroke: var(--ns-success);\r\n}\r\n\r\n.ns-donut__ring[data-tone='warning'] {\r\n stroke: var(--ns-warning);\r\n}\r\n\r\n.ns-donut__ring[data-tone='secondary'] {\r\n stroke: var(--ns-secondary);\r\n}\r\n\r\n.ns-donut__ring[data-tone='destructive'] {\r\n stroke: var(--ns-destructive);\r\n}\r\n\r\n.ns-donut__center {\r\n grid-area: chart;\r\n place-self: center;\r\n font-family: var(--ns-font-mono);\r\n font-size: var(--ns-text-lg);\r\n font-weight: 600;\r\n color: var(--ns-fg);\r\n pointer-events: none;\r\n}\r\n\r\n.ns-donut__legend {\r\n grid-area: legend;\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--ns-space-1-5);\r\n margin: 0;\r\n padding: 0;\r\n list-style: none;\r\n}\r\n\r\n.ns-donut__row {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--ns-space-2);\r\n font-size: var(--ns-text-xs);\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-donut__swatch {\r\n flex-shrink: 0;\r\n width: var(--ns-space-2-5);\r\n height: var(--ns-space-2-5);\r\n border-radius: var(--ns-radius-sm);\r\n background: var(--ns-primary);\r\n}\r\n\r\n.ns-donut__swatch[data-tone='success'] {\r\n background: var(--ns-success);\r\n}\r\n\r\n.ns-donut__swatch[data-tone='warning'] {\r\n background: var(--ns-warning);\r\n}\r\n\r\n.ns-donut__swatch[data-tone='secondary'] {\r\n background: var(--ns-secondary);\r\n}\r\n\r\n.ns-donut__swatch[data-tone='destructive'] {\r\n background: var(--ns-destructive);\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n .ns-donut__ring {\r\n transition: none;\r\n }\r\n}\r\n"; + '/* DetailLayout block styles. */\n\n.ns-detail-layout {\n display: grid;\n gap: var(--ns-space-6);\n}\n\n@media (min-width: 80rem) {\n .ns-detail-layout {\n grid-template-columns: minmax(0, 1.45fr) 360px;\n align-items: start;\n }\n}\n\n.ns-detail-layout__main,\n.ns-detail-layout__aside {\n min-width: 0;\n}\n'; const template_027 = - "/**\n * @component Donut\n * @layer 2\n * @depends theme-seed\n * @description Token-driven donut/pie chart — SVG arc segments (stroke-dasharray)\n * with a center total and a legend. Segment colors come from data-tone or a\n * semantic-token cycle; never a hardcoded color.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\n\n/**\n * Semantic segment intent.\n */\nexport type DonutTone = 'primary' | 'success' | 'warning' | 'secondary' | 'destructive';\n\n/**\n * A single donut segment.\n */\nexport interface DonutDatum {\n label: string;\n value: number;\n tone?: DonutTone;\n}\n\ninterface DonutProps extends Omit, 'class'> {\n data: DonutDatum[];\n /** Override the center label (defaults to the sum). */\n total?: string | number;\n class?: string;\n}\n\nconst RADIUS = 42;\nconst CIRCUMFERENCE = 2 * Math.PI * RADIUS;\nconst CYCLE: DonutTone[] = ['primary', 'success', 'warning', 'secondary', 'destructive'];\n\n/**\n * Renders a donut chart with a center total and legend.\n */\nexport function Donut({ data, total, class: className, ...props }: DonutProps): VNode {\n const sum = data.reduce((acc, datum) => acc + datum.value, 0) || 1;\n let offset = 0;\n\n return (\n
\n \n
{total ?? sum}
\n
    \n {data.map((datum, index) => (\n
  • \n \n {datum.label}\n
  • \n ))}\n
\n
\n );\n}\n"; + "import type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface DetailLayoutSectionProps\n extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n}\n\ntype DetailLayoutComponent = ((props: DetailLayoutSectionProps) => VNode) & {\n Main: (props: DetailLayoutSectionProps) => VNode;\n Aside: (props: DetailLayoutSectionProps) => VNode;\n};\n\nfunction DetailLayoutRoot(\n { children, class: className, ...props }: DetailLayoutSectionProps,\n): VNode {\n return (\n
\n {children}\n
\n );\n}\n\nfunction DetailLayoutMain(\n { children, class: className, ...props }: DetailLayoutSectionProps,\n): VNode {\n return (\n
\n {children}\n
\n );\n}\n\nfunction DetailLayoutAside(\n { children, class: className, ...props }: DetailLayoutSectionProps,\n): VNode {\n return (\n
\n {children}\n
\n );\n}\n\n/**\n * Two-column detail-page layout with main and aside regions.\n */\nexport const DetailLayout: DetailLayoutComponent = Object.assign(DetailLayoutRoot, {\n Main: DetailLayoutMain,\n Aside: DetailLayoutAside,\n});\n"; const template_028 = - '.ns-dropzone {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n gap: var(--ns-space-2);\r\n padding: var(--ns-space-6);\r\n text-align: center;\r\n border: 1px dashed var(--ns-border-strong);\r\n border-radius: var(--ns-radius-lg);\r\n background: var(--ns-surface);\r\n color: var(--ns-muted-fg);\r\n cursor: pointer;\r\n transition: border-color var(--ns-ease-fast), background-color var(--ns-ease-fast);\r\n}\r\n\r\n.ns-dropzone:hover,\r\n.ns-dropzone[data-active] {\r\n border-color: var(--ns-primary);\r\n background: var(--ns-primary-subtle);\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-dropzone:focus-within {\r\n outline: 2px solid var(--ns-ring);\r\n outline-offset: 2px;\r\n}\r\n\r\n.ns-dropzone__icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--ns-space-9);\r\n height: var(--ns-space-9);\r\n border-radius: var(--ns-radius-full);\r\n background: var(--ns-muted);\r\n color: var(--ns-muted-fg);\r\n font-size: var(--ns-text-lg);\r\n}\r\n\r\n.ns-dropzone__label {\r\n font-size: var(--ns-text-sm);\r\n font-weight: 500;\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-dropzone__hint {\r\n font-size: var(--ns-text-2xs);\r\n color: var(--ns-muted-fg);\r\n}\r\n\r\n.ns-dropzone__input,\r\n.ns-dropzone__status {\r\n position: absolute;\r\n width: 1px;\r\n height: 1px;\r\n padding: 0;\r\n margin: -1px;\r\n overflow: hidden;\r\n clip: rect(0 0 0 0);\r\n white-space: nowrap;\r\n border: 0;\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n .ns-dropzone {\r\n transition: none;\r\n }\r\n}\r\n'; + ".ns-donut {\r\n display: grid;\r\n grid-template-columns: auto minmax(0, 1fr);\r\n grid-template-areas: 'chart legend';\r\n align-items: center;\r\n gap: var(--ns-space-4);\r\n}\r\n\r\n.ns-donut__svg {\r\n grid-area: chart;\r\n width: var(--ns-space-24);\r\n height: var(--ns-space-24);\r\n}\r\n\r\n.ns-donut__ring {\r\n stroke: var(--ns-primary);\r\n transition: stroke-dasharray var(--ns-ease-normal);\r\n}\r\n\r\n.ns-donut__ring[data-tone='success'] {\r\n stroke: var(--ns-success);\r\n}\r\n\r\n.ns-donut__ring[data-tone='warning'] {\r\n stroke: var(--ns-warning);\r\n}\r\n\r\n.ns-donut__ring[data-tone='secondary'] {\r\n stroke: var(--ns-secondary);\r\n}\r\n\r\n.ns-donut__ring[data-tone='destructive'] {\r\n stroke: var(--ns-destructive);\r\n}\r\n\r\n.ns-donut__center {\r\n grid-area: chart;\r\n place-self: center;\r\n font-family: var(--ns-font-mono);\r\n font-size: var(--ns-text-lg);\r\n font-weight: 600;\r\n color: var(--ns-fg);\r\n pointer-events: none;\r\n}\r\n\r\n.ns-donut__legend {\r\n grid-area: legend;\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--ns-space-1-5);\r\n margin: 0;\r\n padding: 0;\r\n list-style: none;\r\n}\r\n\r\n.ns-donut__row {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--ns-space-2);\r\n font-size: var(--ns-text-xs);\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-donut__swatch {\r\n flex-shrink: 0;\r\n width: var(--ns-space-2-5);\r\n height: var(--ns-space-2-5);\r\n border-radius: var(--ns-radius-sm);\r\n background: var(--ns-primary);\r\n}\r\n\r\n.ns-donut__swatch[data-tone='success'] {\r\n background: var(--ns-success);\r\n}\r\n\r\n.ns-donut__swatch[data-tone='warning'] {\r\n background: var(--ns-warning);\r\n}\r\n\r\n.ns-donut__swatch[data-tone='secondary'] {\r\n background: var(--ns-secondary);\r\n}\r\n\r\n.ns-donut__swatch[data-tone='destructive'] {\r\n background: var(--ns-destructive);\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n .ns-donut__ring {\r\n transition: none;\r\n }\r\n}\r\n"; const template_029 = - "/**\n * @component Dropzone\n * @layer 2\n * @depends theme-seed\n * @description File-drop affordance — a dashed drop target with icon, label,\n * hint, and reusable file ingest for drag-drop, focused paste, and picker input.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\nexport const DROPZONE_INGEST_SOURCES = ['drop', 'paste', 'picker'] as const;\nexport const DROPZONE_REJECTED_REASONS = ['type', 'too-many'] as const;\n\nexport type DropzoneIngestSource = typeof DROPZONE_INGEST_SOURCES[number];\nexport type DropzoneRejectedReason = typeof DROPZONE_REJECTED_REASONS[number];\n\nexport interface DropzoneRejectedFile {\n /** File that did not pass Dropzone ingest policy. */\n file: File;\n /** Why the file was rejected. */\n reason: DropzoneRejectedReason;\n /** Ingest source that supplied the file. */\n source: DropzoneIngestSource;\n}\n\nexport interface DropzoneIngestDetails {\n /** Files accepted after `accept` and `multiple` filtering. */\n acceptedFiles: readonly File[];\n /** Files rejected after `accept` and `multiple` filtering. */\n rejectedFiles: readonly DropzoneRejectedFile[];\n /** Ingest source that supplied the files. */\n source: DropzoneIngestSource;\n /** Original browser event. */\n event: Event;\n}\n\nexport interface DropzoneProps\n extends\n Omit, 'class' | 'onDrop' | 'onDragOver' | 'onPaste'> {\n /** Primary call-to-action text. */\n label?: string;\n /** Secondary hint (accepted types, size limits). */\n hint?: string;\n /** Leading glyph or icon node. */\n icon?: Renderable;\n /** Active (drag-over) state. */\n active?: boolean;\n /** Typically a visually-hidden . */\n children?: Renderable;\n /** Native accept string applied to drop, paste, and picker ingest. */\n accept?: string;\n /** Whether the dropzone accepts more than one file per ingest event. */\n multiple?: boolean;\n /** Called with the first accepted file for simple single-file consumers. */\n onFile?: (file: File, details: DropzoneIngestDetails) => void;\n /** Called with every accepted file from drop, paste, or picker ingest. */\n onFiles?: (files: readonly File[], details: DropzoneIngestDetails) => void;\n /** Called with every rejected file from drop, paste, or picker ingest. */\n onReject?: (files: readonly DropzoneRejectedFile[], details: DropzoneIngestDetails) => void;\n onDrop?: JSX.DragEventHandler;\n onDragOver?: JSX.DragEventHandler;\n onPaste?: JSX.ClipboardEventHandler;\n class?: string;\n}\n\nfunction filesFromList(list: FileList | readonly File[] | null | undefined): File[] {\n return list ? Array.from(list) : [];\n}\n\nfunction filesFromItems(items: DataTransferItemList | readonly DataTransferItem[] | null): File[] {\n if (!items) return [];\n return Array.from(items)\n .filter((item) => item.kind === 'file')\n .map((item) => item.getAsFile())\n .filter((file): file is File => Boolean(file));\n}\n\nfunction filesFromClipboard(data: DataTransfer | null | undefined): File[] {\n const files = filesFromList(data?.files);\n return files.length ? files : filesFromItems(data?.items ?? null);\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction matchesGlob(value: string, pattern: string): boolean {\n const source = pattern.split('*').map(escapeRegExp).join('.*');\n return new RegExp(`^${source}$`, 'i').test(value);\n}\n\nfunction acceptsFile(file: File, accept: string | undefined): boolean {\n const tokens = accept?.split(',').map((token) => token.trim()).filter(Boolean) ?? [];\n if (!tokens.length) return true;\n\n const fileName = file.name.toLowerCase();\n const mimeType = file.type.toLowerCase();\n\n return tokens.some((token) => {\n const normalized = token.toLowerCase();\n if (normalized.startsWith('.')) {\n return normalized.includes('*')\n ? matchesGlob(fileName, `*${normalized}`)\n : fileName.endsWith(normalized);\n }\n if (normalized.endsWith('/*')) {\n return mimeType.startsWith(normalized.slice(0, -1));\n }\n return normalized.includes('*') ? matchesGlob(mimeType, normalized) : mimeType === normalized;\n });\n}\n\nfunction filterFiles(\n files: readonly File[],\n accept: string | undefined,\n multiple: boolean,\n source: DropzoneIngestSource,\n): Pick {\n const acceptedByType: File[] = [];\n const rejectedFiles: DropzoneRejectedFile[] = [];\n\n for (const file of files) {\n if (acceptsFile(file, accept)) {\n acceptedByType.push(file);\n } else {\n rejectedFiles.push({ file, reason: 'type', source });\n }\n }\n\n if (multiple) return { acceptedFiles: acceptedByType, rejectedFiles };\n\n const [firstFile, ...extraFiles] = acceptedByType;\n rejectedFiles.push(...extraFiles.map((file) => ({ file, reason: 'too-many' as const, source })));\n return { acceptedFiles: firstFile ? [firstFile] : [], rejectedFiles };\n}\n\nfunction announceIngest(event: Event, details: DropzoneIngestDetails): void {\n if (typeof Element === 'undefined') return;\n\n const target = event.currentTarget instanceof Element\n ? event.currentTarget\n : event.target instanceof Element\n ? event.target\n : null;\n const host = target instanceof HTMLInputElement ? target.closest('.ns-dropzone') : target;\n const status = host?.querySelector('[data-dropzone-status]');\n if (!status) return;\n\n const acceptedCount = details.acceptedFiles.length;\n const rejectedCount = details.rejectedFiles.length;\n status.textContent = rejectedCount\n ? `${acceptedCount} file${acceptedCount === 1 ? '' : 's'} accepted, ${rejectedCount} rejected.`\n : `${acceptedCount} file${acceptedCount === 1 ? '' : 's'} accepted.`;\n}\n\n/**\n * Renders a file drop target with drag, focused paste, and picker ingest.\n */\nexport function Dropzone(\n {\n label = 'Drop files or click to upload',\n hint,\n icon,\n active,\n class: className,\n children,\n accept,\n multiple = false,\n onFile,\n onFiles,\n onReject,\n onDrop,\n onDragOver,\n onPaste,\n ...props\n }: DropzoneProps,\n): VNode {\n function ingestFiles(\n files: readonly File[],\n source: DropzoneIngestSource,\n event: Event,\n ): void {\n if (!files.length) return;\n const filtered = filterFiles(files, accept, multiple, source);\n const details: DropzoneIngestDetails = { ...filtered, source, event };\n announceIngest(event, details);\n if (details.acceptedFiles.length) {\n onFile?.(details.acceptedFiles[0], details);\n onFiles?.(details.acceptedFiles, details);\n }\n if (details.rejectedFiles.length) onReject?.(details.rejectedFiles, details);\n }\n\n function handleDragOver(event: JSX.TargetedEvent): void {\n event.preventDefault();\n onDragOver?.(event);\n }\n\n function handleDrop(event: JSX.TargetedEvent): void {\n event.preventDefault();\n ingestFiles(filesFromList(event.dataTransfer?.files), 'drop', event);\n onDrop?.(event);\n }\n\n function handlePaste(event: JSX.TargetedEvent): void {\n ingestFiles(filesFromClipboard(event.clipboardData), 'paste', event);\n onPaste?.(event);\n }\n\n function handlePickerChange(event: JSX.TargetedEvent): void {\n ingestFiles(filesFromList(event.currentTarget.files), 'picker', event);\n event.currentTarget.value = '';\n }\n\n return (\n \n \n {label}\n {hint ? {hint} : null}\n \n \n No files selected.\n \n {children}\n \n );\n}\n"; + "/**\n * @component Donut\n * @layer 2\n * @depends theme-seed\n * @description Token-driven donut/pie chart — SVG arc segments (stroke-dasharray)\n * with a center total and a legend. Segment colors come from data-tone or a\n * semantic-token cycle; never a hardcoded color.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\n\n/**\n * Semantic segment intent.\n */\nexport type DonutTone = 'primary' | 'success' | 'warning' | 'secondary' | 'destructive';\n\n/**\n * A single donut segment.\n */\nexport interface DonutDatum {\n label: string;\n value: number;\n tone?: DonutTone;\n}\n\ninterface DonutProps extends Omit, 'class'> {\n data: DonutDatum[];\n /** Override the center label (defaults to the sum). */\n total?: string | number;\n class?: string;\n}\n\nconst RADIUS = 42;\nconst CIRCUMFERENCE = 2 * Math.PI * RADIUS;\nconst CYCLE: DonutTone[] = ['primary', 'success', 'warning', 'secondary', 'destructive'];\n\n/**\n * Renders a donut chart with a center total and legend.\n */\nexport function Donut({ data, total, class: className, ...props }: DonutProps): VNode {\n const sum = data.reduce((acc, datum) => acc + datum.value, 0) || 1;\n let offset = 0;\n\n return (\n
\n \n
{total ?? sum}
\n
    \n {data.map((datum, index) => (\n
  • \n \n {datum.label}\n
  • \n ))}\n
\n
\n );\n}\n"; const template_030 = - "import type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface EmptyStateProps extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n heading?: Renderable;\n}\n\n/**\n * Renders a muted empty-state callout for lists, rails, and dashboards.\n */\nexport function EmptyState(\n { children, class: className, heading, ...props }: EmptyStateProps,\n): VNode {\n return (\n \n {heading &&

{heading}

}\n
{children}
\n \n );\n}\n"; + '.ns-dropzone {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n gap: var(--ns-space-2);\r\n padding: var(--ns-space-6);\r\n text-align: center;\r\n border: 1px dashed var(--ns-border-strong);\r\n border-radius: var(--ns-radius-lg);\r\n background: var(--ns-surface);\r\n color: var(--ns-muted-fg);\r\n cursor: pointer;\r\n transition: border-color var(--ns-ease-fast), background-color var(--ns-ease-fast);\r\n}\r\n\r\n.ns-dropzone:hover,\r\n.ns-dropzone[data-active] {\r\n border-color: var(--ns-primary);\r\n background: var(--ns-primary-subtle);\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-dropzone:focus-within {\r\n outline: 2px solid var(--ns-ring);\r\n outline-offset: 2px;\r\n}\r\n\r\n.ns-dropzone__icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--ns-space-9);\r\n height: var(--ns-space-9);\r\n border-radius: var(--ns-radius-full);\r\n background: var(--ns-muted);\r\n color: var(--ns-muted-fg);\r\n font-size: var(--ns-text-lg);\r\n}\r\n\r\n.ns-dropzone__label {\r\n font-size: var(--ns-text-sm);\r\n font-weight: 500;\r\n color: var(--ns-fg);\r\n}\r\n\r\n.ns-dropzone__hint {\r\n font-size: var(--ns-text-2xs);\r\n color: var(--ns-muted-fg);\r\n}\r\n\r\n.ns-dropzone__input,\r\n.ns-dropzone__status {\r\n position: absolute;\r\n width: 1px;\r\n height: 1px;\r\n padding: 0;\r\n margin: -1px;\r\n overflow: hidden;\r\n clip: rect(0 0 0 0);\r\n white-space: nowrap;\r\n border: 0;\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n .ns-dropzone {\r\n transition: none;\r\n }\r\n}\r\n'; const template_031 = - "import type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface FilterFormProps {\n children: Renderable;\n class?: string;\n action?: string;\n method?: string;\n id?: string;\n ['f-client-nav']?: boolean;\n}\n\ninterface FilterFormSectionProps\n extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n}\n\ntype FilterFormComponent = ((props: FilterFormProps) => VNode) & {\n Body: (props: FilterFormSectionProps) => VNode;\n Actions: (props: FilterFormSectionProps) => VNode;\n};\n\nfunction FilterFormRoot({ children, class: className, ...props }: FilterFormProps): VNode {\n return
{children}
;\n}\n\nfunction FilterFormBody({ children, class: className, ...props }: FilterFormSectionProps): VNode {\n return
{children}
;\n}\n\nfunction FilterFormActions(\n { children, class: className, ...props }: FilterFormSectionProps,\n): VNode {\n return (\n
\n {children}\n
\n );\n}\n\n/**\n * Card-backed filter form with body and action regions.\n */\nexport const FilterForm: FilterFormComponent = Object.assign(FilterFormRoot, {\n Body: FilterFormBody,\n Actions: FilterFormActions,\n});\n"; + "/**\n * @component Dropzone\n * @layer 2\n * @depends theme-seed\n * @description File-drop affordance — a dashed drop target with icon, label,\n * hint, and reusable file ingest for drag-drop, focused paste, and picker input.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\nexport const DROPZONE_INGEST_SOURCES = ['drop', 'paste', 'picker'] as const;\nexport const DROPZONE_REJECTED_REASONS = ['type', 'too-many'] as const;\n\nexport type DropzoneIngestSource = typeof DROPZONE_INGEST_SOURCES[number];\nexport type DropzoneRejectedReason = typeof DROPZONE_REJECTED_REASONS[number];\n\nexport interface DropzoneRejectedFile {\n /** File that did not pass Dropzone ingest policy. */\n file: File;\n /** Why the file was rejected. */\n reason: DropzoneRejectedReason;\n /** Ingest source that supplied the file. */\n source: DropzoneIngestSource;\n}\n\nexport interface DropzoneIngestDetails {\n /** Files accepted after `accept` and `multiple` filtering. */\n acceptedFiles: readonly File[];\n /** Files rejected after `accept` and `multiple` filtering. */\n rejectedFiles: readonly DropzoneRejectedFile[];\n /** Ingest source that supplied the files. */\n source: DropzoneIngestSource;\n /** Original browser event. */\n event: Event;\n}\n\nexport interface DropzoneProps\n extends\n Omit, 'class' | 'onDrop' | 'onDragOver' | 'onPaste'> {\n /** Primary call-to-action text. */\n label?: string;\n /** Secondary hint (accepted types, size limits). */\n hint?: string;\n /** Leading glyph or icon node. */\n icon?: Renderable;\n /** Active (drag-over) state. */\n active?: boolean;\n /** Typically a visually-hidden . */\n children?: Renderable;\n /** Native accept string applied to drop, paste, and picker ingest. */\n accept?: string;\n /** Whether the dropzone accepts more than one file per ingest event. */\n multiple?: boolean;\n /** Called with the first accepted file for simple single-file consumers. */\n onFile?: (file: File, details: DropzoneIngestDetails) => void;\n /** Called with every accepted file from drop, paste, or picker ingest. */\n onFiles?: (files: readonly File[], details: DropzoneIngestDetails) => void;\n /** Called with every rejected file from drop, paste, or picker ingest. */\n onReject?: (files: readonly DropzoneRejectedFile[], details: DropzoneIngestDetails) => void;\n onDrop?: JSX.DragEventHandler;\n onDragOver?: JSX.DragEventHandler;\n onPaste?: JSX.ClipboardEventHandler;\n class?: string;\n}\n\nfunction filesFromList(list: FileList | readonly File[] | null | undefined): File[] {\n return list ? Array.from(list) : [];\n}\n\nfunction filesFromItems(items: DataTransferItemList | readonly DataTransferItem[] | null): File[] {\n if (!items) return [];\n return Array.from(items)\n .filter((item) => item.kind === 'file')\n .map((item) => item.getAsFile())\n .filter((file): file is File => Boolean(file));\n}\n\nfunction filesFromClipboard(data: DataTransfer | null | undefined): File[] {\n const files = filesFromList(data?.files);\n return files.length ? files : filesFromItems(data?.items ?? null);\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction matchesGlob(value: string, pattern: string): boolean {\n const source = pattern.split('*').map(escapeRegExp).join('.*');\n return new RegExp(`^${source}$`, 'i').test(value);\n}\n\nfunction acceptsFile(file: File, accept: string | undefined): boolean {\n const tokens = accept?.split(',').map((token) => token.trim()).filter(Boolean) ?? [];\n if (!tokens.length) return true;\n\n const fileName = file.name.toLowerCase();\n const mimeType = file.type.toLowerCase();\n\n return tokens.some((token) => {\n const normalized = token.toLowerCase();\n if (normalized.startsWith('.')) {\n return normalized.includes('*')\n ? matchesGlob(fileName, `*${normalized}`)\n : fileName.endsWith(normalized);\n }\n if (normalized.endsWith('/*')) {\n return mimeType.startsWith(normalized.slice(0, -1));\n }\n return normalized.includes('*') ? matchesGlob(mimeType, normalized) : mimeType === normalized;\n });\n}\n\nfunction filterFiles(\n files: readonly File[],\n accept: string | undefined,\n multiple: boolean,\n source: DropzoneIngestSource,\n): Pick {\n const acceptedByType: File[] = [];\n const rejectedFiles: DropzoneRejectedFile[] = [];\n\n for (const file of files) {\n if (acceptsFile(file, accept)) {\n acceptedByType.push(file);\n } else {\n rejectedFiles.push({ file, reason: 'type', source });\n }\n }\n\n if (multiple) return { acceptedFiles: acceptedByType, rejectedFiles };\n\n const [firstFile, ...extraFiles] = acceptedByType;\n rejectedFiles.push(...extraFiles.map((file) => ({ file, reason: 'too-many' as const, source })));\n return { acceptedFiles: firstFile ? [firstFile] : [], rejectedFiles };\n}\n\nfunction announceIngest(event: Event, details: DropzoneIngestDetails): void {\n if (typeof Element === 'undefined') return;\n\n const target = event.currentTarget instanceof Element\n ? event.currentTarget\n : event.target instanceof Element\n ? event.target\n : null;\n const host = target instanceof HTMLInputElement ? target.closest('.ns-dropzone') : target;\n const status = host?.querySelector('[data-dropzone-status]');\n if (!status) return;\n\n const acceptedCount = details.acceptedFiles.length;\n const rejectedCount = details.rejectedFiles.length;\n status.textContent = rejectedCount\n ? `${acceptedCount} file${acceptedCount === 1 ? '' : 's'} accepted, ${rejectedCount} rejected.`\n : `${acceptedCount} file${acceptedCount === 1 ? '' : 's'} accepted.`;\n}\n\n/**\n * Renders a file drop target with drag, focused paste, and picker ingest.\n */\nexport function Dropzone(\n {\n label = 'Drop files or click to upload',\n hint,\n icon,\n active,\n class: className,\n children,\n accept,\n multiple = false,\n onFile,\n onFiles,\n onReject,\n onDrop,\n onDragOver,\n onPaste,\n ...props\n }: DropzoneProps,\n): VNode {\n function ingestFiles(\n files: readonly File[],\n source: DropzoneIngestSource,\n event: Event,\n ): void {\n if (!files.length) return;\n const filtered = filterFiles(files, accept, multiple, source);\n const details: DropzoneIngestDetails = { ...filtered, source, event };\n announceIngest(event, details);\n if (details.acceptedFiles.length) {\n onFile?.(details.acceptedFiles[0], details);\n onFiles?.(details.acceptedFiles, details);\n }\n if (details.rejectedFiles.length) onReject?.(details.rejectedFiles, details);\n }\n\n function handleDragOver(event: JSX.TargetedEvent): void {\n event.preventDefault();\n onDragOver?.(event);\n }\n\n function handleDrop(event: JSX.TargetedEvent): void {\n event.preventDefault();\n ingestFiles(filesFromList(event.dataTransfer?.files), 'drop', event);\n onDrop?.(event);\n }\n\n function handlePaste(event: JSX.TargetedEvent): void {\n ingestFiles(filesFromClipboard(event.clipboardData), 'paste', event);\n onPaste?.(event);\n }\n\n function handlePickerChange(event: JSX.TargetedEvent): void {\n ingestFiles(filesFromList(event.currentTarget.files), 'picker', event);\n event.currentTarget.value = '';\n }\n\n return (\n \n \n {label}\n {hint ? {hint} : null}\n \n \n No files selected.\n \n {children}\n \n );\n}\n"; const template_032 = - ":where(\r\n [data-scope='popover'][data-part='content'],\r\n [data-scope='tooltip'][data-part='content']\r\n) {\r\n position: fixed;\r\n inset: var(\r\n --ns-floating-fallback-inset,\r\n var(--ns-space-4) auto auto var(--ns-space-4)\r\n );\r\n z-index: var(--ns-z-dropdown);\r\n margin: 0;\r\n}\r\n\r\n:where(\r\n [data-scope='popover'][data-part='content'],\r\n [data-scope='tooltip'][data-part='content']\r\n)[data-state='closed'] {\r\n display: none;\r\n}\r\n\r\n:where(\r\n [data-scope='popover'][data-part='content'],\r\n [data-scope='tooltip'][data-part='content']\r\n):popover-open {\r\n display: block;\r\n}\r\n\r\n@supports (anchor-name: --ns-floating-anchor) and (position-area: bottom) {\r\n :where(\r\n [data-scope='popover'][data-part='trigger'],\r\n [data-scope='popover'][data-part='anchor'],\r\n [data-scope='tooltip'][data-part='trigger']\r\n ) {\r\n anchor-name: var(--ns-floating-anchor-name);\r\n }\r\n\r\n :where(\r\n [data-scope='popover'][data-part='content'],\r\n [data-scope='tooltip'][data-part='content']\r\n ) {\r\n inset: auto;\r\n position-anchor: var(--ns-floating-anchor-name);\r\n position-area: var(--ns-floating-position-area, bottom);\r\n }\r\n}\r\n"; + '/* EmptyState block styles. */\n\n.ns-empty-state {\n border: 1px dashed var(--ns-border);\n border-radius: var(--ns-radius-md);\n padding: var(--ns-space-4);\n font-size: var(--ns-text-sm);\n color: var(--ns-muted-fg);\n}\n\n.ns-empty-state__heading {\n font-weight: 600;\n color: var(--ns-fg);\n}\n'; const template_033 = - '.ns-input,\r\n.ns-select,\r\n.ns-textarea {\r\n width: 100%;\r\n font-family: var(--ns-font-sans);\r\n font-size: var(--ns-text-sm);\r\n color: var(--ns-fg);\r\n background: var(--ns-surface);\r\n border: 1px solid var(--ns-input-border);\r\n border-radius: var(--ns-radius-md);\r\n padding: var(--ns-space-2) var(--ns-space-3);\r\n transition: border-color var(--ns-ease-normal), box-shadow var(--ns-ease-normal);\r\n}\r\n\r\n.ns-input::placeholder,\r\n.ns-textarea::placeholder {\r\n color: var(--ns-muted-fg);\r\n}\r\n\r\n.ns-input:hover,\r\n.ns-select:hover,\r\n.ns-textarea:hover {\r\n border-color: var(--ns-border-hover);\r\n}\r\n\r\n.ns-input:focus,\r\n.ns-select:focus,\r\n.ns-textarea:focus {\r\n outline: none;\r\n border-color: var(--ns-ring);\r\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--ns-ring) 15%, transparent);\r\n}\r\n\r\n.ns-input--error,\r\n.ns-select--error,\r\n.ns-textarea--error {\r\n border-color: var(--ns-destructive);\r\n}\r\n\r\n.ns-input--error:focus,\r\n.ns-select--error:focus,\r\n.ns-textarea--error:focus {\r\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--ns-destructive) 15%, transparent);\r\n}\r\n'; + "import type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface EmptyStateProps extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n heading?: Renderable;\n}\n\n/**\n * Renders a muted empty-state callout for lists, rails, and dashboards.\n */\nexport function EmptyState(\n { children, class: className, heading, ...props }: EmptyStateProps,\n): VNode {\n return (\n \n {heading &&

{heading}

}\n
{children}
\n \n );\n}\n"; const template_034 = - '.ns-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--ns-space-1);\r\n}\r\n\r\n.ns-help-text {\r\n font-size: var(--ns-text-xs);\r\n color: var(--ns-muted-fg);\r\n margin-top: var(--ns-space-1);\r\n}\r\n\r\n.ns-error-text {\r\n font-size: var(--ns-text-xs);\r\n color: var(--ns-destructive);\r\n margin-top: var(--ns-space-1);\r\n}\r\n\r\n.ns-field__error-row {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: var(--ns-space-1-5);\r\n}\r\n'; + '/* FilterForm block styles. Combines with .ns-card / .ns-card__body. */\n\n.ns-filter-form__body {\n display: grid;\n gap: var(--ns-space-4);\n}\n\n.ns-filter-form__actions {\n display: flex;\n align-items: flex-end;\n gap: var(--ns-space-2);\n}\n\n@media (min-width: 80rem) {\n .ns-filter-form__actions {\n justify-content: flex-end;\n }\n}\n'; const template_035 = - "/**\n * @component FormField\n * @layer 2\n * @depends Label\n * @description Composed field wrapper for labels, help text, and error messaging.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\nimport { Label } from './label.tsx';\n\ninterface FormFieldProps extends Omit, 'children' | 'class'> {\n label: Renderable;\n name: string;\n required?: boolean;\n error?: string;\n helpText?: string;\n class?: string;\n children: Renderable;\n}\n\n/**\n * Renders a labeled form field wrapper with help and error messaging.\n */\nexport function FormField({\n label,\n name,\n required = false,\n error,\n helpText,\n class: className,\n children,\n ...props\n}: FormFieldProps): VNode {\n return (\n
\n \n {children}\n {error\n ? (\n
\n \n

{error}

\n
\n )\n : helpText\n ?

{helpText}

\n : null}\n
\n );\n}\n"; + "import type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface FilterFormProps {\n children: Renderable;\n class?: string;\n action?: string;\n method?: string;\n id?: string;\n ['f-client-nav']?: boolean;\n}\n\ninterface FilterFormSectionProps\n extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n}\n\ntype FilterFormComponent = ((props: FilterFormProps) => VNode) & {\n Body: (props: FilterFormSectionProps) => VNode;\n Actions: (props: FilterFormSectionProps) => VNode;\n};\n\nfunction FilterFormRoot({ children, class: className, ...props }: FilterFormProps): VNode {\n return
{children}
;\n}\n\nfunction FilterFormBody({ children, class: className, ...props }: FilterFormSectionProps): VNode {\n return (\n
{children}
\n );\n}\n\nfunction FilterFormActions(\n { children, class: className, ...props }: FilterFormSectionProps,\n): VNode {\n return (\n
\n {children}\n
\n );\n}\n\n/**\n * Card-backed filter form with body and action regions.\n */\nexport const FilterForm: FilterFormComponent = Object.assign(FilterFormRoot, {\n Body: FilterFormBody,\n Actions: FilterFormActions,\n});\n"; const template_036 = - "/**\n * @component IconButton\n * @layer 2\n * @depends theme-seed, button\n * @description Compact icon-only action button with accessible labeling.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { Button, type ButtonVariant } from './button.tsx';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface SharedIconButtonProps {\n class?: string;\n disabled?: boolean;\n icon: Renderable;\n label: string;\n loading?: boolean;\n variant?: ButtonVariant;\n}\n\ntype IconButtonElementType = 'button' | 'submit' | 'reset';\n\ntype IconButtonAsButtonProps =\n & SharedIconButtonProps\n & Omit<\n JSX.ButtonHTMLAttributes,\n 'children' | 'class' | 'type'\n >\n & {\n type?: IconButtonElementType;\n href?: never;\n clientNav?: never;\n };\n\ntype IconButtonAsLinkProps =\n & SharedIconButtonProps\n & Omit<\n JSX.AnchorHTMLAttributes,\n 'children' | 'class' | 'href' | 'type'\n >\n & {\n type: 'link';\n href: string;\n clientNav?: boolean;\n };\n\ntype IconButtonProps = IconButtonAsButtonProps | IconButtonAsLinkProps;\n\n/**\n * Renders an icon-only action control with an accessible label.\n */\nexport function IconButton({ icon, label, ...props }: IconButtonProps): VNode {\n return (\n \n );\n}\n"; + ":where(\r\n [data-scope='popover'][data-part='content'],\r\n [data-scope='tooltip'][data-part='content']\r\n) {\r\n position: fixed;\r\n inset: var(\r\n --ns-floating-fallback-inset,\r\n var(--ns-space-4) auto auto var(--ns-space-4)\r\n );\r\n z-index: var(--ns-z-dropdown);\r\n margin: 0;\r\n}\r\n\r\n:where(\r\n [data-scope='popover'][data-part='content'],\r\n [data-scope='tooltip'][data-part='content']\r\n)[data-state='closed'] {\r\n display: none;\r\n}\r\n\r\n:where(\r\n [data-scope='popover'][data-part='content'],\r\n [data-scope='tooltip'][data-part='content']\r\n):popover-open {\r\n display: block;\r\n}\r\n\r\n@supports (anchor-name: --ns-floating-anchor) and (position-area: bottom) {\r\n :where(\r\n [data-scope='popover'][data-part='trigger'],\r\n [data-scope='popover'][data-part='anchor'],\r\n [data-scope='tooltip'][data-part='trigger']\r\n ) {\r\n anchor-name: var(--ns-floating-anchor-name);\r\n }\r\n\r\n :where(\r\n [data-scope='popover'][data-part='content'],\r\n [data-scope='tooltip'][data-part='content']\r\n ) {\r\n inset: auto;\r\n position-anchor: var(--ns-floating-anchor-name);\r\n position-area: var(--ns-floating-position-area, bottom);\r\n }\r\n}\r\n"; const template_037 = - '.ns-inline-notice {\r\n border-radius: var(--ns-radius-md);\r\n padding: var(--ns-space-3) var(--ns-space-4);\r\n background: color-mix(in srgb, var(--ns-surface) 92%, transparent);\r\n}\r\n'; + '.ns-input,\r\n.ns-select,\r\n.ns-textarea {\r\n width: 100%;\r\n font-family: var(--ns-font-sans);\r\n font-size: var(--ns-text-sm);\r\n color: var(--ns-fg);\r\n background: var(--ns-card);\r\n border: 1px solid var(--ns-input-border);\r\n border-radius: var(--ns-radius-md);\r\n padding: var(--ns-space-2) var(--ns-space-3);\r\n transition: border-color var(--ns-ease-normal), box-shadow var(--ns-ease-normal);\r\n}\r\n\r\n.ns-input::placeholder,\r\n.ns-textarea::placeholder {\r\n color: var(--ns-muted-fg);\r\n}\r\n\r\n.ns-input:hover,\r\n.ns-select:hover,\r\n.ns-textarea:hover {\r\n border-color: var(--ns-border-hover);\r\n}\r\n\r\n.ns-input:focus,\r\n.ns-select:focus,\r\n.ns-textarea:focus {\r\n outline: none;\r\n border-color: var(--ns-ring);\r\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--ns-ring) 15%, transparent);\r\n}\r\n\r\n/* Disabled: sunken muted fill, quiet text, no hover/focus affordances.\r\n Declared after :hover so the specificity tie resolves to disabled. */\r\n.ns-input:disabled,\r\n.ns-select:disabled,\r\n.ns-textarea:disabled {\r\n color: var(--ns-muted-fg);\r\n background: var(--ns-muted);\r\n border-color: var(--ns-border);\r\n box-shadow: none;\r\n cursor: not-allowed;\r\n}\r\n\r\n.ns-input--error,\r\n.ns-select--error,\r\n.ns-textarea--error {\r\n border-color: var(--ns-destructive);\r\n}\r\n\r\n.ns-input--error:focus,\r\n.ns-select--error:focus,\r\n.ns-textarea--error:focus {\r\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--ns-destructive) 15%, transparent);\r\n}\r\n'; const template_038 = - "/**\n * @component InlineNotice\n * @layer 2\n * @depends theme-seed\n * @description Compact contextual notice for inline guidance inside forms, panels, and cards.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\n/**\n * Visual variants for the inline notice block.\n */\nexport type InlineNoticeVariant = 'info' | 'success' | 'warning' | 'destructive';\n\ntype InlineNoticeProps = Omit, 'class' | 'children'> & {\n children?: Renderable;\n class?: string;\n icon?: Renderable;\n title?: Renderable;\n variant?: InlineNoticeVariant;\n};\n\nconst DEFAULT_ICONS: Record = {\n info: '⊕',\n success: '◎',\n warning: '⟳',\n destructive: '≠',\n};\n\n/**\n * Renders compact contextual guidance within cards, forms, and panels.\n */\nexport function InlineNotice(\n { children, class: className, icon, role = 'status', title, variant = 'info', ...props }:\n InlineNoticeProps,\n): VNode {\n return (\n \n \n
\n {title ?
{title}
: null}\n {children ?
{children}
: null}\n
\n \n );\n}\n"; + '.ns-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--ns-space-1);\r\n}\r\n\r\n.ns-help-text {\r\n font-size: var(--ns-text-xs);\r\n color: var(--ns-muted-fg);\r\n margin-top: var(--ns-space-1);\r\n}\r\n\r\n.ns-error-text {\r\n font-size: var(--ns-text-xs);\r\n color: var(--ns-destructive);\r\n margin-top: var(--ns-space-1);\r\n}\r\n\r\n.ns-field__error-row {\r\n display: flex;\r\n align-items: baseline;\r\n gap: var(--ns-space-1-5);\r\n margin-top: var(--ns-space-1);\r\n}\r\n\r\n.ns-field__error-row .ns-error-text {\r\n margin-top: 0;\r\n}\r\n\r\n.ns-field__error-icon {\r\n font-family: var(--ns-font-mono);\r\n font-size: var(--ns-text-xs);\r\n color: var(--ns-destructive);\r\n}\r\n'; const template_039 = - "/**\n * @component Input\n * @layer 2\n * @depends theme-seed\n * @description Generic text input with semantic token-driven states.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\n\ninterface InputProps extends Omit, 'type' | 'class'> {\n type?: JSX.HTMLInputTypeAttribute;\n class?: string;\n error?: boolean;\n readonly [key: `data-${string}`]: string | number | boolean | undefined;\n}\n\n/**\n * Renders a token-aware text input.\n */\nexport function Input(\n { type = 'text', class: className, error = false, ...props }: InputProps,\n): VNode {\n return (\n \n );\n}\n"; + "/**\n * @component FormField\n * @layer 2\n * @depends Label\n * @description Composed field wrapper for labels, help text, and error messaging.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\nimport { Label } from './label.tsx';\n\ninterface FormFieldProps extends Omit, 'children' | 'class'> {\n label: Renderable;\n name: string;\n required?: boolean;\n error?: string;\n helpText?: string;\n class?: string;\n children: Renderable;\n}\n\n/**\n * Renders a labeled form field wrapper with help and error messaging.\n */\nexport function FormField({\n label,\n name,\n required = false,\n error,\n helpText,\n class: className,\n children,\n ...props\n}: FormFieldProps): VNode {\n return (\n
\n \n {children}\n {error\n ? (\n
\n \n

{error}

\n
\n )\n : helpText\n ?

{helpText}

\n : null}\n
\n );\n}\n"; const template_040 = - ".ns-label {\r\n display: block;\r\n font-size: var(--ns-text-sm);\r\n font-weight: 500;\r\n color: var(--ns-fg);\r\n margin-bottom: var(--ns-space-1);\r\n}\r\n\r\n.ns-label--required::after {\r\n content: ' *';\r\n color: var(--ns-destructive);\r\n}\r\n"; + "/**\n * @component IconButton\n * @layer 2\n * @depends theme-seed, button\n * @description Compact icon-only action button with accessible labeling.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { Button, type ButtonVariant } from './button.tsx';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface SharedIconButtonProps {\n class?: string;\n disabled?: boolean;\n icon: Renderable;\n label: string;\n loading?: boolean;\n variant?: ButtonVariant;\n}\n\ntype IconButtonElementType = 'button' | 'submit' | 'reset';\n\ntype IconButtonAsButtonProps =\n & SharedIconButtonProps\n & Omit<\n JSX.ButtonHTMLAttributes,\n 'children' | 'class' | 'type'\n >\n & {\n type?: IconButtonElementType;\n href?: never;\n clientNav?: never;\n };\n\ntype IconButtonAsLinkProps =\n & SharedIconButtonProps\n & Omit<\n JSX.AnchorHTMLAttributes,\n 'children' | 'class' | 'href' | 'type'\n >\n & {\n type: 'link';\n href: string;\n clientNav?: boolean;\n };\n\ntype IconButtonProps = IconButtonAsButtonProps | IconButtonAsLinkProps;\n\n/**\n * Renders an icon-only action control with an accessible label.\n */\nexport function IconButton({ icon, label, ...props }: IconButtonProps): VNode {\n return (\n \n );\n}\n"; const template_041 = - "/**\n * @component Label\n * @layer 2\n * @depends theme-seed\n * @description Accessible form label with optional required-state styling.\n */\n\nimport type { JSX, VNode } from 'preact';\nimport { cn } from '../../lib/cn.ts';\nimport type { Renderable } from '../../lib/public-types.ts';\n\ninterface LabelProps extends Omit, 'class' | 'children'> {\n children: Renderable;\n class?: string;\n required?: boolean;\n srOnly?: boolean;\n}\n\n/**\n * Renders a field label with optional required and screen-reader-only states.\n */\nexport function Label({\n children,\n class: className,\n required = false,\n srOnly = false,\n ...props\n}: LabelProps): VNode {\n return (\n \n {children}\n \n );\n}\n"; + '.ns-inline-notice {\r\n border-radius: var(--ns-radius-md);\r\n padding: var(--ns-space-3) var(--ns-space-4);\r\n background: color-mix(in srgb, var(--ns-surface) 92%, transparent);\r\n}\r\n'; const template_042 = - "/**\n * @module\n * @support markdown-pipeline\n * @layer 3\n * @depends citation-chip\n * @description Pure, dependency-free helpers behind the copy-based `markdown`\n * registry item: the `remarkCitations` mdast transform, the `stripIncompleteSyntax`\n * mid-stream guard, and `extendSanitizeSchema` — the whitelist that keeps the\n * MANDATORY `rehype-sanitize` pass safe while still allowing citation chips,\n * KaTeX math markup, and highlight.js class output.\n *\n * This module imports NO npm packages on purpose: it carries the load-bearing,\n * security-relevant logic so it can be type-checked, published, and unit-tested\n * inside `@netscript/fresh-ui` without pulling `react-markdown` (or any of the\n * remark/rehype plugins) into the package's own import graph. The `markdown.tsx`\n * component wires these helpers into `react-markdown`; the npm dependencies live\n * only on the registry item and only land in the consuming app.\n */\n\n/** Custom element name emitted for a recognized citation token. */\nexport const CITATION_ELEMENT = 'citation-chip';\n\n/**\n * Citation token recognized in model output: a bracketed 1–3 digit index such\n * as `[1]`, matching the grounded-agent `[n]` convention shared with `message`.\n */\nexport const CITATION_PATTERN: RegExp = /\\[(\\d{1,3})\\]/g;\n\n/**\n * KaTeX (via `rehype-katex`) emits MathML/HTML elements that the default\n * sanitize schema would strip. These tag names are re-allowed so the sanitize\n * pass can run LAST without erasing rendered math.\n */\nexport const KATEX_TAG_NAMES: readonly string[] = [\n 'math',\n 'semantics',\n 'annotation',\n 'mrow',\n 'mi',\n 'mo',\n 'mn',\n 'ms',\n 'mtext',\n 'mspace',\n 'msup',\n 'msub',\n 'msubsup',\n 'mfrac',\n 'msqrt',\n 'mroot',\n 'munder',\n 'mover',\n 'munderover',\n 'mtable',\n 'mtr',\n 'mtd',\n 'mpadded',\n 'mphantom',\n 'menclose',\n 'mstyle',\n];\n\n/** Minimal mdast node shape touched by {@link remarkCitations}. */\nexport interface MdastNode {\n /** Node type (e.g. `text`, `paragraph`, `root`, or a custom citation type). */\n type: string;\n /** Literal text value, present on `text` nodes. */\n value?: string;\n /** Child nodes, present on parent nodes. */\n children?: MdastNode[];\n /** hast hints used by `mdast-util-to-hast` to emit a custom element. */\n data?: { hName?: string; hProperties?: Record };\n}\n\n/** Minimal mdast root shape passed to the transformer. */\nexport interface MdastRoot extends MdastNode {\n /** Root nodes are always of type `root`. */\n type: 'root';\n /** Top-level block children of the document. */\n children: MdastNode[];\n}\n\n/** A unified transformer over an mdast tree. */\nexport type MdastTransformer = (tree: MdastRoot) => void;\n\n/**\n * Minimal `rehype-sanitize` schema shape. Kept structural so this module never\n * imports `rehype-sanitize`; the component passes the plugin's real\n * `defaultSchema` at call time.\n */\nexport interface SanitizeSchema {\n /** Allowed tag names. */\n tagNames?: string[];\n /** Allowed attributes, keyed by tag name (or `*` for all elements). */\n attributes?: Record;\n /** Other schema fields passed through untouched (e.g. `protocols`, `clobber`). */\n [key: string]: unknown;\n}\n\n/**\n * Splits a text node on citation tokens, replacing each `[n]` with a node that\n * renders as a `` element (via `data.hName`).\n * @param node - The mdast `text` node to scan.\n * @returns The original node, or the split sequence of text + citation nodes.\n */\nfunction splitTextNode(node: MdastNode): MdastNode[] {\n const value = node.value ?? '';\n CITATION_PATTERN.lastIndex = 0;\n if (!CITATION_PATTERN.test(value)) return [node];\n\n CITATION_PATTERN.lastIndex = 0;\n const out: MdastNode[] = [];\n let last = 0;\n let match: RegExpExecArray | null;\n while ((match = CITATION_PATTERN.exec(value)) !== null) {\n if (match.index > last) {\n out.push({ type: 'text', value: value.slice(last, match.index) });\n }\n const index = Number(match[1]);\n out.push({\n type: 'citationReference',\n data: { hName: CITATION_ELEMENT, hProperties: { index } },\n children: [{ type: 'text', value: match[1] }],\n });\n last = match.index + match[0].length;\n }\n if (last < value.length) out.push({ type: 'text', value: value.slice(last) });\n return out;\n}\n\n/**\n * Recursively rewrites citation tokens within a node's children.\n * @param node - The parent node whose children are scanned.\n */\nfunction visit(node: MdastNode): void {\n if (!node.children) return;\n const next: MdastNode[] = [];\n for (const child of node.children) {\n if (child.type === 'text') {\n next.push(...splitTextNode(child));\n } else {\n visit(child);\n next.push(child);\n }\n }\n node.children = next;\n}\n\n/**\n * A remark plugin that rewrites `[n]` citation tokens in model output into\n * `citation-chip` render calls. Pair with `components={{ 'citation-chip': ... }}`\n * on `react-markdown` to render the sibling `citation-chip` registry item.\n * @returns The mdast transformer.\n * @example\n * ```ts\n * import { remarkCitations } from './markdown-pipeline.ts';\n * const transform = remarkCitations();\n * transform({ type: 'root', children: [] });\n * ```\n */\nexport function remarkCitations(): MdastTransformer {\n return (tree: MdastRoot): void => {\n visit(tree);\n };\n}\n\n/**\n * Counts non-overlapping occurrences of a marker in text.\n * @param text - The text to scan.\n * @param marker - The literal marker to count.\n * @returns The occurrence count.\n */\nfunction countMarker(text: string, marker: string): number {\n let count = 0;\n let index = text.indexOf(marker);\n while (index !== -1) {\n count += 1;\n index = text.indexOf(marker, index + marker.length);\n }\n return count;\n}\n\n/**\n * Pre-processes a possibly-truncated mid-stream markdown chunk so partial GFM /\n * math syntax renders meaningfully instead of leaking raw markers. Unterminated\n * fenced code blocks, inline code spans, bold runs, and math are closed, and a\n * dangling incomplete link/image at the tail is dropped. Complete input is\n * returned effectively unchanged.\n * @param chunk - The (possibly partial) markdown source.\n * @returns The repaired markdown source, safe to feed to the renderer.\n * @example\n * ```ts\n * stripIncompleteSyntax('Here is **bold'); // -> 'Here is **bold**'\n * ```\n */\nexport function stripIncompleteSyntax(chunk: string): string {\n let text = chunk;\n\n // 1) Close an unterminated fenced code block (odd number of ``` fences).\n if (countMarker(text, '```') % 2 === 1) {\n if (!text.endsWith('\\n')) text += '\\n';\n text += '```';\n }\n\n // Mask now-balanced fenced blocks so inline scanning ignores code content.\n const masked = text.replace(/```[\\s\\S]*?```/g, '');\n\n // 2) Close an unterminated inline code span.\n if (countMarker(masked, '`') % 2 === 1) text += '`';\n\n // 3) Close an unterminated bold/strong run.\n if (countMarker(masked, '**') % 2 === 1) text += '**';\n\n // 4) Close unterminated block math, else unterminated inline math.\n if (countMarker(masked, '$$') % 2 === 1) {\n text += '$$';\n } else if (countMarker(masked.replace(/\\$\\$/g, ''), '$') % 2 === 1) {\n text += '$';\n }\n\n // 5) Drop a dangling incomplete link/image at the very end.\n text = text\n .replace(/!?\\[[^\\]]*\\]\\([^)]*$/, '')\n .replace(/!?\\[[^\\]]*$/, '');\n\n return text;\n}\n\n/**\n * Extends a base `rehype-sanitize` schema so the MANDATORY final sanitize pass\n * keeps citation chips, KaTeX math markup, and highlight.js class output while\n * still stripping anything dangerous. `script` is force-removed from the allowed\n * tag set and no event-handler attribute is ever added, so model-authored\n * ` + + + + + + + + + + +
+
+ +
+
+
+ + +
+
+ + + local + my-app + aspire + + + +
+
+
+ + +
+
+
+
+

Wiring home

+

Is my app wired the way I declared it — and where do I jump to fix it. Facts only NetScript can compute; everything else hands off.

+
+
+ +
+
+
+ live + · + {{ clock }} + · + launched by netscript dev · Aspire ⇄ this dashboard via its NetScript Dashboard resource URL +
+
+ +
+
AI summary plugin-ai
+
{{ s1Ai.text }}
+
+ + + +
+
{{ s1Ai.meta }}
+
+ +
+ +
+ {{ k.label }} + {{ k.value }}{{ k.delta }} + +
+
+
+ +
+
+ execution outcomes · 24h + 91.2% completed5.6% retried3.2% failed +
+ +
+ +
+ + + +
+ +
+ just happened + + + +
+ +
+
+
+
+ Command palette + Primary navigation — press ⌘K anywhere +
+ +
+
+ + + +
+
+ +
+
+ Contributed panels + The dashboard is itself a plugin — panels arrive through DashboardPanelContribution +
+
+
+ pluginpanelmount target +
+ +
+ {{ p.plugin }} + {{ p.panel }} + {{ p.mount }} +
+
+
+
+
+
+
+ + +
+
+
+
+

Config resolution

+

Declared intent vs. running reality — capability wiring only. Aspire owns the resource graph; every node here jumps into it.

+
+ +
+
+
+ +
+
+ Capability wiring — select a node + + resolved {{ clock }} · re-resolves on netscript dev reload + +
+
+
+ + + + +
+
+
+
+
+
+ + + +
+
+
+
+

Runtime config

+

The live override layer neither Aspire nor Scalar can know exists — streamed as it changes, with gated controls to flip it back.

+
+
+
+ +
+ +
+
{{ st.label }}
+
{{ st.value }}
+
+
+
+ +
+
+
+
+ Live override feed +
+ + + + sse + +
+
+
+
+ +
+ +
+ {{ f.text }} + {{ f.time }} +
+
+
+
+
+
+ +
+
+ Version history +
+ + + +
+
+
+
+ +
+ {{ v.v }} +
+
{{ v.title }} + current +
+ {{ v.meta }} + +
{{ v.v }}.jsonjson
{{ v.json }}
+
+ +
+ + {{ d.text }} + +
+
+ +
+
+
+
+
+
+
+ + +
+
+
+ + + +
+
+
+
+

Service & contract catalog

+

Provenance and coverage above the OpenAPI boundary — what Scalar cannot see. Reference and try-it stay in Scalar.

+
+ {{ s4Summary.thin }} + {{ s4Summary.unbound }} +
+
+
+ + +
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
ProcedureProvenanceMethodCoverageDuality
{{ c.proc }}{{ c.plugin }} › {{ c.ns }}{{ c.method }}{{ c.covLabel }}{{ d.label }}
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + +
Page routeBindingAuthoring formModule / hint
{{ r.route }}{{ r.status }}{{ r.form }}{{ r.target }}
+
+
+
+
+
+
+
+ + + +
+
+
+
+

Plugin control

+

Fleet-level wiring nothing else shows — the dashboard is itself a plugin arriving through the same seam.

+
+
+
+
+ +
+
+
+
+ {{ s5.name }} + {{ s5.status }} + {{ s5.ver }} + + + + +
+
+ +
CLI equivalentsh
{{ s5.cli }}
+
+
+ Contribution axes +
+ + + +
+ Wired axes deep-link to the screen they touch. +
+
+ Doctor checks +
+ +
+ + {{ d.probe }} + {{ d.result }} +
+
+
+
+ +
+ +
+ Version drift + {{ s5.driftText }} +
{{ s5.updateCli }}
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+

Run inspector

+

A run — saga instance, job attempt sequence, trigger firing, stream delivery — is a NetScript primitive Aspire has no vocabulary for.

+
+ +
+
+
+ +
+
+
+ {{ s6.name }} + {{ s6.status }} + {{ s6.meta }} + +
+ + + +
+
+
+
+ correlation + {{ s6.corr }} + · joins trigger event ↔ saga ↔ executions via listExecutionsByCorrelationId +
+
inputjson
{{ s6.input }}
+ +
run.jsonjson
{{ s6.json }}
+
+ +
+ +
+ +
+
{{ st.n }}{{ st.title }} + compensation + attempt {{ st.attempts }} +
+
{{ st.meta }}
+ +
+ payload +
{{ st.io }}
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+

Workers

+

Aspire proves the process is up; only NetScript knows which job ran, retried twice, and failed on attempt 2 of 3.

+
+ + {{ st.value }}{{ st.label }} + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
Job & task registry — job = compiled Deno unit · task = polyglot unit (runtime from entrypoint)
NameKind · runtimeScheduleLast statusTrend 24h
{{ j.name }}{{ j.kind }}{{ j.rt }}{{ j.sched }}{{ j.human }}{{ j.last }}
+
+
+ +
+
+ Scheduler vs. config drift + Live scheduler.list() diffed against declared definitions — the uniquely-NetScript payload +
+
+
+ +
+ + {{ d.probe }} + {{ d.result }} + + + +
+
+
+
+
+ +
+
+ Worker pools — who is consuming + The classic silent bug: nothing polling the queue. Invisible to Aspire’s process view. +
+
+
+ +
+ + {{ p.probe }} + {{ p.result }} +
+
+
+
+
+ +
+
+ Workflow etl.daily-sync +
+
+
+ +
+ +
+
{{ st.n }}{{ st.title }} + attempt {{ st.attempts }} +
+
{{ st.meta }}
+
+
+
+
+
+
+
+ + +
+
+
+ + + +
+
+
+
+

Sagas

+

COMPENSATING is a status no other tool has a concept of — the saga state machine, rendered.

+
+
+
+
+ +
+
+
+ {{ s8.saga }} {{ s8.id }} + {{ s8.status }} + {{ s8.tier }} + + + +
+
+
+ {{ s8.summary }} +
+
history stream · {{ s8.history }}
+
+ +
+ +
+
{{ st.n }}{{ st.title }} + compensation + attempt {{ st.attempts }} +
+
{{ st.meta }}
+ +
+ payload +
{{ st.io }}
+
+
+
+
+
+
+
+ linked executions · listExecutionsByCorrelationId + +
+
+ Future: “Replay saga step N” arrives via Aspire withCommand — surfaced in Aspire’s Actions menu, not here. +
+
+
+
+ +
+
+
+ + + +
+
+
+
+

Triggers

+

When does this cron actually fire next given tz + backfill — and silence a misbehaving trigger without redeploy.

+
+ next fires · nightly-reconcile + 02:00 · 02:00 · 02:00 + next 3 days · America/New_York · backfill on — computed from declared cron, nobody else does this +
+
+
+
+
+
+
+
+ Event history — each event is its own action chain +
+ + + + sse + +
+
+
+
+ +
+ +
+ + +
+ +
+ + {{ a.type }} + {{ a.detail }} + · {{ a.dur }} + + + +
+
+
+
+
+
+
+
+
+ +
+ +
+
+ Schedule preview cron.nightly-reconcile · 0 2 * * * + Next 5 fires · tz America/New_York · backfill honored +
+
+
+ +
+ + {{ p.probe }} + {{ p.result }} +
+
+
+
+
+
+ + +
+
+
+ + + +
+
+
+
+

Streams

+

Which subscribers received this message, and how many delivery attempts each took — invisible to Aspire and Scalar.

+
+
+
+
+ + Streams telemetry: instrumentation registered — delivery read-model lands with the streams contract. Panels below degrade to a “not yet wired” state where it is absent. +
+
+ +
+
+
+ Fan-out · {{ s10SelId }} {{ s10Verdict }} + corr {{ s10Corr }} + + + +
+
+
+ +
+ +
+
{{ st.n }}{{ st.title }} + attempt {{ st.attempts }} +
+
{{ st.meta }}
+ +
+ payload +
{{ st.io }}
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+

DB migrations & drift

+

Aspire shows the DB resource is up; it never shows migration state — a frequent “why is my query failing” root cause.

+
+
+ + + + +
+
+
+
+
+ +
+ +
+ Schema drift detected on table orders + column status type mismatch — introspect diff below. Applying the pending migration resolves it. +
+
+
+ +
+ + Schema in sync — no drift, nothing pending. +
+
+
+
+ + + + + + + + + + + + + + + + + + +
Prisma migration status
MigrationApplied atStatus
{{ r.name }}{{ r.at }}{{ r.status }}
+
+
+
+ +
+
+
+ + + +
+
+
+
+

Dead-letter queues

+

Why did messages die across KV / Redis / Postgres — depth, reason, and gated bulk replay.

+
+
+ + +
+
+
+ +
+ Preview — contract routes pending + DLQ inspection ships behind two thin API slices: a TriggerDlqPort contract route and a queue DeadLetterStore API. This surface renders fully once they land; below is the target design against sample data. +
+ +
+ +
+
{{ d.label }} depth
+
{{ d.value }}
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
{{ s12Caption }}
MessageSourceReasonError codeDead at
+
+ {{ r.id }} ▾ +
{{ r.payload }}
+
+
{{ r.src }}{{ r.reason }}{{ r.code }}{{ r.at }}
+
+ +
+
+
+ + + +
+
+
+
+

Live flow

+

Follow one request through the whole stack — API call → contract → job → saga steps → stream fan-out — as one causal chain with the payload at every seam. Raw timing lives in Aspire.

+
+
+
+ flow assembled by correlation join — boundary events land in beta.7 +
+
+
+ +
+
+
+ {{ s13FlowName }} + {{ s13FlowId }} · {{ s13FlowTime }} + + +
+
+
+ +
+ +
+ +
+ payload at seam +
{{ nd.payload }}
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+

AI agents

+

Agentic workflow traceability — every agent run, every tool call, joined to the same correlation spine as jobs and sagas. Raw GenAI telemetry stays in Aspire.

+
+ + {{ st.value }}{{ st.label }} + +
+
+ +
+
+ +
+ + + +
+ +
+ + +
+
+
+ {{ ai14.agent }} · {{ ai14.id }} + {{ ai14.status }} + {{ ai14.model }} +
+
+ +
+ +
user
+
{{ t.text }}
+
+ +
+ + + {{ t.name }} + tool call · {{ t.dur }} + +
+ input +
{{ t.input }}
+ + output +
{{ t.output }}
+
+
+
+
+ +
assistant
+
{{ t.text }}
+
+
+
+ +
+
assistant + ··· +
+
+
+
+
+
+ + +
+
+
+ + +
+
+
+
+

Auth sessions

+

The session projection from plugin-auth-core’s durable stream — live auth.* events, no provider console needed for local dev.

+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
Active sessions · AuthSessionSchema projection
UserProviderStateStartedLast event
{{ a.user }}{{ a.provider }}{{ a.state }}{{ a.started }}{{ a.last }}
+
+
+ +
+
+
+ + + +
+
+
+ + +
+
+ + + esc +
+
+
+ +
Commands
+
+ +
+ + {{ c.label }} + {{ c.kind }} +
+
+ +
No matching command
+
+
+
+
+
+ + +
+ {{ sheetTitle }} + + +
+ +
+ {{ s2Sel.covLabel }} +
+
backend{{ s2Sel.backend }}
+
mode{{ s2Sel.mode }}
+
contributed by{{ s2Sel.plugin }}
+
coverage{{ s2Sel.covNote }}
+
+
+ + + +
+
+
+ +
+
+
primitive{{ s13Detail.prim }}
+
status{{ s13Detail.status }}
+
plugin owner{{ s13Detail.owner }}
+
queue / topic{{ s13Detail.queue }}
+
correlation id{{ s13Detail.corr }}
+
trace{{ s13Detail.trace }}
+
+
+ + + + +
+
+
+
+ + +
+
{{ confirmTitle }} beta.6 preview · applies to local mock
+
{{ confirmDesc }}
+
+ {{ confirmFrom }} + + {{ confirmTo }} +
+
+ CLI equivalent +
{{ confirmCli }}
+
+
+
+ + +
+
+ + +
{{ toastMsg }}
+
+ + + + + diff --git a/.llm/runs/dashboard-design--orchestrator/prototype/_ds/netscript-ns-one-ec262e10-d4ad-451f-9aeb-e51955db3634/_ds_bundle.js b/.llm/runs/dashboard-design--orchestrator/prototype/_ds/netscript-ns-one-ec262e10-d4ad-451f-9aeb-e51955db3634/_ds_bundle.js new file mode 100644 index 000000000..eec2e720c --- /dev/null +++ b/.llm/runs/dashboard-design--orchestrator/prototype/_ds/netscript-ns-one-ec262e10-d4ad-451f-9aeb-e51955db3634/_ds_bundle.js @@ -0,0 +1,3020 @@ +/* @ds-bundle: {"format":4,"namespace":"NetScriptNSOne_ec262e","components":[{"name":"Breadcrumb","sourcePath":"components/blocks/Breadcrumb/Breadcrumb.tsx"},{"name":"DataTable","sourcePath":"components/blocks/DataTable/DataTable.tsx"},{"name":"DetailLayout","sourcePath":"components/blocks/DetailLayout/DetailLayout.tsx"},{"name":"EmptyState","sourcePath":"components/blocks/EmptyState/EmptyState.tsx"},{"name":"FilterForm","sourcePath":"components/blocks/FilterForm/FilterForm.tsx"},{"name":"PageHeader","sourcePath":"components/blocks/PageHeader/PageHeader.tsx"},{"name":"Pagination","sourcePath":"components/blocks/Pagination/Pagination.tsx"},{"name":"ResponsiveTable","sourcePath":"components/blocks/ResponsiveTable/ResponsiveTable.tsx"},{"name":"SectionDivider","sourcePath":"components/blocks/SectionDivider/SectionDivider.tsx"},{"name":"SidebarShell","sourcePath":"components/blocks/SidebarShell/SidebarShell.tsx"},{"name":"StatsGrid","sourcePath":"components/blocks/StatsGrid/StatsGrid.tsx"},{"name":"Alert","sourcePath":"components/general/Alert/Alert.tsx"},{"name":"Avatar","sourcePath":"components/general/Avatar/Avatar.tsx"},{"name":"Badge","sourcePath":"components/general/Badge/Badge.tsx"},{"name":"Button","sourcePath":"components/general/Button/Button.tsx"},{"name":"Card","sourcePath":"components/general/Card/Card.tsx"},{"name":"ChartBlock","sourcePath":"components/general/ChartBlock/ChartBlock.tsx"},{"name":"Checkbox","sourcePath":"components/general/Checkbox/Checkbox.tsx"},{"name":"CitationChip","sourcePath":"components/general/CitationChip/CitationChip.tsx"},{"name":"CodeBlock","sourcePath":"components/general/CodeBlock/CodeBlock.tsx"},{"name":"CommandPalette","sourcePath":"components/general/CommandPalette/CommandPalette.tsx"},{"name":"Donut","sourcePath":"components/general/Donut/Donut.tsx"},{"name":"DROPZONE_INGEST_SOURCES","sourcePath":"components/general/Dropzone/Dropzone.tsx"},{"name":"DROPZONE_REJECTED_REASONS","sourcePath":"components/general/Dropzone/Dropzone.tsx"},{"name":"Dropzone","sourcePath":"components/general/Dropzone/Dropzone.tsx"},{"name":"FormField","sourcePath":"components/general/FormField/FormField.tsx"},{"name":"IconButton","sourcePath":"components/general/IconButton/IconButton.tsx"},{"name":"InlineNotice","sourcePath":"components/general/InlineNotice/InlineNotice.tsx"},{"name":"Input","sourcePath":"components/general/Input/Input.tsx"},{"name":"Label","sourcePath":"components/general/Label/Label.tsx"},{"name":"TypingIndicator","sourcePath":"components/general/Message/Message.tsx"},{"name":"Message","sourcePath":"components/general/Message/Message.tsx"},{"name":"ModelSelector","sourcePath":"components/general/ModelSelector/ModelSelector.tsx"},{"name":"PanelHeader","sourcePath":"components/general/Panel/Panel.tsx"},{"name":"PanelTitle","sourcePath":"components/general/Panel/Panel.tsx"},{"name":"PanelDescription","sourcePath":"components/general/Panel/Panel.tsx"},{"name":"PanelBody","sourcePath":"components/general/Panel/Panel.tsx"},{"name":"PanelFooter","sourcePath":"components/general/Panel/Panel.tsx"},{"name":"Panel","sourcePath":"components/general/Panel/Panel.tsx"},{"name":"Progress","sourcePath":"components/general/Progress/Progress.tsx"},{"name":"PromptInput","sourcePath":"components/general/PromptInput/PromptInput.tsx"},{"name":"Search","sourcePath":"components/general/Search/Search.tsx"},{"name":"Select","sourcePath":"components/general/Select/Select.tsx"},{"name":"Separator","sourcePath":"components/general/Separator/Separator.tsx"},{"name":"Skeleton","sourcePath":"components/general/Skeleton/Skeleton.tsx"},{"name":"Spinner","sourcePath":"components/general/Spinner/Spinner.tsx"},{"name":"Switch","sourcePath":"components/general/Switch/Switch.tsx"},{"name":"Textarea","sourcePath":"components/general/Textarea/Textarea.tsx"},{"name":"ToolCallCard","sourcePath":"components/general/ToolCallCard/ToolCallCard.tsx"},{"name":"SidebarToggle","sourcePath":"components/islands/SidebarToggle/SidebarToggle.tsx"},{"name":"ThemeToggle","sourcePath":"components/islands/ThemeToggle/ThemeToggle.tsx"},{"name":"Toast","sourcePath":"components/islands/Toast/Toast.tsx"}],"sourceHashes":{"components/blocks/Breadcrumb/Breadcrumb.tsx":"fc10678f5223","components/blocks/DataTable/DataTable.tsx":"cf9952d45bee","components/blocks/DetailLayout/DetailLayout.tsx":"300f0d40633c","components/blocks/EmptyState/EmptyState.tsx":"19909ccd6cad","components/blocks/FilterForm/FilterForm.tsx":"5386bbeb80d6","components/blocks/PageHeader/PageHeader.tsx":"631dd9e01a78","components/blocks/Pagination/Pagination.tsx":"ff2641e7cb82","components/blocks/ResponsiveTable/ResponsiveTable.tsx":"83f87caf33c9","components/blocks/SectionDivider/SectionDivider.tsx":"3b50c31b404f","components/blocks/SidebarShell/SidebarShell.tsx":"fa55af89a70f","components/blocks/StatsGrid/StatsGrid.tsx":"8140be1630d4","components/general/Alert/Alert.tsx":"c506a6868c09","components/general/Avatar/Avatar.tsx":"bd1f06c0ce34","components/general/Badge/Badge.tsx":"8f0d612f4dd7","components/general/Button/Button.tsx":"83b722510682","components/general/Card/Card.tsx":"adddb77512b4","components/general/ChartBlock/ChartBlock.tsx":"dd9321f3699a","components/general/Checkbox/Checkbox.tsx":"b20d0a685f11","components/general/CitationChip/CitationChip.tsx":"93f98a2736e7","components/general/CodeBlock/CodeBlock.tsx":"858cbccd020f","components/general/CommandPalette/CommandPalette.tsx":"8d874ef42770","components/general/Donut/Donut.tsx":"cf97bd5f9a0c","components/general/Dropzone/Dropzone.tsx":"726ec8a63d46","components/general/FormField/FormField.tsx":"c043014a72b4","components/general/IconButton/IconButton.tsx":"e21ac98ad473","components/general/InlineNotice/InlineNotice.tsx":"461156cb2ed4","components/general/Input/Input.tsx":"aa681e1a0c81","components/general/Label/Label.tsx":"ff69864ed1da","components/general/Message/Message.tsx":"aa8826628d8a","components/general/ModelSelector/ModelSelector.tsx":"db54f2199077","components/general/Panel/Panel.tsx":"a9b5a034b2f0","components/general/Progress/Progress.tsx":"05b96185d266","components/general/PromptInput/PromptInput.tsx":"9baf14aa1ac8","components/general/Search/Search.tsx":"20bb4c874fb1","components/general/Select/Select.tsx":"004feab540ac","components/general/Separator/Separator.tsx":"6f2d25cb261c","components/general/Skeleton/Skeleton.tsx":"0f98a17bdd4f","components/general/Spinner/Spinner.tsx":"51bcd3db0d40","components/general/Switch/Switch.tsx":"25464f867af0","components/general/Textarea/Textarea.tsx":"f2adf85bf5db","components/general/ToolCallCard/ToolCallCard.tsx":"1933c65939a2","components/islands/SidebarToggle/SidebarToggle.tsx":"b4489a77d255","components/islands/ThemeToggle/ThemeToggle.tsx":"a9d019c63a29","components/islands/Toast/Toast.tsx":"5fe86b8005cf"},"inlinedExternals":[],"unexposedExports":[{"name":"renderInline","sourcePath":"components/general/Message/Message.tsx"}]} */ + +(() => { + +const __ds_ns = (window.NetScriptNSOne_ec262e = window.NetScriptNSOne_ec262e || {}); + +const __ds_scope = {}; + +(__ds_ns.__errors = __ds_ns.__errors || []); + +// components/blocks/Breadcrumb/Breadcrumb.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * Breadcrumb step metadata for route context navigation. + */ + +/** + * Renders an accessible breadcrumb trail. + */ +function Breadcrumb({ + items, + class: className, + ...props +}) { + if (items.length === 0) return null; + return /*#__PURE__*/React.createElement("nav", _extends({}, props, { + "aria-label": "Breadcrumb", + class: __ds_scope.cn('ns-breadcrumb', className) + }), /*#__PURE__*/React.createElement("ol", { + class: "ns-breadcrumb", + role: "list" + }, items.map((item, index) => { + const isLast = index === items.length - 1; + return /*#__PURE__*/React.createElement("li", { + key: `${item.label}-${index}`, + class: "ns-breadcrumb__item" + }, index > 0 && /*#__PURE__*/React.createElement("span", { + class: "ns-breadcrumb__separator", + "aria-hidden": "true" + }, "/"), isLast ? /*#__PURE__*/React.createElement("span", { + class: "ns-breadcrumb__current", + "aria-current": "page" + }, item.icon && /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true" + }, item.icon), item.label) : item.href ? /*#__PURE__*/React.createElement("a", { + href: item.href, + class: "ns-breadcrumb__link" + }, item.icon && /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true" + }, item.icon), item.label) : /*#__PURE__*/React.createElement("span", { + class: "ns-breadcrumb__link" + }, item.icon && /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true" + }, item.icon), item.label)); + }))); +} +Object.assign(__ds_scope, { Breadcrumb }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/Breadcrumb/Breadcrumb.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/DataTable/DataTable.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +function DataTableRoot({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement(__ds_scope.Card, _extends({}, props, { + class: __ds_scope.cn('overflow-hidden', className) + }), children); +} +function DataTableHeader({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement(__ds_scope.Card.Header, _extends({}, props, { + class: __ds_scope.cn('flex-col items-start gap-3 sm:flex-row sm:items-end sm:justify-between', className) + }), children); +} +function DataTableBody({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('divide-y divide-ns-border', className) + }), children); +} +function DataTableRow({ + children, + class: className, + cols, + style, + ...props +}) { + const gridStyle = cols ? { + ...(style && typeof style === 'object' ? style : null), + gridTemplateColumns: cols + } : style; + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + style: gridStyle, + class: __ds_scope.cn('grid gap-4 px-5 py-4', className) + }), children); +} +function DataTableFooter({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('border-t border-ns-border px-5 py-4', className) + }), children); +} + +/** + * Card-backed data table block with shared header, row, and footer seams. + */ +const DataTable = Object.assign(DataTableRoot, { + Header: DataTableHeader, + Body: DataTableBody, + Row: DataTableRow, + Footer: DataTableFooter +}); +Object.assign(__ds_scope, { DataTable }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/DataTable/DataTable.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/DetailLayout/DetailLayout.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +function DetailLayoutRoot({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('grid gap-6 xl:grid-cols-[minmax(0,1.45fr)_360px]', className) + }), children); +} +function DetailLayoutMain({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-stack ns-stack--md', className) + }), children); +} +function DetailLayoutAside({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-stack ns-stack--md', className) + }), children); +} + +/** + * Two-column detail-page layout with main and aside regions. + */ +const DetailLayout = Object.assign(DetailLayoutRoot, { + Main: DetailLayoutMain, + Aside: DetailLayoutAside +}); +Object.assign(__ds_scope, { DetailLayout }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/DetailLayout/DetailLayout.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/EmptyState/EmptyState.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * Renders a muted empty-state callout for lists, rails, and dashboards. + */ +function EmptyState({ + children, + class: className, + heading, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('rounded-md border border-dashed border-ns-border px-4 py-4 text-sm text-ns-muted-fg', heading ? 'ns-stack ns-stack--xs' : undefined, className) + }), heading && /*#__PURE__*/React.createElement("p", { + class: "font-semibold text-ns-fg" + }, heading), /*#__PURE__*/React.createElement("div", null, children)); +} +Object.assign(__ds_scope, { EmptyState }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/EmptyState/EmptyState.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/FilterForm/FilterForm.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +function FilterFormRoot({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("form", _extends({}, props, { + class: __ds_scope.cn('ns-card', className) + }), children); +} +function FilterFormBody({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-card__body grid gap-4', className) + }), children); +} +function FilterFormActions({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('flex items-end gap-2 xl:justify-end', className) + }), children); +} + +/** + * Card-backed filter form with body and action regions. + */ +const FilterForm = Object.assign(FilterFormRoot, { + Body: FilterFormBody, + Actions: FilterFormActions +}); +Object.assign(__ds_scope, { FilterForm }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/FilterForm/FilterForm.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/PageHeader/PageHeader.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +function PageHeaderRoot({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-page-header', className) + }), children); +} +function PageHeaderLayout({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('grid gap-6 xl:grid-cols-[minmax(0,1.4fr)_360px] xl:items-start', className) + }), children); +} +function PageHeaderMain({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-stack ns-stack--md min-w-0', className) + }), children); +} +function PageHeaderAside({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-stack ns-stack--md', className) + }), children); +} +function PageHeaderBadges({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-cluster', className) + }), children); +} +function PageHeaderIntro({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-stack ns-stack--sm min-w-0', className) + }), children); +} +function PageHeaderActions({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-cluster', className) + }), children); +} +function PageHeaderStatus({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-status-bar flex-wrap', className) + }), children); +} + +/** + * Page header block with layout, intro, badges, actions, and status regions. + */ +const PageHeader = Object.assign(PageHeaderRoot, { + Layout: PageHeaderLayout, + Main: PageHeaderMain, + Aside: PageHeaderAside, + Badges: PageHeaderBadges, + Intro: PageHeaderIntro, + Actions: PageHeaderActions, + Status: PageHeaderStatus +}); +Object.assign(__ds_scope, { PageHeader }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/PageHeader/PageHeader.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/Pagination/Pagination.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +function PaginationRoot({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('flex items-center justify-between gap-3', className) + }), children); +} +function PaginationMeta({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('text-sm text-ns-muted-fg', className) + }), children); +} +function PaginationActions({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-cluster ns-cluster--sm', className) + }), children); +} + +/** + * Pagination meta/actions block for list and table navigation. + */ +const Pagination = Object.assign(PaginationRoot, { + Meta: PaginationMeta, + Actions: PaginationActions +}); +Object.assign(__ds_scope, { Pagination }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/Pagination/Pagination.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/ResponsiveTable/ResponsiveTable.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * Layer-3 data table block that keeps table semantics on wide screens and + * presents row cards with generated cell labels on compact screens. + */ +function ResponsiveTable({ + columns, + rows, + getRowKey, + caption, + emptyState = 'No records to display.', + summary, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-responsive-table', className), + "data-empty": rows.length === 0 ? 'true' : undefined + }), /*#__PURE__*/React.createElement("div", { + class: "ns-responsive-table__scroller" + }, /*#__PURE__*/React.createElement("table", { + class: "ns-responsive-table__table" + }, caption && /*#__PURE__*/React.createElement("caption", { + class: "ns-responsive-table__caption" + }, caption), /*#__PURE__*/React.createElement("thead", { + class: "ns-responsive-table__head" + }, /*#__PURE__*/React.createElement("tr", { + class: "ns-responsive-table__row ns-responsive-table__row--head" + }, columns.map(column => /*#__PURE__*/React.createElement("th", { + key: column.key, + class: __ds_scope.cn('ns-responsive-table__header', column.headerClass), + "data-align": column.align ?? 'start', + scope: "col" + }, column.header ?? column.label)))), /*#__PURE__*/React.createElement("tbody", { + class: "ns-responsive-table__body" + }, rows.length === 0 ? /*#__PURE__*/React.createElement("tr", { + class: "ns-responsive-table__row" + }, /*#__PURE__*/React.createElement("td", { + class: "ns-responsive-table__empty", + colSpan: columns.length + }, emptyState)) : rows.map((row, rowIndex) => /*#__PURE__*/React.createElement("tr", { + key: getRowKey(row, rowIndex), + class: "ns-responsive-table__row" + }, columns.map(column => /*#__PURE__*/React.createElement("td", { + key: column.key, + class: __ds_scope.cn('ns-responsive-table__cell', column.class), + "data-align": column.align ?? 'start', + "data-label": column.label, + "data-priority": column.priority ?? 'secondary' + }, /*#__PURE__*/React.createElement("span", { + class: "ns-responsive-table__cell-value" + }, column.cell(row, rowIndex))))))))), summary && /*#__PURE__*/React.createElement("div", { + class: "ns-responsive-table__summary" + }, summary)); +} +Object.assign(__ds_scope, { ResponsiveTable }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/ResponsiveTable/ResponsiveTable.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/SectionDivider/SectionDivider.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * Renders a labeled divider for detail and form sections. + */ +function SectionDivider({ + label, + class: className, + lineClass, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('flex items-baseline gap-4', className) + }), /*#__PURE__*/React.createElement("span", { + class: "text-[0.65rem] font-mono uppercase tracking-[0.12em] text-ns-muted-fg" + }, label), /*#__PURE__*/React.createElement("div", { + class: __ds_scope.cn('h-px flex-1 bg-ns-border', lineClass) + })); +} +Object.assign(__ds_scope, { SectionDivider }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/SectionDivider/SectionDivider.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/SidebarShell/SidebarShell.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * Sidebar navigation item metadata. + */ + +/** + * Sidebar navigation section metadata. + */ + +function isItemActive(pathname, item) { + if (item.isActive) { + return item.isActive(pathname); + } + if (item.matchPrefix) { + return pathname === item.href || pathname.startsWith(`${item.href}/`); + } + return pathname === item.href; +} +function SidebarShellNavGroup({ + label, + items, + pathname +}) { + return /*#__PURE__*/React.createElement("div", { + class: "ns-dashboard__nav-group", + role: "list" + }, label && /*#__PURE__*/React.createElement("span", { + class: "ns-dashboard__nav-group-label" + }, label), items.map(item => { + const active = isItemActive(pathname, item); + return /*#__PURE__*/React.createElement("a", { + key: item.href, + href: item.href, + role: "listitem", + class: __ds_scope.cn('ns-dashboard__nav-item', active && 'is-active'), + "aria-current": active ? 'page' : undefined + }, item.icon && /*#__PURE__*/React.createElement("span", { + class: "ns-dashboard__nav-icon", + "aria-hidden": "true" + }, item.icon), /*#__PURE__*/React.createElement("span", { + class: "ns-dashboard__nav-label" + }, item.label)); + })); +} + +/** + * Renders the shared dashboard sidebar shell with navigation and topbar slots. + */ +function SidebarShell({ + children, + class: className, + pathname, + navigation, + brand, + brandBadge, + footer, + topbarStart, + topbarEnd, + contentId = 'main-content', + navLabel = 'Sidebar navigation', + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-dashboard', className) + }), /*#__PURE__*/React.createElement("div", { + class: "ns-dashboard__sidebar-backdrop", + "data-sidebar-backdrop": true, + "aria-hidden": "true" + }), /*#__PURE__*/React.createElement("aside", { + class: "ns-dashboard__sidebar", + "data-sidebar": true + }, /*#__PURE__*/React.createElement("div", { + class: "ns-dashboard__sidebar-header" + }, /*#__PURE__*/React.createElement("div", { + class: "flex min-w-0 items-center gap-3" + }, brand), brandBadge), /*#__PURE__*/React.createElement("nav", { + class: "ns-dashboard__sidebar-body", + "aria-label": navLabel + }, navigation.map((section, index) => /*#__PURE__*/React.createElement("div", { + key: section.label ?? `section-${index}` + }, index > 0 && /*#__PURE__*/React.createElement("div", { + class: "ns-dashboard__nav-divider", + role: "separator" + }), /*#__PURE__*/React.createElement(SidebarShellNavGroup, { + label: section.label, + items: section.items, + pathname: pathname + })))), footer && /*#__PURE__*/React.createElement("div", { + class: "ns-dashboard__sidebar-footer" + }, footer)), /*#__PURE__*/React.createElement("div", { + class: "ns-dashboard__main" + }, /*#__PURE__*/React.createElement("header", { + class: "ns-dashboard__topbar" + }, /*#__PURE__*/React.createElement("div", { + class: "flex min-w-0 items-center gap-3" + }, topbarStart), /*#__PURE__*/React.createElement("div", { + class: "flex items-center gap-2" + }, topbarEnd)), /*#__PURE__*/React.createElement("main", { + class: "ns-dashboard__content", + id: contentId + }, children))); +} +Object.assign(__ds_scope, { SidebarShell }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/SidebarShell/SidebarShell.tsx", error: String((e && e.message) || e) }); } + +// components/blocks/StatsGrid/StatsGrid.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * Summary metric card content. + */ + +function StatsGridRoot({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('grid gap-4 md:grid-cols-2 xl:grid-cols-4', className) + }), children); +} +function StatsGridCard({ + label, + value, + detail, + badge, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement(__ds_scope.Card, _extends({}, props, { + class: __ds_scope.cn('overflow-hidden', className) + }), /*#__PURE__*/React.createElement(__ds_scope.Card.Body, { + class: "ns-stack ns-stack--sm min-w-0" + }, /*#__PURE__*/React.createElement("div", { + class: "ns-cluster ns-cluster--between gap-3" + }, /*#__PURE__*/React.createElement("span", { + class: "text-[0.7rem] font-mono uppercase tracking-[0.18em] text-ns-muted-fg" + }, label), badge), /*#__PURE__*/React.createElement("p", { + class: "text-3xl font-semibold tracking-tight tabular-nums text-ns-fg" + }, value), detail && /*#__PURE__*/React.createElement("p", { + class: "text-sm leading-relaxed text-ns-muted-fg" + }, detail))); +} + +/** + * Responsive summary metric grid with a shared metric-card sub-seam. + */ +const StatsGrid = Object.assign(StatsGridRoot, { + Card: StatsGridCard +}); +Object.assign(__ds_scope, { StatsGrid }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/blocks/StatsGrid/StatsGrid.tsx", error: String((e && e.message) || e) }); } + +// components/general/Alert/Alert.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Alert + * @layer 2 + * @depends theme-seed + * @description Persistent section-level feedback banner for success, warning, info, or error states. + */ + +/** + * Visual variants for the alert banner. + */ + +const DEFAULT_ICONS = { + info: '⊕', + success: '◎', + warning: '⟳', + destructive: '≠' +}; + +/** + * Renders a persistent inline banner for section-level feedback. + */ +function Alert({ + children, + class: className, + icon, + role, + title, + variant = 'info', + ...props +}) { + const resolvedRole = role ?? (variant === 'warning' || variant === 'destructive' ? 'alert' : 'status'); + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + role: resolvedRole, + class: __ds_scope.cn('ns-alert', `ns-alert--${variant}`, className) + }), /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + class: "ns-alert__icon" + }, icon ?? DEFAULT_ICONS[variant]), /*#__PURE__*/React.createElement("div", { + class: "ns-alert__body" + }, title ? /*#__PURE__*/React.createElement("div", { + class: "ns-alert__title" + }, title) : null, children ? /*#__PURE__*/React.createElement("div", { + class: "ns-alert__description" + }, children) : null)); +} +Object.assign(__ds_scope, { Alert }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Alert/Alert.tsx", error: String((e && e.message) || e) }); } + +// components/general/Avatar/Avatar.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Avatar + * @layer 2 + * @depends theme-seed + * @description Identity chip for a person or agent — initials or image, with size, + * presence, and agent variants. + */ + +/** + * Avatar diameters, mapped to the --ns-avatar-* sizing tokens. + */ + +/** + * Presence states surfaced as the corner dot. + */ + +const SIZE_CLASSES = { + sm: 'ns-avatar--sm', + md: 'ns-avatar--md', + lg: 'ns-avatar--lg' +}; + +/** + * Derives up to two uppercase initials from a name. + */ +function deriveInitials(name) { + const parts = name.trim().split(/\s+/).filter(Boolean); + if (parts.length === 0) return '?'; + if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase(); + return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); +} + +/** + * Renders an identity chip with an image or initials fallback. + */ +function Avatar({ + name, + src, + initials, + size = 'md', + presence, + agent, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("span", _extends({}, props, { + role: "img", + "aria-label": name, + class: __ds_scope.cn('ns-avatar', SIZE_CLASSES[size], agent && 'ns-avatar--agent', className) + }), src ? /*#__PURE__*/React.createElement("img", { + src: src, + alt: "" + }) : initials ?? deriveInitials(name), presence ? /*#__PURE__*/React.createElement("span", { + class: "ns-avatar__presence", + "data-presence": presence + }) : null); +} +Object.assign(__ds_scope, { Avatar }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Avatar/Avatar.tsx", error: String((e && e.message) || e) }); } + +// components/general/Badge/Badge.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Badge + * @layer 2 + * @depends theme-seed + * @description Compact semantic status label for entity state, tags, and counters. + */ + +/** + * Visual variants for badge labels. + */ + +const VARIANT_CLASSES = { + primary: 'ns-badge--primary', + secondary: 'ns-badge--secondary', + success: 'ns-badge--success', + warning: 'ns-badge--warning', + destructive: 'ns-badge--destructive', + muted: 'ns-badge--muted' +}; + +/** + * Renders a compact semantic label for status, tags, and counters. + */ +function Badge({ + children, + class: className, + variant = 'secondary', + ...props +}) { + return /*#__PURE__*/React.createElement("span", _extends({}, props, { + class: __ds_scope.cn('ns-badge', VARIANT_CLASSES[variant], className) + }), children); +} +Object.assign(__ds_scope, { Badge }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Badge/Badge.tsx", error: String((e && e.message) || e) }); } + +// components/general/Button/Button.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Button + * @layer 2 + * @depends theme-seed + * @description Generic action primitive for forms and navigation. + */ + +/** + * Visual variants for the shared button primitive. + */ + +/** + * Size variants for the shared button primitive. + */ + +/** + * Native button `type` values supported by the shared primitive. + */ + +const VARIANT_CLASSES = { + primary: 'ns-btn--primary', + secondary: 'ns-btn--secondary', + outline: 'ns-btn--outline', + ghost: 'ns-btn--ghost', + destructive: 'ns-btn--destructive' +}; +const SIZE_CLASSES = { + sm: 'ns-btn--sm', + md: undefined, + lg: 'ns-btn--lg', + icon: 'ns-btn--icon' +}; + +/** + * Renders a semantic action control as either a button or a link. + */ +function Button(props) { + const { + children, + variant = 'primary', + size = 'md', + disabled = false, + loading = false, + class: className, + icon, + iconPosition = 'left' + } = props; + const classes = __ds_scope.cn('ns-btn', VARIANT_CLASSES[variant], SIZE_CLASSES[size], className); + const leadingIcon = loading ? /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + class: "ns-spinner ns-spinner--sm" + }) : iconPosition === 'left' ? icon : undefined; + const trailingIcon = !loading && iconPosition === 'right' ? icon : undefined; + const content = /*#__PURE__*/React.createElement(React.Fragment, null, leadingIcon, /*#__PURE__*/React.createElement("span", null, children), trailingIcon); + if (props.type === 'link') { + const { + type: _type, + children: _children, + variant: _variant, + size: _size, + disabled: _disabled, + loading: _loading, + class: _className, + icon: _icon, + iconPosition: _iconPosition, + clientNav = true, + href, + ...linkProps + } = props; + const freshLinkProps = { + ...linkProps, + 'f-client-nav': clientNav + }; + return /*#__PURE__*/React.createElement("a", _extends({}, freshLinkProps, { + href: disabled || loading ? undefined : href, + class: classes, + "aria-disabled": disabled || loading ? 'true' : undefined + }), content); + } + const { + type = 'button', + children: _children, + variant: _variant, + size: _size, + disabled: _disabled, + loading: _loading, + class: _className, + href: _href, + icon: _icon, + iconPosition: _iconPosition, + clientNav: _clientNav, + ...buttonProps + } = props; + return /*#__PURE__*/React.createElement("button", _extends({}, buttonProps, { + type: type, + disabled: disabled || loading, + class: classes + }), content); +} +Object.assign(__ds_scope, { Button }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Button/Button.tsx", error: String((e && e.message) || e) }); } + +// components/general/Card/Card.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Card + * @layer 2 + * @depends theme-seed + * @description Elevated content surface for dashboard tiles, summaries, and grouped content. + */ + +function CardRoot({ + children, + class: className, + interactive = false, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-card', interactive && 'ns-card--interactive', className) + }), children); +} +function CardHeader({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-card__header', className) + }), children); +} +function CardTitle({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("p", _extends({}, props, { + class: __ds_scope.cn('ns-card__title', className) + }), children); +} +function CardDescription({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("p", _extends({}, props, { + class: __ds_scope.cn('ns-card__description', className) + }), children); +} +function CardBody({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-card__body', className) + }), children); +} +function CardFooter({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-card__footer', className) + }), children); +} + +/** + * Card surface with header, body, footer, and text sub-seams. + */ +const Card = Object.assign(CardRoot, { + Header: CardHeader, + Title: CardTitle, + Description: CardDescription, + Body: CardBody, + Footer: CardFooter +}); +Object.assign(__ds_scope, { Card }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Card/Card.tsx", error: String((e && e.message) || e) }); } + +// components/general/ChartBlock/ChartBlock.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component ChartBlock + * @layer 2 + * @depends theme-seed + * @description Inline, token-driven metric chart — horizontal bars (default, + * for long categorical labels) or a vertical column chart with y-axis ticks. + * Intents via data-tone; never a hardcoded color. + */ + +/** + * Semantic bar intent. + */ + +/** + * A single chart entry. + */ + +const TICKS = 4; + +/** + * Rounds a value up to a "nice" axis maximum (1/2/5 × 10ⁿ). + */ +function niceMax(value) { + if (value <= 0) return 1; + const pow = 10 ** Math.floor(Math.log10(value)); + const n = value / pow; + const nice = n <= 1 ? 1 : n <= 2 ? 2 : n <= 5 ? 5 : 10; + return nice * pow; +} +function formatTick(n) { + if (n >= 1000) return `${Math.round(n / 100) / 10}k`; + return `${Math.round(n * 100) / 100}`; +} + +/** + * Renders a horizontal-bar or vertical-column metric chart. + */ +function ChartBlock({ + data, + title, + sub, + unit = '', + variant = 'bar', + class: className, + ...props +}) { + const max = niceMax(Math.max(0, ...data.map(datum => datum.value))); + if (variant === 'column') { + const ticks = Array.from({ + length: TICKS + 1 + }, (_, i) => max / TICKS * (TICKS - i)); + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-colchart', className) + }), title ? /*#__PURE__*/React.createElement("div", { + class: "ns-chart__title" + }, title) : null, sub ? /*#__PURE__*/React.createElement("div", { + class: "ns-chart__sub" + }, sub) : null, /*#__PURE__*/React.createElement("div", { + class: "ns-colchart__plot" + }, /*#__PURE__*/React.createElement("div", { + class: "ns-colchart__yaxis" + }, ticks.map((tick, i) => /*#__PURE__*/React.createElement("span", { + key: i, + class: "ns-colchart__ytick" + }, formatTick(tick)))), /*#__PURE__*/React.createElement("div", { + class: "ns-colchart__grid" + }, data.map((datum, i) => /*#__PURE__*/React.createElement("div", { + key: i, + class: "ns-colchart__col" + }, /*#__PURE__*/React.createElement("div", { + class: "ns-colchart__bar", + "data-tone": datum.tone, + style: { + height: `${datum.value / max * 100}%` + } + }, /*#__PURE__*/React.createElement("span", { + class: "ns-colchart__val" + }, `${datum.value}${unit}`)))))), /*#__PURE__*/React.createElement("div", { + class: "ns-colchart__xaxis" + }, data.map((datum, i) => /*#__PURE__*/React.createElement("span", { + key: i + }, datum.label)))); + } + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-chart', className) + }), title ? /*#__PURE__*/React.createElement("div", { + class: "ns-chart__title" + }, title) : null, sub ? /*#__PURE__*/React.createElement("div", { + class: "ns-chart__sub" + }, sub) : null, data.map(datum => /*#__PURE__*/React.createElement("div", { + class: "ns-chart__row" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-chart__label" + }, datum.label), /*#__PURE__*/React.createElement("span", { + class: "ns-chart__track" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-chart__bar", + "data-tone": datum.tone, + style: { + width: `${datum.value / max * 100}%` + } + })), /*#__PURE__*/React.createElement("span", { + class: "ns-chart__value" + }, `${datum.value}${unit}`)))); +} +Object.assign(__ds_scope, { ChartBlock }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/ChartBlock/ChartBlock.tsx", error: String((e && e.message) || e) }); } + +// components/general/Checkbox/Checkbox.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Checkbox + * @layer 2 + * @depends theme-seed + * @description Styled checkbox with inline label and optional helper copy. + */ + +function Checkbox({ + children, + class: className, + description, + disabled = false, + error = false, + ...props +}) { + return /*#__PURE__*/React.createElement("label", { + class: __ds_scope.cn('ns-choice', disabled && 'ns-choice--disabled', error && 'ns-choice--error', className) + }, /*#__PURE__*/React.createElement("span", { + class: "ns-choice__control" + }, /*#__PURE__*/React.createElement("input", _extends({}, props, { + type: "checkbox", + disabled: disabled, + class: "ns-checkbox" + })), /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + class: "ns-checkbox__indicator" + }, "\u2713")), /*#__PURE__*/React.createElement("span", { + class: "ns-choice__body" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-choice__label" + }, children), description ? /*#__PURE__*/React.createElement("span", { + class: "ns-choice__description" + }, description) : null)); +} +Object.assign(__ds_scope, { Checkbox }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Checkbox/Checkbox.tsx", error: String((e && e.message) || e) }); } + +// components/general/CitationChip/CitationChip.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component CitationChip + * @layer 2 + * @depends theme-seed + * @description Inline per-claim source marker [n] that pairs with a sources list — + * the grounded-agent citation UX. + */ + +/** + * Renders a clickable superscript citation chip. + */ +function CitationChip({ + index, + source, + active, + onClick, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("button", _extends({}, props, { + type: "button", + title: source, + "aria-pressed": active ? 'true' : 'false', + "aria-label": source ? `Source ${index}: ${source}` : `Source ${index}`, + class: __ds_scope.cn('ns-citation', active && 'is-active', className), + onClick: () => onClick?.(index) + }), index); +} +Object.assign(__ds_scope, { CitationChip }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/CitationChip/CitationChip.tsx", error: String((e && e.message) || e) }); } + +// components/general/CodeBlock/CodeBlock.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component CodeBlock + * @layer 2 + * @depends theme-seed + * @description Fenced code surface with a filename/language header and a copy + * affordance. Presentational — clipboard + "Copied" state are hydrated by an app + * island (the button exposes data-part='copy' and data-clipboard); syntax + * highlighting is layered at L4 if desired. + */ + +/** + * Renders a code surface with header metadata and a copy button. + */ +function CodeBlock({ + code, + filename, + lang, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-code', className) + }), /*#__PURE__*/React.createElement("div", { + class: "ns-code__head" + }, filename ? /*#__PURE__*/React.createElement("span", { + class: "ns-code__name" + }, filename) : null, lang ? /*#__PURE__*/React.createElement("span", { + class: "ns-code__lang" + }, lang) : null, /*#__PURE__*/React.createElement("button", { + type: "button", + class: "ns-code__copy", + "data-part": "copy", + "data-clipboard": code, + "aria-label": "Copy code" + }, "Copy")), /*#__PURE__*/React.createElement("pre", null, /*#__PURE__*/React.createElement("code", null, code))); +} +Object.assign(__ds_scope, { CodeBlock }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/CodeBlock/CodeBlock.tsx", error: String((e && e.message) || e) }); } + +// components/general/CommandPalette/CommandPalette.tsx +try { (() => { +/** + * @component CommandPalette + * @layer 2 + * @depends theme-seed + * @description Modal command palette (⌘K surface). Composes the L1 Dialog + * (native backdrop/overlay) wrapping the L1 Combobox (ARIA combobox + + * roving keys). Groups of selectable commands render as combobox items with an + * optional icon, hash, and kind tag. Native-first: Dialog owns open/close + + * Esc + backdrop dismiss; Combobox owns the input, listbox, and keyboard nav. + */ + +/** + * A single selectable command in the palette. + */ + +/** + * A labeled group of commands. + */ + +/** + * Renders the modal command palette. + */ +function CommandPalette({ + open, + onOpenChange, + groups, + placeholder = 'Type a command or search…', + emptyLabel = 'No matching commands', + class: className +}) { + const select = item => { + item.onSelect?.(); + onOpenChange?.(false); + }; + return /*#__PURE__*/React.createElement(__ds_scope.Dialog.Root, { + open: open, + onOpenChange: next => onOpenChange?.(next), + modal: true + }, /*#__PURE__*/React.createElement(__ds_scope.Dialog.Content, { + class: "ns-cmdk__backdrop", + "aria-label": "Command palette" + }, /*#__PURE__*/React.createElement(__ds_scope.Combobox.Root, { + onValueChange: () => {}, + defaultOpen: true + }, /*#__PURE__*/React.createElement("div", { + class: __ds_scope.cn('ns-cmdk', className) + }, /*#__PURE__*/React.createElement("div", { + class: "ns-cmdk__input-row" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-cmdk__search-icon", + "aria-hidden": "true" + }, "\u2315"), /*#__PURE__*/React.createElement(__ds_scope.Combobox.Input, { + class: "ns-cmdk__input", + placeholder: placeholder + })), /*#__PURE__*/React.createElement(__ds_scope.Combobox.Content, { + class: "ns-cmdk__list" + }, groups.map(group => /*#__PURE__*/React.createElement("div", { + key: group.id, + class: "ns-cmdk__group", + role: "group" + }, group.label ? /*#__PURE__*/React.createElement("div", { + class: "ns-cmdk__group-label" + }, group.label) : null, group.items.map(item => /*#__PURE__*/React.createElement(__ds_scope.Combobox.Item, { + key: item.id, + value: item.id, + class: "ns-cmdk__item", + onClick: () => select(item) + }, item.icon ? /*#__PURE__*/React.createElement("span", { + class: "ns-cmdk__item-icon", + "aria-hidden": "true" + }, item.icon) : null, /*#__PURE__*/React.createElement("span", { + class: "ns-cmdk__item-label" + }, item.label), item.hash ? /*#__PURE__*/React.createElement("span", { + class: "ns-cmdk__item-hash" + }, item.hash) : null, item.kind ? /*#__PURE__*/React.createElement("span", { + class: "ns-cmdk__item-kind" + }, item.kind) : null)))), /*#__PURE__*/React.createElement(__ds_scope.Combobox.Empty, { + class: "ns-cmdk__empty" + }, emptyLabel)))))); +} +Object.assign(__ds_scope, { CommandPalette }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/CommandPalette/CommandPalette.tsx", error: String((e && e.message) || e) }); } + +// components/general/Donut/Donut.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Donut + * @layer 2 + * @depends theme-seed + * @description Token-driven donut/pie chart — SVG arc segments (stroke-dasharray) + * with a center total and a legend. Segment colors come from data-tone or a + * semantic-token cycle; never a hardcoded color. + */ + +/** + * Semantic segment intent. + */ + +/** + * A single donut segment. + */ + +const RADIUS = 42; +const CIRCUMFERENCE = 2 * Math.PI * RADIUS; +const CYCLE = ['primary', 'success', 'warning', 'secondary', 'destructive']; + +/** + * Renders a donut chart with a center total and legend. + */ +function Donut({ + data, + total, + class: className, + ...props +}) { + const sum = data.reduce((acc, datum) => acc + datum.value, 0) || 1; + let offset = 0; + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-donut', className) + }), /*#__PURE__*/React.createElement("svg", { + class: "ns-donut__svg", + viewBox: "0 0 100 100", + role: "img", + "aria-hidden": "true" + }, /*#__PURE__*/React.createElement("g", { + transform: "rotate(-90 50 50)" + }, data.map((datum, index) => { + const tone = datum.tone ?? CYCLE[index % CYCLE.length]; + const length = datum.value / sum * CIRCUMFERENCE; + const ring = /*#__PURE__*/React.createElement("circle", { + class: "ns-donut__ring", + "data-tone": tone, + cx: "50", + cy: "50", + r: RADIUS, + fill: "none", + "stroke-width": "12", + "stroke-dasharray": `${length} ${CIRCUMFERENCE - length}`, + "stroke-dashoffset": -offset + }); + offset += length; + return ring; + }))), /*#__PURE__*/React.createElement("div", { + class: "ns-donut__center" + }, total ?? sum), /*#__PURE__*/React.createElement("ul", { + class: "ns-donut__legend" + }, data.map((datum, index) => /*#__PURE__*/React.createElement("li", { + class: "ns-donut__row" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-donut__swatch", + "data-tone": datum.tone ?? CYCLE[index % CYCLE.length] + }), datum.label)))); +} +Object.assign(__ds_scope, { Donut }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Donut/Donut.tsx", error: String((e && e.message) || e) }); } + +// components/general/Dropzone/Dropzone.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Dropzone + * @layer 2 + * @depends theme-seed + * @description File-drop affordance — a dashed drop target with icon, label, + * hint, and reusable file ingest for drag-drop, focused paste, and picker input. + */ + +const DROPZONE_INGEST_SOURCES = ['drop', 'paste', 'picker']; +const DROPZONE_REJECTED_REASONS = ['type', 'too-many']; +function filesFromList(list) { + return list ? Array.from(list) : []; +} +function filesFromItems(items) { + if (!items) return []; + return Array.from(items).filter(item => item.kind === 'file').map(item => item.getAsFile()).filter(file => Boolean(file)); +} +function filesFromClipboard(data) { + const files = filesFromList(data?.files); + return files.length ? files : filesFromItems(data?.items ?? null); +} +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} +function matchesGlob(value, pattern) { + const source = pattern.split('*').map(escapeRegExp).join('.*'); + return new RegExp(`^${source}$`, 'i').test(value); +} +function acceptsFile(file, accept) { + const tokens = accept?.split(',').map(token => token.trim()).filter(Boolean) ?? []; + if (!tokens.length) return true; + const fileName = file.name.toLowerCase(); + const mimeType = file.type.toLowerCase(); + return tokens.some(token => { + const normalized = token.toLowerCase(); + if (normalized.startsWith('.')) { + return normalized.includes('*') ? matchesGlob(fileName, `*${normalized}`) : fileName.endsWith(normalized); + } + if (normalized.endsWith('/*')) { + return mimeType.startsWith(normalized.slice(0, -1)); + } + return normalized.includes('*') ? matchesGlob(mimeType, normalized) : mimeType === normalized; + }); +} +function filterFiles(files, accept, multiple, source) { + const acceptedByType = []; + const rejectedFiles = []; + for (const file of files) { + if (acceptsFile(file, accept)) { + acceptedByType.push(file); + } else { + rejectedFiles.push({ + file, + reason: 'type', + source + }); + } + } + if (multiple) return { + acceptedFiles: acceptedByType, + rejectedFiles + }; + const [firstFile, ...extraFiles] = acceptedByType; + rejectedFiles.push(...extraFiles.map(file => ({ + file, + reason: 'too-many', + source + }))); + return { + acceptedFiles: firstFile ? [firstFile] : [], + rejectedFiles + }; +} +function announceIngest(event, details) { + if (typeof Element === 'undefined') return; + const target = event.currentTarget instanceof Element ? event.currentTarget : event.target instanceof Element ? event.target : null; + const host = target instanceof HTMLInputElement ? target.closest('.ns-dropzone') : target; + const status = host?.querySelector('[data-dropzone-status]'); + if (!status) return; + const acceptedCount = details.acceptedFiles.length; + const rejectedCount = details.rejectedFiles.length; + status.textContent = rejectedCount ? `${acceptedCount} file${acceptedCount === 1 ? '' : 's'} accepted, ${rejectedCount} rejected.` : `${acceptedCount} file${acceptedCount === 1 ? '' : 's'} accepted.`; +} + +/** + * Renders a file drop target with drag, focused paste, and picker ingest. + */ +function Dropzone({ + label = 'Drop files or click to upload', + hint, + icon, + active, + class: className, + children, + accept, + multiple = false, + onFile, + onFiles, + onReject, + onDrop, + onDragOver, + onPaste, + ...props +}) { + function ingestFiles(files, source, event) { + if (!files.length) return; + const filtered = filterFiles(files, accept, multiple, source); + const details = { + ...filtered, + source, + event + }; + announceIngest(event, details); + if (details.acceptedFiles.length) { + onFile?.(details.acceptedFiles[0], details); + onFiles?.(details.acceptedFiles, details); + } + if (details.rejectedFiles.length) onReject?.(details.rejectedFiles, details); + } + function handleDragOver(event) { + event.preventDefault(); + onDragOver?.(event); + } + function handleDrop(event) { + event.preventDefault(); + ingestFiles(filesFromList(event.dataTransfer?.files), 'drop', event); + onDrop?.(event); + } + function handlePaste(event) { + ingestFiles(filesFromClipboard(event.clipboardData), 'paste', event); + onPaste?.(event); + } + function handlePickerChange(event) { + ingestFiles(filesFromList(event.currentTarget.files), 'picker', event); + event.currentTarget.value = ''; + } + return /*#__PURE__*/React.createElement("label", _extends({}, props, { + class: __ds_scope.cn('ns-dropzone', className), + "data-active": active ? '' : undefined, + onDragOver: handleDragOver, + onDrop: handleDrop, + onPaste: handlePaste + }), /*#__PURE__*/React.createElement("span", { + class: "ns-dropzone__icon", + "aria-hidden": "true" + }, icon ?? '↑'), /*#__PURE__*/React.createElement("span", { + class: "ns-dropzone__label" + }, label), hint ? /*#__PURE__*/React.createElement("span", { + class: "ns-dropzone__hint" + }, hint) : null, /*#__PURE__*/React.createElement("input", { + class: "ns-dropzone__input", + type: "file", + accept: accept, + multiple: multiple, + onChange: handlePickerChange + }), /*#__PURE__*/React.createElement("span", { + class: "ns-dropzone__status", + "aria-live": "polite", + "data-dropzone-status": true + }, "No files selected."), children); +} +Object.assign(__ds_scope, { DROPZONE_INGEST_SOURCES, DROPZONE_REJECTED_REASONS, Dropzone }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Dropzone/Dropzone.tsx", error: String((e && e.message) || e) }); } + +// components/general/FormField/FormField.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component FormField + * @layer 2 + * @depends Label + * @description Composed field wrapper for labels, help text, and error messaging. + */ + +/** + * Renders a labeled form field wrapper with help and error messaging. + */ +function FormField({ + label, + name, + required = false, + error, + helpText, + class: className, + children, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-field', className) + }), /*#__PURE__*/React.createElement(__ds_scope.Label, { + htmlFor: name, + required: required + }, label), children, error ? /*#__PURE__*/React.createElement("div", { + class: "ns-field__error-row" + }, /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + class: "font-mono text-xs leading-none text-ns-destructive" + }, "\u2260"), /*#__PURE__*/React.createElement("p", { + class: "ns-error-text" + }, error)) : helpText ? /*#__PURE__*/React.createElement("p", { + class: "ns-help-text" + }, helpText) : null); +} +Object.assign(__ds_scope, { FormField }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/FormField/FormField.tsx", error: String((e && e.message) || e) }); } + +// components/general/IconButton/IconButton.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component IconButton + * @layer 2 + * @depends theme-seed, button + * @description Compact icon-only action button with accessible labeling. + */ + +/** + * Renders an icon-only action control with an accessible label. + */ +function IconButton({ + icon, + label, + ...props +}) { + return /*#__PURE__*/React.createElement(__ds_scope.Button, _extends({}, props, { + size: "icon", + icon: icon, + "aria-label": label, + title: props.title ?? label + }), /*#__PURE__*/React.createElement("span", { + class: "sr-only" + }, label)); +} +Object.assign(__ds_scope, { IconButton }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/IconButton/IconButton.tsx", error: String((e && e.message) || e) }); } + +// components/general/InlineNotice/InlineNotice.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component InlineNotice + * @layer 2 + * @depends theme-seed + * @description Compact contextual notice for inline guidance inside forms, panels, and cards. + */ + +/** + * Visual variants for the inline notice block. + */ + +const DEFAULT_ICONS = { + info: '⊕', + success: '◎', + warning: '⟳', + destructive: '≠' +}; + +/** + * Renders compact contextual guidance within cards, forms, and panels. + */ +function InlineNotice({ + children, + class: className, + icon, + role = 'status', + title, + variant = 'info', + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + role: role, + class: __ds_scope.cn('ns-inline-notice', `ns-inline-notice--${variant}`, className) + }), /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + class: "ns-inline-notice__icon" + }, icon ?? DEFAULT_ICONS[variant]), /*#__PURE__*/React.createElement("div", { + class: "ns-inline-notice__body" + }, title ? /*#__PURE__*/React.createElement("div", { + class: "ns-inline-notice__title" + }, title) : null, children ? /*#__PURE__*/React.createElement("div", { + class: "ns-inline-notice__description" + }, children) : null)); +} +Object.assign(__ds_scope, { InlineNotice }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/InlineNotice/InlineNotice.tsx", error: String((e && e.message) || e) }); } + +// components/general/Input/Input.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Input + * @layer 2 + * @depends theme-seed + * @description Generic text input with semantic token-driven states. + */ + +/** + * Renders a token-aware text input. + */ +function Input({ + type = 'text', + class: className, + error = false, + ...props +}) { + return /*#__PURE__*/React.createElement("input", _extends({}, props, { + type: type, + class: __ds_scope.cn('ns-input', error && 'ns-input--error', className) + })); +} +Object.assign(__ds_scope, { Input }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Input/Input.tsx", error: String((e && e.message) || e) }); } + +// components/general/Label/Label.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Label + * @layer 2 + * @depends theme-seed + * @description Accessible form label with optional required-state styling. + */ + +/** + * Renders a field label with optional required and screen-reader-only states. + */ +function Label({ + children, + class: className, + required = false, + srOnly = false, + ...props +}) { + return /*#__PURE__*/React.createElement("label", _extends({}, props, { + class: __ds_scope.cn(srOnly ? 'sr-only' : 'ns-label', required && !srOnly && 'ns-label--required', className) + }), children); +} +Object.assign(__ds_scope, { Label }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Label/Label.tsx", error: String((e && e.message) || e) }); } + +// components/general/Message/Message.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Message + * @layer 2 + * @depends theme-seed + * @description A chat message in a thread: author + time, inline-markup body + * (**bold**, `code`, [n] citations), tool-call + chart/code blocks, follow-up + * chips, and hover actions. User messages are right-aligned bubbles; assistant + * messages are card-less prose. Exports `renderInline` and `TypingIndicator`. + */ + +/** + * Wiring for citations + follow-ups shared with the surrounding thread. + */ + +const INLINE = /(\*\*([^*]+)\*\*)|(`([^`]+)`)|(\[(\d+)\])/g; + +/** + * Turns a string with `**bold**`, `` `code` ``, and `[n]` citation markers into + * an array of text + element nodes. Exported for reuse in other prose surfaces. + */ +function renderInline(text, ctx) { + const nodes = []; + let last = 0; + let match; + INLINE.lastIndex = 0; + while ((match = INLINE.exec(text)) !== null) { + if (match.index > last) nodes.push(text.slice(last, match.index)); + if (match[2] !== undefined) { + nodes.push(/*#__PURE__*/React.createElement("strong", null, match[2])); + } else if (match[4] !== undefined) { + nodes.push(/*#__PURE__*/React.createElement("code", { + class: "ns-inline-code" + }, match[4])); + } else if (match[6] !== undefined) { + const index = Number(match[6]); + nodes.push(/*#__PURE__*/React.createElement(__ds_scope.CitationChip, { + index: index, + active: ctx?.activeCite === index, + onClick: ctx?.onCite + })); + } + last = INLINE.lastIndex; + } + if (last < text.length) nodes.push(text.slice(last)); + return nodes; +} + +/** + * Animated "assistant is typing" indicator. + */ +function TypingIndicator() { + return /*#__PURE__*/React.createElement("span", { + class: "ns-typing", + role: "status", + "aria-label": "Assistant is typing" + }, /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement("span", null)); +} +function renderBlock(block) { + if (block.type === 'chart') { + return /*#__PURE__*/React.createElement(__ds_scope.ChartBlock, { + title: block.title, + sub: block.sub, + data: block.data, + unit: block.unit, + variant: block.variant + }); + } + return /*#__PURE__*/React.createElement(__ds_scope.CodeBlock, { + code: block.code, + filename: block.filename, + lang: block.lang + }); +} +/** + * Renders a single chat message. + */ +function Message({ + message, + ctx, + class: className, + ...props +}) { + const { + role, + author, + time, + model, + body, + blocks, + tools, + followups, + pending + } = message; + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-message', `ns-message--${role}`, className) + }), /*#__PURE__*/React.createElement("div", { + class: "ns-message__avatar" + }, /*#__PURE__*/React.createElement(__ds_scope.Avatar, { + name: author.name, + initials: author.initials, + agent: author.agent, + size: "sm" + })), /*#__PURE__*/React.createElement("div", { + class: "ns-message__main" + }, /*#__PURE__*/React.createElement("div", { + class: "ns-message__head" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-message__author" + }, author.name), model ? /*#__PURE__*/React.createElement("span", { + class: "ns-message__model" + }, model) : null, time ? /*#__PURE__*/React.createElement("span", { + class: "ns-message__time" + }, time) : null), /*#__PURE__*/React.createElement("div", { + class: "ns-message__body" + }, pending ? /*#__PURE__*/React.createElement(TypingIndicator, null) : null, body ? /*#__PURE__*/React.createElement("p", { + class: "ns-message__text" + }, renderInline(body, ctx)) : null, blocks?.map((block, index) => /*#__PURE__*/React.createElement("div", { + key: `b${index}` + }, renderBlock(block))), tools?.map((tool, index) => /*#__PURE__*/React.createElement(__ds_scope.ToolCallCard, { + key: `t${index}`, + name: tool.name, + args: tool.args, + result: tool.result, + status: tool.status, + defaultOpen: tool.defaultOpen + }))), followups && followups.length ? /*#__PURE__*/React.createElement("div", { + class: "ns-message__followups ns-cluster ns-cluster--sm" + }, followups.map((followup, index) => /*#__PURE__*/React.createElement("button", { + key: `f${index}`, + type: "button", + class: "ns-pill", + onClick: () => ctx?.onFollowup?.(followup) + }, followup))) : null, /*#__PURE__*/React.createElement("div", { + class: "ns-message__actions" + }, /*#__PURE__*/React.createElement("button", { + type: "button", + class: "ns-msg-action", + "aria-label": "Copy message" + }, "Copy"), /*#__PURE__*/React.createElement("button", { + type: "button", + class: "ns-msg-action", + "aria-label": "Regenerate response" + }, "Regenerate")))); +} +Object.assign(__ds_scope, { renderInline, TypingIndicator, Message }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Message/Message.tsx", error: String((e && e.message) || e) }); } + +// components/general/ModelSelector/ModelSelector.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component ModelSelector + * @layer 2 + * @depends theme-seed + * @description Model/provider picker for the prompt composer. Native-first: a + *
disclosure holds the option list (open/close + Esc are native; + * an app island may add outside-click-close and auto-close on select). + */ + +/** + * A selectable model entry. + */ + +/** + * Renders a disclosure-backed model picker. + */ +function ModelSelector({ + value, + models, + onChange, + align = 'left', + class: className, + ...props +}) { + const current = models.find(model => model.id === value) ?? models[0]; + return /*#__PURE__*/React.createElement("details", _extends({}, props, { + class: __ds_scope.cn('ns-model-selector', className), + "data-align": align + }), /*#__PURE__*/React.createElement("summary", { + class: "ns-model-selector__btn" + }, current?.provider ? /*#__PURE__*/React.createElement("span", { + class: "ns-model-selector__provider" + }, current.provider) : null, /*#__PURE__*/React.createElement("span", null, current?.label)), /*#__PURE__*/React.createElement("div", { + class: "ns-model-selector__menu", + role: "listbox" + }, models.map(model => { + const selected = model.id === value; + return /*#__PURE__*/React.createElement("button", { + key: model.id, + type: "button", + role: "option", + "aria-selected": selected ? 'true' : 'false', + class: __ds_scope.cn('ns-model-opt', selected && 'is-active'), + onClick: () => onChange?.(model.id) + }, /*#__PURE__*/React.createElement("span", { + class: "ns-model-opt__main" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-model-opt__label" + }, model.label), model.desc ? /*#__PURE__*/React.createElement("span", { + class: "ns-model-opt__desc" + }, model.desc) : null), selected ? /*#__PURE__*/React.createElement("span", { + class: "ns-model-opt__check", + "aria-hidden": "true" + }, "\u2713") : null); + }))); +} +Object.assign(__ds_scope, { ModelSelector }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/ModelSelector/ModelSelector.tsx", error: String((e && e.message) || e) }); } + +// components/general/Panel/Panel.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Panel + * @layer 2 + * @depends theme-seed + * @description Dense secondary surface for sidebars, filter rails, and grouped dashboard controls. + */ + +const TONE_CLASSES = { + default: undefined, + muted: 'ns-panel--muted', + raised: 'ns-panel--raised' +}; +function PanelRoot({ + children, + class: className, + tone = 'default', + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-panel', TONE_CLASSES[tone], className) + }), children); +} +function PanelHeader({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-panel__header', className) + }), children); +} +function PanelTitle({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("p", _extends({}, props, { + class: __ds_scope.cn('ns-panel__title', className) + }), children); +} +function PanelDescription({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("p", _extends({}, props, { + class: __ds_scope.cn('ns-panel__description', className) + }), children); +} +function PanelBody({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-panel__body', className) + }), children); +} +function PanelFooter({ + children, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + class: __ds_scope.cn('ns-panel__footer', className) + }), children); +} +const Panel = Object.assign(PanelRoot, { + Header: PanelHeader, + Title: PanelTitle, + Description: PanelDescription, + Body: PanelBody, + Footer: PanelFooter +}); +Object.assign(__ds_scope, { PanelHeader, PanelTitle, PanelDescription, PanelBody, PanelFooter, Panel }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Panel/Panel.tsx", error: String((e && e.message) || e) }); } + +// components/general/Progress/Progress.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Progress + * @layer 2 + * @depends theme-seed + * @description Determinate or indeterminate progress indicator for jobs, uploads, and deferred flows. + */ + +const SIZE_CLASSES = { + sm: 'ns-progress--sm', + md: 'ns-progress--md', + lg: 'ns-progress--lg' +}; +const VARIANT_CLASSES = { + primary: undefined, + secondary: 'ns-progress--secondary', + success: 'ns-progress--success', + warning: 'ns-progress--warning', + destructive: 'ns-progress--destructive' +}; +function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); +} +function Progress({ + class: className, + indeterminate = false, + label = 'Progress', + max = 100, + size = 'md', + value = 0, + variant = 'primary', + ...props +}) { + const safeMax = max > 0 ? max : 100; + const normalizedValue = clamp(value, 0, safeMax); + const width = `${normalizedValue / safeMax * 100}%`; + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + role: "progressbar", + "aria-label": label, + "aria-valuemin": 0, + "aria-valuemax": safeMax, + "aria-valuenow": indeterminate ? undefined : normalizedValue, + class: __ds_scope.cn('ns-progress', SIZE_CLASSES[size], VARIANT_CLASSES[variant], indeterminate && 'ns-progress--indeterminate', className) + }), /*#__PURE__*/React.createElement("span", { + class: "ns-progress__track" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-progress__bar", + style: indeterminate ? undefined : { + width + } + }))); +} +Object.assign(__ds_scope, { Progress }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Progress/Progress.tsx", error: String((e && e.message) || e) }); } + +// components/general/PromptInput/PromptInput.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component PromptInput + * @layer 2 + * @depends theme-seed + * @description Chat composer: an auto-grow textarea over a toolbar of toggle + * pills (deep research / grounding), a ModelSelector, attach/screenshot/voice + * affordances, and a send button. Presentational
— onSubmit reads the + * field; textarea auto-grow is CSS-native and Enter-to-send is an app-island + * enhancement. + */ + +/** + * Submit metadata passed alongside the prompt text. + */ + +/** + * Renders the chat composer shell. + */ +function PromptInput({ + placeholder = 'Ask anything…', + onSubmit, + models, + model = '', + onModelChange, + grounding = false, + onGroundingChange, + research = false, + onResearchChange, + hint, + compact, + class: className, + ...props +}) { + function handleSubmit(event) { + event.preventDefault(); + const field = event.currentTarget.elements.namedItem('prompt'); + const text = field?.value.trim() ?? ''; + if (text) onSubmit?.(text, { + grounding, + research, + model + }); + } + return /*#__PURE__*/React.createElement("form", _extends({}, props, { + class: __ds_scope.cn('ns-prompt-input', className), + "data-compact": compact ? '' : undefined, + onSubmit: handleSubmit + }), /*#__PURE__*/React.createElement("textarea", { + name: "prompt", + rows: 1, + class: "ns-prompt-input__field", + placeholder: placeholder + }), /*#__PURE__*/React.createElement("div", { + class: "ns-prompt-input__bar" + }, /*#__PURE__*/React.createElement("button", { + type: "button", + class: "ns-pill", + "aria-pressed": research ? 'true' : 'false', + onClick: () => onResearchChange?.(!research) + }, "Deep research"), /*#__PURE__*/React.createElement("button", { + type: "button", + class: "ns-pill", + "aria-pressed": grounding ? 'true' : 'false', + onClick: () => onGroundingChange?.(!grounding) + }, "Grounding"), models && models.length ? /*#__PURE__*/React.createElement(__ds_scope.ModelSelector, { + value: model, + models: models, + onChange: onModelChange, + align: "left" + }) : null, /*#__PURE__*/React.createElement("span", { + class: "ns-prompt-input__spacer" + }), /*#__PURE__*/React.createElement("button", { + type: "button", + class: "ns-iconbtn", + "aria-label": "Attach file" + }, "+"), /*#__PURE__*/React.createElement("button", { + type: "button", + class: "ns-iconbtn", + "aria-label": "Capture screenshot" + }, "\u25A2"), /*#__PURE__*/React.createElement("button", { + type: "button", + class: "ns-iconbtn", + "aria-label": "Voice input" + }, "\u25CE"), /*#__PURE__*/React.createElement("button", { + type: "submit", + class: "ns-prompt-input__send", + "aria-label": "Send" + }, "\u2191")), hint ? /*#__PURE__*/React.createElement("div", { + class: "ns-prompt-input__hint" + }, hint) : null); +} +Object.assign(__ds_scope, { PromptInput }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/PromptInput/PromptInput.tsx", error: String((e && e.message) || e) }); } + +// components/general/Search/Search.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Search + * @layer 2 + * @depends theme-seed + * @description Compact nav search affordance: a button styled as an input that + * opens the command palette, with a leading search glyph and a trailing ⌘K + * keyboard hint. Presentational — the consumer wires onOpen to its palette + * (and any global ⌘K listener lives in an app island). + */ + +/** + * Renders the compact nav search trigger. + */ +function Search({ + placeholder = 'Search…', + shortcut = '⌘K', + onOpen, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("button", _extends({}, props, { + type: "button", + class: __ds_scope.cn('ns-search', className), + onClick: () => onOpen?.() + }), /*#__PURE__*/React.createElement("span", { + class: "ns-search__icon", + "aria-hidden": "true" + }, "\u2315"), /*#__PURE__*/React.createElement("span", { + class: "ns-search__label" + }, placeholder), shortcut ? /*#__PURE__*/React.createElement("kbd", { + class: "ns-kbd ns-search__kbd" + }, shortcut) : null); +} +Object.assign(__ds_scope, { Search }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Search/Search.tsx", error: String((e && e.message) || e) }); } + +// components/general/Select/Select.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Select + * @layer 2 + * @depends theme-seed + * @description Native select wrapper with token-driven focus and error states. + */ + +/** + * Native select option metadata. + */ + +/** + * Renders a token-aware native select control. + */ +function Select({ + class: className, + error = false, + options, + placeholder, + value, + defaultValue, + selectedValues, + ...props +}) { + const resolvedSelectedValues = new Set(normalizeSelectedValues(selectedValues ?? value ?? defaultValue, props.multiple === true)); + return /*#__PURE__*/React.createElement("select", _extends({}, props, { + value: value, + defaultValue: defaultValue, + class: __ds_scope.cn('ns-select', error && 'ns-select--error', className) + }), placeholder ? /*#__PURE__*/React.createElement("option", { + value: "", + selected: resolvedSelectedValues.size === 0 + }, placeholder) : null, options.map(option => /*#__PURE__*/React.createElement("option", { + key: option.value, + value: option.value, + disabled: option.disabled, + selected: resolvedSelectedValues.has(option.value) + }, option.label))); +} +function normalizeSelectedValues(value, multiple) { + if (Array.isArray(value)) { + return multiple ? [...value] : value.length > 0 ? [value[0] ?? ''] : []; + } + if (typeof value === 'string') { + return value.length > 0 ? [value] : []; + } + return []; +} +Object.assign(__ds_scope, { Select }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Select/Select.tsx", error: String((e && e.message) || e) }); } + +// components/general/Separator/Separator.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Separator + * @layer 2 + * @depends theme-seed + * @description Lightweight divider for separating content groups in cards, forms, and toolbars. + */ + +/** + * Renders a horizontal or vertical separator. + */ +function Separator({ + class: className, + orientation = 'horizontal', + ...props +}) { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + role: "separator", + "aria-orientation": orientation, + class: __ds_scope.cn('ns-separator', orientation === 'vertical' && 'ns-separator--vertical', className) + })); +} +Object.assign(__ds_scope, { Separator }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Separator/Separator.tsx", error: String((e && e.message) || e) }); } + +// components/general/Skeleton/Skeleton.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Skeleton + * @layer 2 + * @depends theme-seed + * @description Generic dashboard loading scaffold for table, stats, detail, and form surfaces. + */ + +function clamp(value, fallback) { + return Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback; +} +function SkeletonBlock({ + class: className, + style +}) { + return /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + class: __ds_scope.cn('ns-skeleton__block', className), + style: style + }); +} + +/** + * Renders loading scaffolds for table, stats, detail, and form states. + */ +function Skeleton({ + cards = 4, + class: className, + columns = 4, + rows = 4, + variant, + ...props +}) { + const resolvedCards = clamp(cards, 4); + const resolvedColumns = clamp(columns, 4); + const resolvedRows = clamp(rows, 4); + if (variant === 'stats') { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + "aria-hidden": "true", + class: __ds_scope.cn('ns-skeleton ns-grid', className) + }), Array.from({ + length: resolvedCards + }, (_, index) => /*#__PURE__*/React.createElement("div", { + key: `stats-${index}`, + class: "ns-stack ns-stack--sm" + }, /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__box ns-skeleton__box--card" + }), /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__line--sm", + style: { + width: '55%' + } + })))); + } + if (variant === 'detail') { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + "aria-hidden": "true", + class: __ds_scope.cn('ns-skeleton ns-stack ns-stack--lg', className) + }), Array.from({ + length: resolvedRows + }, (_, index) => /*#__PURE__*/React.createElement("div", { + key: `detail-${index}`, + class: "ns-stack ns-stack--sm" + }, /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__line--md", + style: { + width: index === 0 ? '32%' : '24%' + } + }), /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__line--sm", + style: { + width: '100%' + } + }), /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__line--sm", + style: { + width: '86%' + } + }), /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__line--sm", + style: { + width: '64%' + } + })))); + } + if (variant === 'form') { + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + "aria-hidden": "true", + class: __ds_scope.cn('ns-skeleton ns-stack ns-stack--md', className) + }), Array.from({ + length: resolvedRows + }, (_, index) => /*#__PURE__*/React.createElement("div", { + key: `form-${index}`, + class: "ns-stack ns-stack--sm" + }, /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__line--xs", + style: { + width: `${30 + index % 3 * 12}%` + } + }), /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__box ns-skeleton__box--input" + }))), /*#__PURE__*/React.createElement("div", { + class: "ns-cluster" + }, /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__box ns-skeleton__box--input", + style: { + width: '7rem' + } + }), /*#__PURE__*/React.createElement(SkeletonBlock, { + class: "ns-skeleton__box ns-skeleton__box--input", + style: { + width: '5.5rem' + } + }))); + } + return /*#__PURE__*/React.createElement("div", _extends({}, props, { + "aria-hidden": "true", + class: __ds_scope.cn('ns-skeleton ns-stack ns-stack--sm', className) + }), /*#__PURE__*/React.createElement("div", { + class: "ns-skeleton__table-row", + style: { + gridTemplateColumns: `repeat(${resolvedColumns}, minmax(0, 1fr))` + } + }, Array.from({ + length: resolvedColumns + }, (_, index) => /*#__PURE__*/React.createElement(SkeletonBlock, { + key: `table-head-${index}`, + class: "ns-skeleton__line--xs", + style: { + width: `${60 + index % 2 * 15}%` + } + }))), Array.from({ + length: resolvedRows + }, (_, rowIndex) => /*#__PURE__*/React.createElement("div", { + key: `table-row-${rowIndex}`, + class: "ns-skeleton__table-row", + style: { + gridTemplateColumns: `repeat(${resolvedColumns}, minmax(0, 1fr))` + } + }, Array.from({ + length: resolvedColumns + }, (_, columnIndex) => /*#__PURE__*/React.createElement(SkeletonBlock, { + key: `table-cell-${rowIndex}-${columnIndex}`, + class: "ns-skeleton__line--sm", + style: { + width: `${70 + (rowIndex + columnIndex) % 3 * 10}%` + } + }))))); +} +Object.assign(__ds_scope, { Skeleton }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Skeleton/Skeleton.tsx", error: String((e && e.message) || e) }); } + +// components/general/Spinner/Spinner.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Spinner + * @layer 2 + * @depends theme-seed + * @description Small loading indicator for async actions and deferred surfaces. + */ + +/** + * Size variants for the spinner primitive. + */ + +const SIZE_CLASSES = { + sm: 'ns-spinner--sm', + md: 'ns-spinner--md', + lg: 'ns-spinner--lg' +}; + +/** + * Renders a loading spinner with optional accessible label text. + */ +function Spinner({ + class: className, + label, + size = 'md', + ...props +}) { + const indicatorClass = __ds_scope.cn('ns-spinner', SIZE_CLASSES[size], !label && className); + if (!label) { + return /*#__PURE__*/React.createElement("span", _extends({}, props, { + "aria-hidden": "true", + class: indicatorClass + })); + } + return /*#__PURE__*/React.createElement("span", _extends({}, props, { + role: "status", + "aria-label": label, + class: className + }), /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + class: __ds_scope.cn('ns-spinner', SIZE_CLASSES[size]) + }), /*#__PURE__*/React.createElement("span", { + class: "sr-only" + }, label)); +} +Object.assign(__ds_scope, { Spinner }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Spinner/Spinner.tsx", error: String((e && e.message) || e) }); } + +// components/general/Switch/Switch.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Switch + * @layer 2 + * @depends theme-seed + * @description CSS-first toggle switch built on a native checkbox input. + */ + +function Switch({ + children, + class: className, + description, + disabled = false, + error = false, + ...props +}) { + return /*#__PURE__*/React.createElement("label", { + class: __ds_scope.cn('ns-choice', disabled && 'ns-choice--disabled', error && 'ns-choice--error', className) + }, /*#__PURE__*/React.createElement("span", { + class: "ns-choice__control" + }, /*#__PURE__*/React.createElement("input", _extends({}, props, { + type: "checkbox", + role: "switch", + disabled: disabled, + class: "ns-switch" + })), /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + class: "ns-switch__track" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-switch__thumb" + }))), /*#__PURE__*/React.createElement("span", { + class: "ns-choice__body" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-choice__label" + }, children), description ? /*#__PURE__*/React.createElement("span", { + class: "ns-choice__description" + }, description) : null)); +} +Object.assign(__ds_scope, { Switch }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Switch/Switch.tsx", error: String((e && e.message) || e) }); } + +// components/general/Textarea/Textarea.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component Textarea + * @layer 2 + * @depends theme-seed + * @description Generic multi-line text input with semantic token-driven states. + */ + +/** + * Renders a token-aware multiline text input. + */ +function Textarea({ + class: className, + error = false, + ...props +}) { + return /*#__PURE__*/React.createElement("textarea", _extends({}, props, { + class: __ds_scope.cn('ns-textarea', error && 'ns-textarea--error', className) + })); +} +Object.assign(__ds_scope, { Textarea }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/Textarea/Textarea.tsx", error: String((e && e.message) || e) }); } + +// components/general/ToolCallCard/ToolCallCard.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * @component ToolCallCard + * @layer 2 + * @depends theme-seed + * @description Inline MCP/tool invocation + result as a native
+ * disclosure: name, status badge, and an args/result panel. + */ + +/** + * Lifecycle state of a tool call. + */ + +const STATUS_VARIANT = { + running: 'warning', + done: 'success', + error: 'destructive' +}; +const STATUS_LABEL = { + running: 'Running', + done: 'Done', + error: 'Error' +}; + +/** + * Renders a collapsible tool-call card with status and IO panel. + */ +function ToolCallCard({ + name, + args, + result, + status, + defaultOpen, + class: className, + ...props +}) { + return /*#__PURE__*/React.createElement("details", _extends({}, props, { + open: defaultOpen, + class: __ds_scope.cn('ns-tool-call', className), + "data-status": status + }), /*#__PURE__*/React.createElement("summary", null, /*#__PURE__*/React.createElement("span", { + class: "ns-tool-call__icon", + "aria-hidden": "true" + }, "\u0192"), /*#__PURE__*/React.createElement("span", { + class: "ns-tool-call__name" + }, name), status === 'running' ? /*#__PURE__*/React.createElement(__ds_scope.Spinner, { + size: "sm" + }) : null, /*#__PURE__*/React.createElement(__ds_scope.Badge, { + variant: STATUS_VARIANT[status] + }, STATUS_LABEL[status]), /*#__PURE__*/React.createElement("span", { + class: "ns-tool-call__chevron", + "aria-hidden": "true" + }, "\u25BE")), /*#__PURE__*/React.createElement("div", { + class: "ns-tool-call__panel" + }, args ? /*#__PURE__*/React.createElement("div", { + class: "ns-tool-call__io" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-tool-call__io-label" + }, "args"), /*#__PURE__*/React.createElement("pre", null, args)) : null, result ? /*#__PURE__*/React.createElement("div", { + class: "ns-tool-call__io" + }, /*#__PURE__*/React.createElement("span", { + class: "ns-tool-call__io-label" + }, "result"), /*#__PURE__*/React.createElement("pre", null, result)) : null)); +} +Object.assign(__ds_scope, { ToolCallCard }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/general/ToolCallCard/ToolCallCard.tsx", error: String((e && e.message) || e) }); } + +// components/islands/SidebarToggle/SidebarToggle.tsx +try { (() => { +function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } +/** + * Props for the registry sidebar toggle island. + */ + +/** + * Toggles the mobile dashboard sidebar and its backdrop state. + * @param props Button, selector, and icon overrides for the toggle. + * @returns A hydrated sidebar toggle button. + */ +function SidebarToggle({ + class: className, + sidebarSelector = '[data-sidebar]', + backdropSelector = '[data-sidebar-backdrop]', + openLabel = 'Open sidebar', + closeLabel = 'Close sidebar', + openIcon, + closeIcon, + ...props +}) { + const [open, setOpen] = __ds_scope.useState(false); + const toggle = __ds_scope.useCallback(() => setOpen(prev => !prev), []); + const close = __ds_scope.useCallback(() => setOpen(false), []); + __ds_scope.useEffect(() => { + const sidebar = document.querySelector(sidebarSelector); + const backdrop = document.querySelector(backdropSelector); + const handleEscape = event => { + if (event.key === 'Escape') close(); + }; + sidebar?.classList.toggle('is-open', open); + backdrop?.classList.toggle('is-visible', open); + if (open) { + document.body.style.overflow = 'hidden'; + document.addEventListener('keydown', handleEscape); + backdrop?.addEventListener('click', close); + } + return () => { + document.removeEventListener('keydown', handleEscape); + backdrop?.removeEventListener('click', close); + document.body.style.overflow = ''; + }; + }, [backdropSelector, close, open, sidebarSelector]); + __ds_scope.useEffect(() => { + const handleNavigation = () => close(); + globalThis.addEventListener('popstate', handleNavigation); + return () => globalThis.removeEventListener('popstate', handleNavigation); + }, [close]); + return /*#__PURE__*/React.createElement("button", _extends({}, props, { + type: "button", + class: __ds_scope.cn('ns-dashboard__mobile-trigger ns-btn ns-btn--ghost ns-btn--icon ns-btn--sm', className), + "aria-label": open ? closeLabel : openLabel, + "aria-expanded": open, + onClick: toggle + }), /*#__PURE__*/React.createElement("span", { + "aria-hidden": "true", + style: { + fontSize: '1.1rem', + lineHeight: 1 + } + }, open ? closeIcon ?? '✕' : openIcon ?? '☰')); +} +Object.assign(__ds_scope, { SidebarToggle, __ds_default_components_islands_SidebarToggle_SidebarToggle_rwy1ge: SidebarToggle }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/islands/SidebarToggle/SidebarToggle.tsx", error: String((e && e.message) || e) }); } + +// components/islands/ThemeToggle/ThemeToggle.tsx +try { (() => { +/** + * @component ThemeToggle + * @layer 2 + * @depends theme-seed + * @description Generic Fresh island for dark/light theme switching. + */ + +const STORAGE_KEY = 'ns-theme'; +function getInitialTheme() { + if (typeof document === 'undefined') { + return 'dark'; + } + const stored = localStorage.getItem(STORAGE_KEY); + if (stored === 'light' || stored === 'dark') { + return stored; + } + return globalThis.matchMedia?.('(prefers-color-scheme: light)').matches ? 'light' : 'dark'; +} +function applyTheme(theme) { + document.documentElement.setAttribute('data-theme', theme); + localStorage.setItem(STORAGE_KEY, theme); +} + +/** + * Switches the active document theme and persists the selection locally. + * @returns A hydrated button that flips the `data-theme` attribute. + */ +function ThemeToggle() { + const theme = __ds_scope.useSignal(getInitialTheme()); + __ds_scope.useEffect(() => { + applyTheme(theme.value); + }, []); + const toggle = () => { + const next = theme.value === 'dark' ? 'light' : 'dark'; + theme.value = next; + applyTheme(next); + }; + return /*#__PURE__*/React.createElement("button", { + type: "button", + onClick: toggle, + class: "inline-flex h-9 w-9 items-center justify-center rounded-md border border-ns-border bg-transparent text-ns-muted-fg transition-colors duration-150 hover:border-ns-border-hover hover:bg-ns-surface-raised hover:text-ns-fg", + "aria-label": `Switch to ${theme.value === 'dark' ? 'light' : 'dark'} mode`, + title: `Switch to ${theme.value === 'dark' ? 'light' : 'dark'} mode` + }, theme.value === 'dark' ? /*#__PURE__*/React.createElement("svg", { + width: "16", + height: "16", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + strokeWidth: "2", + strokeLinecap: "round", + strokeLinejoin: "round" + }, /*#__PURE__*/React.createElement("circle", { + cx: "12", + cy: "12", + r: "5" + }), /*#__PURE__*/React.createElement("line", { + x1: "12", + y1: "1", + x2: "12", + y2: "3" + }), /*#__PURE__*/React.createElement("line", { + x1: "12", + y1: "21", + x2: "12", + y2: "23" + }), /*#__PURE__*/React.createElement("line", { + x1: "4.22", + y1: "4.22", + x2: "5.64", + y2: "5.64" + }), /*#__PURE__*/React.createElement("line", { + x1: "18.36", + y1: "18.36", + x2: "19.78", + y2: "19.78" + }), /*#__PURE__*/React.createElement("line", { + x1: "1", + y1: "12", + x2: "3", + y2: "12" + }), /*#__PURE__*/React.createElement("line", { + x1: "21", + y1: "12", + x2: "23", + y2: "12" + }), /*#__PURE__*/React.createElement("line", { + x1: "4.22", + y1: "19.78", + x2: "5.64", + y2: "18.36" + }), /*#__PURE__*/React.createElement("line", { + x1: "18.36", + y1: "5.64", + x2: "19.78", + y2: "4.22" + })) : /*#__PURE__*/React.createElement("svg", { + width: "16", + height: "16", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + strokeWidth: "2", + strokeLinecap: "round", + strokeLinejoin: "round" + }, /*#__PURE__*/React.createElement("path", { + d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" + }))); +} +Object.assign(__ds_scope, { ThemeToggle, __ds_default_components_islands_ThemeToggle_ThemeToggle_9s19g0: ThemeToggle }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/islands/ThemeToggle/ThemeToggle.tsx", error: String((e && e.message) || e) }); } + +// components/islands/Toast/Toast.tsx +try { (() => { +/** + * @component Toast + * @layer 2 + * @depends theme-seed, toast-support + * @description Redirect-flash notification island for Fresh applications. + */ + +const TOAST_SYMBOLS = { + success: '◎', + error: '≠', + warning: '⟳', + info: '⊕' +}; +const TOAST_LABELS = { + success: 'Success', + error: 'Error', + warning: 'Warning', + info: 'Notice' +}; + +/** + * Renders a redirect-flash toast and cleans toast query params from the URL. + * @param props Toast payload and timing overrides. + * @returns A hydrated toast notification or `null` when inactive. + */ +function Toast({ + message, + title, + type = 'info', + duration = 4200, + cleanUrl +}) { + const exitTimeoutRef = __ds_scope.useRef(); + const hideTimeoutRef = __ds_scope.useRef(); + const urlCleanupTimeoutRef = __ds_scope.useRef(); + const countdownStartedAtRef = __ds_scope.useRef(0); + const remainingTimeRef = __ds_scope.useRef(duration); + const [visible, setVisible] = __ds_scope.useState(Boolean(message)); + const [exiting, setExiting] = __ds_scope.useState(false); + const [instanceKey, setInstanceKey] = __ds_scope.useState(''); + const [paused, setPaused] = __ds_scope.useState(false); + const cleanup = () => { + if (exitTimeoutRef.current) { + globalThis.clearTimeout(exitTimeoutRef.current); + } + if (hideTimeoutRef.current) { + globalThis.clearTimeout(hideTimeoutRef.current); + } + if (urlCleanupTimeoutRef.current) { + globalThis.clearTimeout(urlCleanupTimeoutRef.current); + } + }; + const normalizeBrowserUrl = () => { + const targetUrl = cleanUrl ?? __ds_scope.stripToastFromUrl(new URL(globalThis.location.href)); + let attempts = 0; + const applyCleanUrl = () => { + const currentUrl = `${globalThis.location.pathname}${globalThis.location.search}${globalThis.location.hash}`; + if (currentUrl !== targetUrl) { + globalThis.history.replaceState(globalThis.history.state, '', targetUrl); + } + attempts += 1; + if (attempts < 10) { + urlCleanupTimeoutRef.current = globalThis.setTimeout(applyCleanUrl, 50); + } + }; + applyCleanUrl(); + }; + const dismiss = () => { + cleanup(); + setExiting(true); + hideTimeoutRef.current = globalThis.setTimeout(() => setVisible(false), 220); + }; + const scheduleDismiss = delay => { + if (delay <= 0) { + dismiss(); + return; + } + countdownStartedAtRef.current = Date.now(); + exitTimeoutRef.current = globalThis.setTimeout(() => dismiss(), delay); + }; + const pauseDismiss = () => { + if (paused || exiting) { + return; + } + if (exitTimeoutRef.current) { + const elapsed = Date.now() - countdownStartedAtRef.current; + remainingTimeRef.current = Math.max(remainingTimeRef.current - elapsed, 0); + globalThis.clearTimeout(exitTimeoutRef.current); + exitTimeoutRef.current = undefined; + } + setPaused(true); + }; + const resumeDismiss = () => { + if (!paused || exiting) { + return; + } + setPaused(false); + scheduleDismiss(remainingTimeRef.current); + }; + __ds_scope.useEffect(() => { + if (!message) { + cleanup(); + setVisible(false); + return; + } + cleanup(); + setVisible(true); + setExiting(false); + setPaused(false); + setInstanceKey(globalThis.crypto.randomUUID()); + remainingTimeRef.current = duration; + normalizeBrowserUrl(); + scheduleDismiss(duration); + return () => cleanup(); + }, [cleanUrl, duration, message, title, type]); + if (!message || !visible) { + return null; + } + return /*#__PURE__*/React.createElement("div", { + key: instanceKey, + class: `ns-toast-wrapper ${exiting ? 'ns-toast-exit' : 'ns-toast-enter'}` + }, /*#__PURE__*/React.createElement("div", { + class: `ns-toast ns-toast--${type}`, + onMouseEnter: pauseDismiss, + onMouseLeave: resumeDismiss + }, /*#__PURE__*/React.createElement("div", { + class: "ns-toast__progress-track" + }, /*#__PURE__*/React.createElement("div", { + class: "ns-toast__progress-bar", + style: { + animation: `ns-toast-progress ${duration}ms linear forwards`, + animationPlayState: paused ? 'paused' : 'running' + } + })), /*#__PURE__*/React.createElement("div", { + class: "ns-toast__panel" + }, /*#__PURE__*/React.createElement("div", { + class: "ns-toast__header" + }, /*#__PURE__*/React.createElement("div", { + class: "ns-toast__title-row" + }, /*#__PURE__*/React.createElement("div", { + class: "ns-toast__symbol" + }, TOAST_SYMBOLS[type]), /*#__PURE__*/React.createElement("div", { + class: "min-w-0" + }, /*#__PURE__*/React.createElement("p", { + class: "ns-toast__eyebrow" + }, TOAST_LABELS[type]), /*#__PURE__*/React.createElement("p", { + class: "ns-toast__title" + }, title ?? TOAST_LABELS[type]))), /*#__PURE__*/React.createElement("button", { + type: "button", + "aria-label": "Dismiss notification", + class: "ns-toast__dismiss", + onClick: dismiss + }, "\xD7")), /*#__PURE__*/React.createElement("p", { + class: "ns-toast__message" + }, message)))); +} +Object.assign(__ds_scope, { Toast, __ds_default_components_islands_Toast_Toast_121fo58: Toast }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/islands/Toast/Toast.tsx", error: String((e && e.message) || e) }); } + +__ds_ns.Breadcrumb = __ds_scope.Breadcrumb; + +__ds_ns.DataTable = __ds_scope.DataTable; + +__ds_ns.DetailLayout = __ds_scope.DetailLayout; + +__ds_ns.EmptyState = __ds_scope.EmptyState; + +__ds_ns.FilterForm = __ds_scope.FilterForm; + +__ds_ns.PageHeader = __ds_scope.PageHeader; + +__ds_ns.Pagination = __ds_scope.Pagination; + +__ds_ns.ResponsiveTable = __ds_scope.ResponsiveTable; + +__ds_ns.SectionDivider = __ds_scope.SectionDivider; + +__ds_ns.SidebarShell = __ds_scope.SidebarShell; + +__ds_ns.StatsGrid = __ds_scope.StatsGrid; + +__ds_ns.Alert = __ds_scope.Alert; + +__ds_ns.Avatar = __ds_scope.Avatar; + +__ds_ns.Badge = __ds_scope.Badge; + +__ds_ns.Button = __ds_scope.Button; + +__ds_ns.Card = __ds_scope.Card; + +__ds_ns.ChartBlock = __ds_scope.ChartBlock; + +__ds_ns.Checkbox = __ds_scope.Checkbox; + +__ds_ns.CitationChip = __ds_scope.CitationChip; + +__ds_ns.CodeBlock = __ds_scope.CodeBlock; + +__ds_ns.CommandPalette = __ds_scope.CommandPalette; + +__ds_ns.Donut = __ds_scope.Donut; + +__ds_ns.DROPZONE_INGEST_SOURCES = __ds_scope.DROPZONE_INGEST_SOURCES; + +__ds_ns.DROPZONE_REJECTED_REASONS = __ds_scope.DROPZONE_REJECTED_REASONS; + +__ds_ns.Dropzone = __ds_scope.Dropzone; + +__ds_ns.FormField = __ds_scope.FormField; + +__ds_ns.IconButton = __ds_scope.IconButton; + +__ds_ns.InlineNotice = __ds_scope.InlineNotice; + +__ds_ns.Input = __ds_scope.Input; + +__ds_ns.Label = __ds_scope.Label; + +__ds_ns.TypingIndicator = __ds_scope.TypingIndicator; + +__ds_ns.Message = __ds_scope.Message; + +__ds_ns.ModelSelector = __ds_scope.ModelSelector; + +__ds_ns.PanelHeader = __ds_scope.PanelHeader; + +__ds_ns.PanelTitle = __ds_scope.PanelTitle; + +__ds_ns.PanelDescription = __ds_scope.PanelDescription; + +__ds_ns.PanelBody = __ds_scope.PanelBody; + +__ds_ns.PanelFooter = __ds_scope.PanelFooter; + +__ds_ns.Panel = __ds_scope.Panel; + +__ds_ns.Progress = __ds_scope.Progress; + +__ds_ns.PromptInput = __ds_scope.PromptInput; + +__ds_ns.Search = __ds_scope.Search; + +__ds_ns.Select = __ds_scope.Select; + +__ds_ns.Separator = __ds_scope.Separator; + +__ds_ns.Skeleton = __ds_scope.Skeleton; + +__ds_ns.Spinner = __ds_scope.Spinner; + +__ds_ns.Switch = __ds_scope.Switch; + +__ds_ns.Textarea = __ds_scope.Textarea; + +__ds_ns.ToolCallCard = __ds_scope.ToolCallCard; + +__ds_ns.SidebarToggle = __ds_scope.SidebarToggle; + +__ds_ns.ThemeToggle = __ds_scope.ThemeToggle; + +__ds_ns.Toast = __ds_scope.Toast; + +})(); diff --git a/.llm/runs/dashboard-design--orchestrator/prototype/_ds/netscript-ns-one-ec262e10-d4ad-451f-9aeb-e51955db3634/_ns_runtime.js b/.llm/runs/dashboard-design--orchestrator/prototype/_ds/netscript-ns-one-ec262e10-d4ad-451f-9aeb-e51955db3634/_ns_runtime.js new file mode 100644 index 000000000..b2e4b341e --- /dev/null +++ b/.llm/runs/dashboard-design--orchestrator/prototype/_ds/netscript-ns-one-ec262e10-d4ad-451f-9aeb-e51955db3634/_ns_runtime.js @@ -0,0 +1,4761 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + 1 ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// ../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react/19.2.0/cjs/react.development.js +var require_react_development = __commonJS({ + "../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react/19.2.0/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn("%s(...) is deprecated in plain JavaScript React classes. %s", info[0], info[1]); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", callerName, publicInstance), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function noop() { + } + function testStringCoercion(value) { + return "" + value; + } + function checkKeyStringCoercion(value) { + try { + testStringCoercion(value); + var JSCompiler_inline_result = false; + } catch (e) { + JSCompiler_inline_result = true; + } + if (JSCompiler_inline_result) { + JSCompiler_inline_result = console; + var JSCompiler_temp_const = JSCompiler_inline_result.error; + var JSCompiler_inline_result$jscomp$0 = "function" === typeof Symbol && Symbol.toStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object"; + JSCompiler_temp_const.call(JSCompiler_inline_result, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", JSCompiler_inline_result$jscomp$0); + return testStringCoercion(value); + } + } + function getComponentNameFromType(type) { + if (null == type) return null; + if ("function" === typeof type) return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + case REACT_SUSPENSE_LIST_TYPE: + return "SuspenseList"; + case REACT_ACTIVITY_TYPE: + return "Activity"; + } + if ("object" === typeof type) switch ("number" === typeof type.tag && console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), type.$$typeof) { + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_CONTEXT_TYPE: + return type.displayName || "Context"; + case REACT_CONSUMER_TYPE: + return (type._context.displayName || "Context") + ".Consumer"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + type = type.displayName; + type || (type = innerType.displayName || innerType.name || "", type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef"); + return type; + case REACT_MEMO_TYPE: + return innerType = type.displayName || null, null !== innerType ? innerType : getComponentNameFromType(type.type) || "Memo"; + case REACT_LAZY_TYPE: + innerType = type._payload; + type = type._init; + try { + return getComponentNameFromType(type(innerType)); + } catch (x) { + } + } + return null; + } + function getTaskName(type) { + if (type === REACT_FRAGMENT_TYPE) return "<>"; + if ("object" === typeof type && null !== type && type.$$typeof === REACT_LAZY_TYPE) return "<...>"; + try { + var name = getComponentNameFromType(type); + return name ? "<" + name + ">" : "<...>"; + } catch (x) { + return "<...>"; + } + } + function getOwner() { + var dispatcher = ReactSharedInternals.A; + return null === dispatcher ? null : dispatcher.getOwner(); + } + function UnknownOwner() { + return Error("react-stack-top-frame"); + } + function hasValidKey(config) { + if (hasOwnProperty.call(config, "key")) { + var getter = Object.getOwnPropertyDescriptor(config, "key").get; + if (getter && getter.isReactWarning) return false; + } + return void 0 !== config.key; + } + function defineKeyPropWarningGetter(props, displayName) { + function warnAboutAccessingKey() { + specialPropKeyWarningShown || (specialPropKeyWarningShown = true, console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", displayName)); + } + warnAboutAccessingKey.isReactWarning = true; + Object.defineProperty(props, "key", { + get: warnAboutAccessingKey, + configurable: true + }); + } + function elementRefGetterWithDeprecationWarning() { + var componentName = getComponentNameFromType(this.type); + didWarnAboutElementRef[componentName] || (didWarnAboutElementRef[componentName] = true, console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")); + componentName = this.props.ref; + return void 0 !== componentName ? componentName : null; + } + function ReactElement(type, key, props, owner, debugStack, debugTask) { + var refProp = props.ref; + type = { + $$typeof: REACT_ELEMENT_TYPE, + type, + key, + props, + _owner: owner + }; + null !== (void 0 !== refProp ? refProp : null) ? Object.defineProperty(type, "ref", { + enumerable: false, + get: elementRefGetterWithDeprecationWarning + }) : Object.defineProperty(type, "ref", { + enumerable: false, + value: null + }); + type._store = {}; + Object.defineProperty(type._store, "validated", { + configurable: false, + enumerable: false, + writable: true, + value: 0 + }); + Object.defineProperty(type, "_debugInfo", { + configurable: false, + enumerable: false, + writable: true, + value: null + }); + Object.defineProperty(type, "_debugStack", { + configurable: false, + enumerable: false, + writable: true, + value: debugStack + }); + Object.defineProperty(type, "_debugTask", { + configurable: false, + enumerable: false, + writable: true, + value: debugTask + }); + Object.freeze && (Object.freeze(type.props), Object.freeze(type)); + return type; + } + function cloneAndReplaceKey(oldElement, newKey) { + newKey = ReactElement(oldElement.type, newKey, oldElement.props, oldElement._owner, oldElement._debugStack, oldElement._debugTask); + oldElement._store && (newKey._store.validated = oldElement._store.validated); + return newKey; + } + function validateChildKeys(node) { + isValidElement(node) ? node._store && (node._store.validated = 1) : "object" === typeof node && null !== node && node.$$typeof === REACT_LAZY_TYPE && ("fulfilled" === node._payload.status ? isValidElement(node._payload.value) && node._payload.value._store && (node._payload.value._store.validated = 1) : node._store && (node._store.validated = 1)); + } + function isValidElement(object) { + return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE; + } + function escape(key) { + var escaperLookup = { + "=": "=0", + ":": "=2" + }; + return "$" + key.replace(/[=:]/g, function(match) { + return escaperLookup[match]; + }); + } + function getElementKey(element, index) { + return "object" === typeof element && null !== element && null != element.key ? (checkKeyStringCoercion(element.key), escape("" + element.key)) : index.toString(36); + } + function resolveThenable(thenable) { + switch (thenable.status) { + case "fulfilled": + return thenable.value; + case "rejected": + throw thenable.reason; + default: + switch ("string" === typeof thenable.status ? thenable.then(noop, noop) : (thenable.status = "pending", thenable.then(function(fulfilledValue) { + "pending" === thenable.status && (thenable.status = "fulfilled", thenable.value = fulfilledValue); + }, function(error) { + "pending" === thenable.status && (thenable.status = "rejected", thenable.reason = error); + })), thenable.status) { + case "fulfilled": + return thenable.value; + case "rejected": + throw thenable.reason; + } + } + throw thenable; + } + function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) { + var type = typeof children; + if ("undefined" === type || "boolean" === type) children = null; + var invokeCallback = false; + if (null === children) invokeCallback = true; + else switch (type) { + case "bigint": + case "string": + case "number": + invokeCallback = true; + break; + case "object": + switch (children.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + invokeCallback = true; + break; + case REACT_LAZY_TYPE: + return invokeCallback = children._init, mapIntoArray(invokeCallback(children._payload), array, escapedPrefix, nameSoFar, callback); + } + } + if (invokeCallback) { + invokeCallback = children; + callback = callback(invokeCallback); + var childKey = "" === nameSoFar ? "." + getElementKey(invokeCallback, 0) : nameSoFar; + isArrayImpl(callback) ? (escapedPrefix = "", null != childKey && (escapedPrefix = childKey.replace(userProvidedKeyEscapeRegex, "$&/") + "/"), mapIntoArray(callback, array, escapedPrefix, "", function(c) { + return c; + })) : null != callback && (isValidElement(callback) && (null != callback.key && (invokeCallback && invokeCallback.key === callback.key || checkKeyStringCoercion(callback.key)), escapedPrefix = cloneAndReplaceKey(callback, escapedPrefix + (null == callback.key || invokeCallback && invokeCallback.key === callback.key ? "" : ("" + callback.key).replace(userProvidedKeyEscapeRegex, "$&/") + "/") + childKey), "" !== nameSoFar && null != invokeCallback && isValidElement(invokeCallback) && null == invokeCallback.key && invokeCallback._store && !invokeCallback._store.validated && (escapedPrefix._store.validated = 2), callback = escapedPrefix), array.push(callback)); + return 1; + } + invokeCallback = 0; + childKey = "" === nameSoFar ? "." : nameSoFar + ":"; + if (isArrayImpl(children)) for (var i = 0; i < children.length; i++) nameSoFar = children[i], type = childKey + getElementKey(nameSoFar, i), invokeCallback += mapIntoArray(nameSoFar, array, escapedPrefix, type, callback); + else if (i = getIteratorFn(children), "function" === typeof i) for (i === children.entries && (didWarnAboutMaps || console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."), didWarnAboutMaps = true), children = i.call(children), i = 0; !(nameSoFar = children.next()).done; ) nameSoFar = nameSoFar.value, type = childKey + getElementKey(nameSoFar, i++), invokeCallback += mapIntoArray(nameSoFar, array, escapedPrefix, type, callback); + else if ("object" === type) { + if ("function" === typeof children.then) return mapIntoArray(resolveThenable(children), array, escapedPrefix, nameSoFar, callback); + array = String(children); + throw Error("Objects are not valid as a React child (found: " + ("[object Object]" === array ? "object with keys {" + Object.keys(children).join(", ") + "}" : array) + "). If you meant to render a collection of children, use an array instead."); + } + return invokeCallback; + } + function mapChildren(children, func, context) { + if (null == children) return children; + var result = [], count = 0; + mapIntoArray(children, result, "", "", function(child) { + return func.call(context, child, count++); + }); + return result; + } + function lazyInitializer(payload) { + if (-1 === payload._status) { + var ioInfo = payload._ioInfo; + null != ioInfo && (ioInfo.start = ioInfo.end = performance.now()); + ioInfo = payload._result; + var thenable = ioInfo(); + thenable.then(function(moduleObject) { + if (0 === payload._status || -1 === payload._status) { + payload._status = 1; + payload._result = moduleObject; + var _ioInfo = payload._ioInfo; + null != _ioInfo && (_ioInfo.end = performance.now()); + void 0 === thenable.status && (thenable.status = "fulfilled", thenable.value = moduleObject); + } + }, function(error) { + if (0 === payload._status || -1 === payload._status) { + payload._status = 2; + payload._result = error; + var _ioInfo2 = payload._ioInfo; + null != _ioInfo2 && (_ioInfo2.end = performance.now()); + void 0 === thenable.status && (thenable.status = "rejected", thenable.reason = error); + } + }); + ioInfo = payload._ioInfo; + if (null != ioInfo) { + ioInfo.value = thenable; + var displayName = thenable.displayName; + "string" === typeof displayName && (ioInfo.name = displayName); + } + -1 === payload._status && (payload._status = 0, payload._result = thenable); + } + if (1 === payload._status) return ioInfo = payload._result, void 0 === ioInfo && console.error("lazy: Expected the result of a dynamic import() call. Instead received: %s\n\nYour code should look like: \n const MyComponent = lazy(() => import('./MyComponent'))\n\nDid you accidentally put curly braces around the import?", ioInfo), "default" in ioInfo || console.error("lazy: Expected the result of a dynamic import() call. Instead received: %s\n\nYour code should look like: \n const MyComponent = lazy(() => import('./MyComponent'))", ioInfo), ioInfo.default; + throw payload._result; + } + function resolveDispatcher() { + var dispatcher = ReactSharedInternals.H; + null === dispatcher && console.error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem."); + return dispatcher; + } + function releaseAsyncTransition() { + ReactSharedInternals.asyncTransitions--; + } + function enqueueTask(task) { + if (null === enqueueTaskImpl) try { + var requireString = ("require" + Math.random()).slice(0, 7); + enqueueTaskImpl = (module && module[requireString]).call(module, "timers").setImmediate; + } catch (_err) { + enqueueTaskImpl = function(callback) { + false === didWarnAboutMessageChannel && (didWarnAboutMessageChannel = true, "undefined" === typeof MessageChannel && console.error("This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning.")); + var channel = new MessageChannel(); + channel.port1.onmessage = callback; + channel.port2.postMessage(void 0); + }; + } + return enqueueTaskImpl(task); + } + function aggregateErrors(errors) { + return 1 < errors.length && "function" === typeof AggregateError ? new AggregateError(errors) : errors[0]; + } + function popActScope(prevActQueue, prevActScopeDepth) { + prevActScopeDepth !== actScopeDepth - 1 && console.error("You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. "); + actScopeDepth = prevActScopeDepth; + } + function recursivelyFlushAsyncActWork(returnValue, resolve, reject) { + var queue = ReactSharedInternals.actQueue; + if (null !== queue) if (0 !== queue.length) try { + flushActQueue(queue); + enqueueTask(function() { + return recursivelyFlushAsyncActWork(returnValue, resolve, reject); + }); + return; + } catch (error) { + ReactSharedInternals.thrownErrors.push(error); + } + else ReactSharedInternals.actQueue = null; + 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve(returnValue); + } + function flushActQueue(queue) { + if (!isFlushing) { + isFlushing = true; + var i = 0; + try { + for (; i < queue.length; i++) { + var callback = queue[i]; + do { + ReactSharedInternals.didUsePromise = false; + var continuation = callback(false); + if (null !== continuation) { + if (ReactSharedInternals.didUsePromise) { + queue[i] = callback; + queue.splice(0, i); + return; + } + callback = continuation; + } else break; + } while (1); + } + queue.length = 0; + } catch (error) { + queue.splice(0, i + 1), ReactSharedInternals.thrownErrors.push(error); + } finally { + isFlushing = false; + } + } + } + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error()); + var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), MAYBE_ITERATOR_SYMBOL = Symbol.iterator, didWarnStateUpdateForUnmountedComponent = {}, ReactNoopUpdateQueue = { + isMounted: function() { + return false; + }, + enqueueForceUpdate: function(publicInstance) { + warnNoop(publicInstance, "forceUpdate"); + }, + enqueueReplaceState: function(publicInstance) { + warnNoop(publicInstance, "replaceState"); + }, + enqueueSetState: function(publicInstance) { + warnNoop(publicInstance, "setState"); + } + }, assign = Object.assign, emptyObject = {}; + Object.freeze(emptyObject); + Component.prototype.isReactComponent = {}; + Component.prototype.setState = function(partialState, callback) { + if ("object" !== typeof partialState && "function" !== typeof partialState && null != partialState) throw Error("takes an object of state variables to update or a function which returns an object of state variables."); + this.updater.enqueueSetState(this, partialState, callback, "setState"); + }; + Component.prototype.forceUpdate = function(callback) { + this.updater.enqueueForceUpdate(this, callback, "forceUpdate"); + }; + var deprecatedAPIs = { + isMounted: [ + "isMounted", + "Instead, make sure to clean up subscriptions and pending requests in componentWillUnmount to prevent memory leaks." + ], + replaceState: [ + "replaceState", + "Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236)." + ] + }; + for (fnName in deprecatedAPIs) deprecatedAPIs.hasOwnProperty(fnName) && defineDeprecationWarning(fnName, deprecatedAPIs[fnName]); + ComponentDummy.prototype = Component.prototype; + deprecatedAPIs = PureComponent.prototype = new ComponentDummy(); + deprecatedAPIs.constructor = PureComponent; + assign(deprecatedAPIs, Component.prototype); + deprecatedAPIs.isPureReactComponent = true; + var isArrayImpl = Array.isArray, REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = { + H: null, + A: null, + T: null, + S: null, + actQueue: null, + asyncTransitions: 0, + isBatchingLegacy: false, + didScheduleLegacyUpdate: false, + didUsePromise: false, + thrownErrors: [], + getCurrentStack: null, + recentlyCreatedOwnerStacks: 0 + }, hasOwnProperty = Object.prototype.hasOwnProperty, createTask = console.createTask ? console.createTask : function() { + return null; + }; + deprecatedAPIs = { + react_stack_bottom_frame: function(callStackForError) { + return callStackForError(); + } + }; + var specialPropKeyWarningShown, didWarnAboutOldJSXRuntime; + var didWarnAboutElementRef = {}; + var unknownOwnerDebugStack = deprecatedAPIs.react_stack_bottom_frame.bind(deprecatedAPIs, UnknownOwner)(); + var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner)); + var didWarnAboutMaps = false, userProvidedKeyEscapeRegex = /\/+/g, reportGlobalError = "function" === typeof reportError ? reportError : function(error) { + if ("object" === typeof window && "function" === typeof window.ErrorEvent) { + var event = new window.ErrorEvent("error", { + bubbles: true, + cancelable: true, + message: "object" === typeof error && null !== error && "string" === typeof error.message ? String(error.message) : String(error), + error + }); + if (!window.dispatchEvent(event)) return; + } else if ("object" === typeof process && "function" === typeof process.emit) { + process.emit("uncaughtException", error); + return; + } + console.error(error); + }, didWarnAboutMessageChannel = false, enqueueTaskImpl = null, actScopeDepth = 0, didWarnNoAwaitAct = false, isFlushing = false, queueSeveralMicrotasks = "function" === typeof queueMicrotask ? function(callback) { + queueMicrotask(function() { + return queueMicrotask(callback); + }); + } : enqueueTask; + deprecatedAPIs = Object.freeze({ + __proto__: null, + c: function(size) { + return resolveDispatcher().useMemoCache(size); + } + }); + var fnName = { + map: mapChildren, + forEach: function(children, forEachFunc, forEachContext) { + mapChildren(children, function() { + forEachFunc.apply(this, arguments); + }, forEachContext); + }, + count: function(children) { + var n = 0; + mapChildren(children, function() { + n++; + }); + return n; + }, + toArray: function(children) { + return mapChildren(children, function(child) { + return child; + }) || []; + }, + only: function(children) { + if (!isValidElement(children)) throw Error("React.Children.only expected to receive a single React element child."); + return children; + } + }; + exports.Activity = REACT_ACTIVITY_TYPE; + exports.Children = fnName; + exports.Component = Component; + exports.Fragment = REACT_FRAGMENT_TYPE; + exports.Profiler = REACT_PROFILER_TYPE; + exports.PureComponent = PureComponent; + exports.StrictMode = REACT_STRICT_MODE_TYPE; + exports.Suspense = REACT_SUSPENSE_TYPE; + exports.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = ReactSharedInternals; + exports.__COMPILER_RUNTIME = deprecatedAPIs; + exports.act = function(callback) { + var prevActQueue = ReactSharedInternals.actQueue, prevActScopeDepth = actScopeDepth; + actScopeDepth++; + var queue = ReactSharedInternals.actQueue = null !== prevActQueue ? prevActQueue : [], didAwaitActCall = false; + try { + var result = callback(); + } catch (error) { + ReactSharedInternals.thrownErrors.push(error); + } + if (0 < ReactSharedInternals.thrownErrors.length) throw popActScope(prevActQueue, prevActScopeDepth), callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback; + if (null !== result && "object" === typeof result && "function" === typeof result.then) { + var thenable = result; + queueSeveralMicrotasks(function() { + didAwaitActCall || didWarnNoAwaitAct || (didWarnNoAwaitAct = true, console.error("You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);")); + }); + return { + then: function(resolve, reject) { + didAwaitActCall = true; + thenable.then(function(returnValue) { + popActScope(prevActQueue, prevActScopeDepth); + if (0 === prevActScopeDepth) { + try { + flushActQueue(queue), enqueueTask(function() { + return recursivelyFlushAsyncActWork(returnValue, resolve, reject); + }); + } catch (error$0) { + ReactSharedInternals.thrownErrors.push(error$0); + } + if (0 < ReactSharedInternals.thrownErrors.length) { + var _thrownError = aggregateErrors(ReactSharedInternals.thrownErrors); + ReactSharedInternals.thrownErrors.length = 0; + reject(_thrownError); + } + } else resolve(returnValue); + }, function(error) { + popActScope(prevActQueue, prevActScopeDepth); + 0 < ReactSharedInternals.thrownErrors.length ? (error = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(error)) : reject(error); + }); + } + }; + } + var returnValue$jscomp$0 = result; + popActScope(prevActQueue, prevActScopeDepth); + 0 === prevActScopeDepth && (flushActQueue(queue), 0 !== queue.length && queueSeveralMicrotasks(function() { + didAwaitActCall || didWarnNoAwaitAct || (didWarnNoAwaitAct = true, console.error("A component suspended inside an `act` scope, but the `act` call was not awaited. When testing React components that depend on asynchronous data, you must await the result:\n\nawait act(() => ...)")); + }), ReactSharedInternals.actQueue = null); + if (0 < ReactSharedInternals.thrownErrors.length) throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback; + return { + then: function(resolve, reject) { + didAwaitActCall = true; + 0 === prevActScopeDepth ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() { + return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve, reject); + })) : resolve(returnValue$jscomp$0); + } + }; + }; + exports.cache = function(fn) { + return function() { + return fn.apply(null, arguments); + }; + }; + exports.cacheSignal = function() { + return null; + }; + exports.captureOwnerStack = function() { + var getCurrentStack = ReactSharedInternals.getCurrentStack; + return null === getCurrentStack ? null : getCurrentStack(); + }; + exports.cloneElement = function(element, config, children) { + if (null === element || void 0 === element) throw Error("The argument must be a React element, but you passed " + element + "."); + var props = assign({}, element.props), key = element.key, owner = element._owner; + if (null != config) { + var JSCompiler_inline_result; + a: { + if (hasOwnProperty.call(config, "ref") && (JSCompiler_inline_result = Object.getOwnPropertyDescriptor(config, "ref").get) && JSCompiler_inline_result.isReactWarning) { + JSCompiler_inline_result = false; + break a; + } + JSCompiler_inline_result = void 0 !== config.ref; + } + JSCompiler_inline_result && (owner = getOwner()); + hasValidKey(config) && (checkKeyStringCoercion(config.key), key = "" + config.key); + for (propName in config) !hasOwnProperty.call(config, propName) || "key" === propName || "__self" === propName || "__source" === propName || "ref" === propName && void 0 === config.ref || (props[propName] = config[propName]); + } + var propName = arguments.length - 2; + if (1 === propName) props.children = children; + else if (1 < propName) { + JSCompiler_inline_result = Array(propName); + for (var i = 0; i < propName; i++) JSCompiler_inline_result[i] = arguments[i + 2]; + props.children = JSCompiler_inline_result; + } + props = ReactElement(element.type, key, props, owner, element._debugStack, element._debugTask); + for (key = 2; key < arguments.length; key++) validateChildKeys(arguments[key]); + return props; + }; + exports.createContext = function(defaultValue) { + defaultValue = { + $$typeof: REACT_CONTEXT_TYPE, + _currentValue: defaultValue, + _currentValue2: defaultValue, + _threadCount: 0, + Provider: null, + Consumer: null + }; + defaultValue.Provider = defaultValue; + defaultValue.Consumer = { + $$typeof: REACT_CONSUMER_TYPE, + _context: defaultValue + }; + defaultValue._currentRenderer = null; + defaultValue._currentRenderer2 = null; + return defaultValue; + }; + exports.createElement = function(type, config, children) { + for (var i = 2; i < arguments.length; i++) validateChildKeys(arguments[i]); + i = {}; + var key = null; + if (null != config) for (propName in didWarnAboutOldJSXRuntime || !("__self" in config) || "key" in config || (didWarnAboutOldJSXRuntime = true, console.warn("Your app (or one of its dependencies) is using an outdated JSX transform. Update to the modern JSX transform for faster performance: https://react.dev/link/new-jsx-transform")), hasValidKey(config) && (checkKeyStringCoercion(config.key), key = "" + config.key), config) hasOwnProperty.call(config, propName) && "key" !== propName && "__self" !== propName && "__source" !== propName && (i[propName] = config[propName]); + var childrenLength = arguments.length - 2; + if (1 === childrenLength) i.children = children; + else if (1 < childrenLength) { + for (var childArray = Array(childrenLength), _i = 0; _i < childrenLength; _i++) childArray[_i] = arguments[_i + 2]; + Object.freeze && Object.freeze(childArray); + i.children = childArray; + } + if (type && type.defaultProps) for (propName in childrenLength = type.defaultProps, childrenLength) void 0 === i[propName] && (i[propName] = childrenLength[propName]); + key && defineKeyPropWarningGetter(i, "function" === typeof type ? type.displayName || type.name || "Unknown" : type); + var propName = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++; + return ReactElement(type, key, i, getOwner(), propName ? Error("react-stack-top-frame") : unknownOwnerDebugStack, propName ? createTask(getTaskName(type)) : unknownOwnerDebugTask); + }; + exports.createRef = function() { + var refObject = { + current: null + }; + Object.seal(refObject); + return refObject; + }; + exports.forwardRef = function(render) { + null != render && render.$$typeof === REACT_MEMO_TYPE ? console.error("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...)).") : "function" !== typeof render ? console.error("forwardRef requires a render function but was given %s.", null === render ? "null" : typeof render) : 0 !== render.length && 2 !== render.length && console.error("forwardRef render functions accept exactly two parameters: props and ref. %s", 1 === render.length ? "Did you forget to use the ref parameter?" : "Any additional parameter will be undefined."); + null != render && null != render.defaultProps && console.error("forwardRef render functions do not support defaultProps. Did you accidentally pass a React component?"); + var elementType = { + $$typeof: REACT_FORWARD_REF_TYPE, + render + }, ownName; + Object.defineProperty(elementType, "displayName", { + enumerable: false, + configurable: true, + get: function() { + return ownName; + }, + set: function(name) { + ownName = name; + render.name || render.displayName || (Object.defineProperty(render, "name", { + value: name + }), render.displayName = name); + } + }); + return elementType; + }; + exports.isValidElement = isValidElement; + exports.lazy = function(ctor) { + ctor = { + _status: -1, + _result: ctor + }; + var lazyType = { + $$typeof: REACT_LAZY_TYPE, + _payload: ctor, + _init: lazyInitializer + }, ioInfo = { + name: "lazy", + start: -1, + end: -1, + value: null, + owner: null, + debugStack: Error("react-stack-top-frame"), + debugTask: console.createTask ? console.createTask("lazy()") : null + }; + ctor._ioInfo = ioInfo; + lazyType._debugInfo = [ + { + awaited: ioInfo + } + ]; + return lazyType; + }; + exports.memo = function(type, compare) { + null == type && console.error("memo: The first argument must be a component. Instead received: %s", null === type ? "null" : typeof type); + compare = { + $$typeof: REACT_MEMO_TYPE, + type, + compare: void 0 === compare ? null : compare + }; + var ownName; + Object.defineProperty(compare, "displayName", { + enumerable: false, + configurable: true, + get: function() { + return ownName; + }, + set: function(name) { + ownName = name; + type.name || type.displayName || (Object.defineProperty(type, "name", { + value: name + }), type.displayName = name); + } + }); + return compare; + }; + exports.startTransition = function(scope) { + var prevTransition = ReactSharedInternals.T, currentTransition = {}; + currentTransition._updatedFibers = /* @__PURE__ */ new Set(); + ReactSharedInternals.T = currentTransition; + try { + var returnValue = scope(), onStartTransitionFinish = ReactSharedInternals.S; + null !== onStartTransitionFinish && onStartTransitionFinish(currentTransition, returnValue); + "object" === typeof returnValue && null !== returnValue && "function" === typeof returnValue.then && (ReactSharedInternals.asyncTransitions++, returnValue.then(releaseAsyncTransition, releaseAsyncTransition), returnValue.then(noop, reportGlobalError)); + } catch (error) { + reportGlobalError(error); + } finally { + null === prevTransition && currentTransition._updatedFibers && (scope = currentTransition._updatedFibers.size, currentTransition._updatedFibers.clear(), 10 < scope && console.warn("Detected a large number of updates inside startTransition. If this is due to a subscription please re-write it to use React provided hooks. Otherwise concurrent mode guarantees are off the table.")), null !== prevTransition && null !== currentTransition.types && (null !== prevTransition.types && prevTransition.types !== currentTransition.types && console.error("We expected inner Transitions to have transferred the outer types set and that you cannot add to the outer Transition while inside the inner.This is a bug in React."), prevTransition.types = currentTransition.types), ReactSharedInternals.T = prevTransition; + } + }; + exports.unstable_useCacheRefresh = function() { + return resolveDispatcher().useCacheRefresh(); + }; + exports.use = function(usable) { + return resolveDispatcher().use(usable); + }; + exports.useActionState = function(action, initialState, permalink) { + return resolveDispatcher().useActionState(action, initialState, permalink); + }; + exports.useCallback = function(callback, deps) { + return resolveDispatcher().useCallback(callback, deps); + }; + exports.useContext = function(Context) { + var dispatcher = resolveDispatcher(); + Context.$$typeof === REACT_CONSUMER_TYPE && console.error("Calling useContext(Context.Consumer) is not supported and will cause bugs. Did you mean to call useContext(Context) instead?"); + return dispatcher.useContext(Context); + }; + exports.useDebugValue = function(value, formatterFn) { + return resolveDispatcher().useDebugValue(value, formatterFn); + }; + exports.useDeferredValue = function(value, initialValue) { + return resolveDispatcher().useDeferredValue(value, initialValue); + }; + exports.useEffect = function(create, deps) { + null == create && console.warn("React Hook useEffect requires an effect callback. Did you forget to pass a callback to the hook?"); + return resolveDispatcher().useEffect(create, deps); + }; + exports.useEffectEvent = function(callback) { + return resolveDispatcher().useEffectEvent(callback); + }; + exports.useId = function() { + return resolveDispatcher().useId(); + }; + exports.useImperativeHandle = function(ref, create, deps) { + return resolveDispatcher().useImperativeHandle(ref, create, deps); + }; + exports.useInsertionEffect = function(create, deps) { + null == create && console.warn("React Hook useInsertionEffect requires an effect callback. Did you forget to pass a callback to the hook?"); + return resolveDispatcher().useInsertionEffect(create, deps); + }; + exports.useLayoutEffect = function(create, deps) { + null == create && console.warn("React Hook useLayoutEffect requires an effect callback. Did you forget to pass a callback to the hook?"); + return resolveDispatcher().useLayoutEffect(create, deps); + }; + exports.useMemo = function(create, deps) { + return resolveDispatcher().useMemo(create, deps); + }; + exports.useOptimistic = function(passthrough, reducer) { + return resolveDispatcher().useOptimistic(passthrough, reducer); + }; + exports.useReducer = function(reducer, initialArg, init) { + return resolveDispatcher().useReducer(reducer, initialArg, init); + }; + exports.useRef = function(initialValue) { + return resolveDispatcher().useRef(initialValue); + }; + exports.useState = function(initialState) { + return resolveDispatcher().useState(initialState); + }; + exports.useSyncExternalStore = function(subscribe, getSnapshot, getServerSnapshot) { + return resolveDispatcher().useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); + }; + exports.useTransition = function() { + return resolveDispatcher().useTransition(); + }; + exports.version = "19.2.0"; + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error()); + })(); + } +}); + +// ../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react/19.2.0/index.js +var require__ = __commonJS({ + "../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react/19.2.0/index.js"(exports, module) { + "use strict"; + if (false) { + module.exports = null; + } else { + module.exports = require_react_development(); + } + } +}); + +// ../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/scheduler/0.27.0/cjs/scheduler.development.js +var require_scheduler_development = __commonJS({ + "../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/scheduler/0.27.0/cjs/scheduler.development.js"(exports) { + "use strict"; + (function() { + function performWorkUntilDeadline() { + needsPaint = false; + if (isMessageLoopRunning) { + var currentTime = exports.unstable_now(); + startTime = currentTime; + var hasMoreWork = true; + try { + a: { + isHostCallbackScheduled = false; + isHostTimeoutScheduled && (isHostTimeoutScheduled = false, localClearTimeout(taskTimeoutID), taskTimeoutID = -1); + isPerformingWork = true; + var previousPriorityLevel = currentPriorityLevel; + try { + b: { + advanceTimers(currentTime); + for (currentTask = peek(taskQueue); null !== currentTask && !(currentTask.expirationTime > currentTime && shouldYieldToHost()); ) { + var callback = currentTask.callback; + if ("function" === typeof callback) { + currentTask.callback = null; + currentPriorityLevel = currentTask.priorityLevel; + var continuationCallback = callback(currentTask.expirationTime <= currentTime); + currentTime = exports.unstable_now(); + if ("function" === typeof continuationCallback) { + currentTask.callback = continuationCallback; + advanceTimers(currentTime); + hasMoreWork = true; + break b; + } + currentTask === peek(taskQueue) && pop(taskQueue); + advanceTimers(currentTime); + } else pop(taskQueue); + currentTask = peek(taskQueue); + } + if (null !== currentTask) hasMoreWork = true; + else { + var firstTimer = peek(timerQueue); + null !== firstTimer && requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); + hasMoreWork = false; + } + } + break a; + } finally { + currentTask = null, currentPriorityLevel = previousPriorityLevel, isPerformingWork = false; + } + hasMoreWork = void 0; + } + } finally { + hasMoreWork ? schedulePerformWorkUntilDeadline() : isMessageLoopRunning = false; + } + } + } + function push(heap, node) { + var index = heap.length; + heap.push(node); + a: for (; 0 < index; ) { + var parentIndex = index - 1 >>> 1, parent = heap[parentIndex]; + if (0 < compare(parent, node)) heap[parentIndex] = node, heap[index] = parent, index = parentIndex; + else break a; + } + } + function peek(heap) { + return 0 === heap.length ? null : heap[0]; + } + function pop(heap) { + if (0 === heap.length) return null; + var first = heap[0], last = heap.pop(); + if (last !== first) { + heap[0] = last; + a: for (var index = 0, length = heap.length, halfLength = length >>> 1; index < halfLength; ) { + var leftIndex = 2 * (index + 1) - 1, left = heap[leftIndex], rightIndex = leftIndex + 1, right = heap[rightIndex]; + if (0 > compare(left, last)) rightIndex < length && 0 > compare(right, left) ? (heap[index] = right, heap[rightIndex] = last, index = rightIndex) : (heap[index] = left, heap[leftIndex] = last, index = leftIndex); + else if (rightIndex < length && 0 > compare(right, last)) heap[index] = right, heap[rightIndex] = last, index = rightIndex; + else break a; + } + } + return first; + } + function compare(a, b) { + var diff = a.sortIndex - b.sortIndex; + return 0 !== diff ? diff : a.id - b.id; + } + function advanceTimers(currentTime) { + for (var timer = peek(timerQueue); null !== timer; ) { + if (null === timer.callback) pop(timerQueue); + else if (timer.startTime <= currentTime) pop(timerQueue), timer.sortIndex = timer.expirationTime, push(taskQueue, timer); + else break; + timer = peek(timerQueue); + } + } + function handleTimeout(currentTime) { + isHostTimeoutScheduled = false; + advanceTimers(currentTime); + if (!isHostCallbackScheduled) if (null !== peek(taskQueue)) isHostCallbackScheduled = true, isMessageLoopRunning || (isMessageLoopRunning = true, schedulePerformWorkUntilDeadline()); + else { + var firstTimer = peek(timerQueue); + null !== firstTimer && requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); + } + } + function shouldYieldToHost() { + return needsPaint ? true : exports.unstable_now() - startTime < frameInterval ? false : true; + } + function requestHostTimeout(callback, ms) { + taskTimeoutID = localSetTimeout(function() { + callback(exports.unstable_now()); + }, ms); + } + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error()); + exports.unstable_now = void 0; + if ("object" === typeof performance && "function" === typeof performance.now) { + var localPerformance = performance; + exports.unstable_now = function() { + return localPerformance.now(); + }; + } else { + var localDate = Date, initialTime = localDate.now(); + exports.unstable_now = function() { + return localDate.now() - initialTime; + }; + } + var taskQueue = [], timerQueue = [], taskIdCounter = 1, currentTask = null, currentPriorityLevel = 3, isPerformingWork = false, isHostCallbackScheduled = false, isHostTimeoutScheduled = false, needsPaint = false, localSetTimeout = "function" === typeof setTimeout ? setTimeout : null, localClearTimeout = "function" === typeof clearTimeout ? clearTimeout : null, localSetImmediate = "undefined" !== typeof setImmediate ? setImmediate : null, isMessageLoopRunning = false, taskTimeoutID = -1, frameInterval = 5, startTime = -1; + if ("function" === typeof localSetImmediate) var schedulePerformWorkUntilDeadline = function() { + localSetImmediate(performWorkUntilDeadline); + }; + else if ("undefined" !== typeof MessageChannel) { + var channel = new MessageChannel(), port = channel.port2; + channel.port1.onmessage = performWorkUntilDeadline; + schedulePerformWorkUntilDeadline = function() { + port.postMessage(null); + }; + } else schedulePerformWorkUntilDeadline = function() { + localSetTimeout(performWorkUntilDeadline, 0); + }; + exports.unstable_IdlePriority = 5; + exports.unstable_ImmediatePriority = 1; + exports.unstable_LowPriority = 4; + exports.unstable_NormalPriority = 3; + exports.unstable_Profiling = null; + exports.unstable_UserBlockingPriority = 2; + exports.unstable_cancelCallback = function(task) { + task.callback = null; + }; + exports.unstable_forceFrameRate = function(fps) { + 0 > fps || 125 < fps ? console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported") : frameInterval = 0 < fps ? Math.floor(1e3 / fps) : 5; + }; + exports.unstable_getCurrentPriorityLevel = function() { + return currentPriorityLevel; + }; + exports.unstable_next = function(eventHandler) { + switch (currentPriorityLevel) { + case 1: + case 2: + case 3: + var priorityLevel = 3; + break; + default: + priorityLevel = currentPriorityLevel; + } + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = priorityLevel; + try { + return eventHandler(); + } finally { + currentPriorityLevel = previousPriorityLevel; + } + }; + exports.unstable_requestPaint = function() { + needsPaint = true; + }; + exports.unstable_runWithPriority = function(priorityLevel, eventHandler) { + switch (priorityLevel) { + case 1: + case 2: + case 3: + case 4: + case 5: + break; + default: + priorityLevel = 3; + } + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = priorityLevel; + try { + return eventHandler(); + } finally { + currentPriorityLevel = previousPriorityLevel; + } + }; + exports.unstable_scheduleCallback = function(priorityLevel, callback, options) { + var currentTime = exports.unstable_now(); + "object" === typeof options && null !== options ? (options = options.delay, options = "number" === typeof options && 0 < options ? currentTime + options : currentTime) : options = currentTime; + switch (priorityLevel) { + case 1: + var timeout = -1; + break; + case 2: + timeout = 250; + break; + case 5: + timeout = 1073741823; + break; + case 4: + timeout = 1e4; + break; + default: + timeout = 5e3; + } + timeout = options + timeout; + priorityLevel = { + id: taskIdCounter++, + callback, + priorityLevel, + startTime: options, + expirationTime: timeout, + sortIndex: -1 + }; + options > currentTime ? (priorityLevel.sortIndex = options, push(timerQueue, priorityLevel), null === peek(taskQueue) && priorityLevel === peek(timerQueue) && (isHostTimeoutScheduled ? (localClearTimeout(taskTimeoutID), taskTimeoutID = -1) : isHostTimeoutScheduled = true, requestHostTimeout(handleTimeout, options - currentTime))) : (priorityLevel.sortIndex = timeout, push(taskQueue, priorityLevel), isHostCallbackScheduled || isPerformingWork || (isHostCallbackScheduled = true, isMessageLoopRunning || (isMessageLoopRunning = true, schedulePerformWorkUntilDeadline()))); + return priorityLevel; + }; + exports.unstable_shouldYield = shouldYieldToHost; + exports.unstable_wrapCallback = function(callback) { + var parentPriorityLevel = currentPriorityLevel; + return function() { + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = parentPriorityLevel; + try { + return callback.apply(this, arguments); + } finally { + currentPriorityLevel = previousPriorityLevel; + } + }; + }; + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error()); + })(); + } +}); + +// ../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/scheduler/0.27.0/index.js +var require__2 = __commonJS({ + "../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/scheduler/0.27.0/index.js"(exports, module) { + "use strict"; + if (false) { + module.exports = null; + } else { + module.exports = require_scheduler_development(); + } + } +}); + +// ../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react-dom/19.2.0/cjs/react-dom.development.js +var require_react_dom_development = __commonJS({ + "../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react-dom/19.2.0/cjs/react-dom.development.js"(exports) { + "use strict"; + (function() { + function noop() { + } + function testStringCoercion(value) { + return "" + value; + } + function createPortal$1(children, containerInfo, implementation) { + var key = 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + try { + testStringCoercion(key); + var JSCompiler_inline_result = false; + } catch (e) { + JSCompiler_inline_result = true; + } + JSCompiler_inline_result && (console.error("The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", "function" === typeof Symbol && Symbol.toStringTag && key[Symbol.toStringTag] || key.constructor.name || "Object"), testStringCoercion(key)); + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children, + containerInfo, + implementation + }; + } + function getCrossOriginStringAs(as, input) { + if ("font" === as) return ""; + if ("string" === typeof input) return "use-credentials" === input ? input : ""; + } + function getValueDescriptorExpectingObjectForWarning(thing) { + return null === thing ? "`null`" : void 0 === thing ? "`undefined`" : "" === thing ? "an empty string" : 'something with type "' + typeof thing + '"'; + } + function getValueDescriptorExpectingEnumForWarning(thing) { + return null === thing ? "`null`" : void 0 === thing ? "`undefined`" : "" === thing ? "an empty string" : "string" === typeof thing ? JSON.stringify(thing) : "number" === typeof thing ? "`" + thing + "`" : 'something with type "' + typeof thing + '"'; + } + function resolveDispatcher() { + var dispatcher = ReactSharedInternals.H; + null === dispatcher && console.error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem."); + return dispatcher; + } + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error()); + var React2 = require__(), Internals = { + d: { + f: noop, + r: function() { + throw Error("Invalid form element. requestFormReset must be passed a form that was rendered by React."); + }, + D: noop, + C: noop, + L: noop, + m: noop, + X: noop, + S: noop, + M: noop + }, + p: 0, + findDOMNode: null + }, REACT_PORTAL_TYPE = Symbol.for("react.portal"), ReactSharedInternals = React2.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; + "function" === typeof Map && null != Map.prototype && "function" === typeof Map.prototype.forEach && "function" === typeof Set && null != Set.prototype && "function" === typeof Set.prototype.clear && "function" === typeof Set.prototype.forEach || console.error("React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"); + exports.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = Internals; + exports.createPortal = function(children, container) { + var key = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null; + if (!container || 1 !== container.nodeType && 9 !== container.nodeType && 11 !== container.nodeType) throw Error("Target container is not a DOM element."); + return createPortal$1(children, container, null, key); + }; + exports.flushSync = function(fn) { + var previousTransition = ReactSharedInternals.T, previousUpdatePriority = Internals.p; + try { + if (ReactSharedInternals.T = null, Internals.p = 2, fn) return fn(); + } finally { + ReactSharedInternals.T = previousTransition, Internals.p = previousUpdatePriority, Internals.d.f() && console.error("flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task."); + } + }; + exports.preconnect = function(href, options) { + "string" === typeof href && href ? null != options && "object" !== typeof options ? console.error("ReactDOM.preconnect(): Expected the `options` argument (second) to be an object but encountered %s instead. The only supported option at this time is `crossOrigin` which accepts a string.", getValueDescriptorExpectingEnumForWarning(options)) : null != options && "string" !== typeof options.crossOrigin && console.error("ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered %s instead. Try removing this option or passing a string value instead.", getValueDescriptorExpectingObjectForWarning(options.crossOrigin)) : console.error("ReactDOM.preconnect(): Expected the `href` argument (first) to be a non-empty string but encountered %s instead.", getValueDescriptorExpectingObjectForWarning(href)); + "string" === typeof href && (options ? (options = options.crossOrigin, options = "string" === typeof options ? "use-credentials" === options ? options : "" : void 0) : options = null, Internals.d.C(href, options)); + }; + exports.prefetchDNS = function(href) { + if ("string" !== typeof href || !href) console.error("ReactDOM.prefetchDNS(): Expected the `href` argument (first) to be a non-empty string but encountered %s instead.", getValueDescriptorExpectingObjectForWarning(href)); + else if (1 < arguments.length) { + var options = arguments[1]; + "object" === typeof options && options.hasOwnProperty("crossOrigin") ? console.error("ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered %s as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.", getValueDescriptorExpectingEnumForWarning(options)) : console.error("ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered %s as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.", getValueDescriptorExpectingEnumForWarning(options)); + } + "string" === typeof href && Internals.d.D(href); + }; + exports.preinit = function(href, options) { + "string" === typeof href && href ? null == options || "object" !== typeof options ? console.error("ReactDOM.preinit(): Expected the `options` argument (second) to be an object with an `as` property describing the type of resource to be preinitialized but encountered %s instead.", getValueDescriptorExpectingEnumForWarning(options)) : "style" !== options.as && "script" !== options.as && console.error('ReactDOM.preinit(): Expected the `as` property in the `options` argument (second) to contain a valid value describing the type of resource to be preinitialized but encountered %s instead. Valid values for `as` are "style" and "script".', getValueDescriptorExpectingEnumForWarning(options.as)) : console.error("ReactDOM.preinit(): Expected the `href` argument (first) to be a non-empty string but encountered %s instead.", getValueDescriptorExpectingObjectForWarning(href)); + if ("string" === typeof href && options && "string" === typeof options.as) { + var as = options.as, crossOrigin = getCrossOriginStringAs(as, options.crossOrigin), integrity = "string" === typeof options.integrity ? options.integrity : void 0, fetchPriority = "string" === typeof options.fetchPriority ? options.fetchPriority : void 0; + "style" === as ? Internals.d.S(href, "string" === typeof options.precedence ? options.precedence : void 0, { + crossOrigin, + integrity, + fetchPriority + }) : "script" === as && Internals.d.X(href, { + crossOrigin, + integrity, + fetchPriority, + nonce: "string" === typeof options.nonce ? options.nonce : void 0 + }); + } + }; + exports.preinitModule = function(href, options) { + var encountered = ""; + "string" === typeof href && href || (encountered += " The `href` argument encountered was " + getValueDescriptorExpectingObjectForWarning(href) + "."); + void 0 !== options && "object" !== typeof options ? encountered += " The `options` argument encountered was " + getValueDescriptorExpectingObjectForWarning(options) + "." : options && "as" in options && "script" !== options.as && (encountered += " The `as` option encountered was " + getValueDescriptorExpectingEnumForWarning(options.as) + "."); + if (encountered) console.error("ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property.%s", encountered); + else switch (encountered = options && "string" === typeof options.as ? options.as : "script", encountered) { + case "script": + break; + default: + encountered = getValueDescriptorExpectingEnumForWarning(encountered), console.error('ReactDOM.preinitModule(): Currently the only supported "as" type for this function is "script" but received "%s" instead. This warning was generated for `href` "%s". In the future other module types will be supported, aligning with the import-attributes proposal. Learn more here: (https://github.com/tc39/proposal-import-attributes)', encountered, href); + } + if ("string" === typeof href) if ("object" === typeof options && null !== options) { + if (null == options.as || "script" === options.as) encountered = getCrossOriginStringAs(options.as, options.crossOrigin), Internals.d.M(href, { + crossOrigin: encountered, + integrity: "string" === typeof options.integrity ? options.integrity : void 0, + nonce: "string" === typeof options.nonce ? options.nonce : void 0 + }); + } else null == options && Internals.d.M(href); + }; + exports.preload = function(href, options) { + var encountered = ""; + "string" === typeof href && href || (encountered += " The `href` argument encountered was " + getValueDescriptorExpectingObjectForWarning(href) + "."); + null == options || "object" !== typeof options ? encountered += " The `options` argument encountered was " + getValueDescriptorExpectingObjectForWarning(options) + "." : "string" === typeof options.as && options.as || (encountered += " The `as` option encountered was " + getValueDescriptorExpectingObjectForWarning(options.as) + "."); + encountered && console.error('ReactDOM.preload(): Expected two arguments, a non-empty `href` string and an `options` object with an `as` property valid for a `` tag.%s', encountered); + if ("string" === typeof href && "object" === typeof options && null !== options && "string" === typeof options.as) { + encountered = options.as; + var crossOrigin = getCrossOriginStringAs(encountered, options.crossOrigin); + Internals.d.L(href, encountered, { + crossOrigin, + integrity: "string" === typeof options.integrity ? options.integrity : void 0, + nonce: "string" === typeof options.nonce ? options.nonce : void 0, + type: "string" === typeof options.type ? options.type : void 0, + fetchPriority: "string" === typeof options.fetchPriority ? options.fetchPriority : void 0, + referrerPolicy: "string" === typeof options.referrerPolicy ? options.referrerPolicy : void 0, + imageSrcSet: "string" === typeof options.imageSrcSet ? options.imageSrcSet : void 0, + imageSizes: "string" === typeof options.imageSizes ? options.imageSizes : void 0, + media: "string" === typeof options.media ? options.media : void 0 + }); + } + }; + exports.preloadModule = function(href, options) { + var encountered = ""; + "string" === typeof href && href || (encountered += " The `href` argument encountered was " + getValueDescriptorExpectingObjectForWarning(href) + "."); + void 0 !== options && "object" !== typeof options ? encountered += " The `options` argument encountered was " + getValueDescriptorExpectingObjectForWarning(options) + "." : options && "as" in options && "string" !== typeof options.as && (encountered += " The `as` option encountered was " + getValueDescriptorExpectingObjectForWarning(options.as) + "."); + encountered && console.error('ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `` tag.%s', encountered); + "string" === typeof href && (options ? (encountered = getCrossOriginStringAs(options.as, options.crossOrigin), Internals.d.m(href, { + as: "string" === typeof options.as && "script" !== options.as ? options.as : void 0, + crossOrigin: encountered, + integrity: "string" === typeof options.integrity ? options.integrity : void 0 + })) : Internals.d.m(href)); + }; + exports.requestFormReset = function(form) { + Internals.d.r(form); + }; + exports.unstable_batchedUpdates = function(fn, a) { + return fn(a); + }; + exports.useFormState = function(action, initialState, permalink) { + return resolveDispatcher().useFormState(action, initialState, permalink); + }; + exports.useFormStatus = function() { + return resolveDispatcher().useHostTransitionStatus(); + }; + exports.version = "19.2.0"; + "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error()); + })(); + } +}); + +// ../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react-dom/19.2.0/index.js +var require__3 = __commonJS({ + "../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react-dom/19.2.0/index.js"(exports, module) { + "use strict"; + if (false) { + checkDCE(); + module.exports = null; + } else { + module.exports = require_react_dom_development(); + } + } +}); + +// ../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react-dom/19.2.0/cjs/react-dom-client.development.js +var require_react_dom_client_development = __commonJS({ + "../../../../../../../../Users/chaut/AppData/Local/deno/npm/registry.npmjs.org/react-dom/19.2.0/cjs/react-dom-client.development.js"(exports) { + "use strict"; + (function() { + function findHook(fiber, id) { + for (fiber = fiber.memoizedState; null !== fiber && 0 < id; ) fiber = fiber.next, id--; + return fiber; + } + function copyWithSetImpl(obj, path, index, value) { + if (index >= path.length) return value; + var key = path[index], updated = isArrayImpl(obj) ? obj.slice() : assign({}, obj); + updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); + return updated; + } + function copyWithRename(obj, oldPath, newPath) { + if (oldPath.length !== newPath.length) console.warn("copyWithRename() expects paths of the same length"); + else { + for (var i = 0; i < newPath.length - 1; i++) if (oldPath[i] !== newPath[i]) { + console.warn("copyWithRename() expects paths to be the same except for the deepest key"); + return; + } + return copyWithRenameImpl(obj, oldPath, newPath, 0); + } + } + function copyWithRenameImpl(obj, oldPath, newPath, index) { + var oldKey = oldPath[index], updated = isArrayImpl(obj) ? obj.slice() : assign({}, obj); + index + 1 === oldPath.length ? (updated[newPath[index]] = updated[oldKey], isArrayImpl(updated) ? updated.splice(oldKey, 1) : delete updated[oldKey]) : updated[oldKey] = copyWithRenameImpl(obj[oldKey], oldPath, newPath, index + 1); + return updated; + } + function copyWithDeleteImpl(obj, path, index) { + var key = path[index], updated = isArrayImpl(obj) ? obj.slice() : assign({}, obj); + if (index + 1 === path.length) return isArrayImpl(updated) ? updated.splice(key, 1) : delete updated[key], updated; + updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); + return updated; + } + function shouldSuspendImpl() { + return false; + } + function shouldErrorImpl() { + return null; + } + function warnInvalidHookAccess() { + console.error("Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. You can only call Hooks at the top level of your React function. For more information, see https://react.dev/link/rules-of-hooks"); + } + function warnInvalidContextAccess() { + console.error("Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()."); + } + function noop() { + } + function warnForMissingKey() { + } + function setToSortedString(set) { + var array = []; + set.forEach(function(value) { + array.push(value); + }); + return array.sort().join(", "); + } + function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); + } + function scheduleRoot(root2, element) { + root2.context === emptyContextObject && (updateContainerImpl(root2.current, 2, element, root2, null, null), flushSyncWork$1()); + } + function scheduleRefresh(root2, update) { + if (null !== resolveFamily) { + var staleFamilies = update.staleFamilies; + update = update.updatedFamilies; + flushPendingEffects(); + scheduleFibersWithFamiliesRecursively(root2.current, update, staleFamilies); + flushSyncWork$1(); + } + } + function setRefreshHandler(handler) { + resolveFamily = handler; + } + function isValidContainer(node) { + return !(!node || 1 !== node.nodeType && 9 !== node.nodeType && 11 !== node.nodeType); + } + function getNearestMountedFiber(fiber) { + var node = fiber, nearestMounted = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + fiber = node; + do + node = fiber, 0 !== (node.flags & 4098) && (nearestMounted = node.return), fiber = node.return; + while (fiber); + } + return 3 === node.tag ? nearestMounted : null; + } + function getSuspenseInstanceFromFiber(fiber) { + if (13 === fiber.tag) { + var suspenseState = fiber.memoizedState; + null === suspenseState && (fiber = fiber.alternate, null !== fiber && (suspenseState = fiber.memoizedState)); + if (null !== suspenseState) return suspenseState.dehydrated; + } + return null; + } + function getActivityInstanceFromFiber(fiber) { + if (31 === fiber.tag) { + var activityState = fiber.memoizedState; + null === activityState && (fiber = fiber.alternate, null !== fiber && (activityState = fiber.memoizedState)); + if (null !== activityState) return activityState.dehydrated; + } + return null; + } + function assertIsMounted(fiber) { + if (getNearestMountedFiber(fiber) !== fiber) throw Error("Unable to find node on an unmounted component."); + } + function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = getNearestMountedFiber(fiber); + if (null === alternate) throw Error("Unable to find node on an unmounted component."); + return alternate !== fiber ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw Error("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) a = parentA, b = parentB; + else { + for (var didFindChild = false, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) throw Error("Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue."); + } + } + if (a.alternate !== b) throw Error("Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue."); + } + if (3 !== a.tag) throw Error("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; + } + function findCurrentHostFiberImpl(node) { + var tag = node.tag; + if (5 === tag || 26 === tag || 27 === tag || 6 === tag) return node; + for (node = node.child; null !== node; ) { + tag = findCurrentHostFiberImpl(node); + if (null !== tag) return tag; + node = node.sibling; + } + return null; + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function getComponentNameFromType(type) { + if (null == type) return null; + if ("function" === typeof type) return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + case REACT_SUSPENSE_LIST_TYPE: + return "SuspenseList"; + case REACT_ACTIVITY_TYPE: + return "Activity"; + } + if ("object" === typeof type) switch ("number" === typeof type.tag && console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), type.$$typeof) { + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_CONTEXT_TYPE: + return type.displayName || "Context"; + case REACT_CONSUMER_TYPE: + return (type._context.displayName || "Context") + ".Consumer"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + type = type.displayName; + type || (type = innerType.displayName || innerType.name || "", type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef"); + return type; + case REACT_MEMO_TYPE: + return innerType = type.displayName || null, null !== innerType ? innerType : getComponentNameFromType(type.type) || "Memo"; + case REACT_LAZY_TYPE: + innerType = type._payload; + type = type._init; + try { + return getComponentNameFromType(type(innerType)); + } catch (x) { + } + } + return null; + } + function getComponentNameFromOwner(owner) { + return "number" === typeof owner.tag ? getComponentNameFromFiber(owner) : "string" === typeof owner.name ? owner.name : null; + } + function getComponentNameFromFiber(fiber) { + var type = fiber.type; + switch (fiber.tag) { + case 31: + return "Activity"; + case 24: + return "Cache"; + case 9: + return (type._context.displayName || "Context") + ".Consumer"; + case 10: + return type.displayName || "Context"; + case 18: + return "DehydratedFragment"; + case 11: + return fiber = type.render, fiber = fiber.displayName || fiber.name || "", type.displayName || ("" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef"); + case 7: + return "Fragment"; + case 26: + case 27: + case 5: + return type; + case 4: + return "Portal"; + case 3: + return "Root"; + case 6: + return "Text"; + case 16: + return getComponentNameFromType(type); + case 8: + return type === REACT_STRICT_MODE_TYPE ? "StrictMode" : "Mode"; + case 22: + return "Offscreen"; + case 12: + return "Profiler"; + case 21: + return "Scope"; + case 13: + return "Suspense"; + case 19: + return "SuspenseList"; + case 25: + return "TracingMarker"; + case 1: + case 0: + case 14: + case 15: + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + break; + case 29: + type = fiber._debugInfo; + if (null != type) { + for (var i = type.length - 1; 0 <= i; i--) if ("string" === typeof type[i].name) return type[i].name; + } + if (null !== fiber.return) return getComponentNameFromFiber(fiber.return); + } + return null; + } + function createCursor(defaultValue) { + return { + current: defaultValue + }; + } + function pop(cursor, fiber) { + 0 > index$jscomp$0 ? console.error("Unexpected pop.") : (fiber !== fiberStack[index$jscomp$0] && console.error("Unexpected Fiber popped."), cursor.current = valueStack[index$jscomp$0], valueStack[index$jscomp$0] = null, fiberStack[index$jscomp$0] = null, index$jscomp$0--); + } + function push(cursor, value, fiber) { + index$jscomp$0++; + valueStack[index$jscomp$0] = cursor.current; + fiberStack[index$jscomp$0] = fiber; + cursor.current = value; + } + function requiredContext(c) { + null === c && console.error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."); + return c; + } + function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, null, fiber); + var nextRootContext = nextRootInstance.nodeType; + switch (nextRootContext) { + case 9: + case 11: + nextRootContext = 9 === nextRootContext ? "#document" : "#fragment"; + nextRootInstance = (nextRootInstance = nextRootInstance.documentElement) ? (nextRootInstance = nextRootInstance.namespaceURI) ? getOwnHostContext(nextRootInstance) : HostContextNamespaceNone : HostContextNamespaceNone; + break; + default: + if (nextRootContext = nextRootInstance.tagName, nextRootInstance = nextRootInstance.namespaceURI) nextRootInstance = getOwnHostContext(nextRootInstance), nextRootInstance = getChildHostContextProd(nextRootInstance, nextRootContext); + else switch (nextRootContext) { + case "svg": + nextRootInstance = HostContextNamespaceSvg; + break; + case "math": + nextRootInstance = HostContextNamespaceMath; + break; + default: + nextRootInstance = HostContextNamespaceNone; + } + } + nextRootContext = nextRootContext.toLowerCase(); + nextRootContext = updatedAncestorInfoDev(null, nextRootContext); + nextRootContext = { + context: nextRootInstance, + ancestorInfo: nextRootContext + }; + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootContext, fiber); + } + function popHostContainer(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); + } + function getHostContext() { + return requiredContext(contextStackCursor.current); + } + function pushHostContext(fiber) { + null !== fiber.memoizedState && push(hostTransitionProviderCursor, fiber, fiber); + var context = requiredContext(contextStackCursor.current); + var type = fiber.type; + var nextContext = getChildHostContextProd(context.context, type); + type = updatedAncestorInfoDev(context.ancestorInfo, type); + nextContext = { + context: nextContext, + ancestorInfo: type + }; + context !== nextContext && (push(contextFiberStackCursor, fiber, fiber), push(contextStackCursor, nextContext, fiber)); + } + function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && (pop(contextStackCursor, fiber), pop(contextFiberStackCursor, fiber)); + hostTransitionProviderCursor.current === fiber && (pop(hostTransitionProviderCursor, fiber), HostTransitionContext._currentValue = NotPendingTransition); + } + function disabledLog() { + } + function disableLogs() { + if (0 === disabledDepth) { + prevLog = console.log; + prevInfo = console.info; + prevWarn = console.warn; + prevError = console.error; + prevGroup = console.group; + prevGroupCollapsed = console.groupCollapsed; + prevGroupEnd = console.groupEnd; + var props = { + configurable: true, + enumerable: true, + value: disabledLog, + writable: true + }; + Object.defineProperties(console, { + info: props, + log: props, + warn: props, + error: props, + group: props, + groupCollapsed: props, + groupEnd: props + }); + } + disabledDepth++; + } + function reenableLogs() { + disabledDepth--; + if (0 === disabledDepth) { + var props = { + configurable: true, + enumerable: true, + writable: true + }; + Object.defineProperties(console, { + log: assign({}, props, { + value: prevLog + }), + info: assign({}, props, { + value: prevInfo + }), + warn: assign({}, props, { + value: prevWarn + }), + error: assign({}, props, { + value: prevError + }), + group: assign({}, props, { + value: prevGroup + }), + groupCollapsed: assign({}, props, { + value: prevGroupCollapsed + }), + groupEnd: assign({}, props, { + value: prevGroupEnd + }) + }); + } + 0 > disabledDepth && console.error("disabledDepth fell below zero. This is a bug in React. Please file an issue."); + } + function formatOwnerStack(error) { + var prevPrepareStackTrace = Error.prepareStackTrace; + Error.prepareStackTrace = void 0; + error = error.stack; + Error.prepareStackTrace = prevPrepareStackTrace; + error.startsWith("Error: react-stack-top-frame\n") && (error = error.slice(29)); + prevPrepareStackTrace = error.indexOf("\n"); + -1 !== prevPrepareStackTrace && (error = error.slice(prevPrepareStackTrace + 1)); + prevPrepareStackTrace = error.indexOf("react_stack_bottom_frame"); + -1 !== prevPrepareStackTrace && (prevPrepareStackTrace = error.lastIndexOf("\n", prevPrepareStackTrace)); + if (-1 !== prevPrepareStackTrace) error = error.slice(0, prevPrepareStackTrace); + else return ""; + return error; + } + function describeBuiltInComponentFrame(name) { + if (void 0 === prefix) try { + throw Error(); + } catch (x) { + var match = x.stack.trim().match(/\n( *(at )?)/); + prefix = match && match[1] || ""; + suffix = -1 < x.stack.indexOf("\n at") ? " ()" : -1 < x.stack.indexOf("@") ? "@unknown:0:0" : ""; + } + return "\n" + prefix + name + suffix; + } + function describeNativeComponentFrame(fn, construct) { + if (!fn || reentry) return ""; + var frame = componentFrameCache.get(fn); + if (void 0 !== frame) return frame; + reentry = true; + frame = Error.prepareStackTrace; + Error.prepareStackTrace = void 0; + var previousDispatcher2 = null; + previousDispatcher2 = ReactSharedInternals.H; + ReactSharedInternals.H = null; + disableLogs(); + try { + var RunInRootFrame = { + DetermineComponentFrameRoot: function() { + try { + if (construct) { + var Fake = function() { + throw Error(); + }; + Object.defineProperty(Fake.prototype, "props", { + set: function() { + throw Error(); + } + }); + if ("object" === typeof Reflect && Reflect.construct) { + try { + Reflect.construct(Fake, []); + } catch (x) { + var control = x; + } + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x$0) { + control = x$0; + } + fn.call(Fake.prototype); + } + } else { + try { + throw Error(); + } catch (x$1) { + control = x$1; + } + (Fake = fn()) && "function" === typeof Fake.catch && Fake.catch(function() { + }); + } + } catch (sample) { + if (sample && control && "string" === typeof sample.stack) return [ + sample.stack, + control.stack + ]; + } + return [ + null, + null + ]; + } + }; + RunInRootFrame.DetermineComponentFrameRoot.displayName = "DetermineComponentFrameRoot"; + var namePropDescriptor = Object.getOwnPropertyDescriptor(RunInRootFrame.DetermineComponentFrameRoot, "name"); + namePropDescriptor && namePropDescriptor.configurable && Object.defineProperty(RunInRootFrame.DetermineComponentFrameRoot, "name", { + value: "DetermineComponentFrameRoot" + }); + var _RunInRootFrame$Deter = RunInRootFrame.DetermineComponentFrameRoot(), sampleStack = _RunInRootFrame$Deter[0], controlStack = _RunInRootFrame$Deter[1]; + if (sampleStack && controlStack) { + var sampleLines = sampleStack.split("\n"), controlLines = controlStack.split("\n"); + for (_RunInRootFrame$Deter = namePropDescriptor = 0; namePropDescriptor < sampleLines.length && !sampleLines[namePropDescriptor].includes("DetermineComponentFrameRoot"); ) namePropDescriptor++; + for (; _RunInRootFrame$Deter < controlLines.length && !controlLines[_RunInRootFrame$Deter].includes("DetermineComponentFrameRoot"); ) _RunInRootFrame$Deter++; + if (namePropDescriptor === sampleLines.length || _RunInRootFrame$Deter === controlLines.length) for (namePropDescriptor = sampleLines.length - 1, _RunInRootFrame$Deter = controlLines.length - 1; 1 <= namePropDescriptor && 0 <= _RunInRootFrame$Deter && sampleLines[namePropDescriptor] !== controlLines[_RunInRootFrame$Deter]; ) _RunInRootFrame$Deter--; + for (; 1 <= namePropDescriptor && 0 <= _RunInRootFrame$Deter; namePropDescriptor--, _RunInRootFrame$Deter--) if (sampleLines[namePropDescriptor] !== controlLines[_RunInRootFrame$Deter]) { + if (1 !== namePropDescriptor || 1 !== _RunInRootFrame$Deter) { + do + if (namePropDescriptor--, _RunInRootFrame$Deter--, 0 > _RunInRootFrame$Deter || sampleLines[namePropDescriptor] !== controlLines[_RunInRootFrame$Deter]) { + var _frame = "\n" + sampleLines[namePropDescriptor].replace(" at new ", " at "); + fn.displayName && _frame.includes("") && (_frame = _frame.replace("", fn.displayName)); + "function" === typeof fn && componentFrameCache.set(fn, _frame); + return _frame; + } + while (1 <= namePropDescriptor && 0 <= _RunInRootFrame$Deter); + } + break; + } + } + } finally { + reentry = false, ReactSharedInternals.H = previousDispatcher2, reenableLogs(), Error.prepareStackTrace = frame; + } + sampleLines = (sampleLines = fn ? fn.displayName || fn.name : "") ? describeBuiltInComponentFrame(sampleLines) : ""; + "function" === typeof fn && componentFrameCache.set(fn, sampleLines); + return sampleLines; + } + function describeFiber(fiber, childFiber) { + switch (fiber.tag) { + case 26: + case 27: + case 5: + return describeBuiltInComponentFrame(fiber.type); + case 16: + return describeBuiltInComponentFrame("Lazy"); + case 13: + return fiber.child !== childFiber && null !== childFiber ? describeBuiltInComponentFrame("Suspense Fallback") : describeBuiltInComponentFrame("Suspense"); + case 19: + return describeBuiltInComponentFrame("SuspenseList"); + case 0: + case 15: + return describeNativeComponentFrame(fiber.type, false); + case 11: + return describeNativeComponentFrame(fiber.type.render, false); + case 1: + return describeNativeComponentFrame(fiber.type, true); + case 31: + return describeBuiltInComponentFrame("Activity"); + default: + return ""; + } + } + function getStackByFiberInDevAndProd(workInProgress2) { + try { + var info = "", previous = null; + do { + info += describeFiber(workInProgress2, previous); + var debugInfo = workInProgress2._debugInfo; + if (debugInfo) for (var i = debugInfo.length - 1; 0 <= i; i--) { + var entry = debugInfo[i]; + if ("string" === typeof entry.name) { + var JSCompiler_temp_const = info; + a: { + var name = entry.name, env = entry.env, location = entry.debugLocation; + if (null != location) { + var childStack = formatOwnerStack(location), idx = childStack.lastIndexOf("\n"), lastLine = -1 === idx ? childStack : childStack.slice(idx + 1); + if (-1 !== lastLine.indexOf(name)) { + var JSCompiler_inline_result = "\n" + lastLine; + break a; + } + } + JSCompiler_inline_result = describeBuiltInComponentFrame(name + (env ? " [" + env + "]" : "")); + } + info = JSCompiler_temp_const + JSCompiler_inline_result; + } + } + previous = workInProgress2; + workInProgress2 = workInProgress2.return; + } while (workInProgress2); + return info; + } catch (x) { + return "\nError generating stack: " + x.message + "\n" + x.stack; + } + } + function describeFunctionComponentFrameWithoutLineNumber(fn) { + return (fn = fn ? fn.displayName || fn.name : "") ? describeBuiltInComponentFrame(fn) : ""; + } + function getCurrentFiberOwnerNameInDevOrNull() { + if (null === current) return null; + var owner = current._debugOwner; + return null != owner ? getComponentNameFromOwner(owner) : null; + } + function getCurrentFiberStackInDev() { + if (null === current) return ""; + var workInProgress2 = current; + try { + var info = ""; + 6 === workInProgress2.tag && (workInProgress2 = workInProgress2.return); + switch (workInProgress2.tag) { + case 26: + case 27: + case 5: + info += describeBuiltInComponentFrame(workInProgress2.type); + break; + case 13: + info += describeBuiltInComponentFrame("Suspense"); + break; + case 19: + info += describeBuiltInComponentFrame("SuspenseList"); + break; + case 31: + info += describeBuiltInComponentFrame("Activity"); + break; + case 30: + case 0: + case 15: + case 1: + workInProgress2._debugOwner || "" !== info || (info += describeFunctionComponentFrameWithoutLineNumber(workInProgress2.type)); + break; + case 11: + workInProgress2._debugOwner || "" !== info || (info += describeFunctionComponentFrameWithoutLineNumber(workInProgress2.type.render)); + } + for (; workInProgress2; ) if ("number" === typeof workInProgress2.tag) { + var fiber = workInProgress2; + workInProgress2 = fiber._debugOwner; + var debugStack = fiber._debugStack; + if (workInProgress2 && debugStack) { + var formattedStack = formatOwnerStack(debugStack); + "" !== formattedStack && (info += "\n" + formattedStack); + } + } else if (null != workInProgress2.debugStack) { + var ownerStack = workInProgress2.debugStack; + (workInProgress2 = workInProgress2.owner) && ownerStack && (info += "\n" + formatOwnerStack(ownerStack)); + } else break; + var JSCompiler_inline_result = info; + } catch (x) { + JSCompiler_inline_result = "\nError generating stack: " + x.message + "\n" + x.stack; + } + return JSCompiler_inline_result; + } + function runWithFiberInDEV(fiber, callback, arg0, arg1, arg2, arg3, arg4) { + var previousFiber = current; + setCurrentFiber(fiber); + try { + return null !== fiber && fiber._debugTask ? fiber._debugTask.run(callback.bind(null, arg0, arg1, arg2, arg3, arg4)) : callback(arg0, arg1, arg2, arg3, arg4); + } finally { + setCurrentFiber(previousFiber); + } + throw Error("runWithFiberInDEV should never be called in production. This is a bug in React."); + } + function setCurrentFiber(fiber) { + ReactSharedInternals.getCurrentStack = null === fiber ? null : getCurrentFiberStackInDev; + isRendering = false; + current = fiber; + } + function typeName(value) { + return "function" === typeof Symbol && Symbol.toStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object"; + } + function willCoercionThrow(value) { + try { + return testStringCoercion(value), false; + } catch (e) { + return true; + } + } + function testStringCoercion(value) { + return "" + value; + } + function checkAttributeStringCoercion(value, attributeName) { + if (willCoercionThrow(value)) return console.error("The provided `%s` attribute is an unsupported type %s. This value must be coerced to a string before using it here.", attributeName, typeName(value)), testStringCoercion(value); + } + function checkCSSPropertyStringCoercion(value, propName) { + if (willCoercionThrow(value)) return console.error("The provided `%s` CSS property is an unsupported type %s. This value must be coerced to a string before using it here.", propName, typeName(value)), testStringCoercion(value); + } + function checkFormFieldValueStringCoercion(value) { + if (willCoercionThrow(value)) return console.error("Form field values (value, checked, defaultValue, or defaultChecked props) must be strings, not %s. This value must be coerced to a string before using it here.", typeName(value)), testStringCoercion(value); + } + function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return false; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled) return true; + if (!hook.supportsFiber) return console.error("The installed version of React DevTools is too old and will not work with the current version of React. Please update React DevTools. https://react.dev/link/react-devtools"), true; + try { + rendererID = hook.inject(internals), injectedHook = hook; + } catch (err) { + console.error("React instrumentation encountered an error: %o.", err); + } + return hook.checkDCE ? true : false; + } + function setIsStrictModeForDevtools(newIsStrictMode) { + "function" === typeof log$1 && unstable_setDisableYieldValue(newIsStrictMode); + if (injectedHook && "function" === typeof injectedHook.setStrictMode) try { + injectedHook.setStrictMode(rendererID, newIsStrictMode); + } catch (err) { + hasLoggedError || (hasLoggedError = true, console.error("React instrumentation encountered an error: %o", err)); + } + } + function clz32Fallback(x) { + x >>>= 0; + return 0 === x ? 32 : 31 - (log(x) / LN2 | 0) | 0; + } + function getHighestPriorityLanes(lanes) { + var pendingSyncLanes = lanes & 42; + if (0 !== pendingSyncLanes) return pendingSyncLanes; + switch (lanes & -lanes) { + 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 lanes & 261888; + case 262144: + case 524288: + case 1048576: + case 2097152: + return lanes & 3932160; + case 4194304: + case 8388608: + case 16777216: + case 33554432: + return lanes & 62914560; + case 67108864: + return 67108864; + case 134217728: + return 134217728; + case 268435456: + return 268435456; + case 536870912: + return 536870912; + case 1073741824: + return 0; + default: + return console.error("Should have found matching lanes. This is a bug in React."), lanes; + } + } + function getNextLanes(root2, wipLanes, rootHasPendingCommit) { + var pendingLanes = root2.pendingLanes; + if (0 === pendingLanes) return 0; + var nextLanes = 0, suspendedLanes = root2.suspendedLanes, pingedLanes = root2.pingedLanes; + root2 = root2.warmLanes; + var nonIdlePendingLanes = pendingLanes & 134217727; + 0 !== nonIdlePendingLanes ? (pendingLanes = nonIdlePendingLanes & ~suspendedLanes, 0 !== pendingLanes ? nextLanes = getHighestPriorityLanes(pendingLanes) : (pingedLanes &= nonIdlePendingLanes, 0 !== pingedLanes ? nextLanes = getHighestPriorityLanes(pingedLanes) : rootHasPendingCommit || (rootHasPendingCommit = nonIdlePendingLanes & ~root2, 0 !== rootHasPendingCommit && (nextLanes = getHighestPriorityLanes(rootHasPendingCommit))))) : (nonIdlePendingLanes = pendingLanes & ~suspendedLanes, 0 !== nonIdlePendingLanes ? nextLanes = getHighestPriorityLanes(nonIdlePendingLanes) : 0 !== pingedLanes ? nextLanes = getHighestPriorityLanes(pingedLanes) : rootHasPendingCommit || (rootHasPendingCommit = pendingLanes & ~root2, 0 !== rootHasPendingCommit && (nextLanes = getHighestPriorityLanes(rootHasPendingCommit)))); + return 0 === nextLanes ? 0 : 0 !== wipLanes && wipLanes !== nextLanes && 0 === (wipLanes & suspendedLanes) && (suspendedLanes = nextLanes & -nextLanes, rootHasPendingCommit = wipLanes & -wipLanes, suspendedLanes >= rootHasPendingCommit || 32 === suspendedLanes && 0 !== (rootHasPendingCommit & 4194048)) ? wipLanes : nextLanes; + } + function checkIfRootIsPrerendering(root2, renderLanes2) { + return 0 === (root2.pendingLanes & ~(root2.suspendedLanes & ~root2.pingedLanes) & renderLanes2); + } + function computeExpirationTime(lane, currentTime) { + switch (lane) { + case 1: + case 2: + case 4: + case 8: + case 64: + return currentTime + 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 currentTime + 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 console.error("Should have found matching lanes. This is a bug in React."), -1; + } + } + function claimNextRetryLane() { + var lane = nextRetryLane; + nextRetryLane <<= 1; + 0 === (nextRetryLane & 62914560) && (nextRetryLane = 4194304); + return lane; + } + function createLaneMap(initial) { + for (var laneMap = [], i = 0; 31 > i; i++) laneMap.push(initial); + return laneMap; + } + function markRootUpdated$1(root2, updateLane) { + root2.pendingLanes |= updateLane; + 268435456 !== updateLane && (root2.suspendedLanes = 0, root2.pingedLanes = 0, root2.warmLanes = 0); + } + function markRootFinished(root2, finishedLanes, remainingLanes, spawnedLane, updatedLanes, suspendedRetryLanes) { + var previouslyPendingLanes = root2.pendingLanes; + root2.pendingLanes = remainingLanes; + root2.suspendedLanes = 0; + root2.pingedLanes = 0; + root2.warmLanes = 0; + root2.expiredLanes &= remainingLanes; + root2.entangledLanes &= remainingLanes; + root2.errorRecoveryDisabledLanes &= remainingLanes; + root2.shellSuspendCounter = 0; + var entanglements = root2.entanglements, expirationTimes = root2.expirationTimes, hiddenUpdates = root2.hiddenUpdates; + for (remainingLanes = previouslyPendingLanes & ~remainingLanes; 0 < remainingLanes; ) { + var index = 31 - clz32(remainingLanes), lane = 1 << index; + entanglements[index] = 0; + expirationTimes[index] = -1; + var hiddenUpdatesForLane = hiddenUpdates[index]; + if (null !== hiddenUpdatesForLane) for (hiddenUpdates[index] = null, index = 0; index < hiddenUpdatesForLane.length; index++) { + var update = hiddenUpdatesForLane[index]; + null !== update && (update.lane &= -536870913); + } + remainingLanes &= ~lane; + } + 0 !== spawnedLane && markSpawnedDeferredLane(root2, spawnedLane, 0); + 0 !== suspendedRetryLanes && 0 === updatedLanes && 0 !== root2.tag && (root2.suspendedLanes |= suspendedRetryLanes & ~(previouslyPendingLanes & ~finishedLanes)); + } + function markSpawnedDeferredLane(root2, spawnedLane, entangledLanes) { + root2.pendingLanes |= spawnedLane; + root2.suspendedLanes &= ~spawnedLane; + var spawnedLaneIndex = 31 - clz32(spawnedLane); + root2.entangledLanes |= spawnedLane; + root2.entanglements[spawnedLaneIndex] = root2.entanglements[spawnedLaneIndex] | 1073741824 | entangledLanes & 261930; + } + function markRootEntangled(root2, entangledLanes) { + var rootEntangledLanes = root2.entangledLanes |= entangledLanes; + for (root2 = root2.entanglements; rootEntangledLanes; ) { + var index = 31 - clz32(rootEntangledLanes), lane = 1 << index; + lane & entangledLanes | root2[index] & entangledLanes && (root2[index] |= entangledLanes); + rootEntangledLanes &= ~lane; + } + } + function getBumpedLaneForHydration(root2, renderLanes2) { + var renderLane = renderLanes2 & -renderLanes2; + renderLane = 0 !== (renderLane & 42) ? 1 : getBumpedLaneForHydrationByLane(renderLane); + return 0 !== (renderLane & (root2.suspendedLanes | renderLanes2)) ? 0 : renderLane; + } + function getBumpedLaneForHydrationByLane(lane) { + switch (lane) { + case 2: + lane = 1; + break; + case 8: + lane = 4; + break; + case 32: + lane = 16; + break; + 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: + case 4194304: + case 8388608: + case 16777216: + case 33554432: + lane = 128; + break; + case 268435456: + lane = 134217728; + break; + default: + lane = 0; + } + return lane; + } + function addFiberToLanesMap(root2, fiber, lanes) { + if (isDevToolsPresent) for (root2 = root2.pendingUpdatersLaneMap; 0 < lanes; ) { + var index = 31 - clz32(lanes), lane = 1 << index; + root2[index].add(fiber); + lanes &= ~lane; + } + } + function movePendingFibersToMemoized(root2, lanes) { + if (isDevToolsPresent) for (var pendingUpdatersLaneMap = root2.pendingUpdatersLaneMap, memoizedUpdaters = root2.memoizedUpdaters; 0 < lanes; ) { + var index = 31 - clz32(lanes); + root2 = 1 << index; + index = pendingUpdatersLaneMap[index]; + 0 < index.size && (index.forEach(function(fiber) { + var alternate = fiber.alternate; + null !== alternate && memoizedUpdaters.has(alternate) || memoizedUpdaters.add(fiber); + }), index.clear()); + lanes &= ~root2; + } + } + function lanesToEventPriority(lanes) { + lanes &= -lanes; + return 0 !== DiscreteEventPriority && DiscreteEventPriority < lanes ? 0 !== ContinuousEventPriority && ContinuousEventPriority < lanes ? 0 !== (lanes & 134217727) ? DefaultEventPriority : IdleEventPriority : ContinuousEventPriority : DiscreteEventPriority; + } + function resolveUpdatePriority() { + var updatePriority = ReactDOMSharedInternals.p; + if (0 !== updatePriority) return updatePriority; + updatePriority = window.event; + return void 0 === updatePriority ? DefaultEventPriority : getEventPriority(updatePriority.type); + } + function runWithPriority(priority, fn) { + var previousPriority = ReactDOMSharedInternals.p; + try { + return ReactDOMSharedInternals.p = priority, fn(); + } finally { + ReactDOMSharedInternals.p = previousPriority; + } + } + function detachDeletedInstance(node) { + delete node[internalInstanceKey]; + delete node[internalPropsKey]; + delete node[internalEventHandlersKey]; + delete node[internalEventHandlerListenersKey]; + delete node[internalEventHandlesSetKey]; + } + function getClosestInstanceFromNode(targetNode) { + var targetInst = targetNode[internalInstanceKey]; + if (targetInst) return targetInst; + for (var parentNode = targetNode.parentNode; parentNode; ) { + if (targetInst = parentNode[internalContainerInstanceKey] || parentNode[internalInstanceKey]) { + parentNode = targetInst.alternate; + if (null !== targetInst.child || null !== parentNode && null !== parentNode.child) for (targetNode = getParentHydrationBoundary(targetNode); null !== targetNode; ) { + if (parentNode = targetNode[internalInstanceKey]) return parentNode; + targetNode = getParentHydrationBoundary(targetNode); + } + return targetInst; + } + targetNode = parentNode; + parentNode = targetNode.parentNode; + } + return null; + } + function getInstanceFromNode(node) { + if (node = node[internalInstanceKey] || node[internalContainerInstanceKey]) { + var tag = node.tag; + if (5 === tag || 6 === tag || 13 === tag || 31 === tag || 26 === tag || 27 === tag || 3 === tag) return node; + } + return null; + } + function getNodeFromInstance(inst) { + var tag = inst.tag; + if (5 === tag || 26 === tag || 27 === tag || 6 === tag) return inst.stateNode; + throw Error("getNodeFromInstance: Invalid argument."); + } + function getResourcesFromRoot(root2) { + var resources = root2[internalRootNodeResourcesKey]; + resources || (resources = root2[internalRootNodeResourcesKey] = { + hoistableStyles: /* @__PURE__ */ new Map(), + hoistableScripts: /* @__PURE__ */ new Map() + }); + return resources; + } + function markNodeAsHoistable(node) { + node[internalHoistableMarker] = true; + } + function registerTwoPhaseEvent(registrationName, dependencies) { + registerDirectEvent(registrationName, dependencies); + registerDirectEvent(registrationName + "Capture", dependencies); + } + function registerDirectEvent(registrationName, dependencies) { + registrationNameDependencies[registrationName] && console.error("EventRegistry: More than one plugin attempted to publish the same registration name, `%s`.", registrationName); + registrationNameDependencies[registrationName] = dependencies; + var lowerCasedName = registrationName.toLowerCase(); + possibleRegistrationNames[lowerCasedName] = registrationName; + "onDoubleClick" === registrationName && (possibleRegistrationNames.ondblclick = registrationName); + for (registrationName = 0; registrationName < dependencies.length; registrationName++) allNativeEvents.add(dependencies[registrationName]); + } + function checkControlledValueProps(tagName, props) { + hasReadOnlyValue[props.type] || props.onChange || props.onInput || props.readOnly || props.disabled || null == props.value || ("select" === tagName ? console.error("You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set `onChange`.") : console.error("You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.")); + props.onChange || props.readOnly || props.disabled || null == props.checked || console.error("You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`."); + } + function isAttributeNameSafe(attributeName) { + if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) return true; + if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) return false; + if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) return validatedAttributeNameCache[attributeName] = true; + illegalAttributeNameCache[attributeName] = true; + console.error("Invalid attribute name: `%s`", attributeName); + return false; + } + function getValueForAttributeOnCustomComponent(node, name, expected) { + if (isAttributeNameSafe(name)) { + if (!node.hasAttribute(name)) { + switch (typeof expected) { + case "symbol": + case "object": + return expected; + case "function": + return expected; + case "boolean": + if (false === expected) return expected; + } + return void 0 === expected ? void 0 : null; + } + node = node.getAttribute(name); + if ("" === node && true === expected) return true; + checkAttributeStringCoercion(expected, name); + return node === "" + expected ? expected : node; + } + } + function setValueForAttribute(node, name, value) { + if (isAttributeNameSafe(name)) if (null === value) node.removeAttribute(name); + else { + switch (typeof value) { + case "undefined": + case "function": + case "symbol": + node.removeAttribute(name); + return; + case "boolean": + var prefix2 = name.toLowerCase().slice(0, 5); + if ("data-" !== prefix2 && "aria-" !== prefix2) { + node.removeAttribute(name); + return; + } + } + checkAttributeStringCoercion(value, name); + node.setAttribute(name, "" + value); + } + } + function setValueForKnownAttribute(node, name, value) { + if (null === value) node.removeAttribute(name); + else { + switch (typeof value) { + case "undefined": + case "function": + case "symbol": + case "boolean": + node.removeAttribute(name); + return; + } + checkAttributeStringCoercion(value, name); + node.setAttribute(name, "" + value); + } + } + function setValueForNamespacedAttribute(node, namespace, name, value) { + if (null === value) node.removeAttribute(name); + else { + switch (typeof value) { + case "undefined": + case "function": + case "symbol": + case "boolean": + node.removeAttribute(name); + return; + } + checkAttributeStringCoercion(value, name); + node.setAttributeNS(namespace, name, "" + value); + } + } + function getToStringValue(value) { + switch (typeof value) { + case "bigint": + case "boolean": + case "number": + case "string": + case "undefined": + return value; + case "object": + return checkFormFieldValueStringCoercion(value), value; + default: + return ""; + } + } + function isCheckable(elem) { + var type = elem.type; + return (elem = elem.nodeName) && "input" === elem.toLowerCase() && ("checkbox" === type || "radio" === type); + } + function trackValueOnNode(node, valueField, currentValue) { + var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); + if (!node.hasOwnProperty(valueField) && "undefined" !== typeof descriptor && "function" === typeof descriptor.get && "function" === typeof descriptor.set) { + var get = descriptor.get, set = descriptor.set; + Object.defineProperty(node, valueField, { + configurable: true, + get: function() { + return get.call(this); + }, + set: function(value) { + checkFormFieldValueStringCoercion(value); + currentValue = "" + value; + set.call(this, value); + } + }); + Object.defineProperty(node, valueField, { + enumerable: descriptor.enumerable + }); + return { + getValue: function() { + return currentValue; + }, + setValue: function(value) { + checkFormFieldValueStringCoercion(value); + currentValue = "" + value; + }, + stopTracking: function() { + node._valueTracker = null; + delete node[valueField]; + } + }; + } + } + function track(node) { + if (!node._valueTracker) { + var valueField = isCheckable(node) ? "checked" : "value"; + node._valueTracker = trackValueOnNode(node, valueField, "" + node[valueField]); + } + } + function updateValueIfChanged(node) { + if (!node) return false; + var tracker = node._valueTracker; + if (!tracker) return true; + var lastValue = tracker.getValue(); + var value = ""; + node && (value = isCheckable(node) ? node.checked ? "true" : "false" : node.value); + node = value; + return node !== lastValue ? (tracker.setValue(node), true) : false; + } + function getActiveElement(doc) { + doc = doc || ("undefined" !== typeof document ? document : void 0); + if ("undefined" === typeof doc) return null; + try { + return doc.activeElement || doc.body; + } catch (e) { + return doc.body; + } + } + function escapeSelectorAttributeValueInsideDoubleQuotes(value) { + return value.replace(escapeSelectorAttributeValueInsideDoubleQuotesRegex, function(ch) { + return "\\" + ch.charCodeAt(0).toString(16) + " "; + }); + } + function validateInputProps(element, props) { + void 0 === props.checked || void 0 === props.defaultChecked || didWarnCheckedDefaultChecked || (console.error("%s contains an input of type %s with both checked and defaultChecked props. Input elements must be either controlled or uncontrolled (specify either the checked prop, or the defaultChecked prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://react.dev/link/controlled-components", getCurrentFiberOwnerNameInDevOrNull() || "A component", props.type), didWarnCheckedDefaultChecked = true); + void 0 === props.value || void 0 === props.defaultValue || didWarnValueDefaultValue$1 || (console.error("%s contains an input of type %s with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://react.dev/link/controlled-components", getCurrentFiberOwnerNameInDevOrNull() || "A component", props.type), didWarnValueDefaultValue$1 = true); + } + function updateInput(element, value, defaultValue, lastDefaultValue, checked, defaultChecked, type, name) { + element.name = ""; + null != type && "function" !== typeof type && "symbol" !== typeof type && "boolean" !== typeof type ? (checkAttributeStringCoercion(type, "type"), element.type = type) : element.removeAttribute("type"); + if (null != value) if ("number" === type) { + if (0 === value && "" === element.value || element.value != value) element.value = "" + getToStringValue(value); + } else element.value !== "" + getToStringValue(value) && (element.value = "" + getToStringValue(value)); + else "submit" !== type && "reset" !== type || element.removeAttribute("value"); + null != value ? setDefaultValue(element, type, getToStringValue(value)) : null != defaultValue ? setDefaultValue(element, type, getToStringValue(defaultValue)) : null != lastDefaultValue && element.removeAttribute("value"); + null == checked && null != defaultChecked && (element.defaultChecked = !!defaultChecked); + null != checked && (element.checked = checked && "function" !== typeof checked && "symbol" !== typeof checked); + null != name && "function" !== typeof name && "symbol" !== typeof name && "boolean" !== typeof name ? (checkAttributeStringCoercion(name, "name"), element.name = "" + getToStringValue(name)) : element.removeAttribute("name"); + } + function initInput(element, value, defaultValue, checked, defaultChecked, type, name, isHydrating2) { + null != type && "function" !== typeof type && "symbol" !== typeof type && "boolean" !== typeof type && (checkAttributeStringCoercion(type, "type"), element.type = type); + if (null != value || null != defaultValue) { + if (!("submit" !== type && "reset" !== type || void 0 !== value && null !== value)) { + track(element); + return; + } + defaultValue = null != defaultValue ? "" + getToStringValue(defaultValue) : ""; + value = null != value ? "" + getToStringValue(value) : defaultValue; + isHydrating2 || value === element.value || (element.value = value); + element.defaultValue = value; + } + checked = null != checked ? checked : defaultChecked; + checked = "function" !== typeof checked && "symbol" !== typeof checked && !!checked; + element.checked = isHydrating2 ? element.checked : !!checked; + element.defaultChecked = !!checked; + null != name && "function" !== typeof name && "symbol" !== typeof name && "boolean" !== typeof name && (checkAttributeStringCoercion(name, "name"), element.name = name); + track(element); + } + function setDefaultValue(node, type, value) { + "number" === type && getActiveElement(node.ownerDocument) === node || node.defaultValue === "" + value || (node.defaultValue = "" + value); + } + function validateOptionProps(element, props) { + null == props.value && ("object" === typeof props.children && null !== props.children ? React2.Children.forEach(props.children, function(child) { + null == child || "string" === typeof child || "number" === typeof child || "bigint" === typeof child || didWarnInvalidChild || (didWarnInvalidChild = true, console.error("Cannot infer the option value of complex children. Pass a `value` prop or use a plain string as children to