diff --git a/.claude/agents/team-leader.md b/.claude/agents/team-leader.md new file mode 100644 index 0000000..04c5873 --- /dev/null +++ b/.claude/agents/team-leader.md @@ -0,0 +1,65 @@ +# Team Leader + +Orchestrator agent for the Agentic Terminal Wrapper. Decomposes features into tasks, delegates to specialist agents, manages branch lifecycle, and coordinates QA/Guardian reviews. + +## Initialization Protocol + +Before doing ANY work: +1. Read `CLAUDE.md` — Project rules and conventions +2. Read `.claude/docs/ARCHITECTURE.md` — System architecture +3. Read the progress directory for current feature context +4. Check `.claude/agents/` to understand available specialists + +## Scope — Coordination Only + +You do NOT write application code directly. You: +- Decompose features into agent-ready tasks +- Assign tasks to specialist agents with clear scope and acceptance criteria +- Manage the wave execution order +- Spawn QA reviewer after each task completion +- Spawn Codebase Guardian before final merge +- Track progress via /track events + +## Agent Roster + +| Agent | Domain | Key Files | +|-------|--------|-----------| +| desktop-engineer | Main process, IPC, preload | `src/main/`, `src/preload/` | +| component-engineer | React components, state, pane system | `src/renderer/src/components/PaneContainer.jsx`, `src/renderer/src/App.jsx` | +| styling-engineer | CSS theme, layout, pane styles | `src/renderer/src/App.css` | +| terminal-engineer | xterm.js, PTY lifecycle | `src/renderer/src/hooks/useTerminal.js`, `src/renderer/src/components/TerminalPane.jsx` | +| editor-engineer | CodeMirror, file tabs | `src/renderer/src/components/EditorPanel.jsx` | +| test-engineer | Test infrastructure, coverage | `tests/`, `*.test.js`, `*.test.jsx` | +| qa-reviewer | Code review, verification | Read-only on all files | +| codebase-guardian | Structural integrity | Read-only on all files | + +## Pane System Context + +Panes are typed (`terminal | editor | timeline | project`). The `createPane(type)` function in App.jsx creates pane objects with `{ id, type, ptyId }`. PaneContainer does type-based rendering — terminal panes use TerminalPane (own header), non-terminal panes get a generic `.typed-pane` wrapper with `.pane-header` (type label + close button). The `+ New` dropdown in the toolbar lets users add any pane type. When decomposing tasks that touch the pane system, assign component-engineer for PaneContainer/App.jsx changes and styling-engineer for CSS. + +## Branching Model + +- Primary branch: `master` +- Feature branches: `work//` +- Never commit directly to `master` + +## Quality Gates + +- Every task gets QA review before merge +- Final feature gets Codebase Guardian check +- All tasks must pass lint/build before merge + +## Workflow Step Events + +When executing a workflow, emit step events to the progress file so the Workflow Panel can track progress in real-time: + +```jsonl +{"type":"workflow_step","step":"","status":"active","timestamp":"","feature":""} +{"type":"workflow_step","step":"","status":"completed","timestamp":"","feature":""} +``` + +Step IDs: create-plan, implement-plan, team-management, review, test, update-docs + +Emit `active` when entering a step and `completed` when leaving it. +Read the active workflow from `.claude/workflow.json` → `activeWorkflow` field. +Step documentation lives in `.claude/docs/workflows//steps/`. diff --git a/.claude/docs/workflows/default/steps/01-create-plan.md b/.claude/docs/workflows/default/steps/01-create-plan.md new file mode 100644 index 0000000..c0b44e8 --- /dev/null +++ b/.claude/docs/workflows/default/steps/01-create-plan.md @@ -0,0 +1,59 @@ +# Create Plan + +## Overview + +Every feature begins with deep technical planning and task decomposition. No implementation work starts until the plan is complete and recorded in the progress file. This step corresponds to the PLAN phase of the lifecycle: reading requirements, analyzing the codebase, decomposing work into agent-ready tasks, mapping dependencies, and planning wave execution order. + +The Team Leader drives this step. The output is a fully decomposed task list with file-level scoping, dependency graphs, wave assignments, context budget estimates, and pre-filled QA checklists for every task. Skipping or rushing this step is the single biggest predictor of feature failure. + +Planning also includes risk assessment: identifying files that multiple tasks might need to touch, flagging large tasks that exceed context budget limits, and establishing the conflict prevention layers (file scoping, wave ordering, pre-merge rebase, sequential merges, escalation). + +## Process + +1. **Read requirements** -- Gather the feature request, user story, or bug report. Clarify ambiguities before proceeding. +2. **Read project rules** -- Load `CLAUDE.md` and `.claude/docs/ARCHITECTURE.md` to understand conventions, file structure, naming rules, and security constraints. +3. **Analyze the codebase** -- Identify which existing files, modules, and patterns the feature touches. Map the relevant IPC channels, components, hooks, and CSS. +4. **Architectural design** -- Decide how the feature fits into the three-process Electron model (main, preload, renderer). Determine which IPC channels to add, which components to create or modify, and which hooks to extract. +5. **Task decomposition** -- Break the feature into tasks where each task is assignable to exactly one agent, has a clear file scope (specific files to create or modify), has explicit acceptance criteria, and has no file-level overlap with any other task. +6. **Wave planning** -- Group tasks into waves based on dependencies. Wave 1 is foundation (types, schemas, contracts). Wave 2 is business logic (services, domain logic). Wave 3 is integration (API routes, handlers, state management). Wave 4 is presentation (UI components, styling). Wave 5 is automatic (QA handles doc updates per workbranch). +7. **Context budget estimation** -- For each task, estimate context usage: `8,000 base + (files x 1,000) + 3,000 margin`. If a task touches 13+ files, it must be split. Tasks touching 8-12 files should be evaluated for splitting. +8. **Fill QA checklists** -- Copy the QA Checklist Template into every task assignment. Fill in task-specific sections and feature-specific checks. Use auto-fill rules to select sections based on the assigned agent's role. +9. **Create progress file** -- Write the progress file to `.claude/progress//events.jsonl` before spawning any agents. Include the task list, dependency graph, wave plan, branch status table, and context budget estimates. + +## Rules + +- No phase may be skipped in the lifecycle: PLAN > BRANCH > TRACK > ASSIGN > BUILD > QA > MERGE > GUARDIAN > PR. +- Each task must be assignable to exactly one agent with no file-level overlap. +- Tasks must have explicit acceptance criteria and a filled QA checklist. +- The progress file must be created before spawning any agents. +- Context budget must be estimated before every agent spawn (strict and standard modes). +- If a task touches more than 10 files, split it using the splitting protocol: identify natural split points (layer, feature, or file group boundaries), create sub-tasks with distinct file sets, assign to adjacent waves. +- Workflow mode (strict, standard, fast) must be resolved at feature start and recorded in the progress file. Resolution priority: per-invocation override > CLAUDE.md setting > default (strict). + +## Checks + +- Every task has exactly one assigned agent type from the agent roster. +- No two tasks modify the same file. +- Every task has explicit acceptance criteria listed. +- Every task has a pre-filled QA checklist. +- Wave dependencies form a DAG (no circular dependencies). +- Context budget estimates are recorded for each task (strict/standard modes). +- The progress file exists at `.claude/progress//events.jsonl` with initial state. +- Feature branch `/` is created from the base branch. + +## Inputs + +- Feature request, user story, or bug report from the user. +- Current codebase state (CLAUDE.md, ARCHITECTURE.md, existing files). +- Workflow mode (strict, standard, or fast). +- Agent roster from `.claude/agents/`. + +## Outputs + +- Fully decomposed task list with file scopes and acceptance criteria. +- Dependency graph mapping task relationships. +- Wave execution plan (which tasks run in which wave). +- Context budget estimates per task. +- Pre-filled QA checklists for every task. +- Progress file initialized at `.claude/progress//events.jsonl`. +- Feature branch created from base branch. diff --git a/.claude/docs/workflows/default/steps/02-implement-plan.md b/.claude/docs/workflows/default/steps/02-implement-plan.md new file mode 100644 index 0000000..1c22d43 --- /dev/null +++ b/.claude/docs/workflows/default/steps/02-implement-plan.md @@ -0,0 +1,55 @@ +# Implement Plan + +## Overview + +Implementation is executed by specialist agents working in isolated worktrees. Each agent follows a mandatory phased workflow with blocking gates between phases. This structure exists because agents tend to skip planning, chase errors down rabbit holes, run out of context, and produce work that ignores project conventions. The phased workflow with written plans prevents all of these failure modes. + +Every agent -- coding, QA, and Guardian -- operates under the same phased structure. The Team Leader spawns agents using full templates from the playbook that embed the phased workflow and error recovery directly into the agent's prompt. Minimal prompts like "implement X in file Y" are never used. + +Agents work exclusively in their assigned worktree directory. They never commit directly to the feature branch. Each worktree is created from the feature branch HEAD at the start of its wave, giving the agent a clean, isolated working directory with its own index and HEAD. + +## Process + +1. **Phase 0: Load Rules** -- The agent reads all required files before doing any work. This includes `CLAUDE.md` (project rules), `.claude/docs/ARCHITECTURE.md` (system architecture), the agent's own definition from `.claude/agents/`, the task description with acceptance criteria, and the QA checklist. The agent must not skim; this phase is blocking. +2. **Phase 1: Write Execution Plan** -- The agent produces a written plan that cites specific rules by name. The plan includes: task summary, applicable rules (cited by section), files to create/modify/avoid, step-by-step implementation order, acceptance criteria mapping, and risk assessment. No code is written until the plan is complete. +3. **Phase 2: Execute Plan** -- The agent follows its plan step by step, stating each step before executing it. On any error, the Error Recovery Protocol fires: stop, re-read the Phase 1 plan, classify the error scope (in scope my file, in scope not my file, out of scope), and fix with a maximum of 2 attempts. The agent never modifies files outside its scope, never refactors unrelated code, and never abandons the plan for tangential investigation. +4. **Phase 3: Self-Review** -- The agent re-reads its Phase 1 plan and verifies every acceptance criterion is met. It checks that all files listed in the plan were created or modified as intended, that no files outside scope were touched, and that the work follows project conventions. +5. **Phase 4: Spawn QA** -- The agent spawns a QA Review Agent on the same workbranch, passing along its Phase 1 plan so QA can verify the agent followed it. The QA checklist and task context are included in the spawn. + +## Rules + +- Every agent operates under the mandatory phased workflow. No phase may be skipped. +- Phase gates are blocking: Phase 0 must complete before Phase 1, Phase 1 before Phase 2, etc. +- Written plans must cite specific rules by name, proving the agent read and understood them. +- The Error Recovery Protocol limits fix attempts to 2 per error. After 2 failures, the agent reports to the Team Leader. +- Agents never modify files outside their assigned scope. +- Agents never commit directly to the feature branch -- only to their workbranch. +- All IPC goes through the preload bridge -- agents must not import `electron` in renderer code. +- `contextIsolation: true` and `nodeIntegration: false` must always be maintained. +- Components must clean up effects on unmount (event listeners, timers, observers, PTY processes). +- Naming conventions must be followed: PascalCase components, camelCase hooks with `use` prefix, `namespace:kebab-action` IPC channels, BEM CSS classes. + +## Checks + +- Agent's Phase 1 plan exists as text output before any code is written. +- All files created or modified match the task's file scope. +- No files outside the task's scope were modified. +- Error Recovery Protocol was followed for any errors encountered (max 2 attempts per error). +- All acceptance criteria from the task description are addressed. +- Code follows project conventions from CLAUDE.md (naming, patterns, security). +- Agent committed its work to the workbranch, not the feature branch. +- QA Review Agent was spawned with the Phase 1 plan included. + +## Inputs + +- Task description with acceptance criteria and file scope (from Create Plan step). +- Pre-filled QA checklist for the task. +- Worktree created from the feature branch HEAD. +- Agent spawn template with embedded phased workflow and error recovery. + +## Outputs + +- Completed code committed to the workbranch in the agent's worktree. +- Phase 1 plan (text output, preserved in context for QA). +- Self-review results confirming acceptance criteria are met. +- QA Review Agent spawned on the same workbranch. diff --git a/.claude/docs/workflows/default/steps/03-team-management.md b/.claude/docs/workflows/default/steps/03-team-management.md new file mode 100644 index 0000000..d125c22 --- /dev/null +++ b/.claude/docs/workflows/default/steps/03-team-management.md @@ -0,0 +1,61 @@ +# Team Management + +## Overview + +The Team Leader orchestrates agent teams across waves with dependency tracking, progress monitoring, and crash recovery. This step covers the ongoing coordination work that happens throughout the feature lifecycle: creating teams and tasks, spawning agents on worktrees, tracking progress, managing wave transitions, and recovering from crashes. + +Wave execution is the core coordination pattern. Tasks are grouped into waves based on dependencies. Within a wave, agents that touch different files run in parallel in isolated worktrees. Between waves, a fence check verifies the feature branch is stable before the next wave starts. The Team Leader never writes application code directly -- it decomposes, delegates, monitors, and coordinates. + +Progress tracking is crash-safe by design. The progress file on disk (`.claude/progress//events.jsonl`) survives terminal close, process kill, and session timeout. Git branches persist independently. When a new session picks up interrupted work, it reads the progress file and branch status to resume from the exact point of interruption. + +## Process + +1. **Create the team** -- Use `TeamCreate` with the feature name and description. +2. **Create tasks with dependencies** -- Use `TaskCreate` for each task, then `TaskUpdate` with `addBlockedBy` to establish the dependency chain. Standard dependency flow: types/schemas (no blockers) > business logic (blocked by types) > integration (blocked by logic) > presentation (blocked by integration). +3. **Create worktrees for Wave 1** -- From the feature branch HEAD, create a worktree per task: `git worktree add // -b //`. All prefixes are configurable in `.claude/workflow.json`. +4. **Spawn agents** -- Use the full spawn templates from the playbook. Each agent prompt includes all 4 phases with blocking gates, the Error Recovery Protocol, task context, acceptance criteria, file scope, and QA checklist. Never use minimal prompts. +5. **Monitor progress** -- Update the progress file after every significant state change: team/tasks created, workbranch created, agent completes work, QA cycle (pass/fail), workbranch merged, integration complete. +6. **Complete a wave** -- Wait for all agents in the wave to report QA PASS. Merge all workbranches sequentially (one at a time, in task-number order). Delete merged workbranches. Run the wave fence check based on workflow mode. +7. **Wave fence verification** -- In strict mode: verify all workbranches merged and deleted, feature branch is clean, run lint/typecheck/test/build. In standard mode: verify workbranches merged, run lint only. In fast mode: skip fence entirely. +8. **Start next wave** -- After the fence passes, create new worktrees from the updated feature branch HEAD. Spawn agents for the next wave. Update the wave status table. +9. **Handle fence failures** -- For lint/typecheck failures: identify the responsible merged task, fix on the feature branch directly or create a fix task. For test failures: determine if from a new or existing test, investigate the gap. For build failures: fix missing imports or type mismatches on the feature branch. +10. **Crash recovery** -- Check for existing progress files, workbranches, feature branches, and teams. Read the JSONL event log. Resume from the first non-COMPLETE task: if workbranch has commits check QA status, if workbranch has no commits re-spawn the agent, if workbranch doesn't exist create it and spawn. + +## Rules + +- The Team Leader does not write application code directly. It decomposes, delegates, monitors, and coordinates. +- Agents work exclusively in their worktree directory -- no direct commits to the feature branch. +- Workbranches are merged one at a time, in wave order, then task-number order within a wave. +- After each merge, rebase the next workbranch on the updated feature branch HEAD before merging. +- Conflict prevention has 5 layers: file scoping, wave ordering, pre-merge rebase, sequential merges, and escalation. +- If rebase conflicts are non-trivial, escalate to the user. Never force through conflicts silently. +- Wave fence mode follows the workflow mode: strict = full verify, standard = lint only, fast = skip. +- QA round limits depend on workflow mode: strict = 3 rounds max, standard = 2 rounds, fast = 1 round. +- The progress file must be updated after every significant state change. +- Worktrees are removed after successful merge: `git worktree remove //`. + +## Checks + +- Team exists with all tasks created and dependencies established. +- Each wave's worktrees were created from the correct feature branch HEAD. +- All agents were spawned with full templates (not minimal prompts). +- Progress file is up-to-date with current state of all tasks, branches, and waves. +- Wave status table shows correct status for each wave (PENDING, IN_PROGRESS, FENCE_CHECK, COMPLETE, BLOCKED). +- Branch status table shows correct state for each workbranch (status, merged flag). +- Workbranches are deleted after successful merge. +- Wave fence check passed before starting the next wave (in strict/standard modes). + +## Inputs + +- Decomposed task list with dependencies, wave assignments, and file scopes (from Create Plan). +- Feature branch created from the base branch. +- `.claude/workflow.json` configuration (prefixes, worktree directory, mode). +- Agent roster from `.claude/agents/`. + +## Outputs + +- All workbranches merged to the feature branch in wave order. +- Progress file fully updated with task statuses, QA results, merge log, and wave status. +- All worktrees removed after merge. +- Feature branch stable and passing fence checks. +- Ready for Codebase Guardian final gate. diff --git a/.claude/docs/workflows/default/steps/04-review.md b/.claude/docs/workflows/default/steps/04-review.md new file mode 100644 index 0000000..88e8ac8 --- /dev/null +++ b/.claude/docs/workflows/default/steps/04-review.md @@ -0,0 +1,57 @@ +# Review + +## Overview + +QA review is a per-task quality gate, not an end-of-pipeline step. Each coding agent spawns its own QA Review Agent immediately after completing work. QA happens on the same workbranch, ensuring the branch is self-contained: code changes, QA verdict, and documentation updates all live together. When the workbranch merges, incremental documentation updates come with it. + +The QA Review Agent follows the same mandatory phased workflow as coding agents. It reads the task description, acceptance criteria, QA checklist, and the coding agent's Phase 1 plan. It then runs automated checks, reviews every changed file, traces data flow, and delivers a PASS or FAIL verdict with specific file paths and line numbers for any issues found. + +QA round limits depend on the workflow mode. In strict mode, a task gets up to 3 QA rounds. In standard mode, 2 rounds. In fast mode, 1 round. If a task exhausts its QA rounds without passing, the coding agent reports to the Team Leader, who may reassign, intervene directly, or escalate to the user. + +## Process + +1. **Phase 1: Automated Checks** -- Run `npm run build` (must succeed). Check for console errors, unused imports, and dead code. Adapt checks to the project's actual toolchain. If a check command fails with "command not found" or "script not found", skip that check and log a warning. +2. **Phase 2: Code Diff Review** -- Review the git diff on the workbranch. Verify changes match the task description. Check for scope creep (files modified outside the task scope). Verify no security issues: path traversal in IPC handlers, unsanitized input, missing argument validation. +3. **Phase 3: Electron-Specific Checks** -- Verify IPC handlers validate arguments. Confirm no `nodeIntegration: true` or `contextIsolation: false`. Verify the preload bridge exposes minimal API surface. Confirm no arbitrary file system access without bounds checking. +4. **Phase 4: React/UI Checks** -- Verify components clean up effects on unmount. Check for memory leaks (event listeners, timers, observers). Verify state updates don't cause unnecessary re-renders. Confirm keyboard shortcuts don't conflict. +5. **Phase 5: Terminal/Editor Checks** -- Verify PTY processes are properly killed on cleanup. Confirm xterm.js instances are disposed. Check CodeMirror instances handle external file changes. Verify resize observers are disconnected. +6. **Phase 6: Verdict** -- Deliver PASS or FAIL. + - **PASS**: QA updates documentation on the workbranch. Update `ARCHITECTURE.md` if structural changes were made. Update other project docs if conventions or patterns changed. Commit doc updates on the workbranch. + - **FAIL**: Return specific issues with file paths and line numbers. List required fixes before re-review. + +## Rules + +- QA agents review all files but may only modify documentation files (on PASS) and progress/tracking files. +- QA agents never modify application source code. If changes are needed, FAIL the review with specific instructions. +- QA round limits: strict mode = 3 max, standard mode = 2 max, fast mode = 1 max. +- If a task fails QA after exhausting rounds, report to the Team Leader for reassignment or escalation. +- On PASS, QA must update documentation on the workbranch before the branch is merged. +- The QA report must follow the standard format: PASS/FAIL, task name, files reviewed count, issues count, and specific issue descriptions with file:line references. +- QA validates every item in the pre-filled QA checklist from the task assignment. +- QA compares the agent's actual work against its Phase 1 plan to verify the agent followed its own plan. + +## Checks + +- Build succeeds (`npm run build` or equivalent). +- No files modified outside the task's declared file scope. +- No security violations: IPC handlers validate arguments, contextIsolation is true, nodeIntegration is false, no unvalidated file system access. +- Components clean up all effects on unmount (event listeners, timers, observers, PTY processes, file watchers). +- All acceptance criteria from the task description are verified as met. +- Every item in the QA checklist is validated. +- The coding agent's Phase 1 plan was followed (plan vs actual comparison). +- On PASS: documentation is updated and committed on the workbranch. + +## Inputs + +- Coding agent's completed work committed on the workbranch. +- Coding agent's Phase 1 plan (for plan vs actual verification). +- Task description with acceptance criteria and file scope. +- Pre-filled QA checklist from the task assignment. +- Project rules from CLAUDE.md and ARCHITECTURE.md. + +## Outputs + +- QA verdict: PASS or FAIL. +- If PASS: documentation updates committed on the workbranch. The workbranch is ready for merge. +- If FAIL: issue list with file paths, line numbers, and specific fix instructions. The coding agent fixes and re-spawns QA (within round limits). +- QA report in standard format logged to the progress file. diff --git a/.claude/docs/workflows/default/steps/05-test.md b/.claude/docs/workflows/default/steps/05-test.md new file mode 100644 index 0000000..513cc94 --- /dev/null +++ b/.claude/docs/workflows/default/steps/05-test.md @@ -0,0 +1,55 @@ +# Test + +## Overview + +Testing and build verification happen at multiple points in the workflow: during per-task QA (automated checks), during wave fence verification (between waves), and during the final Codebase Guardian check. This step documents the testing strategy across all these points and the specific checks that must pass before the feature can be considered complete. + +The project uses `npm run build` as the primary build verification command. There is no separate lint or typecheck command in the current toolchain -- the build step via electron-vite catches compilation errors, missing imports, and bundling issues across all three processes (main, preload, renderer). Agents must adapt their check commands to the detected toolchain and never assume commands like `npm run lint` or `npm run test` exist. + +Pre-flight checks are an additional verification layer in strict mode. Before spawning any agents, the Team Leader verifies the codebase baseline (build succeeds on the base branch). This is also mandatory for `/refactor` operations regardless of mode, since refactors must confirm the baseline is clean before making structural changes. + +## Process + +1. **Per-task automated checks (during QA)** -- The QA Review Agent runs `npm run build` as part of Phase 1 automated checks. The build must succeed. Additional checks for unused imports, dead code, and console errors are performed through code review rather than automated tooling. +2. **Wave fence verification (between waves)** -- After all agents in a wave complete and their workbranches are merged to the feature branch, the Team Leader runs the wave fence check: + - Strict mode: verify all workbranches from this wave are merged and deleted, verify the feature branch is clean (`git status`), run `npm run build`. + - Standard mode: verify workbranches are merged, run build only. + - Fast mode: skip wave fence entirely, merge and proceed. +3. **Fence failure handling** -- If the build fails after merging a wave, the issue is usually missing imports or mismatches across merged modules. Fix on the feature branch directly, commit as `fix: resolve wave N fence failure`. If a test existed and broke, determine whether it was a new test (QA gap) or an existing test (cross-module issue from merging). +4. **Pre-flight checks (strict mode only)** -- Before spawning any agents, verify the baseline: `npm run build` on the base branch must succeed. If it fails, stop and report to the user. This is mandatory for `/refactor` regardless of mode. +5. **Final build verification (Codebase Guardian)** -- The Codebase Guardian runs `npm run build` on the fully-merged feature branch as check #7 (Build Verification). This is the final confirmation that the entire feature builds correctly when all tasks are combined. The Guardian also checks for circular dependencies and verifies all imports resolve. +6. **Merge protocol verification** -- After each workbranch merge, the Team Leader runs a quick sanity check: `git log --oneline -5` to confirm the merge commit, then adapts any available lint/build check to the project. + +## Rules + +- `npm run build` must succeed at every verification point: per-task QA, wave fence, and final Guardian check. +- Do not assume `npm run lint`, `npm run test`, or `npm run typecheck` exist. Check the project's `package.json` for available scripts. +- If a check command fails with "command not found" or "script not found", skip that check and log a warning. Do not treat it as a test failure. +- Pre-flight checks are mandatory in strict mode and for all `/refactor` operations. +- Wave fence strictness follows workflow mode: strict = full verify, standard = build only, fast = skip. +- Fence failures must be investigated and fixed before the next wave starts (in strict/standard modes). +- Never force through build failures silently. If the build breaks after merge, revert the merge (`git revert -m 1 `), investigate, fix on the workbranch, and re-merge. + +## Checks + +- `npm run build` succeeds on the feature branch after all merges. +- No circular dependencies introduced by the feature. +- All imports resolve (no missing modules after merge). +- Wave fence verification passed for each completed wave (strict/standard modes). +- Pre-flight baseline was verified before agent spawning (strict mode). +- Any fence failures were resolved with fix commits on the feature branch. +- Build verification passes in the final Codebase Guardian check. + +## Inputs + +- Merged feature branch with all workbranch changes combined. +- Wave status table showing which waves have completed fence checks. +- Project toolchain information from `package.json`. +- Workflow mode (strict, standard, or fast). + +## Outputs + +- Confirmed build success on the feature branch. +- Wave fence results recorded in the progress file. +- Any fence failure fix commits on the feature branch. +- Build verification PASS from the Codebase Guardian. diff --git a/.claude/docs/workflows/default/steps/06-update-docs.md b/.claude/docs/workflows/default/steps/06-update-docs.md new file mode 100644 index 0000000..4bb461c --- /dev/null +++ b/.claude/docs/workflows/default/steps/06-update-docs.md @@ -0,0 +1,63 @@ +# Update Docs + +## Overview + +Documentation updates happen at two distinct points in the workflow. First, the QA Review Agent updates documentation incrementally on each workbranch when it issues a PASS verdict. This includes updating `ARCHITECTURE.md` for structural changes, updating other project docs when conventions or patterns change, and documenting new modules, services, or APIs. Second, the Codebase Guardian performs a final documentation coherence check on the fully-merged feature branch to ensure all per-task doc updates are consistent when combined. + +The reason QA handles per-task doc updates is practical: QA has just reviewed the code in detail and has the deepest understanding of the changes. The workbranch becomes self-contained (code + QA verdict + doc updates), and when it merges, incremental doc updates come with it. No separate documentation agent is needed per task. + +The Codebase Guardian's documentation coherence check (one of its 7 structural integrity checks) catches cross-cutting issues that per-task QA cannot see: conflicting descriptions of the same module across different doc updates, stale references to renamed files or removed features, and inconsistencies in the architecture description that only appear when all tasks are viewed together. + +## Process + +1. **Per-task doc updates (QA on PASS)** -- When the QA Review Agent issues a PASS verdict, it updates documentation on the workbranch before the branch is merged: + - Update `.claude/docs/ARCHITECTURE.md` if structural changes were made (new IPC channels, new components, new hooks, changed state model, new extension points). + - Update other project docs if conventions or patterns changed. + - Document new modules, services, or API endpoints. + - Commit documentation updates on the workbranch. +2. **Codebase Guardian structural checks** -- After all workbranches are merged to the feature branch, the Guardian runs 7 checks: + - **File Placement**: Main process code only in `src/main/`, preload in `src/preload/`, React components in `src/renderer/src/components/`, hooks in `src/renderer/src/hooks/`, styles only in `src/renderer/src/App.css`. + - **Electron Architecture**: Main process does not import renderer code, renderer does not import main process code, all cross-process communication goes through the preload bridge, IPC channels follow `namespace:action` naming, every `ipcMain.handle` has a corresponding `contextBridge` exposure. + - **Component Consistency**: All components export a default function, props are destructured, event handlers use `useCallback`, side effects use `useEffect` with cleanup. + - **State Management**: No prop drilling deeper than 2 levels, state lives at the lowest common ancestor, no duplicated state. + - **Resource Cleanup**: Every `addEventListener` has a matching `removeEventListener`, intervals/timeouts are cleared, ResizeObservers are disconnected, PTY processes are killed on pane close, file watchers are closed on unmount. + - **Naming Conventions**: PascalCase components, camelCase hooks with `use` prefix, `namespace:kebab-action` IPC channels, BEM CSS classes, `--category-name` CSS variables. + - **Build Verification**: `npm run build` succeeds, no circular dependencies, all imports resolve. +3. **Guardian documentation fixes** -- The Guardian may fix minor structural issues (missing exports, import ordering) and documentation inconsistencies directly. For anything larger, it fails with instructions for the Team Leader. +4. **Final documentation coherence** -- The Guardian verifies that per-task doc updates are consistent when combined: no conflicting module descriptions, no stale file references, architecture description reflects the actual merged codebase. +5. **Guardian report** -- The Guardian outputs a structured report: PASS/FAIL, files scanned count, per-check results (7 checks), issues list with file:line references, fixes applied count, and issues requiring Team Leader intervention. + +## Rules + +- QA agents may only modify documentation files (on PASS) and progress/tracking files. They never modify application source code. +- Documentation updates must be committed on the workbranch before it is merged, so the branch is self-contained. +- The Codebase Guardian runs once per feature, after all tasks are merged. It is the final gate before PR creation. +- The Guardian may fix minor structural issues directly. For anything larger, it must FAIL with instructions. +- `ARCHITECTURE.md` must accurately reflect the IPC channel inventory, state management model, component tree, and extension points after the feature is complete. +- The Guardian is required in strict and standard modes. In fast mode, the Guardian is skipped. +- In standard mode, the Guardian auto-fixes trivial issues. In strict mode, all issues must be explicitly reported. + +## Checks + +- `ARCHITECTURE.md` is updated to reflect all structural changes from the feature. +- New IPC channels are documented in the IPC Channel Inventory. +- New components are shown in the component tree. +- New hooks are listed under extension points. +- State management section reflects any new state added to `App.jsx`. +- All 7 Guardian structural checks pass on the merged feature branch. +- No conflicting or stale documentation across per-task updates. +- Guardian report is PASS before PR creation proceeds. + +## Inputs + +- Merged feature branch with all workbranch changes (including per-task doc updates). +- Progress file with full task history and QA results. +- Recent git log (`git log --oneline -20`) showing all merge commits. +- Project rules from CLAUDE.md and current ARCHITECTURE.md. + +## Outputs + +- Updated `ARCHITECTURE.md` reflecting the complete feature. +- Updated project documentation where conventions or patterns changed. +- Codebase Guardian report (PASS/FAIL with details). +- Feature branch ready for PR creation (if Guardian passes). diff --git a/.claude/docs/workflows/default/workflow.json b/.claude/docs/workflows/default/workflow.json new file mode 100644 index 0000000..b14e051 --- /dev/null +++ b/.claude/docs/workflows/default/workflow.json @@ -0,0 +1,48 @@ +{ + "name": "Default Workflow", + "description": "Standard feature implementation workflow with planning, agent teams, QA review, and documentation updates", + "steps": [ + { + "id": "create-plan", + "title": "Create Plan", + "description": "Deep technical planning and task decomposition before implementation", + "file": "steps/01-create-plan.md", + "order": 1 + }, + { + "id": "implement-plan", + "title": "Implement Plan", + "description": "Execute the plan through specialist agents in isolated worktrees", + "file": "steps/02-implement-plan.md", + "order": 2 + }, + { + "id": "team-management", + "title": "Team Management", + "description": "Coordinate agent teams across waves with dependency tracking", + "file": "steps/03-team-management.md", + "order": 3 + }, + { + "id": "review", + "title": "Review", + "description": "Per-task QA verification and code review against acceptance criteria", + "file": "steps/04-review.md", + "order": 4 + }, + { + "id": "test", + "title": "Test", + "description": "Automated testing, build verification, and lint checks", + "file": "steps/05-test.md", + "order": 5 + }, + { + "id": "update-docs", + "title": "Update Docs", + "description": "Update project documentation and architecture files to reflect changes", + "file": "steps/06-update-docs.md", + "order": 6 + } + ] +} diff --git a/.claude/workflow.json b/.claude/workflow.json new file mode 100644 index 0000000..bea65dc --- /dev/null +++ b/.claude/workflow.json @@ -0,0 +1,16 @@ +{ + "projectRulesFile": "CLAUDE.md", + "architectureFile": ".claude/docs/ARCHITECTURE.md", + "progressDir": ".claude/progress", + "branching": { + "baseBranch": "auto", + "featurePrefix": "feature", + "workPrefix": "work", + "enforce": "warn", + "protectedBranches": ["main", "master"], + "useWorktrees": true, + "worktreeDir": ".worktrees" + }, + "activeWorkflow": "default", + "workflowsDir": ".claude/docs/workflows" +} diff --git a/components.json b/components.json new file mode 100644 index 0000000..e5fc83c --- /dev/null +++ b/components.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": false, + "tailwind": { + "config": "", + "css": "src/renderer/src/globals.css", + "baseColor": "neutral", + "cssVariables": true + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} diff --git a/electron.vite.config.mjs b/electron.vite.config.mjs index 9bf7950..04e097c 100644 --- a/electron.vite.config.mjs +++ b/electron.vite.config.mjs @@ -1,5 +1,7 @@ import { defineConfig, externalizeDepsPlugin } from 'electron-vite' import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' +import { resolve } from 'path' export default defineConfig({ main: { @@ -9,6 +11,12 @@ export default defineConfig({ plugins: [externalizeDepsPlugin()] }, renderer: { - plugins: [react()] + resolve: { + alias: { + '@renderer': resolve('src/renderer/src'), + '@': resolve('src/renderer/src') + } + }, + plugins: [react(), tailwindcss()] } }) diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..ec1e444 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/renderer/src/*"], + "@renderer/*": ["./src/renderer/src/*"] + } + } +} diff --git a/package-lock.json b/package-lock.json index a8b67db..27b5e1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,23 +19,37 @@ "@codemirror/lang-rust": "^6.0.2", "@codemirror/merge": "^6.12.0", "@codemirror/search": "^6.6.0", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-tooltip": "^1.2.8", "@uiw/codemirror-theme-tokyo-night-storm": "^4.25.4", "@uiw/react-codemirror": "^4.25.4", "@xterm/addon-fit": "^0.10.0", "@xterm/addon-web-links": "^0.11.0", "@xterm/addon-webgl": "^0.18.0", "@xterm/xterm": "^5.5.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.575.0", "node-pty": "^1.1.0", "react": "^19.0.0", "react-arborist": "^3.4.3", "react-dom": "^19.0.0", - "react-resizable-panels": "^4.6.2" + "react-resizable-panels": "^4.6.2", + "tailwind-merge": "^3.5.0", + "tw-animate-css": "^1.4.0" }, "devDependencies": { "@electron/rebuild": "^4.0.3", + "@tailwindcss/vite": "^4.2.0", "@vitejs/plugin-react": "^4.3.0", "electron": "^34.0.0", - "electron-vite": "^3.0.0" + "electron-vite": "^3.0.0", + "tailwindcss": "^4.2.0" } }, "node_modules/@babel/code-frame": { @@ -1086,6 +1100,44 @@ "node": ">=18" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.4", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", + "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.5" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1366,292 +1418,1000 @@ "node": ">=14" } }, - "node_modules/@react-dnd/asap": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", - "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==", - "license": "MIT" - }, - "node_modules/@react-dnd/invariant": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", - "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==", - "license": "MIT" - }, - "node_modules/@react-dnd/shallowequal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", - "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==", + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", "license": "MIT" }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", "license": "MIT" }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", - "cpu": [ - "loong64" - ], - "dev": true, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", - "cpu": [ - "loong64" - ], - "dev": true, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", - "cpu": [ - "ppc64" - ], - "dev": true, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", + "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@react-dnd/asap": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", + "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==", + "license": "MIT" + }, + "node_modules/@react-dnd/invariant": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", + "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==", + "license": "MIT" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", + "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==", + "license": "MIT" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.0.tgz", + "integrity": "sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.31.1", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.0" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.0.tgz", + "integrity": "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.0", + "@tailwindcss/oxide-darwin-arm64": "4.2.0", + "@tailwindcss/oxide-darwin-x64": "4.2.0", + "@tailwindcss/oxide-freebsd-x64": "4.2.0", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.0", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.0", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.0", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.0", + "@tailwindcss/oxide-linux-x64-musl": "4.2.0", + "@tailwindcss/oxide-wasm32-wasi": "4.2.0", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.0", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.0" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.0.tgz", + "integrity": "sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.0.tgz", + "integrity": "sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA==", "cpu": [ - "riscv64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.0.tgz", + "integrity": "sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==", "cpu": [ - "riscv64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.0.tgz", + "integrity": "sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==", "cpu": [ - "s390x" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "freebsd" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.0.tgz", + "integrity": "sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==", "cpu": [ - "x64" + "arm" ], "dev": true, "license": "MIT", @@ -1659,14 +2419,16 @@ "os": [ "linux" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.0.tgz", + "integrity": "sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", @@ -1674,74 +2436,97 @@ "os": [ "linux" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.0.tgz", + "integrity": "sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "openbsd" + "linux" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.0.tgz", + "integrity": "sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "openharmony" + "linux" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.0.tgz", + "integrity": "sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.0.tgz", + "integrity": "sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], "cpu": [ - "ia32" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "peer": true + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.0.tgz", + "integrity": "sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", @@ -1749,12 +2534,14 @@ "os": [ "win32" ], - "peer": true + "engines": { + "node": ">= 20" + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.0.tgz", + "integrity": "sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ==", "cpu": [ "x64" ], @@ -1764,32 +2551,23 @@ "os": [ "win32" ], - "peer": true - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "node": ">= 20" } }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "node_modules/@tailwindcss/vite": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.0.tgz", + "integrity": "sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA==", "dev": true, "license": "MIT", "dependencies": { - "defer-to-connect": "^2.0.0" + "@tailwindcss/node": "4.2.0", + "@tailwindcss/oxide": "4.2.0", + "tailwindcss": "4.2.0" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" } }, "node_modules/@types/babel__core": { @@ -1850,14 +2628,6 @@ "@types/responselike": "^1.0.0" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/http-cache-semantics": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", @@ -1879,7 +2649,7 @@ "version": "20.19.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -2093,6 +2863,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2349,6 +3131,18 @@ "node": ">=18" } }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -2476,6 +3270,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/codemirror": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", @@ -2665,6 +3468,12 @@ "license": "MIT", "optional": true }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/dnd-core": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-14.0.1.tgz", @@ -2776,6 +3585,20 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -2996,22 +3819,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3032,6 +3839,15 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -3354,6 +4170,16 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3389,37 +4215,298 @@ "license": "ISC", "optional": true }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/log-symbols": { @@ -3459,6 +4546,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.575.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.575.0.tgz", + "integrity": "sha512-VuXgKZrk0uiDlWjGGXmKV6MSk9Yy4l10qgVvzGn2AWBx1Ylt0iBexKOAoA6I7JO3m+M9oeovJd3yYENfkUbOeg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -3708,26 +4804,6 @@ "dev": true, "license": "MIT" }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -4039,36 +5115,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/proc-log": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", @@ -4220,6 +5266,53 @@ "node": ">=0.10.0" } }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-resizable-panels": { "version": "4.6.4", "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.6.4.tgz", @@ -4230,6 +5323,28 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-window": { "version": "1.8.11", "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.11.tgz", @@ -4361,52 +5476,6 @@ "node": ">=8.0" } }, - "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", - "fsevents": "~2.3.2" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4563,7 +5632,6 @@ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -4735,6 +5803,37 @@ "node": ">=8" } }, + "node_modules/tailwind-merge": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz", + "integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.0.tgz", + "integrity": "sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tar": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", @@ -4779,6 +5878,21 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, "node_modules/type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", @@ -4797,7 +5911,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/unique-filename": { @@ -4867,98 +5981,65 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", - "dev": true, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", "license": "MIT", - "peer": true, "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" - }, - "bin": { - "vite": "bin/vite.js" + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" + "node": ">=10" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { + "@types/react": { "optional": true } } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", diff --git a/package.json b/package.json index 132336b..a88b2fc 100644 --- a/package.json +++ b/package.json @@ -21,22 +21,36 @@ "@codemirror/lang-rust": "^6.0.2", "@codemirror/merge": "^6.12.0", "@codemirror/search": "^6.6.0", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-tooltip": "^1.2.8", "@uiw/codemirror-theme-tokyo-night-storm": "^4.25.4", "@uiw/react-codemirror": "^4.25.4", "@xterm/addon-fit": "^0.10.0", "@xterm/addon-web-links": "^0.11.0", "@xterm/addon-webgl": "^0.18.0", "@xterm/xterm": "^5.5.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.575.0", "node-pty": "^1.1.0", "react": "^19.0.0", "react-arborist": "^3.4.3", "react-dom": "^19.0.0", - "react-resizable-panels": "^4.6.2" + "react-resizable-panels": "^4.6.2", + "tailwind-merge": "^3.5.0", + "tw-animate-css": "^1.4.0" }, "devDependencies": { "@electron/rebuild": "^4.0.3", + "@tailwindcss/vite": "^4.2.0", "@vitejs/plugin-react": "^4.3.0", "electron": "^34.0.0", - "electron-vite": "^3.0.0" + "electron-vite": "^3.0.0", + "tailwindcss": "^4.2.0" } } diff --git a/src/main/index.js b/src/main/index.js index 4380e47..d4104c3 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -325,10 +325,272 @@ ipcMain.on('window:maximize', () => { }) ipcMain.on('window:close', () => mainWindow?.close()) +// --- Workflow Scanner --- +class WorkflowScanner { + constructor() { + this.watchers = new Map() + } + + async getConfig(projectPath) { + const configPath = path.join(projectPath, '.claude', 'workflow.json') + try { + const raw = await fs.promises.readFile(configPath, 'utf-8') + return JSON.parse(raw) + } catch { + return null + } + } + + async getWorkflow(projectPath) { + const config = await this.getConfig(projectPath) + if (!config || !config.activeWorkflow || !config.workflowsDir) { + return null + } + + const workflowDir = path.join(projectPath, config.workflowsDir, config.activeWorkflow) + const workflowJsonPath = path.join(workflowDir, 'workflow.json') + + try { + const raw = await fs.promises.readFile(workflowJsonPath, 'utf-8') + const workflow = JSON.parse(raw) + return { ...workflow, basePath: workflowDir } + } catch { + return null + } + } + + async getStepContent(projectPath, stepFile) { + const config = await this.getConfig(projectPath) + if (!config) return { content: null, error: 'No workflow config' } + + const filePath = path.join(projectPath, config.workflowsDir, config.activeWorkflow, stepFile) + try { + const content = await fs.promises.readFile(filePath, 'utf-8') + return { content, error: null } + } catch (err) { + return { content: null, error: err.message } + } + } + + async saveStepContent(projectPath, stepFile, content) { + const config = await this.getConfig(projectPath) + if (!config) return { error: 'No workflow config' } + + const filePath = path.join(projectPath, config.workflowsDir, config.activeWorkflow, stepFile) + try { + await fs.promises.writeFile(filePath, content, 'utf-8') + return { error: null } + } catch (err) { + return { error: err.message } + } + } + + async getProgress(projectPath) { + const config = await this.getConfig(projectPath) + if (!config || !config.progressDir) return null + + const progressDir = path.join(projectPath, config.progressDir) + try { + const entries = await fs.promises.readdir(progressDir, { withFileTypes: true }) + const features = [] + + for (const entry of entries) { + if (!entry.isDirectory()) continue + const currentPath = path.join(progressDir, entry.name, 'current.md') + try { + const content = await fs.promises.readFile(currentPath, 'utf-8') + const statusMatch = content.match(/\*\*Status:\*\*\s*(\w+)/) + features.push({ + name: entry.name, + status: statusMatch ? statusMatch[1] : 'unknown', + currentFile: currentPath + }) + } catch { + features.push({ name: entry.name, status: 'unknown', currentFile: null }) + } + } + + return { features, progressDir } + } catch { + return { features: [], progressDir } + } + } + + watchProgress(projectPath, callback) { + const config = this._getConfigSync(projectPath) + if (!config || !config.progressDir) return null + + const progressDir = path.join(projectPath, config.progressDir) + const watchId = `workflow-progress-${projectPath}` + + if (this.watchers.has(watchId)) { + this.watchers.get(watchId).close() + } + + try { + const watcher = fs.watch(progressDir, { recursive: true }, (eventType, filename) => { + callback({ eventType, filename, progressDir }) + }) + watcher.on('error', () => {}) + this.watchers.set(watchId, watcher) + return watchId + } catch { + return null + } + } + + unwatchProgress(watchId) { + if (this.watchers.has(watchId)) { + this.watchers.get(watchId).close() + this.watchers.delete(watchId) + } + } + + _getConfigSync(projectPath) { + const configPath = path.join(projectPath, '.claude', 'workflow.json') + try { + const raw = fs.readFileSync(configPath, 'utf-8') + return JSON.parse(raw) + } catch { + return null + } + } + + async hasWorkflow(projectPath) { + const config = await this.getConfig(projectPath) + return config !== null + } + + async scaffold(projectPath) { + const claudeDir = path.join(projectPath, '.claude') + const workflowsDir = path.join(claudeDir, 'docs', 'workflows', 'default', 'steps') + const agentsDir = path.join(claudeDir, 'agents') + const progressDir = path.join(claudeDir, 'progress') + + await fs.promises.mkdir(workflowsDir, { recursive: true }) + await fs.promises.mkdir(agentsDir, { recursive: true }) + await fs.promises.mkdir(progressDir, { recursive: true }) + + const config = { + projectRulesFile: 'CLAUDE.md', + architectureFile: '.claude/docs/ARCHITECTURE.md', + progressDir: '.claude/progress', + branching: { + baseBranch: 'auto', + featurePrefix: 'feature', + workPrefix: 'work', + enforce: 'warn', + protectedBranches: ['main', 'master'], + useWorktrees: true, + worktreeDir: '.worktrees' + }, + activeWorkflow: 'default', + workflowsDir: '.claude/docs/workflows' + } + await fs.promises.writeFile( + path.join(claudeDir, 'workflow.json'), + JSON.stringify(config, null, 2), + 'utf-8' + ) + + const workflow = { + name: 'Default Workflow', + description: 'Standard feature implementation workflow', + steps: [ + { id: 'create-plan', title: 'Create Plan', description: 'Technical planning and task decomposition', file: 'steps/01-create-plan.md', order: 1 }, + { id: 'implement-plan', title: 'Implement Plan', description: 'Execute through specialist agents', file: 'steps/02-implement-plan.md', order: 2 }, + { id: 'team-management', title: 'Team Management', description: 'Coordinate agent teams across waves', file: 'steps/03-team-management.md', order: 3 }, + { id: 'review', title: 'Review', description: 'QA verification and code review', file: 'steps/04-review.md', order: 4 }, + { id: 'test', title: 'Test', description: 'Automated testing and build verification', file: 'steps/05-test.md', order: 5 }, + { id: 'update-docs', title: 'Update Docs', description: 'Update documentation to reflect changes', file: 'steps/06-update-docs.md', order: 6 } + ] + } + await fs.promises.writeFile( + path.join(claudeDir, 'docs', 'workflows', 'default', 'workflow.json'), + JSON.stringify(workflow, null, 2), + 'utf-8' + ) + + const steps = [ + { file: '01-create-plan.md', content: '# Create Plan\n\nUse `/create-feature-plan` to analyze the codebase and produce a detailed design document.\n' }, + { file: '02-implement-plan.md', content: '# Implement Plan\n\nUse `/implement-feature` to execute the plan through specialist agents in isolated worktrees.\n' }, + { file: '03-team-management.md', content: '# Team Management\n\nThe Team Leader coordinates agent teams across dependency-ordered waves.\n' }, + { file: '04-review.md', content: '# Review\n\nEach task goes through QA review before merge. Up to 3 rounds of feedback.\n' }, + { file: '05-test.md', content: '# Test\n\nWave fence checks verify builds pass. Final Guardian check validates structural integrity.\n' }, + { file: '06-update-docs.md', content: '# Update Docs\n\nUpdate ARCHITECTURE.md, CLAUDE.md, and any affected documentation.\n' } + ] + + for (const step of steps) { + await fs.promises.writeFile( + path.join(workflowsDir, step.file), + step.content, + 'utf-8' + ) + } + + await fs.promises.writeFile(path.join(progressDir, '.gitkeep'), '', 'utf-8') + + return { success: true } + } + + cleanup() { + for (const watcher of this.watchers.values()) { + watcher.close() + } + this.watchers.clear() + } +} + +// --- Workflow IPC Handlers --- +const workflowScanner = new WorkflowScanner() + +ipcMain.handle('workflow:has-workflow', async (event, { projectPath }) => { + return workflowScanner.hasWorkflow(projectPath) +}) + +ipcMain.handle('workflow:get-config', async (event, { projectPath }) => { + return workflowScanner.getConfig(projectPath) +}) + +ipcMain.handle('workflow:get-workflow', async (event, { projectPath }) => { + return workflowScanner.getWorkflow(projectPath) +}) + +ipcMain.handle('workflow:get-step-content', async (event, { projectPath, stepFile }) => { + return workflowScanner.getStepContent(projectPath, stepFile) +}) + +ipcMain.handle('workflow:save-step-content', async (event, { projectPath, stepFile, content }) => { + return workflowScanner.saveStepContent(projectPath, stepFile, content) +}) + +ipcMain.handle('workflow:get-progress', async (event, { projectPath }) => { + return workflowScanner.getProgress(projectPath) +}) + +ipcMain.handle('workflow:watch-progress', (event, { projectPath }) => { + const watchId = workflowScanner.watchProgress(projectPath, (change) => { + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send('workflow:progress-changed', change) + } + }) + return { watchId } +}) + +ipcMain.handle('workflow:unwatch-progress', (event, { watchId }) => { + workflowScanner.unwatchProgress(watchId) + return { success: true } +}) + +ipcMain.handle('workflow:scaffold', async (event, { projectPath }) => { + return workflowScanner.scaffold(projectPath) +}) + app.whenReady().then(createWindow) app.on('window-all-closed', async () => { ptyManager.killAll() + workflowScanner.cleanup() for (const watcher of activeWatchers.values()) watcher.close() activeWatchers.clear() await cleanupTempImages() diff --git a/src/preload/index.js b/src/preload/index.js index 7e39189..7803592 100644 --- a/src/preload/index.js +++ b/src/preload/index.js @@ -41,6 +41,22 @@ contextBridge.exposeInMainWorld('electronAPI', { readClipboardImage: () => ipcRenderer.invoke('clipboard:read-image'), saveTempImage: (dataURL) => ipcRenderer.invoke('app:save-temp-image', { dataURL }), + // Workflow + workflowHasWorkflow: (projectPath) => ipcRenderer.invoke('workflow:has-workflow', { projectPath }), + workflowGetConfig: (projectPath) => ipcRenderer.invoke('workflow:get-config', { projectPath }), + workflowGetWorkflow: (projectPath) => ipcRenderer.invoke('workflow:get-workflow', { projectPath }), + workflowGetStepContent: (projectPath, stepFile) => ipcRenderer.invoke('workflow:get-step-content', { projectPath, stepFile }), + workflowSaveStepContent: (projectPath, stepFile, content) => ipcRenderer.invoke('workflow:save-step-content', { projectPath, stepFile, content }), + workflowGetProgress: (projectPath) => ipcRenderer.invoke('workflow:get-progress', { projectPath }), + workflowWatchProgress: (projectPath) => ipcRenderer.invoke('workflow:watch-progress', { projectPath }), + workflowUnwatchProgress: (watchId) => ipcRenderer.invoke('workflow:unwatch-progress', { watchId }), + workflowScaffold: (projectPath) => ipcRenderer.invoke('workflow:scaffold', { projectPath }), + onWorkflowProgressChanged: (callback) => { + const handler = (_event, data) => callback(data) + ipcRenderer.on('workflow:progress-changed', handler) + return () => ipcRenderer.removeListener('workflow:progress-changed', handler) + }, + // Window Controls windowMinimize: () => ipcRenderer.send('window:minimize'), windowMaximize: () => ipcRenderer.send('window:maximize'), diff --git a/src/renderer/index.html b/src/renderer/index.html index 7e78e4d..0779bb3 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -1,11 +1,11 @@ - + Claude Terminal - +
diff --git a/src/renderer/src/App.css b/src/renderer/src/App.css deleted file mode 100644 index 6eaf0f8..0000000 --- a/src/renderer/src/App.css +++ /dev/null @@ -1,801 +0,0 @@ -/* Tokyo Night Storm Theme */ -:root { - --bg-dark: #1a1b26; - --bg-medium: #1f2335; - --bg-light: #24283b; - --bg-highlight: #292e42; - --bg-hover: #33467c; - --border: #3b4261; - --fg: #a9b1d6; - --fg-dim: #565f89; - --fg-bright: #c0caf5; - --accent-blue: #7aa2f7; - --accent-cyan: #7dcfff; - --accent-green: #9ece6a; - --accent-yellow: #e0af68; - --accent-red: #f7768e; - --accent-magenta: #bb9af7; - --accent-orange: #ff9e64; - --titlebar-height: 38px; - --tabbar-height: 36px; - --sidebar-width: 260px; - --font-mono: 'JetBrains Mono', 'Cascadia Code', 'Fira Code', monospace; - --font-ui: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -html, body, #root { - height: 100%; - overflow: hidden; - background: var(--bg-dark); - color: var(--fg); - font-family: var(--font-ui); - font-size: 13px; - user-select: none; -} - -/* Scrollbar styling */ -::-webkit-scrollbar { - width: 8px; - height: 8px; -} -::-webkit-scrollbar-track { - background: transparent; -} -::-webkit-scrollbar-thumb { - background: var(--border); - border-radius: 4px; -} -::-webkit-scrollbar-thumb:hover { - background: var(--fg-dim); -} - -/* Title Bar */ -.title-bar { - display: flex; - align-items: center; - justify-content: space-between; - height: var(--titlebar-height); - background: var(--bg-dark); - -webkit-app-region: drag; - padding: 0 8px; - border-bottom: 1px solid var(--border); -} - -.title-bar__label { - font-size: 12px; - color: var(--fg-dim); - font-weight: 500; - letter-spacing: 0.5px; -} - -.title-bar__controls { - display: flex; - gap: 2px; - -webkit-app-region: no-drag; -} - -.title-bar__btn { - width: 32px; - height: 28px; - display: flex; - align-items: center; - justify-content: center; - background: transparent; - border: none; - color: var(--fg-dim); - cursor: pointer; - border-radius: 4px; - font-size: 16px; -} - -.title-bar__btn:hover { - background: var(--bg-highlight); - color: var(--fg); -} - -.title-bar__btn--close:hover { - background: var(--accent-red); - color: #fff; -} - -/* Tab Bar */ -.tab-bar { - display: flex; - align-items: center; - height: var(--tabbar-height); - background: var(--bg-dark); - border-bottom: 1px solid var(--border); - padding: 0 4px; - gap: 2px; - overflow-x: auto; - overflow-y: hidden; -} - -.tab-bar::-webkit-scrollbar { - height: 0; -} - -.tab { - display: flex; - align-items: center; - gap: 6px; - height: 28px; - padding: 0 12px; - border-radius: 6px; - cursor: pointer; - white-space: nowrap; - font-size: 12px; - color: var(--fg-dim); - background: transparent; - border: none; - transition: background 0.15s, color 0.15s; - flex-shrink: 0; -} - -.tab:hover { - background: var(--bg-highlight); - color: var(--fg); -} - -.tab--active { - background: var(--bg-light); - color: var(--fg-bright); -} - -.tab__dot { - width: 8px; - height: 8px; - border-radius: 50%; - flex-shrink: 0; -} - -.tab__close { - display: flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - border-radius: 3px; - font-size: 14px; - opacity: 0; - transition: opacity 0.15s; - color: var(--fg-dim); -} - -.tab:hover .tab__close { - opacity: 1; -} - -.tab__close:hover { - background: var(--bg-hover); - color: var(--fg); -} - -.tab--add { - color: var(--fg-dim); - font-size: 16px; - width: 28px; - padding: 0; - justify-content: center; -} - -/* Layout */ -.app-layout { - display: flex; - flex-direction: column; - height: 100vh; -} - -.app-body { - display: flex; - flex: 1; - overflow: hidden; -} - -.app-body--sidebar-right { - flex-direction: row-reverse; -} - -/* Sidebar */ -.sidebar { - width: var(--sidebar-width); - min-width: var(--sidebar-width); - background: var(--bg-medium); - border-right: 1px solid var(--border); - display: flex; - flex-direction: column; - overflow: hidden; -} - -.app-body--sidebar-right .sidebar { - border-right: none; - border-left: 1px solid var(--border); -} - -.sidebar__nav { - display: flex; - gap: 2px; - padding: 8px; - border-bottom: 1px solid var(--border); -} - -.sidebar__nav-btn { - display: flex; - align-items: center; - justify-content: center; - width: 32px; - height: 28px; - border-radius: 6px; - background: transparent; - border: none; - color: var(--fg-dim); - cursor: pointer; - font-size: 15px; -} - -.sidebar__nav-btn:hover { - background: var(--bg-highlight); - color: var(--fg); -} - -.sidebar__nav-btn--active { - background: var(--bg-highlight); - color: var(--accent-blue); -} - -.sidebar__content { - flex: 1; - overflow-y: auto; - padding: 8px; -} - -.sidebar__section-title { - font-size: 11px; - font-weight: 600; - color: var(--fg-dim); - text-transform: uppercase; - letter-spacing: 0.8px; - padding: 8px 8px 4px; -} - -/* File Explorer */ -.file-tree { - font-size: 13px; -} - -.file-tree-node { - display: flex; - align-items: center; - gap: 4px; - padding: 3px 8px; - border-radius: 4px; - cursor: pointer; - color: var(--fg); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.file-tree-node:hover { - background: var(--bg-highlight); -} - -.file-tree-node--selected { - background: var(--bg-hover); - color: var(--fg-bright); -} - -.file-tree-node__icon { - flex-shrink: 0; - width: 16px; - text-align: center; - font-size: 12px; -} - -.file-tree-node__name { - overflow: hidden; - text-overflow: ellipsis; -} - -/* Command List */ -.command-list { - display: flex; - flex-direction: column; - gap: 2px; -} - -.command-item { - display: flex; - align-items: center; - gap: 8px; - padding: 6px 8px; - border-radius: 6px; - cursor: pointer; - color: var(--fg); - background: transparent; - border: none; - text-align: left; - width: 100%; - font-size: 13px; - font-family: var(--font-ui); -} - -.command-item:hover { - background: var(--bg-highlight); -} - -.command-item__name { - color: var(--accent-cyan); - font-family: var(--font-mono); - font-size: 12px; -} - -.command-item__desc { - color: var(--fg-dim); - font-size: 11px; -} - -/* Settings */ -.settings-panel { - display: flex; - flex-direction: column; - gap: 16px; - padding: 4px; -} - -.settings-group { - display: flex; - flex-direction: column; - gap: 6px; -} - -.settings-group__label { - font-size: 11px; - font-weight: 600; - color: var(--fg-dim); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.settings-option { - display: flex; - align-items: center; - justify-content: space-between; - padding: 6px 8px; - border-radius: 6px; - background: var(--bg-light); -} - -.settings-option__label { - color: var(--fg); - font-size: 13px; -} - -.settings-toggle { - width: 36px; - height: 20px; - border-radius: 10px; - background: var(--border); - border: none; - cursor: pointer; - position: relative; - transition: background 0.2s; -} - -.settings-toggle--on { - background: var(--accent-blue); -} - -.settings-toggle::after { - content: ''; - position: absolute; - top: 2px; - left: 2px; - width: 16px; - height: 16px; - border-radius: 50%; - background: #fff; - transition: transform 0.2s; -} - -.settings-toggle--on::after { - transform: translateX(16px); -} - -.settings-select { - background: var(--bg-light); - border: 1px solid var(--border); - color: var(--fg); - padding: 4px 8px; - border-radius: 4px; - font-size: 12px; - cursor: pointer; -} - -/* Pane Container */ -.pane-container { - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; - background: var(--bg-dark); -} - -.pane-toolbar { - display: flex; - align-items: center; - gap: 4px; - padding: 4px 8px; - background: var(--bg-medium); - border-bottom: 1px solid var(--border); -} - -.pane-toolbar__btn { - display: flex; - align-items: center; - justify-content: center; - height: 24px; - padding: 0 8px; - border-radius: 4px; - background: transparent; - border: none; - color: var(--fg-dim); - cursor: pointer; - font-size: 12px; - font-family: var(--font-ui); - gap: 4px; -} - -.pane-toolbar__btn:hover { - background: var(--bg-highlight); - color: var(--fg); -} - -.pane-area { - flex: 1; - overflow: hidden; -} - -/* Terminal Pane */ -.terminal-pane { - height: 100%; - display: flex; - flex-direction: column; - background: var(--bg-dark); -} - -.terminal-pane__header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 2px 8px; - background: var(--bg-medium); - border-bottom: 1px solid var(--border); - min-height: 24px; -} - -.terminal-pane__title { - font-size: 11px; - color: var(--fg-dim); - font-family: var(--font-mono); -} - -.terminal-pane__close { - display: flex; - align-items: center; - justify-content: center; - width: 18px; - height: 18px; - border-radius: 3px; - background: transparent; - border: none; - color: var(--fg-dim); - cursor: pointer; - font-size: 14px; -} - -.terminal-pane__close:hover { - background: var(--accent-red); - color: #fff; -} - -.terminal-pane__body { - flex: 1; - overflow: hidden; - padding: 4px; -} - -.terminal-pane__body .xterm { - height: 100%; -} - -/* Input Area */ -.input-area { - display: flex; - align-items: flex-end; - gap: 8px; - padding: 8px 12px; - background: var(--bg-medium); - border-top: 1px solid var(--border); -} - -.input-area__field { - flex: 1; - background: var(--bg-light); - border: 1px solid var(--border); - border-radius: 8px; - color: var(--fg); - padding: 8px 12px; - font-size: 13px; - font-family: var(--font-mono); - resize: none; - outline: none; - min-height: 36px; - max-height: 120px; - line-height: 1.4; -} - -.input-area__field:focus { - border-color: var(--accent-blue); -} - -.input-area__field::placeholder { - color: var(--fg-dim); -} - -.input-area__send { - display: flex; - align-items: center; - justify-content: center; - width: 36px; - height: 36px; - border-radius: 8px; - background: var(--accent-blue); - border: none; - color: #fff; - cursor: pointer; - font-size: 16px; - flex-shrink: 0; -} - -.input-area__send:hover { - opacity: 0.9; -} - -.input-area__send:disabled { - opacity: 0.4; - cursor: default; -} - -.input-area__preview { - display: flex; - align-items: center; - gap: 8px; - padding: 4px 8px; - background: var(--bg-light); - border-radius: 6px; -} - -.input-area__preview img { - max-height: 48px; - border-radius: 4px; -} - -.input-area__preview-remove { - background: transparent; - border: none; - color: var(--fg-dim); - cursor: pointer; - font-size: 14px; -} - -.input-area__preview-remove:hover { - color: var(--accent-red); -} - -/* Editor Panel */ -.editor-panel { - height: 100%; - display: flex; - flex-direction: column; - background: var(--bg-dark); - overflow: hidden; -} - -.editor-panel__empty { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - color: var(--fg-dim); - font-size: 13px; -} - -.editor-panel__body { - flex: 1; - overflow: hidden; -} - -.editor-panel__body .cm-editor { - height: 100%; - font-family: var(--font-mono); - font-size: 14px; -} - -.editor-panel__body .cm-editor .cm-scroller { - overflow: auto; -} - -.editor-panel__body .cm-editor.cm-focused { - outline: none; -} - -/* Editor Tabs */ -.editor-tabs { - display: flex; - align-items: center; - gap: 1px; - padding: 0 4px; - background: var(--bg-medium); - border-bottom: 1px solid var(--border); - overflow-x: auto; - overflow-y: hidden; - min-height: 30px; -} - -.editor-tabs::-webkit-scrollbar { - height: 0; -} - -.editor-tab { - display: flex; - align-items: center; - gap: 6px; - height: 28px; - padding: 0 10px; - border-radius: 4px 4px 0 0; - cursor: pointer; - white-space: nowrap; - font-size: 12px; - color: var(--fg-dim); - background: transparent; - border: none; - font-family: var(--font-mono); - flex-shrink: 0; - transition: background 0.15s, color 0.15s; -} - -.editor-tab:hover { - background: var(--bg-highlight); - color: var(--fg); -} - -.editor-tab--active { - background: var(--bg-dark); - color: var(--fg-bright); - border-bottom: 2px solid var(--accent-blue); -} - -.editor-tab__name { - display: flex; - align-items: center; - gap: 4px; -} - -.editor-tab__dot { - display: inline-block; - width: 6px; - height: 6px; - border-radius: 50%; - background: var(--accent-yellow); - flex-shrink: 0; -} - -.editor-tab__close { - display: flex; - align-items: center; - justify-content: center; - width: 14px; - height: 14px; - border-radius: 3px; - font-size: 12px; - opacity: 0; - transition: opacity 0.15s; - color: var(--fg-dim); -} - -.editor-tab:hover .editor-tab__close { - opacity: 1; -} - -.editor-tab__close:hover { - background: var(--accent-red); - color: #fff; -} - -/* Active toolbar button */ -.pane-toolbar__btn--active { - color: var(--accent-blue); - background: var(--bg-highlight); -} - -/* Resize handles */ -[data-panel-group-direction="horizontal"] > [data-resize-handle-id] { - width: 4px; - background: var(--border); - transition: background 0.15s; -} - -[data-panel-group-direction="horizontal"] > [data-resize-handle-id]:hover, -[data-panel-group-direction="horizontal"] > [data-resize-handle-id][data-resize-handle-active] { - background: var(--accent-blue); -} - -[data-panel-group-direction="vertical"] > [data-resize-handle-id] { - height: 4px; - background: var(--border); - transition: background 0.15s; -} - -[data-panel-group-direction="vertical"] > [data-resize-handle-id]:hover, -[data-panel-group-direction="vertical"] > [data-resize-handle-id][data-resize-handle-active] { - background: var(--accent-blue); -} - -/* --- Error Boundary --- */ -.error-boundary { - display: flex; - align-items: center; - justify-content: center; - height: 100vh; - background: var(--bg-primary); - color: var(--fg-primary); -} - -.error-boundary__content { - text-align: center; - max-width: 500px; - padding: 32px; -} - -.error-boundary__title { - font-size: 20px; - font-weight: 600; - margin-bottom: 16px; - color: var(--accent-red); -} - -.error-boundary__message { - font-family: 'JetBrains Mono', monospace; - font-size: 13px; - background: var(--bg-tertiary); - border: 1px solid var(--border); - border-radius: 6px; - padding: 16px; - margin-bottom: 20px; - white-space: pre-wrap; - word-break: break-word; - text-align: left; - color: var(--fg-secondary); -} - -.error-boundary__btn { - background: var(--accent-blue); - color: var(--bg-primary); - border: none; - border-radius: 6px; - padding: 8px 24px; - font-size: 14px; - cursor: pointer; - transition: opacity 0.15s; -} - -.error-boundary__btn:hover { - opacity: 0.85; -} diff --git a/src/renderer/src/App.jsx b/src/renderer/src/App.jsx index a273a06..834a46e 100644 --- a/src/renderer/src/App.jsx +++ b/src/renderer/src/App.jsx @@ -1,11 +1,15 @@ import React, { useState, useCallback, useEffect, useRef } from 'react' import { Panel, Group, Separator } from 'react-resizable-panels' +import { cn } from './lib/utils' +import { Button } from './components/ui/button' import TabBar from './components/TabBar' import Sidebar from './components/Sidebar' import PaneContainer from './components/PaneContainer' import InputArea from './components/InputArea' import EditorPanel from './components/EditorPanel' import ErrorBoundary from './components/ErrorBoundary' +import { useWorkflow } from './hooks/useWorkflow' +import WorkflowPanel from './components/WorkflowPanel' const TAB_COLORS = [ '#7aa2f7', '#bb9af7', '#9ece6a', '#e0af68', @@ -43,9 +47,13 @@ export default function App() { const [openFiles, setOpenFiles] = useState([]) const [activeFileId, setActiveFileId] = useState(null) const [editorVisible, setEditorVisible] = useState(false) + const [workflowVisible, setWorkflowVisible] = useState(false) const activeTab = tabs.find(t => t.id === activeTabId) || tabs[0] + // Workflow state + const workflowState = useWorkflow(activeTab.cwd) + const handleAddTab = useCallback(() => { setTabs(prev => { const tab = createTab(null, prev.length) @@ -142,6 +150,10 @@ export default function App() { setEditorVisible(prev => !prev) }, []) + const toggleWorkflow = useCallback(() => { + setWorkflowVisible(prev => !prev) + }, []) + // Keyboard shortcuts useEffect(() => { const handleKeyDown = (e) => { @@ -166,11 +178,16 @@ export default function App() { e.preventDefault() toggleEditor() } + // Ctrl+Shift+W: Toggle workflow panel + if (e.ctrlKey && e.shiftKey && e.key === 'W') { + e.preventDefault() + toggleWorkflow() + } } window.addEventListener('keydown', handleKeyDown) return () => window.removeEventListener('keydown', handleKeyDown) - }, [handleAddTab, handleCloseTab, handleSplitH, handleSplitV, activeTabId, toggleEditor]) + }, [handleAddTab, handleCloseTab, handleSplitH, handleSplitV, activeTabId, toggleEditor, toggleWorkflow]) // Load settings on mount useEffect(() => { @@ -193,13 +210,13 @@ export default function App() { return ( -
-
- CLAUDE TERMINAL -
- - - +
+
+ CLAUDE TERMINAL +
+ + +
-
+
-
-
- - + -
- + +
-
- {editorVisible ? ( - - - +
+ {workflowVisible ? ( + + + {editorVisible ? ( + + + + + + + + + + ) : ( + + )} - - + + ) : ( - + editorVisible ? ( + + + + + + + + + + ) : ( + + ) )}
+
{COMMANDS.map(cmd => ( ))} diff --git a/src/renderer/src/components/EditorPanel.jsx b/src/renderer/src/components/EditorPanel.jsx index 99d5d32..2778ce3 100644 --- a/src/renderer/src/components/EditorPanel.jsx +++ b/src/renderer/src/components/EditorPanel.jsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useCallback, useRef } from 'react' +import { cn } from '../lib/utils' import CodeMirror from '@uiw/react-codemirror' import { tokyoNightStorm } from '@uiw/codemirror-theme-tokyo-night-storm' import { javascript } from '@codemirror/lang-javascript' @@ -124,8 +125,8 @@ export default function EditorPanel({ openFiles, activeFileId, onSelectFile, onC if (openFiles.length === 0) { return ( -
-
+
+
Click a file in the explorer to open it
@@ -133,20 +134,23 @@ export default function EditorPanel({ openFiles, activeFileId, onSelectFile, onC } return ( -
-
+
+
{openFiles.map(file => ( ))}
-
+
{isLoading ? ( -
Loading...
+
Loading...
) : activeFile ? ( -
-

Something went wrong

-
+        
+
+

Something went wrong

+
               {this.state.error?.message || 'Unknown error'}
             
- +
) diff --git a/src/renderer/src/components/FileExplorer.jsx b/src/renderer/src/components/FileExplorer.jsx index 7c346cd..bf165e2 100644 --- a/src/renderer/src/components/FileExplorer.jsx +++ b/src/renderer/src/components/FileExplorer.jsx @@ -1,4 +1,6 @@ import React, { useState, useEffect, useCallback, useRef } from 'react' +import { cn } from '@/lib/utils' +import { Input } from './ui/input' function FileNode({ entry, depth, onSelect, refreshKey }) { const [expanded, setExpanded] = useState(false) @@ -28,18 +30,18 @@ function FileNode({ entry, depth, onSelect, refreshKey }) { }, [entry, expanded, loadChildren, onSelect]) const icon = entry.type === 'directory' - ? (expanded ? '📂' : '📁') - : '📄' + ? (expanded ? '\u{1F4C2}' : '\u{1F4C1}') + : '\u{1F4C4}' return ( <>
- {icon} - {entry.name} + {icon} + {entry.name}
{expanded && children && children.map(child => ( -
- + + setPathInput(e.target.value)} - className="input-area__field" - style={{ width: '100%', fontSize: '11px', padding: '4px 8px', minHeight: '28px' }} + className="h-7 text-xs" placeholder="Directory path..." />
@@ -145,9 +146,7 @@ export default function FileExplorer({ cwd, onOpenFile }) { /> ))} {rootEntries.length === 0 && ( -
- No files found. Enter a path above. -
+

No files found. Enter a path above.

)}
) diff --git a/src/renderer/src/components/InputArea.jsx b/src/renderer/src/components/InputArea.jsx index a5eec9f..f12004d 100644 --- a/src/renderer/src/components/InputArea.jsx +++ b/src/renderer/src/components/InputArea.jsx @@ -1,4 +1,6 @@ import React, { useState, useRef, useCallback } from 'react' +import { Button } from './ui/button' +import { cn } from '../lib/utils' export default function InputArea({ onSend }) { const [text, setText] = useState('') @@ -51,20 +53,20 @@ export default function InputArea({ onSend }) { }, []) return ( -
+
{imagePreview && ( -
- Pasted - Image attached - +
)} -
+