From 1e47ed11f8d4e8964a1bf0d697923392fb92a816 Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Wed, 27 May 2026 22:06:57 +0200 Subject: [PATCH 1/7] feat(cli): add agent watch --- .../design/2026-05-27-feature-agent-watch.md | 216 ++ .../2026-05-27-feature-agent-watch.md | 65 + .../2026-05-27-feature-agent-watch.md | 100 + .../2026-05-27-feature-agent-watch.md | 99 + .../testing/2026-05-27-feature-agent-watch.md | 81 + package-lock.json | 2785 +++++------------ packages/agent-manager/src/AgentManager.ts | 39 +- packages/agent-manager/src/index.ts | 2 + .../agent-manager/src/utils/sortAgents.ts | 52 + packages/cli/package.json | 4 + packages/cli/src/commands/agent.ts | 49 + packages/cli/src/lib/Config.ts | 2 +- packages/cli/src/lib/SkillManager.ts | 3 +- .../src/services/install/install.service.ts | 5 +- packages/cli/src/tui/watch/AgentListPane.tsx | 128 + packages/cli/src/tui/watch/ChatInput.tsx | 82 + packages/cli/src/tui/watch/FooterSection.tsx | 26 + packages/cli/src/tui/watch/HeaderBar.tsx | 18 + packages/cli/src/tui/watch/ListSection.tsx | 37 + packages/cli/src/tui/watch/PreviewPane.tsx | 140 + packages/cli/src/tui/watch/PreviewSection.tsx | 44 + packages/cli/src/tui/watch/StatusFooter.tsx | 82 + packages/cli/src/tui/watch/WatchApp.tsx | 207 ++ .../cli/src/tui/watch/actions/runAction.ts | 36 + packages/cli/src/tui/watch/actions/types.ts | 3 + .../tui/watch/hooks/useAgentConversation.ts | 164 + .../cli/src/tui/watch/hooks/useAgentList.ts | 99 + .../src/tui/watch/hooks/useTerminalSize.ts | 37 + .../cli/src/tui/watch/render/formatStatus.tsx | 32 + .../cli/src/tui/watch/state/WatchContext.tsx | 30 + packages/cli/tsconfig.json | 3 +- 31 files changed, 2696 insertions(+), 1974 deletions(-) create mode 100644 docs/ai/design/2026-05-27-feature-agent-watch.md create mode 100644 docs/ai/implementation/2026-05-27-feature-agent-watch.md create mode 100644 docs/ai/planning/2026-05-27-feature-agent-watch.md create mode 100644 docs/ai/requirements/2026-05-27-feature-agent-watch.md create mode 100644 docs/ai/testing/2026-05-27-feature-agent-watch.md create mode 100644 packages/agent-manager/src/utils/sortAgents.ts create mode 100644 packages/cli/src/tui/watch/AgentListPane.tsx create mode 100644 packages/cli/src/tui/watch/ChatInput.tsx create mode 100644 packages/cli/src/tui/watch/FooterSection.tsx create mode 100644 packages/cli/src/tui/watch/HeaderBar.tsx create mode 100644 packages/cli/src/tui/watch/ListSection.tsx create mode 100644 packages/cli/src/tui/watch/PreviewPane.tsx create mode 100644 packages/cli/src/tui/watch/PreviewSection.tsx create mode 100644 packages/cli/src/tui/watch/StatusFooter.tsx create mode 100644 packages/cli/src/tui/watch/WatchApp.tsx create mode 100644 packages/cli/src/tui/watch/actions/runAction.ts create mode 100644 packages/cli/src/tui/watch/actions/types.ts create mode 100644 packages/cli/src/tui/watch/hooks/useAgentConversation.ts create mode 100644 packages/cli/src/tui/watch/hooks/useAgentList.ts create mode 100644 packages/cli/src/tui/watch/hooks/useTerminalSize.ts create mode 100644 packages/cli/src/tui/watch/render/formatStatus.tsx create mode 100644 packages/cli/src/tui/watch/state/WatchContext.tsx diff --git a/docs/ai/design/2026-05-27-feature-agent-watch.md b/docs/ai/design/2026-05-27-feature-agent-watch.md new file mode 100644 index 00000000..633318cc --- /dev/null +++ b/docs/ai/design/2026-05-27-feature-agent-watch.md @@ -0,0 +1,216 @@ +--- +phase: design +title: System Design & Architecture +description: Define the technical architecture, components, and data models +--- + +# System Design & Architecture — Agent Watch + +## Architecture Overview + +`ai-devkit agent watch` is a new CLI subcommand that launches an Ink-based React TUI inside the user's terminal. The TUI reads agent state in-process via the existing `AgentManager` and adapter APIs, renders a two-pane master-detail view, and shells out to existing `ai-devkit agent open` / `ai-devkit agent send` commands for user actions. + +```mermaid +graph TD + CLI["packages/cli
agent watch command"] -->|render| TUI["Ink App
WatchApp.tsx"] + TUI --> ListPane["AgentListPane
(left, ~35%)"] + TUI --> PreviewPane["PreviewPane
(right, ~65%)"] + TUI --> Footer["StatusFooter"] + TUI --> MessageModal["SendMessageModal
(overlay)"] + + ListPane -->|poll 2s| ListPoller["useAgentList hook"] + PreviewPane -->|poll 1s| PreviewPoller["useAgentConversation hook"] + + ListPoller -->|manager.listAgents| Manager["AgentManager
(in-process)"] + PreviewPoller -->|adapter.getConversation| Manager + Manager --> ClaudeAdapter + Manager --> CodexAdapter + Manager --> GeminiAdapter + Manager --> OpenCodeAdapter + + TUI -->|Enter| OpenSpawn["spawn ai-devkit agent open name
(suspend + resume)"] + TUI -->|m + submit| SendSpawn["spawn ai-devkit agent send --id name msg"] +``` + +### Key components and responsibilities + +- **`agent watch` command** (`packages/cli/src/commands/agent.ts`): Registers the subcommand, verifies stdout is a TTY, instantiates `AgentManager`, and renders the Ink app with `render()`. +- **`WatchApp`**: Root Ink component. Owns selection state, modal state, "ended-agent" banner state. Wires polling hooks to panes. +- **`AgentListPane`**: Renders the live agent table, handles `↑↓`/`j k` selection, exposes the selected `AgentInfo` to parent. +- **`PreviewPane`**: Renders the selected agent's recent conversation messages with collapsible tool calls. Auto-scrolls to bottom unless user scrolls up. +- **`StatusFooter`**: Renders agent counts, selected agent metadata, keybinding hints, transient error/info lines. +- **`SendMessageModal`**: Overlay text input; on submit, spawns `ai-devkit agent send --id `. On cancel, returns to list. +- **Polling hooks** (`useAgentList`, `useAgentConversation`): Encapsulate the polling state machine — setInterval, in-flight cancellation, error capture, "data freshness" timestamps. +- **Action runners** (`runAgentOpen`, `runAgentSend`): Suspend Ink, spawn the child CLI via `tea.ExecProcess`-equivalent (Ink supports this via stdin/stdout takeover), wait for exit, resume. + +### Technology stack + +| Choice | Rationale | +|---|---| +| **Ink 5** (`ink`, `ink-text-input`, `ink-spinner`) | React for terminals; matches existing TS codebase; ecosystem covers list/input/spinner widgets. Ink 5 supports ESM-only deps and aligns with current Node ≥18 target. | +| **In-process `AgentManager`** | Avoids fork/parse overhead of `ai-devkit agent list --json` polling; preview reads session files via the adapter directly. Trade-off: TUI depends on `@ai-devkit/agent-manager` package internals. | +| **`child_process.spawn` for `open`/`send`** | Keep the existing CLI as the source of truth for these verbs. No duplication of terminal-focus or send logic. | +| **No new persistent state, no daemon** | v1 is a pure viewer; closing the TUI loses nothing. Polling is sufficient at the stated cadence. | + +## Data Models + +The TUI does not introduce new persistent data. It consumes existing types from `@ai-devkit/agent-manager`: + +### From `manager.listAgents()` +```ts +type AgentInfo = { + name: string; + type: 'claude' | 'codex' | 'gemini_cli' | 'opencode'; + status: AgentStatus; // RUNNING | WAITING | IDLE | UNKNOWN + projectPath: string; + summary?: string; // "working on" line + lastActive: Date; + sessionId?: string; + sessionFilePath?: string; +} +``` + +### From `adapter.getConversation(sessionFilePath, opts)` +```ts +type ConversationMessage = { + role: 'user' | 'assistant' | 'tool_use' | 'tool_result'; + content: string; + timestamp?: string; + // tool-call specific fields when verbose +} +``` + +### TUI-local view models + +- `WatchState`: `{ agents: AgentInfo[], selectedName: string | null, lastListUpdate: Date, listError: string | null, view: 'list' | 'sendModal' }` +- `PreviewState`: `{ messages: ConversationMessage[], expandedToolIndexes: Set, autoScroll: boolean, lastPreviewUpdate: Date, previewError: string | null }` + +### Sort order + +The TUI uses the order returned by `AgentManager.listAgents()` directly: WAITING → RUNNING → IDLE → UNKNOWN, then `lastActive` desc within each group. Waiting agents bubble to the top for free; the non-color row cue (requirement #4) is reinforcement. No client-side re-sort, no upstream change. + +## API Design + +### New CLI surface +``` +ai-devkit agent watch +``` +No flags in v1. Constants in code: list poll = 2000ms, preview poll = 1000ms, preview tail = 20 messages. No JSON output mode (interactive only). Exits 0 on `q`, 1 on fatal init error (no TTY, manager init failure). + +### Internal interfaces + +- `WatchApp` consumes `{ manager: AgentManager }` as prop. +- Polling hooks take the manager + cadence and return `{ data, error, isLoading, lastUpdated }`. They handle their own intervals and cancellation; React unmount stops the loop. +- Action runners take `{ name, message? }` and return `Promise<{ exitCode: number, stderr: string }>` after the child process exits. + +### Suspend / resume for `agent open` + +Ink's `useApp().exit()` returns control to the parent process. The runner uses Ink's documented "exec external command" pattern: +1. Capture current screen state (cursor position, alt-screen). +2. Call `app.unmount()` to release stdin/stdout. +3. `spawn('ai-devkit', ['agent', 'open', name], { stdio: 'inherit' })`. +4. Await exit. +5. Re-`render()`, restoring the prior `selectedName`. + +For `agent send`, the child's stdio is also inherited so any prompts (e.g., the existing "agent not waiting" warning) display in-place; the user sees normal CLI output then is returned to the TUI. + +## Component Breakdown + +### File layout +``` +packages/cli/src/commands/agent.ts # add .command('watch') +packages/cli/src/tui/watch/ + WatchApp.tsx # root component + AgentListPane.tsx + PreviewPane.tsx + StatusFooter.tsx + SendMessageModal.tsx + hooks/ + useAgentList.ts + useAgentConversation.ts + useTerminalSize.ts + actions/ + runAgentOpen.ts + runAgentSend.ts + render/ + formatStatus.tsx # color + glyph + label (no-color cue) + formatMessage.tsx # assistant / tool_use / tool_result rendering + state/ + watchReducer.ts # selection, modal, banner state +``` + +### Polling state machine + +Single hook handles both panes (parameterized): + +``` +state: idle | loading | success | error +on mount → start interval +each tick → if not loading: fetch; on resolve → setState success; on reject → setState error (keep stale data visible) +selection change (preview only) → cancel in-flight, refetch immediately +unmount → clear interval, abort in-flight +``` + +Cancellation: hold a `runToken` ref, bump on every fetch start, only commit results matching the current token. + +### Narrow-terminal fallback + +Detect via `useTerminalSize` (listens on `process.stdout` `resize`). Below 100 columns, hide the preview pane and show a footer line: `resize ≥100 cols to show preview`. Selection still works. + +## Design Decisions + +### D1. In-process manager vs shell-out +**Chosen:** in-process import of `@ai-devkit/agent-manager`. +**Alternative:** spawn `ai-devkit agent list --json` / `agent detail --json --tail 20`. +**Trade-off:** in-process is ~10–20ms faster per tick and avoids JSON parse + process startup cost (Node CLI cold start is ~150–300ms). The cost is tighter coupling: a manager API rename will break the TUI. Accepted because both packages ship together and the manager is internal to ai-devkit. + +### D2. Polling vs streaming +**Chosen:** polling (2s list, 1s preview). +**Alternative:** add `--watch` NDJSON to `agent list`, subscribe via stdin. +**Trade-off:** polling ships now without modifying the manager. Worst-case staleness is 2s for the list, which satisfies success criterion #3 (3s). Streaming can be added later behind the same hook interface. + +### D3. Use the manager's native sort +**Chosen:** consume `listAgents()` order as-is (status priority, then `lastActive` desc within each group). +**Alternative:** re-sort client-side or change the manager. +**Trade-off:** native order already surfaces waiting agents first, which is the actual UX goal behind the requirement; client-side re-sort would have hidden that signal. Zero new code, zero coupling. + +### D4. Inherited stdio vs captured stdio for `agent open` / `send` +**Chosen:** inherited (`stdio: 'inherit'`). +**Alternative:** capture stdout/stderr and render inside the TUI. +**Trade-off:** capturing requires re-implementing prompts and color handling. Inherited just hands the terminal over; for `open`, that's required anyway since it focuses another terminal window. Inherited stdio also makes it impossible to leak the parent's TUI state — the child sees a clean terminal. + +### D5. Single window vs multi-window +**Chosen:** single window, two panes. +**Alternative:** Ink-supported tabs/windows. +**Trade-off:** Single window matches requirements (no splits in v1) and keeps the mental model simple. Tabs can be added later without restructuring. + +### D6. Tool-call rendering: collapsed by default +**Chosen:** Render `tool_use` / `tool_result` as one-liners (`→ read src/auth/mw.ts`); `v` toggles expansion on the focused message. +**Alternative:** Always expand (more context, but a single 50-line file read dominates the preview). +**Trade-off:** Collapsed default preserves the "what is the agent doing right now" signal. Expansion stays available. + +### D7. Pure viewer, no kill action +**Chosen:** No destructive verbs in v1. Confirms non-goal from requirements. +**Alternative:** Add a `k` keybinding + new `ai-devkit agent kill` CLI verb. +**Trade-off:** Out of scope by requirement. Worth revisiting in a follow-up once the CLI verb exists. + +## Non-Functional Requirements + +| Property | Target | How | +|---|---|---| +| **Launch latency** | <1s on ≤10 agents | First render before first poll completes (skeleton row); manager init is sync. | +| **Selection-to-preview latency** | <1s | Preview poll fires immediately on selection change, not on next interval. | +| **State-change visibility** | ≤3s | 2s list poll cadence + 1 frame render < 3s ceiling. | +| **Input latency** | <100ms | Ink renders on state change; keystrokes never wait for I/O (in-flight fetches don't block input). | +| **CPU at idle (20 agents)** | <5% of one core on M-series Mac | Polling at 2s × `listAgents` (which already runs in parallel across adapters); preview reads only one session file per second. | +| **Memory** | <50 MB resident | One Node process; no transcript buffering beyond current `--tail`. | +| **Compatibility** | macOS, Linux | Inherits from agent module. Windows: explicitly unsupported in v1. | +| **Security** | No new attack surface | TUI does not parse user input as code; `agent send` payload is passed as an argv element, not shell-interpreted. | +| **Failure isolation** | Adapter errors don't crash the TUI | `listAgents()` already swallows per-adapter errors; the TUI surfaces them as a footer line, not a crash. | + +## Open Items Resolved from Requirements Phase + +- **Preview rendering (req open item):** collapsed tool calls, `v` to expand (D6). +- **Narrow-terminal fallback:** threshold 100 cols, list-only below. +- **Resize behavior:** redraw on `SIGWINCH`/`stdout.resize`; preview re-wraps to new width; selection preserved. +- **Empty / missing session file:** preview shows distinct messages — "No messages yet" vs "Session file unreadable: " with the cause; list keeps polling. diff --git a/docs/ai/implementation/2026-05-27-feature-agent-watch.md b/docs/ai/implementation/2026-05-27-feature-agent-watch.md new file mode 100644 index 00000000..d1c0729c --- /dev/null +++ b/docs/ai/implementation/2026-05-27-feature-agent-watch.md @@ -0,0 +1,65 @@ +--- +phase: implementation +title: Implementation Guide +description: Technical implementation notes, patterns, and code guidelines +--- + +# Implementation Guide + +## Development Setup +**How do we get started?** + +- Prerequisites and dependencies +- Environment setup steps +- Configuration needed + +## Code Structure +**How is the code organized?** + +- Directory structure +- Module organization +- Naming conventions + +## Implementation Notes +**Key technical details to remember:** + +### Core Features +- Feature 1: Implementation approach +- Feature 2: Implementation approach +- Feature 3: Implementation approach + +### Patterns & Best Practices +- Design patterns being used +- Code style guidelines +- Common utilities/helpers + +## Integration Points +**How do pieces connect?** + +- API integration details +- Database connections +- Third-party service setup + +## Error Handling +**How do we handle failures?** + +- Error handling strategy +- Logging approach +- Retry/fallback mechanisms + +## Performance Considerations +**How do we keep it fast?** + +- Optimization strategies +- Caching approach +- Query optimization +- Resource management + +## Security Notes +**What security measures are in place?** + +- Authentication/authorization +- Input validation +- Data encryption +- Secrets management + diff --git a/docs/ai/planning/2026-05-27-feature-agent-watch.md b/docs/ai/planning/2026-05-27-feature-agent-watch.md new file mode 100644 index 00000000..29d91c0d --- /dev/null +++ b/docs/ai/planning/2026-05-27-feature-agent-watch.md @@ -0,0 +1,100 @@ +--- +phase: planning +title: Project Planning & Task Breakdown +description: Break down work into actionable tasks and estimate timeline +--- + +# Project Planning & Task Breakdown — Agent Watch + +## Milestones + +- [ ] **M1 — Skeleton runs**: `ai-devkit agent watch` launches an Ink app that lists agents (no preview, no actions). +- [ ] **M2 — Preview works**: selecting an agent renders its recent conversation, refreshes automatically. +- [ ] **M3 — Actions work**: `⏎` opens an agent (suspend/resume), `m` sends a message. +- [ ] **M4 — Polish + tests**: narrow-terminal fallback, error states, unit tests, manual smoke against Claude + Codex. + +## Task Breakdown + +### Phase 1 — Foundation +- [x] **T1.1** Add `ink`, `ink-text-input` to `packages/cli` dependencies; verify build still passes. _(Picked Ink 3.2.0 + React 17 because the CLI compiles to CommonJS and Ink 4+ is ESM-only. Added `jsx: "react"` to `packages/cli/tsconfig.json`.)_ +- [x] **T1.2** Create directory scaffold under `packages/cli/src/tui/watch/` per design file layout. Empty placeholder files only. _(Created subdirs `hooks/`, `actions/`, `render/`, `state/`. Files added incrementally per later tasks.)_ +- [x] **T1.3** Register `agent watch` subcommand in `packages/cli/src/commands/agent.ts`. TTY guard: if `!process.stdout.isTTY`, print error and exit 1. Instantiate `AgentManager`, call `render()`. _(Verified `--help` renders and TTY guard fires under non-TTY stdin. Lazy-require Ink/React/WatchApp so they only load when this command runs.)_ + +### Phase 2 — Core Features +- [x] **T2.1** Implement `useAgentList` polling hook: 2s interval, in-flight cancellation via `runToken`, returns `{ agents, error, lastUpdated }`. Errors keep stale data visible. _(`hooks/useAgentList.ts`. Tracks `mountedRef` + `runTokenRef` so stale fetches don't commit. Errors set `error` but leave `agents` intact. Exports `LIST_POLL_INTERVAL_MS = 2000`. Build passes.)_ +- [x] **T2.2** Implement `useAgentConversation` hook: 1s interval for the selected agent; refetch immediately on selection change; same `runToken` discipline. _(`hooks/useAgentConversation.ts`. Fetches via `manager.getAdapter(type).getConversation(sessionFilePath)`. mtime cache skips re-parse when the session file hasn't changed. Classifies errors as `no-session-file`/`no-adapter`/`parse-error` for distinct preview copy later.)_ +- [x] **T2.3** Implement `AgentListPane` — table render of name, type, status (color + glyph + label), summary, lastActive (relative). Keyboard nav `↑↓`/`j k`. Uses native `listAgents()` order (no client-side sort). _(`AgentListPane.tsx`. Auto-selects first agent and re-selects on list change if the previous selection disappeared. Empty-state copy shipped. Wired into `WatchApp` — `agent watch` now renders the live list. M1 milestone reached.)_ +- [x] **T2.4** Implement `formatStatus` render helper: per-status color + non-color glyph (e.g., `● run`, `◐ wait`, `○ idle`, `? unk`). _(`render/formatStatus.tsx`. Glyph + short label, color is reinforcement not the sole signal. Exports `statusDisplayWidth()` for column sizing.)_ +- [x] **T2.5** Implement `PreviewPane` — render messages by role (user/assistant/system). _(`PreviewPane.tsx`. `ConversationMessage` is `{role, content, timestamp}` only — no separate tool_use/tool_result, tool calls already embedded in content. So the `v`-to-expand keybinding and auto-scroll/`G` complexity are out: instead we render from most-recent backward into a fixed line budget (~`rows-8`), guaranteeing the latest message is always visible. Master-detail layout wired into WatchApp with 40%/60% split. Narrow-terminal fallback already present (<100 cols hides preview, footer note shown). M2 milestone reached.)_ +- [x] **T2.6** Implement `StatusFooter` — agent counts (running / waiting / idle), selected agent metadata (cwd, message count, last active), keybinding hints, transient error/info line. _(`StatusFooter.tsx`. Shows counts, last-updated relative time, keybinding hint, selected agent meta. Accepts a `transient` prop for action feedback.)_ +- [x] **T2.7** Implement `WatchApp` root: owns selection, modal flag, error banner; wires hooks to panes; handles global keys (`q`, `r`, `v`). _(`WatchApp.tsx`. Owns `selectedName`, derives `selectedAgent`, computes narrow layout. Modal flag will be added in T3.2.)_ + +### Phase 3 — Integration & Polish +- [x] **T3.1** Implement `runAgentOpen` action: `app.unmount()` → `spawn('ai-devkit', ['agent', 'open', name], { stdio: 'inherit' })` → await exit → re-`render()` with `initialSelection` prop. Preserve selection across the round trip. _(`actions/runAction.ts`. Resolves CLI entry via `process.execPath` + `path.resolve(__dirname, ../../../cli.js)` so it works regardless of PATH. The render/exit loop lives in the `agent watch` command and re-mounts with `lastSelection` and a `transient` message on action failure. Requires manual TTY smoke to verify suspend/resume cleanliness — deferred to T4.4.)_ +- [x] **T3.2** Implement `SendMessageModal` overlay (`ink-text-input`): captures text, on submit calls `runAgentSend` (same spawn pattern, `agent send --id `), on cancel returns to list. Empty input is a no-op cancel. _(`SendMessageModal.tsx`. `m` toggles open, Enter submits, Esc cancels. Submit triggers a `send` intent which routes through the same suspend/resume loop in the command. M3 milestone reached.)_ +- [x] **T3.3** Implement narrow-terminal fallback (<100 cols hides preview, footer shows `resize ≥100 cols to show preview`). _(Completed inside T2.5/T2.6 — `WatchApp` reads `process.stdout.columns` once per render, hides preview pane below 100 cols, footer shows the resize hint. No dedicated `useTerminalSize` hook needed yet; can be added if dynamic resize feels janky during smoke testing.)_ +- [x] **T3.4** Empty-state copy: zero agents, missing session file, empty conversation, action error. _(Implemented across `AgentListPane` ("No running agents detected"), `PreviewPane` ("No messages yet" / "No session file available" / typed `parse-error` copy), `StatusFooter` (transient error line). No separate "ended agent banner" — when an agent disappears the list auto-selects another; preview shows "No messages yet" if the new selection's session is bare. Acceptable for v1.)_ +- [ ] **T3.5** Document the command in `web/content/docs/8-agent-management.md` under a new "Watch Agents" section. Mark experimental. + +### Phase 4 — Verification (handed to Phases 6–8 of dev-lifecycle) +- [ ] **T4.1** Unit tests for `useAgentList` / `useAgentConversation` polling/cancellation (mock manager). +- [ ] **T4.2** Unit tests for `formatMessage` render helper (assistant text, tool_use one-liner, tool_result one-liner, expansion). +- [ ] **T4.3** Snapshot tests for `AgentListPane` and `PreviewPane` via `ink-testing-library` — happy path, empty, error. +- [ ] **T4.4** Manual smoke on macOS: one Claude Code + one Codex agent running concurrently; verify launch <1s, selection-to-preview <1s, `⏎`/`m` round trips, narrow-terminal fallback, ended-agent banner. + +## Dependencies + +| Task | Depends on | +|---|---| +| T1.3 | T1.1, T1.2 | +| T2.1, T2.2 | T1.3 | +| T2.3 | T2.1, T2.4 | +| T2.5 | T2.2 | +| T2.6, T2.7 | T2.3, T2.5 | +| T3.1, T3.2 | T2.7 | +| T3.3 | T2.7 | +| T3.4 | T2.7 | +| T3.5 | T3.1, T3.2 done (so doc reflects shipped behavior) | +| T4.1–T4.3 | their corresponding implementation tasks | +| T4.4 | all of Phase 1–3 | + +External dependencies: `@ai-devkit/agent-manager` (existing, internal). `ai-devkit agent open` / `agent send` (existing CLI verbs). + +## Implementation order (linear) + +1. T1.1 → T1.2 → T1.3 (skeleton compiles and runs, prints "TUI placeholder") +2. T2.1 → T2.4 → T2.3 (M1: list renders and updates) +3. T2.2 → T2.5 (M2: preview renders and updates) +4. T2.6 → T2.7 (footer + global keys wired) +5. T3.1 → T3.2 (M3: actions work) +6. T3.3 → T3.4 (polish) +7. T3.5 (docs) +8. T4.1–T4.4 (verification; Phase 7 of dev-lifecycle) + +## Timeline & Estimates + +| Phase | Effort | Notes | +|---|---|---| +| Foundation | 0.5d | Mostly dependency wiring + boilerplate. | +| Core Features | 2d | Bulk of the work; hooks + three pane components. | +| Integration & Polish | 1d | Suspend/resume is the only risky bit; tested early via T3.1. | +| Verification | 1d | Unit + snapshot + manual smoke. | +| **Total** | **~4.5d** | Within the single-developer-week target from requirements. | + +## Risks & Mitigation + +| Risk | Likelihood | Impact | Mitigation | +|---|---|---|---| +| Ink suspend/resume leaves terminal in a bad state (alt-screen artifacts) after `agent open` | Medium | High — kills the "feels like a hub" UX | Build T3.1 early (immediately after T2.7). If broken, fall back to TUI-exits-on-open pattern documented as known limitation. | +| `getConversation()` is slow on large session files at 1Hz | Medium | Medium — preview lags | Use `--tail 20` semantics (already supported by adapter); cache by session-file mtime so unchanged files don't re-parse. | +| Inputs collide with Ink built-in raw-mode quirks (e.g., Ctrl-C handling) | Low | Medium | Use Ink's `useInput` hook conventionally; let Ctrl-C exit normally; document `q` as the standard exit. | +| `ink-text-input` ergonomics for the send modal feel cramped | Low | Low | If problematic, switch to `ink-multi-select-input`-style or roll a minimal input using `useInput`. | +| `child_process.spawn` cannot find `ai-devkit` in PATH when invoked from inside a worktree's `node_modules/.bin` | Low | High — actions fail silently | Resolve the path explicitly: `process.execPath` + the absolute CLI entry script, or use `npm bin` resolution. Validate in T3.1. | +| Adapter parse error (e.g., session file mid-write) crashes a fetch | Medium | Low | Manager already swallows per-adapter errors; the TUI surfaces them as a footer line and keeps polling. | + +## Resources Needed + +- One developer (TypeScript + React familiarity). +- Local Claude Code and Codex agents for smoke testing. +- macOS dev machine (iTerm2 or Apple Terminal for `agent open` verification). +- Existing CI pipeline (no infra changes). diff --git a/docs/ai/requirements/2026-05-27-feature-agent-watch.md b/docs/ai/requirements/2026-05-27-feature-agent-watch.md new file mode 100644 index 00000000..c7acb12e --- /dev/null +++ b/docs/ai/requirements/2026-05-27-feature-agent-watch.md @@ -0,0 +1,99 @@ +--- +phase: requirements +title: Requirements & Problem Understanding +description: Clarify the problem space, gather requirements, and define success criteria +--- + +# Requirements & Problem Understanding — Agent Watch + +## Problem Statement + +Users running multiple AI coding agents (Claude Code, Codex, OpenCode, Gemini CLI) have no live, single-pane view of what each agent is doing. Today they must repeatedly run `ai-devkit agent list` to see status, then `ai-devkit agent detail --id ` to inspect any single agent's recent activity. Switching attention between agents requires re-running commands and mentally diffing snapshots. + +Adjacent products (cmux and similar terminal "mission control" tools) are gaining traction, signalling real user demand for an always-on monitor. AI DevKit already has the data sources (`agent list`, `agent detail`) and an `agent open` verb to hand control to the live session. What is missing is a thin viewer that ties them together. + +**Affected users:** developers running 2+ agents in parallel during refactors, feature work, or comparative experiments. Especially relevant for ai-devkit users on macOS who already invoke `agent open`/`agent send` from their shell. + +**Current workaround:** alternating between `agent list` and `agent detail`, or keeping a tmux window per agent. Both lose the "all agents at a glance" view. + +## Goals & Objectives + +### Primary goals +1. Provide a single TUI command (`ai-devkit agent watch`) that shows all running agents and a live preview of the selected agent's recent activity, refreshing automatically. +2. Make hand-off to existing verbs frictionless: one keystroke to `agent open`, one to `agent send`. +3. Reuse existing data sources — no new long-lived daemon, no new persistent state. + +### Secondary goals +- Establish an Ink-based TUI foundation that future surfaces (history browser, multi-agent diff view) can build on without an architectural rewrite. +- Keep the watch UI fully stateless: closing it loses nothing; reopening picks up live state. + +### Non-goals (v1) +- Pane splitting or multi-agent side-by-side preview. +- Killing agents from the TUI (no `kill` verb exists; would require new destructive CLI surface). +- Creating new agents from the TUI. +- Browsing historical sessions (`agent sessions` stays a separate command). +- An NDJSON `--watch` stream on `agent list` (polling is sufficient for v1; can be added later without changing the TUI shape). +- Windows support (inherits macOS/Linux constraint from the existing agent module). +- Mouse interaction. + +## User Stories & Use Cases + +- **As a developer running multiple agents,** I want to open one command and see every agent's status update live, so I can tell at a glance which agent needs my attention. +- **As a developer reviewing what an agent is doing,** I want to select an agent and see its last ~20 conversation messages refresh automatically, so I can decide whether to intervene without context-switching to its terminal. +- **As a developer who decides an agent needs input,** I want to press one key to jump into that agent's live terminal (via `agent open`), so the watch view feels like a hub I return to. +- **As a developer who wants to nudge an agent,** I want to press one key, type a message, and have it sent via `agent send`, so I don't need to focus the agent's terminal to dispatch a short instruction. +- **As a developer with one agent waiting for input,** I want the watch UI to surface that state visibly (e.g., highlighted row), so I notice immediately. +- **As a developer scanning the agent list,** I want the most recently active agents at the top, so the agents I'm currently working with are always visible without scrolling. + +### List ordering + +The TUI uses the order returned by `AgentManager.listAgents()`: status priority (WAITING → RUNNING → IDLE → UNKNOWN), then `lastActive` descending within each group. This bubbles waiting agents to the top automatically; the non-color visual cue is reinforcement, not the sole signal. + +### Edge cases +- Selected agent finishes / disappears mid-session → preview greys out with an "ended" banner; cursor does not auto-jump. +- Zero agents running → empty-state hint pointing at `agent list` and the docs. +- Session file unreadable / `agent detail` fails → preview shows an error line, list continues to refresh. +- Terminal too narrow to render two panes → fall back to list-only with a footer note (`resize ≥ N cols to show preview`). +- `agent open` fails (terminal not supported) → show the error in the TUI footer, do not crash. + +## Success Criteria + +1. `ai-devkit agent watch` launches and displays the agent list in under 1 second on a machine with ≤10 agents running. +2. Selecting a different agent updates the preview pane in under 1 second. +3. The list reflects underlying status changes (new agent, status transition, agent ended) within 3 seconds of the change, without user input. +4. An agent in the `waiting` state is surfaced first in the list (existing `AgentManager.listAgents()` ordering: WAITING → RUNNING → IDLE → UNKNOWN, then `lastActive` desc within each group) and rendered with a non-color cue (label, glyph, or weight) in addition to color so it remains distinguishable in a monochrome terminal. +5. `⏎` cleanly suspends the TUI, executes `agent open` for the selected agent, and returns to the watch view on detach without losing selection. +6. `m` opens a prompt, captures a message, and dispatches `ai-devkit agent send --id ` with the captured text, returning to the watch view afterward. The prompt always targets the currently selected agent; there is no agent picker inside the prompt. +7. Existing `agent list`, `agent detail`, `agent open`, and `agent send` commands continue to work unchanged — verified via manual smoke after the change lands. +8. Manual smoke test passes with at least one Claude Code agent and one Codex agent running concurrently on macOS. +9. Performance target: the TUI remains responsive (input latency <100ms, no visible frame drops) with up to 20 concurrent agents. Behavior beyond 20 agents is best-effort and not part of v1 acceptance. + +## Constraints & Assumptions + +### Technical constraints +- Must run in standard macOS/Linux terminals (iTerm2, Terminal.app, tmux, common Linux emulators). No Windows support in v1. +- Must integrate cleanly with the existing TypeScript CLI in `packages/cli`. +- Hand-off to `agent open` must suspend/resume; nested-tmux behavior must not break the parent shell. +- Polling cadence (1–2s) must not noticeably degrade CPU or session-file I/O for users with many agents. + +### Business / scope constraints +- Single-developer-week effort target for v1. +- No new long-running daemon; no new persistent state on disk. +- No new destructive CLI verbs (no `kill`). + +### Assumptions +- `createAgentManager()` is callable in-process from the watch command, returning the same `AgentInfo[]` shape `agent list` uses today. +- Adapter `getConversation(sessionFilePath, opts)` is callable in-process and returns the same shape `agent detail` renders. +- Ink (`ink` + `ink-text-input` + `ink-select-input` or equivalent) can be added as a dependency to `packages/cli` without breaking existing builds. +- Users running the watch command have a TTY (the command refuses to start under a non-TTY stdout). + +## Questions & Open Items + +No material open questions at requirements time. Items deferred to design: + +- Exact Ink component decomposition (list widget choice, viewport for preview). +- Whether the preview pane reads session files directly via the adapter or shells out to `agent detail --json` (perf vs boundary cleanliness). +- Footer status content and exact column widths. +- Behavior when the user resizes the terminal during a session. + +These are design-phase decisions and do not block Phase 1 sign-off. diff --git a/docs/ai/testing/2026-05-27-feature-agent-watch.md b/docs/ai/testing/2026-05-27-feature-agent-watch.md new file mode 100644 index 00000000..50958b29 --- /dev/null +++ b/docs/ai/testing/2026-05-27-feature-agent-watch.md @@ -0,0 +1,81 @@ +--- +phase: testing +title: Testing Strategy +description: Define testing approach, test cases, and quality assurance +--- + +# Testing Strategy + +## Test Coverage Goals +**What level of testing do we aim for?** + +- Unit test coverage target (default: 100% of new/changed code) +- Integration test scope (critical paths + error handling) +- End-to-end test scenarios (key user journeys) +- Alignment with requirements/design acceptance criteria + +## Unit Tests +**What individual components need testing?** + +### Component/Module 1 +- [ ] Test case 1: [Description] (covers scenario / branch) +- [ ] Test case 2: [Description] (covers edge case / error handling) +- [ ] Additional coverage: [Description] + +### Component/Module 2 +- [ ] Test case 1: [Description] +- [ ] Test case 2: [Description] +- [ ] Additional coverage: [Description] + +## Integration Tests +**How do we test component interactions?** + +- [ ] Integration scenario 1 +- [ ] Integration scenario 2 +- [ ] API endpoint tests +- [ ] Integration scenario 3 (failure mode / rollback) + +## End-to-End Tests +**What user flows need validation?** + +- [ ] User flow 1: [Description] +- [ ] User flow 2: [Description] +- [ ] Critical path testing +- [ ] Regression of adjacent features + +## Test Data +**What data do we use for testing?** + +- Test fixtures and mocks +- Seed data requirements +- Test database setup + +## Test Reporting & Coverage +**How do we verify and communicate test results?** + +- Coverage commands and thresholds (`npm run test -- --coverage`) +- Coverage gaps (files/functions below 100% and rationale) +- Links to test reports or dashboards +- Manual testing outcomes and sign-off + +## Manual Testing +**What requires human validation?** + +- UI/UX testing checklist (include accessibility) +- Browser/device compatibility +- Smoke tests after deployment + +## Performance Testing +**How do we validate performance?** + +- Load testing scenarios +- Stress testing approach +- Performance benchmarks + +## Bug Tracking +**How do we manage issues?** + +- Issue tracking process +- Bug severity levels +- Regression testing strategy + diff --git a/package-lock.json b/package-lock.json index f733a1b1..6e3a14e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,46 @@ "resolved": "packages/memory", "link": true }, + "node_modules/@alcalzone/ansi-tokenize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.3.0.tgz", + "integrity": "sha512-p+CMKJ93HFmLkjXKlXiVGlMQEuRb6H0MokBSwUsX+S6BRX8eV5naFZpQJFfJHjRZY0Hmnqy1/r6UWl3x+19zYA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@alcalzone/ansi-tokenize/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@alcalzone/ansi-tokenize/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -60,8 +100,6 @@ }, "node_modules/@babel/code-frame": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", - "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -75,8 +113,6 @@ }, "node_modules/@babel/compat-data": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", - "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", "dev": true, "license": "MIT", "engines": { @@ -85,8 +121,6 @@ }, "node_modules/@babel/core": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", "dependencies": { @@ -116,8 +150,6 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -126,8 +158,6 @@ }, "node_modules/@babel/generator": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", - "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", "dev": true, "license": "MIT", "dependencies": { @@ -143,8 +173,6 @@ }, "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -154,8 +182,6 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, "license": "MIT", "dependencies": { @@ -167,8 +193,6 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { @@ -184,8 +208,6 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -194,8 +216,6 @@ }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", - "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "dev": true, "license": "MIT", "dependencies": { @@ -216,8 +236,6 @@ }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -226,8 +244,6 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", "dev": true, "license": "MIT", "dependencies": { @@ -244,8 +260,6 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -254,8 +268,6 @@ }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", "dev": true, "license": "MIT", "dependencies": { @@ -271,8 +283,6 @@ }, "node_modules/@babel/helper-globals": { "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, "license": "MIT", "engines": { @@ -281,8 +291,6 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "dev": true, "license": "MIT", "dependencies": { @@ -295,8 +303,6 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { @@ -309,8 +315,6 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { @@ -327,8 +331,6 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "dev": true, "license": "MIT", "dependencies": { @@ -340,8 +342,6 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -350,8 +350,6 @@ }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", "dev": true, "license": "MIT", "dependencies": { @@ -368,8 +366,6 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", - "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, "license": "MIT", "dependencies": { @@ -386,8 +382,6 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "dev": true, "license": "MIT", "dependencies": { @@ -400,8 +394,6 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -410,8 +402,6 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -420,8 +410,6 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -430,8 +418,6 @@ }, "node_modules/@babel/helper-wrap-function": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", - "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -445,8 +431,6 @@ }, "node_modules/@babel/helpers": { "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, "license": "MIT", "dependencies": { @@ -459,8 +443,6 @@ }, "node_modules/@babel/parser": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -475,8 +457,6 @@ }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", - "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -492,8 +472,6 @@ }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "dev": true, "license": "MIT", "dependencies": { @@ -508,8 +486,6 @@ }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "dev": true, "license": "MIT", "dependencies": { @@ -524,8 +500,6 @@ }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "dev": true, "license": "MIT", "dependencies": { @@ -542,8 +516,6 @@ }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", - "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", "dev": true, "license": "MIT", "dependencies": { @@ -559,8 +531,6 @@ }, "node_modules/@babel/plugin-proposal-decorators": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.28.6.tgz", - "integrity": "sha512-RVdFPPyY9fCRAX68haPmOk2iyKW8PKJFthmm8NeSI3paNxKWGZIn99+VbIf0FrtCpFnPgnpF/L48tadi617ULg==", "dev": true, "license": "MIT", "dependencies": { @@ -577,8 +547,6 @@ }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, "license": "MIT", "engines": { @@ -590,8 +558,6 @@ }, "node_modules/@babel/plugin-syntax-decorators": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.28.6.tgz", - "integrity": "sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==", "dev": true, "license": "MIT", "dependencies": { @@ -606,8 +572,6 @@ }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", - "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", "dev": true, "license": "MIT", "dependencies": { @@ -622,8 +586,6 @@ }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, "license": "MIT", "dependencies": { @@ -638,8 +600,6 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, "license": "MIT", "dependencies": { @@ -654,8 +614,6 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "license": "MIT", "dependencies": { @@ -670,8 +628,6 @@ }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, "license": "MIT", "dependencies": { @@ -687,8 +643,6 @@ }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", "dev": true, "license": "MIT", "dependencies": { @@ -703,8 +657,6 @@ }, "node_modules/@babel/plugin-transform-async-generator-functions": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.6.tgz", - "integrity": "sha512-9knsChgsMzBV5Yh3kkhrZNxH3oCYAfMBkNNaVN4cP2RVlFPe8wYdwwcnOsAbkdDoV9UjFtOXWrWB52M8W4jNeA==", "dev": true, "license": "MIT", "dependencies": { @@ -721,8 +673,6 @@ }, "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", - "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", "dev": true, "license": "MIT", "dependencies": { @@ -739,8 +689,6 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "dev": true, "license": "MIT", "dependencies": { @@ -755,8 +703,6 @@ }, "node_modules/@babel/plugin-transform-block-scoping": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", - "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", "dev": true, "license": "MIT", "dependencies": { @@ -771,8 +717,6 @@ }, "node_modules/@babel/plugin-transform-class-properties": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", - "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", "dev": true, "license": "MIT", "dependencies": { @@ -788,8 +732,6 @@ }, "node_modules/@babel/plugin-transform-class-static-block": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", - "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -805,8 +747,6 @@ }, "node_modules/@babel/plugin-transform-classes": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", - "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", "dev": true, "license": "MIT", "dependencies": { @@ -826,8 +766,6 @@ }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", - "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", "dev": true, "license": "MIT", "dependencies": { @@ -843,8 +781,6 @@ }, "node_modules/@babel/plugin-transform-destructuring": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "dev": true, "license": "MIT", "dependencies": { @@ -860,8 +796,6 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", - "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", "dev": true, "license": "MIT", "dependencies": { @@ -877,8 +811,6 @@ }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "dev": true, "license": "MIT", "dependencies": { @@ -893,8 +825,6 @@ }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.28.6.tgz", - "integrity": "sha512-5suVoXjC14lUN6ZL9OLKIHCNVWCrqGqlmEp/ixdXjvgnEl/kauLvvMO/Xw9NyMc95Joj1AeLVPVMvibBgSoFlA==", "dev": true, "license": "MIT", "dependencies": { @@ -910,8 +840,6 @@ }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", "dev": true, "license": "MIT", "dependencies": { @@ -926,8 +854,6 @@ }, "node_modules/@babel/plugin-transform-explicit-resource-management": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", - "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", "dev": true, "license": "MIT", "dependencies": { @@ -943,8 +869,6 @@ }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", - "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", "dev": true, "license": "MIT", "dependencies": { @@ -959,8 +883,6 @@ }, "node_modules/@babel/plugin-transform-export-namespace-from": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -975,8 +897,6 @@ }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", "dev": true, "license": "MIT", "dependencies": { @@ -992,8 +912,6 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1010,8 +928,6 @@ }, "node_modules/@babel/plugin-transform-json-strings": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", - "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", "dev": true, "license": "MIT", "dependencies": { @@ -1026,8 +942,6 @@ }, "node_modules/@babel/plugin-transform-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", "dev": true, "license": "MIT", "dependencies": { @@ -1042,8 +956,6 @@ }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", - "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", "dev": true, "license": "MIT", "dependencies": { @@ -1058,8 +970,6 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1074,8 +984,6 @@ }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "dev": true, "license": "MIT", "dependencies": { @@ -1091,8 +999,6 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", - "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "dev": true, "license": "MIT", "dependencies": { @@ -1108,8 +1014,6 @@ }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", "dev": true, "license": "MIT", "dependencies": { @@ -1127,8 +1031,6 @@ }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", "dev": true, "license": "MIT", "dependencies": { @@ -1144,8 +1046,6 @@ }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", "dev": true, "license": "MIT", "dependencies": { @@ -1161,8 +1061,6 @@ }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1177,8 +1075,6 @@ }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", - "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", "dev": true, "license": "MIT", "dependencies": { @@ -1193,8 +1089,6 @@ }, "node_modules/@babel/plugin-transform-numeric-separator": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", - "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", "dev": true, "license": "MIT", "dependencies": { @@ -1209,8 +1103,6 @@ }, "node_modules/@babel/plugin-transform-object-rest-spread": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", - "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", "dev": true, "license": "MIT", "dependencies": { @@ -1229,8 +1121,6 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "dev": true, "license": "MIT", "dependencies": { @@ -1246,8 +1136,6 @@ }, "node_modules/@babel/plugin-transform-optional-catch-binding": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", - "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1262,8 +1150,6 @@ }, "node_modules/@babel/plugin-transform-optional-chaining": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", - "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", "dev": true, "license": "MIT", "dependencies": { @@ -1279,8 +1165,6 @@ }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "dev": true, "license": "MIT", "dependencies": { @@ -1295,8 +1179,6 @@ }, "node_modules/@babel/plugin-transform-private-methods": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", - "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", "dev": true, "license": "MIT", "dependencies": { @@ -1312,8 +1194,6 @@ }, "node_modules/@babel/plugin-transform-private-property-in-object": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", - "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", "dev": true, "license": "MIT", "dependencies": { @@ -1330,8 +1210,6 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1346,8 +1224,6 @@ }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.6.tgz", - "integrity": "sha512-eZhoEZHYQLL5uc1gS5e9/oTknS0sSSAtd5TkKMUp3J+S/CaUjagc0kOUPsEbDmMeva0nC3WWl4SxVY6+OBuxfw==", "dev": true, "license": "MIT", "dependencies": { @@ -1362,8 +1238,6 @@ }, "node_modules/@babel/plugin-transform-regexp-modifiers": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", - "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", "dev": true, "license": "MIT", "dependencies": { @@ -1379,8 +1253,6 @@ }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "dev": true, "license": "MIT", "dependencies": { @@ -1395,8 +1267,6 @@ }, "node_modules/@babel/plugin-transform-runtime": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.5.tgz", - "integrity": "sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==", "dev": true, "license": "MIT", "dependencies": { @@ -1416,8 +1286,6 @@ }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -1426,8 +1294,6 @@ }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1442,8 +1308,6 @@ }, "node_modules/@babel/plugin-transform-spread": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", - "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", "dev": true, "license": "MIT", "dependencies": { @@ -1459,8 +1323,6 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", "dev": true, "license": "MIT", "dependencies": { @@ -1475,8 +1337,6 @@ }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "dev": true, "license": "MIT", "dependencies": { @@ -1491,8 +1351,6 @@ }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "dev": true, "license": "MIT", "dependencies": { @@ -1507,8 +1365,6 @@ }, "node_modules/@babel/plugin-transform-typescript": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", - "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", "dev": true, "license": "MIT", "dependencies": { @@ -1527,8 +1383,6 @@ }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "dev": true, "license": "MIT", "dependencies": { @@ -1543,8 +1397,6 @@ }, "node_modules/@babel/plugin-transform-unicode-property-regex": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", - "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", "dev": true, "license": "MIT", "dependencies": { @@ -1560,8 +1412,6 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", "dev": true, "license": "MIT", "dependencies": { @@ -1577,8 +1427,6 @@ }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", - "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1594,8 +1442,6 @@ }, "node_modules/@babel/preset-env": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.6.tgz", - "integrity": "sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw==", "dev": true, "license": "MIT", "dependencies": { @@ -1679,8 +1525,6 @@ }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -1689,8 +1533,6 @@ }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, "license": "MIT", "dependencies": { @@ -1704,8 +1546,6 @@ }, "node_modules/@babel/preset-typescript": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", - "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", "dev": true, "license": "MIT", "dependencies": { @@ -1724,8 +1564,6 @@ }, "node_modules/@babel/runtime": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "dev": true, "license": "MIT", "engines": { @@ -1734,8 +1572,6 @@ }, "node_modules/@babel/template": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1749,8 +1585,6 @@ }, "node_modules/@babel/traverse": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", - "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", "dev": true, "license": "MIT", "dependencies": { @@ -1768,8 +1602,6 @@ }, "node_modules/@babel/types": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { @@ -1782,15 +1614,11 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true, "license": "MIT" }, "node_modules/@borewit/text-codec": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz", - "integrity": "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==", "dev": true, "license": "MIT", "funding": { @@ -1800,8 +1628,6 @@ }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", "dependencies": { @@ -1813,8 +1639,6 @@ }, "node_modules/@emnapi/core": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", "dev": true, "license": "MIT", "dependencies": { @@ -1824,8 +1648,6 @@ }, "node_modules/@emnapi/runtime": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", "dev": true, "license": "MIT", "dependencies": { @@ -1834,8 +1656,6 @@ }, "node_modules/@emnapi/wasi-threads": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2235,8 +2055,6 @@ }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "license": "MIT", "dependencies": { @@ -2254,8 +2072,6 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", "engines": { @@ -2264,8 +2080,6 @@ }, "node_modules/@eslint/eslintrc": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2288,8 +2102,6 @@ }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -2299,8 +2111,6 @@ }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -2312,8 +2122,6 @@ }, "node_modules/@eslint/js": { "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "license": "MIT", "engines": { @@ -2322,8 +2130,6 @@ }, "node_modules/@hono/node-server": { "version": "1.19.13", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.13.tgz", - "integrity": "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==", "license": "MIT", "engines": { "node": ">=18.14.1" @@ -2334,9 +2140,6 @@ }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2350,8 +2153,6 @@ }, "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -2361,8 +2162,6 @@ }, "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -2374,8 +2173,6 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2388,16 +2185,11 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@inquirer/external-editor": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", - "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", "license": "MIT", "dependencies": { "chardet": "^2.1.0", @@ -2529,8 +2321,6 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "license": "MIT", "engines": { @@ -2539,8 +2329,6 @@ }, "node_modules/@jest/diff-sequences": { "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", "dev": true, "license": "MIT", "engines": { @@ -2549,8 +2337,6 @@ }, "node_modules/@jest/get-type": { "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "dev": true, "license": "MIT", "engines": { @@ -2559,8 +2345,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { @@ -2570,8 +2354,6 @@ }, "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -2581,8 +2363,6 @@ }, "node_modules/@jridgewell/remapping": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2592,8 +2372,6 @@ }, "node_modules/@jridgewell/remapping/node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -2603,8 +2381,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { @@ -2613,15 +2389,11 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2631,8 +2403,6 @@ }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", - "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9", @@ -2671,8 +2441,6 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -2687,14 +2455,10 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/@napi-rs/nice": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", - "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", "dev": true, "license": "MIT", "optional": true, @@ -2725,476 +2489,178 @@ "@napi-rs/nice-win32-x64-msvc": "1.1.1" } }, - "node_modules/@napi-rs/nice-android-arm-eabi": { + "node_modules/@napi-rs/nice-darwin-arm64": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", - "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", "cpu": [ - "arm" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "android" + "darwin" ], "engines": { "node": ">= 10" } }, - "node_modules/@napi-rs/nice-android-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", - "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", - "cpu": [ - "arm64" - ], + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.4", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@emnapi/core": "^1.1.0", + "@emnapi/runtime": "^1.1.0", + "@tybys/wasm-util": "^0.9.0" } }, - "node_modules/@napi-rs/nice-darwin-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", - "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", - "cpu": [ - "arm64" - ], + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, "engines": { - "node": ">= 10" + "node": ">= 8" } }, - "node_modules/@napi-rs/nice-darwin-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", - "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", - "cpu": [ - "x64" - ], + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">= 10" + "node": ">= 8" } }, - "node_modules/@napi-rs/nice-freebsd-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", - "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", - "cpu": [ - "x64" - ], + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, "engines": { - "node": ">= 10" + "node": ">= 8" } }, - "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", - "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", - "cpu": [ - "arm" - ], + "node_modules/@nx/devkit": { + "version": "22.6.5", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@zkochan/js-yaml": "0.0.7", + "ejs": "5.0.1", + "enquirer": "~2.3.6", + "minimatch": "10.2.4", + "semver": "^7.6.3", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 21 <= 23 || ^22.0.0-0" } }, - "node_modules/@napi-rs/nice-linux-arm64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", - "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", - "cpu": [ - "arm64" - ], + "node_modules/@nx/devkit/node_modules/balanced-match": { + "version": "4.0.4", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10" + "node": "18 || 20 || >=22" } }, - "node_modules/@napi-rs/nice-linux-arm64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", - "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", - "cpu": [ - "arm64" - ], + "node_modules/@nx/devkit/node_modules/brace-expansion": { + "version": "5.0.5", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "balanced-match": "^4.0.2" + }, "engines": { - "node": ">= 10" + "node": "18 || 20 || >=22" } }, - "node_modules/@napi-rs/nice-linux-ppc64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", - "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", - "cpu": [ - "ppc64" - ], + "node_modules/@nx/devkit/node_modules/minimatch": { + "version": "10.2.4", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, "engines": { - "node": ">= 10" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@napi-rs/nice-linux-riscv64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", - "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", - "cpu": [ - "riscv64" - ], + "node_modules/@nx/js": { + "version": "22.6.5", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@babel/core": "^7.23.2", + "@babel/plugin-proposal-decorators": "^7.22.7", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-runtime": "^7.23.2", + "@babel/preset-env": "^7.23.2", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", + "@nx/devkit": "22.6.5", + "@nx/workspace": "22.6.5", + "@zkochan/js-yaml": "0.0.7", + "babel-plugin-const-enum": "^1.0.1", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-transform-typescript-metadata": "^0.3.1", + "chalk": "^4.1.0", + "columnify": "^1.6.0", + "detect-port": "^1.5.1", + "ignore": "^5.0.4", + "js-tokens": "^4.0.0", + "jsonc-parser": "3.2.0", + "npm-run-path": "^4.0.1", + "picocolors": "^1.1.0", + "picomatch": "4.0.4", + "semver": "^7.6.3", + "source-map-support": "0.5.19", + "tinyglobby": "^0.2.12", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "verdaccio": "^6.0.5" + }, + "peerDependenciesMeta": { + "verdaccio": { + "optional": true + } } }, - "node_modules/@napi-rs/nice-linux-s390x-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", - "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", - "cpu": [ - "s390x" - ], + "node_modules/@nx/js/node_modules/picomatch": { + "version": "4.0.4", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@napi-rs/nice-linux-x64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", - "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", - "cpu": [ - "x64" - ], + "node_modules/@nx/js/node_modules/source-map-support": { + "version": "0.5.19", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/@napi-rs/nice-linux-x64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", - "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "node_modules/@nx/nx-darwin-arm64": { + "version": "22.6.5", "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-openharmony-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", - "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-arm64-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", - "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-ia32-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", - "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-x64-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", - "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", - "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emnapi/core": "^1.1.0", - "@emnapi/runtime": "^1.1.0", - "@tybys/wasm-util": "^0.9.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nx/devkit": { - "version": "22.6.5", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-22.6.5.tgz", - "integrity": "sha512-9kvAI+kk2pfEXLqS8OyjI9XvWmp+Gdn7jPfxDAz8BOqxMyPy3p5hYl+jc4TIsLOWunAFl8azqrcYsHzEpaWCIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@zkochan/js-yaml": "0.0.7", - "ejs": "5.0.1", - "enquirer": "~2.3.6", - "minimatch": "10.2.4", - "semver": "^7.6.3", - "tslib": "^2.3.0", - "yargs-parser": "21.1.1" - }, - "peerDependencies": { - "nx": ">= 21 <= 23 || ^22.0.0-0" - } - }, - "node_modules/@nx/devkit/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@nx/devkit/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@nx/devkit/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@nx/js": { - "version": "22.6.5", - "resolved": "https://registry.npmjs.org/@nx/js/-/js-22.6.5.tgz", - "integrity": "sha512-bmikz6qaBHfuAgsqPB/TfLIKfvI4g+EKIRAiU2FHnEtVWOKDAmSQXHFwE3rMS49jl2JLgxkdNjZHpg4g/OLy0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.23.2", - "@babel/plugin-proposal-decorators": "^7.22.7", - "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-runtime": "^7.23.2", - "@babel/preset-env": "^7.23.2", - "@babel/preset-typescript": "^7.22.5", - "@babel/runtime": "^7.22.6", - "@nx/devkit": "22.6.5", - "@nx/workspace": "22.6.5", - "@zkochan/js-yaml": "0.0.7", - "babel-plugin-const-enum": "^1.0.1", - "babel-plugin-macros": "^3.1.0", - "babel-plugin-transform-typescript-metadata": "^0.3.1", - "chalk": "^4.1.0", - "columnify": "^1.6.0", - "detect-port": "^1.5.1", - "ignore": "^5.0.4", - "js-tokens": "^4.0.0", - "jsonc-parser": "3.2.0", - "npm-run-path": "^4.0.1", - "picocolors": "^1.1.0", - "picomatch": "4.0.4", - "semver": "^7.6.3", - "source-map-support": "0.5.19", - "tinyglobby": "^0.2.12", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "verdaccio": "^6.0.5" - }, - "peerDependenciesMeta": { - "verdaccio": { - "optional": true - } - } - }, - "node_modules/@nx/js/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@nx/js/node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/@nx/nx-darwin-arm64": { - "version": "22.6.5", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-22.6.5.tgz", - "integrity": "sha512-qT77Omkg5xQuL2+pDbneX2tI+XW5ZeayMylu7UUgK8OhTrAkJLKjpuYRH4xT5XBipxbDtlxmO3aLS3Ib1pKzJQ==", - "cpu": [ - "arm64" + "arm64" ], "dev": true, "license": "MIT", @@ -3253,6 +2719,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3267,6 +2736,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3281,6 +2753,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3295,6 +2770,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3331,8 +2809,6 @@ }, "node_modules/@nx/workspace": { "version": "22.6.5", - "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-22.6.5.tgz", - "integrity": "sha512-/CZtv1ESSfZ1MVqSlCsmnBWysU1z5VdNlwANlqL6BV2X6RUHKDPVj4YuNPvCK+0LsqyzfJdUt3pcnBYxnT5TIg==", "dev": true, "license": "MIT", "dependencies": { @@ -3349,8 +2825,6 @@ }, "node_modules/@nx/workspace/node_modules/picomatch": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -3762,8 +3236,6 @@ }, "node_modules/@sindresorhus/is": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", - "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", "dev": true, "license": "MIT", "engines": { @@ -3775,8 +3247,6 @@ }, "node_modules/@swc/cli": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.5.2.tgz", - "integrity": "sha512-ul2qIqjM5bfe9zWLqFDmHZCf9HXXSZZAlZLe4czn+lH4PewO+OWZnQcYCscnJKlbx6MuWjzXVR7gkspjNEJwJA==", "dev": true, "license": "MIT", "dependencies": { @@ -3810,8 +3280,6 @@ }, "node_modules/@swc/cli/node_modules/commander": { "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, "license": "MIT", "engines": { @@ -3820,8 +3288,6 @@ }, "node_modules/@swc/cli/node_modules/source-map": { "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -3830,8 +3296,6 @@ }, "node_modules/@swc/core": { "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.10.tgz", - "integrity": "sha512-udNofxftduMUEv7nqahl2nvodCiCDQ4Ge0ebzsEm6P8s0RC2tBM0Hqx0nNF5J/6t9uagFJyWIDjXy3IIWMHDJw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -3869,8 +3333,6 @@ }, "node_modules/@swc/core-darwin-arm64": { "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.10.tgz", - "integrity": "sha512-U72pGqmJYbjrLhMndIemZ7u9Q9owcJczGxwtfJlz/WwMaGYAV/g4nkGiUVk/+QSX8sFCAjanovcU1IUsP2YulA==", "cpu": [ "arm64" ], @@ -3884,170 +3346,13 @@ "node": ">=10" } }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.10.tgz", - "integrity": "sha512-NZpDXtwHH083L40xdyj1sY31MIwLgOxKfZEAGCI8xHXdHa+GWvEiVdGiu4qhkJctoHFzAEc7ZX3GN5phuJcPuQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.10.tgz", - "integrity": "sha512-ioieF5iuRziUF1HkH1gg1r93e055dAdeBAPGAk40VjqpL5/igPJ/WxFHGvc6WMLhUubSJI4S0AiZAAhEAp1jDg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.10.tgz", - "integrity": "sha512-tD6BClOrxSsNus9cJL7Gxdv7z7Y2hlyvZd9l0NQz+YXzmTWqnfzLpg16ovEI7gknH2AgDBB5ywOsqu8hUgSeEQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.10.tgz", - "integrity": "sha512-4uAHO3nbfbrTcmO/9YcVweTQdx5fN3l7ewwl5AEK4yoC4wXmoBTEPHAVdKNe4r9+xrTgd4BgyPsy0409OjjlMw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.10.tgz", - "integrity": "sha512-W0h9ONNw1pVIA0cN7wtboOSTl4Jk3tHq+w2cMPQudu9/+3xoCxpFb9ZdehwCAk29IsvdWzGzY6P7dDVTyFwoqg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.10.tgz", - "integrity": "sha512-XQNZlLZB62S8nAbw7pqoqwy91Ldy2RpaMRqdRN3T+tAg6Xg6FywXRKCsLh6IQOadr4p1+lGnqM/Wn35z5a/0Vw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.10.tgz", - "integrity": "sha512-qnAGrRv5Nj/DATxAmCnJQRXXQqnJwR0trxLndhoHoxGci9MuguNIjWahS0gw8YZFjgTinbTxOwzatkoySihnmw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.10.tgz", - "integrity": "sha512-i4X/q8QSvzVlaRtv1xfnfl+hVKpCfiJ+9th484rh937fiEZKxZGf51C+uO0lfKDP1FfnT6C1yBYwHy7FLBVXFw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.10.tgz", - "integrity": "sha512-HvY8XUFuoTXn6lSccDLYFlXv1SU/PzYi4PyUqGT++WfTnbw/68N/7BdUZqglGRwiSqr0qhYt/EhmBpULj0J9rA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, "node_modules/@swc/counter": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true, "license": "Apache-2.0" }, "node_modules/@swc/types": { "version": "0.1.25", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz", - "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4056,8 +3361,6 @@ }, "node_modules/@szmarczak/http-timer": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", "dev": true, "license": "MIT", "dependencies": { @@ -4069,14 +3372,10 @@ }, "node_modules/@telegraf/types": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@telegraf/types/-/types-7.1.0.tgz", - "integrity": "sha512-kGevOIbpMcIlCDeorKGpwZmdH7kHbqlk/Yj6dEpJMKEQw5lk0KVQY0OLXaCswy8GqlIVLd5625OB+rAntP9xVw==", "license": "MIT" }, "node_modules/@tokenizer/inflate": { "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.2.7.tgz", - "integrity": "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==", "dev": true, "license": "MIT", "dependencies": { @@ -4094,43 +3393,31 @@ }, "node_modules/@tokenizer/token": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node10": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", "dev": true, "license": "MIT", "dependencies": { @@ -4139,8 +3426,6 @@ }, "node_modules/@types/better-sqlite3": { "version": "7.6.13", - "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", - "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", "dev": true, "license": "MIT", "dependencies": { @@ -4149,8 +3434,6 @@ }, "node_modules/@types/debug": { "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", "dev": true, "license": "MIT", "dependencies": { @@ -4166,8 +3449,6 @@ }, "node_modules/@types/fs-extra": { "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", - "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4177,8 +3458,6 @@ }, "node_modules/@types/http-cache-semantics": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true, "license": "MIT" }, @@ -4195,15 +3474,11 @@ }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, "node_modules/@types/jsonfile": { "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", - "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4212,16 +3487,12 @@ }, "node_modules/@types/ms": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "20.19.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.21.tgz", - "integrity": "sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -4229,22 +3500,26 @@ }, "node_modules/@types/parse-json": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "dev": true, "license": "MIT" }, + "node_modules/@types/react": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", + "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, "node_modules/@types/semver": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", "dev": true, "license": "MIT" }, "node_modules/@types/through": { "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", - "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4253,15 +3528,11 @@ }, "node_modules/@types/uuid": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "license": "MIT", "dependencies": { @@ -4296,8 +3567,6 @@ }, "node_modules/@typescript-eslint/parser": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4325,8 +3594,6 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "license": "MIT", "dependencies": { @@ -4343,8 +3610,6 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "license": "MIT", "dependencies": { @@ -4371,8 +3636,6 @@ }, "node_modules/@typescript-eslint/types": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "license": "MIT", "engines": { @@ -4385,8 +3648,6 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4414,8 +3675,6 @@ }, "node_modules/@typescript-eslint/utils": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4440,8 +3699,6 @@ }, "node_modules/@typescript-eslint/visitor-keys": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, "license": "MIT", "dependencies": { @@ -4458,8 +3715,6 @@ }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, "license": "ISC" }, @@ -4729,8 +3984,6 @@ }, "node_modules/@xhmikosr/archive-type": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/archive-type/-/archive-type-7.1.0.tgz", - "integrity": "sha512-xZEpnGplg1sNPyEgFh0zbHxqlw5dtYg6viplmWSxUj12+QjU9SKu3U/2G73a15pEjLaOqTefNSZ1fOPUOT4Xgg==", "dev": true, "license": "MIT", "dependencies": { @@ -4742,8 +3995,6 @@ }, "node_modules/@xhmikosr/bin-check": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/bin-check/-/bin-check-7.1.0.tgz", - "integrity": "sha512-y1O95J4mnl+6MpVmKfMYXec17hMEwE/yeCglFNdx+QvLLtP0yN4rSYcbkXnth+lElBuKKek2NbvOfOGPpUXCvw==", "dev": true, "license": "MIT", "dependencies": { @@ -4756,8 +4007,6 @@ }, "node_modules/@xhmikosr/bin-wrapper": { "version": "13.2.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/bin-wrapper/-/bin-wrapper-13.2.0.tgz", - "integrity": "sha512-t9U9X0sDPRGDk5TGx4dv5xiOvniVJpXnfTuynVKwHgtib95NYEw4MkZdJqhoSiz820D9m0o6PCqOPMXz0N9fIw==", "dev": true, "license": "MIT", "dependencies": { @@ -4772,8 +4021,6 @@ }, "node_modules/@xhmikosr/decompress": { "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress/-/decompress-10.2.0.tgz", - "integrity": "sha512-MmDBvu0+GmADyQWHolcZuIWffgfnuTo4xpr2I/Qw5Ox0gt+e1Be7oYqJM4te5ylL6mzlcoicnHVDvP27zft8tg==", "dev": true, "license": "MIT", "dependencies": { @@ -4790,8 +4037,6 @@ }, "node_modules/@xhmikosr/decompress-tar": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tar/-/decompress-tar-8.1.0.tgz", - "integrity": "sha512-m0q8x6lwxenh1CrsTby0Jrjq4vzW/QU1OLhTHMQLEdHpmjR1lgahGz++seZI0bXF3XcZw3U3xHfqZSz+JPP2Gg==", "dev": true, "license": "MIT", "dependencies": { @@ -4805,8 +4050,6 @@ }, "node_modules/@xhmikosr/decompress-tar/node_modules/tar-stream": { "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4817,8 +4060,6 @@ }, "node_modules/@xhmikosr/decompress-tarbz2": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tarbz2/-/decompress-tarbz2-8.1.0.tgz", - "integrity": "sha512-aCLfr3A/FWZnOu5eqnJfme1Z1aumai/WRw55pCvBP+hCGnTFrcpsuiaVN5zmWTR53a8umxncY2JuYsD42QQEbw==", "dev": true, "license": "MIT", "dependencies": { @@ -4834,8 +4075,6 @@ }, "node_modules/@xhmikosr/decompress-targz": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-targz/-/decompress-targz-8.1.0.tgz", - "integrity": "sha512-fhClQ2wTmzxzdz2OhSQNo9ExefrAagw93qaG1YggoIz/QpI7atSRa7eOHv4JZkpHWs91XNn8Hry3CwUlBQhfPA==", "dev": true, "license": "MIT", "dependencies": { @@ -4849,8 +4088,6 @@ }, "node_modules/@xhmikosr/decompress-unzip": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-unzip/-/decompress-unzip-7.1.0.tgz", - "integrity": "sha512-oqTYAcObqTlg8owulxFTqiaJkfv2SHsxxxz9Wg4krJAHVzGWlZsU8tAB30R6ow+aHrfv4Kub6WQ8u04NWVPUpA==", "dev": true, "license": "MIT", "dependencies": { @@ -4864,8 +4101,6 @@ }, "node_modules/@xhmikosr/downloader": { "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/downloader/-/downloader-15.2.0.tgz", - "integrity": "sha512-lAqbig3uRGTt0sHNIM4vUG9HoM+mRl8K28WuYxyXLCUT6pyzl4Y4i0LZ3jMEsCYZ6zjPZbO9XkG91OSTd4si7g==", "dev": true, "license": "MIT", "dependencies": { @@ -4885,8 +4120,6 @@ }, "node_modules/@xhmikosr/downloader/node_modules/content-disposition": { "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4898,8 +4131,6 @@ }, "node_modules/@xhmikosr/downloader/node_modules/defaults": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-2.0.2.tgz", - "integrity": "sha512-cuIw0PImdp76AOfgkjbW4VhQODRmNNcKR73vdCH5cLd/ifj7aamfoXvYgfGkEAjNJZ3ozMIy9Gu2LutUkGEPbA==", "dev": true, "license": "MIT", "engines": { @@ -4911,8 +4142,6 @@ }, "node_modules/@xhmikosr/os-filter-obj": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/os-filter-obj/-/os-filter-obj-3.0.0.tgz", - "integrity": "sha512-siPY6BD5dQ2SZPl3I0OZBHL27ZqZvLEosObsZRQ1NUB8qcxegwt0T9eKtV96JMFQpIz1elhkzqOg4c/Ri6Dp9A==", "dev": true, "license": "MIT", "dependencies": { @@ -4924,15 +4153,11 @@ }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", "dev": true, "license": "BSD-2-Clause" }, "node_modules/@yarnpkg/parsers": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.2.tgz", - "integrity": "sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4945,8 +4170,6 @@ }, "node_modules/@yarnpkg/parsers/node_modules/argparse": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", "dependencies": { @@ -4955,8 +4178,6 @@ }, "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -4969,8 +4190,6 @@ }, "node_modules/@zkochan/js-yaml": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", - "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4982,8 +4201,6 @@ }, "node_modules/abort-controller": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" @@ -4994,8 +4211,6 @@ }, "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -5007,8 +4222,6 @@ }, "node_modules/acorn": { "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", "bin": { @@ -5020,8 +4233,6 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -5030,8 +4241,6 @@ }, "node_modules/acorn-walk": { "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -5043,8 +4252,6 @@ }, "node_modules/address": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", - "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", "dev": true, "license": "MIT", "engines": { @@ -5057,8 +4264,6 @@ }, "node_modules/ajv": { "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -5074,8 +4279,6 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -5091,8 +4294,6 @@ }, "node_modules/ajv-formats/node_modules/ajv": { "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -5107,14 +4308,10 @@ }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/ansi-colors": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "license": "MIT", "engines": { @@ -5123,8 +4320,6 @@ }, "node_modules/ansi-escapes": { "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -5138,8 +4333,6 @@ }, "node_modules/ansi-escapes/node_modules/type-fest": { "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -5150,8 +4343,6 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -5159,8 +4350,6 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5174,8 +4363,6 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", "dependencies": { @@ -5188,8 +4375,6 @@ }, "node_modules/arch": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-3.0.0.tgz", - "integrity": "sha512-AmIAC+Wtm2AU8lGfTtHsw0Y9Qtftx2YXEEtiBP10xFUtMOA+sHHx6OAddyL52mUKh1vsXQ6/w1mVDptZCyUt4Q==", "dev": true, "funding": [ { @@ -5209,22 +4394,16 @@ }, "node_modules/arg": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, "license": "Python-2.0" }, "node_modules/array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, "license": "MIT", "engines": { @@ -5243,15 +4422,23 @@ }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, "license": "MIT" }, + "node_modules/auto-bind": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", + "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/axios": { "version": "1.15.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", - "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "dev": true, "license": "MIT", "dependencies": { @@ -5262,8 +4449,6 @@ }, "node_modules/b4a": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", - "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -5277,8 +4462,6 @@ }, "node_modules/babel-plugin-const-enum": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-const-enum/-/babel-plugin-const-enum-1.2.0.tgz", - "integrity": "sha512-o1m/6iyyFnp9MRsK1dHF3bneqyf3AlM2q3A/YbgQr2pCat6B6XJVDv2TXqzfY2RYUi4mak6WAksSBPlyYGx9dg==", "dev": true, "license": "MIT", "dependencies": { @@ -5292,8 +4475,6 @@ }, "node_modules/babel-plugin-macros": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "dev": true, "license": "MIT", "dependencies": { @@ -5308,8 +4489,6 @@ }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", "dev": true, "license": "MIT", "dependencies": { @@ -5323,8 +4502,6 @@ }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -5333,8 +4510,6 @@ }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "dev": true, "license": "MIT", "dependencies": { @@ -5347,8 +4522,6 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", "dev": true, "license": "MIT", "dependencies": { @@ -5360,8 +4533,6 @@ }, "node_modules/babel-plugin-transform-typescript-metadata": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-typescript-metadata/-/babel-plugin-transform-typescript-metadata-0.3.2.tgz", - "integrity": "sha512-mWEvCQTgXQf48yDqgN7CH50waTyYBeP2Lpqx4nNWab9sxEpdXVeKgfj1qYI2/TgUPQtNFZ85i3PemRtnXVYYJg==", "dev": true, "license": "MIT", "dependencies": { @@ -5370,15 +4541,11 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, "license": "MIT" }, "node_modules/bare-events": { "version": "2.8.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", - "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -5392,8 +4559,6 @@ }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -5412,8 +4577,6 @@ }, "node_modules/baseline-browser-mapping": { "version": "2.9.17", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.17.tgz", - "integrity": "sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5422,8 +4585,6 @@ }, "node_modules/better-sqlite3": { "version": "12.6.2", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.6.2.tgz", - "integrity": "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -5436,8 +4597,6 @@ }, "node_modules/bin-version": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", - "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", "dev": true, "license": "MIT", "dependencies": { @@ -5453,8 +4612,6 @@ }, "node_modules/bin-version-check": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.1.0.tgz", - "integrity": "sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==", "dev": true, "license": "MIT", "dependencies": { @@ -5471,8 +4628,6 @@ }, "node_modules/binary-extensions": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", "engines": { @@ -5484,8 +4639,6 @@ }, "node_modules/bindings": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "license": "MIT", "dependencies": { "file-uri-to-path": "1.0.0" @@ -5493,8 +4646,6 @@ }, "node_modules/bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "license": "MIT", "dependencies": { "buffer": "^5.5.0", @@ -5504,8 +4655,6 @@ }, "node_modules/body-parser": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -5528,8 +4677,6 @@ }, "node_modules/brace-expansion": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -5538,8 +4685,6 @@ }, "node_modules/braces": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", "dependencies": { @@ -5551,8 +4696,6 @@ }, "node_modules/browserslist": { "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -5585,8 +4728,6 @@ }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { "type": "github", @@ -5609,8 +4750,6 @@ }, "node_modules/buffer-alloc": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "license": "MIT", "dependencies": { "buffer-alloc-unsafe": "^1.1.0", @@ -5619,14 +4758,10 @@ }, "node_modules/buffer-alloc-unsafe": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", "license": "MIT" }, "node_modules/buffer-crc32": { "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "license": "MIT", "engines": { @@ -5635,21 +4770,15 @@ }, "node_modules/buffer-fill": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", "license": "MIT" }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, "license": "MIT" }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -5667,8 +4796,6 @@ }, "node_modules/cacheable-lookup": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", "dev": true, "license": "MIT", "engines": { @@ -5677,8 +4804,6 @@ }, "node_modules/cacheable-request": { "version": "10.2.14", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", - "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5696,8 +4821,6 @@ }, "node_modules/cacheable-request/node_modules/mimic-response": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", "dev": true, "license": "MIT", "engines": { @@ -5709,8 +4832,6 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5722,8 +4843,6 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -5738,8 +4857,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", "engines": { @@ -5748,8 +4865,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001765", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz", - "integrity": "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==", "dev": true, "funding": [ { @@ -5786,8 +4901,6 @@ }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -5802,8 +4915,6 @@ }, "node_modules/chardet": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", - "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", "license": "MIT" }, "node_modules/check-error": { @@ -5818,8 +4929,6 @@ }, "node_modules/chokidar": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", "dependencies": { @@ -5843,8 +4952,6 @@ }, "node_modules/chokidar/node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { @@ -5856,32 +4963,97 @@ }, "node_modules/chownr": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "license": "ISC" }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/cli-boxes": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-4.0.1.tgz", + "integrity": "sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw==", + "license": "MIT", + "engines": { + "node": ">=18.20 <19 || >=20.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-6.0.0.tgz", + "integrity": "sha512-3+YKIUFsohD9MIoOFPFBldjAlnfCmCDcqe6aYGFqlDTRKg80p4wg35L+j83QQ63iOlKRccEkbn8IuM++HsgEjA==", + "license": "MIT", + "dependencies": { + "slice-ansi": "^9.0.0", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", "license": "MIT", "dependencies": { - "restore-cursor": "^3.1.0" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, "engines": { - "node": ">=6" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/cli-width": { @@ -5895,8 +5067,6 @@ }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", "dependencies": { @@ -5910,8 +5080,6 @@ }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { @@ -5928,17 +5096,25 @@ }, "node_modules/clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "license": "MIT", "engines": { "node": ">=0.8" } }, + "node_modules/code-excerpt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", + "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", + "license": "MIT", + "dependencies": { + "convert-to-spaces": "^2.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -5949,14 +5125,10 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, "node_modules/columnify": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", - "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -5969,8 +5141,6 @@ }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", "dependencies": { @@ -5982,8 +5152,6 @@ }, "node_modules/commander": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "license": "MIT", "engines": { "node": ">=16" @@ -5991,15 +5159,11 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, "license": "MIT" }, "node_modules/content-disposition": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", "engines": { "node": ">=18" @@ -6011,8 +5175,6 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6020,15 +5182,20 @@ }, "node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, + "node_modules/convert-to-spaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/cookie": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6036,8 +5203,6 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "engines": { "node": ">=6.6.0" @@ -6045,8 +5210,6 @@ }, "node_modules/core-js-compat": { "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", - "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", "dev": true, "license": "MIT", "dependencies": { @@ -6059,8 +5222,6 @@ }, "node_modules/cors": { "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -6072,8 +5233,6 @@ }, "node_modules/cosmiconfig": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "license": "MIT", "dependencies": { @@ -6089,8 +5248,6 @@ }, "node_modules/cosmiconfig/node_modules/yaml": { "version": "1.10.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", - "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { @@ -6099,15 +5256,11 @@ }, "node_modules/create-require": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6118,10 +5271,13 @@ "node": ">= 8" } }, + "node_modules/csstype": { + "version": "3.2.3", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6137,8 +5293,6 @@ }, "node_modules/decompress-response": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" @@ -6162,8 +5316,6 @@ }, "node_modules/deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "license": "MIT", "engines": { "node": ">=4.0.0" @@ -6171,15 +5323,11 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT" }, "node_modules/defaults": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "license": "MIT", "dependencies": { "clone": "^1.0.2" @@ -6190,8 +5338,6 @@ }, "node_modules/defer-to-connect": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", "dev": true, "license": "MIT", "engines": { @@ -6200,8 +5346,6 @@ }, "node_modules/define-lazy-prop": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, "license": "MIT", "engines": { @@ -6210,8 +5354,6 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", "engines": { @@ -6220,8 +5362,6 @@ }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -6229,8 +5369,6 @@ }, "node_modules/detect-libc": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", "engines": { "node": ">=8" @@ -6238,8 +5376,6 @@ }, "node_modules/detect-port": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", - "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", "dev": true, "license": "MIT", "dependencies": { @@ -6256,8 +5392,6 @@ }, "node_modules/diff": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -6266,8 +5400,6 @@ }, "node_modules/dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "license": "MIT", "dependencies": { @@ -6279,8 +5411,6 @@ }, "node_modules/doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -6292,8 +5422,6 @@ }, "node_modules/dotenv": { "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -6305,8 +5433,6 @@ }, "node_modules/dotenv-expand": { "version": "11.0.7", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", - "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -6321,8 +5447,6 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -6342,14 +5466,10 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, "node_modules/ejs": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-5.0.1.tgz", - "integrity": "sha512-COqBPFMxuPTPspXl2DkVYaDS3HtrD1GpzOGkNTJ1IYkifq/r9h8SVEFrjA3D9/VJGOEoMQcrlhpntcSUrM8k6A==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6361,21 +5481,15 @@ }, "node_modules/electron-to-chromium": { "version": "1.5.277", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.277.tgz", - "integrity": "sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw==", "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -6383,8 +5497,6 @@ }, "node_modules/end-of-stream": { "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -6392,8 +5504,6 @@ }, "node_modules/enquirer": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, "license": "MIT", "dependencies": { @@ -6403,10 +5513,20 @@ "node": ">=8.6" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6415,8 +5535,6 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -6424,8 +5542,6 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -6440,8 +5556,6 @@ }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -6452,8 +5566,6 @@ }, "node_modules/es-set-tostringtag": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", "dependencies": { @@ -6466,6 +5578,16 @@ "node": ">= 0.4" } }, + "node_modules/es-toolkit": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.47.0.tgz", + "integrity": "sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -6507,8 +5629,6 @@ }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -6517,14 +5637,10 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", "engines": { @@ -6536,9 +5652,6 @@ }, "node_modules/eslint": { "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", "dependencies": { @@ -6593,8 +5706,6 @@ }, "node_modules/eslint-scope": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -6610,8 +5721,6 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { @@ -6623,8 +5732,6 @@ }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -6634,8 +5741,6 @@ }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -6647,8 +5752,6 @@ }, "node_modules/espree": { "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -6665,8 +5768,6 @@ }, "node_modules/esprima": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -6678,8 +5779,6 @@ }, "node_modules/esquery": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6691,8 +5790,6 @@ }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -6704,8 +5801,6 @@ }, "node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -6724,8 +5819,6 @@ }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -6734,8 +5827,6 @@ }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6743,8 +5834,6 @@ }, "node_modules/event-target-shim": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", "engines": { "node": ">=6" @@ -6752,8 +5841,6 @@ }, "node_modules/events-universal": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", - "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -6762,8 +5849,6 @@ }, "node_modules/eventsource": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" @@ -6774,8 +5859,6 @@ }, "node_modules/eventsource-parser": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -6783,8 +5866,6 @@ }, "node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "license": "MIT", "dependencies": { @@ -6807,8 +5888,6 @@ }, "node_modules/expand-template": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "license": "(MIT OR WTFPL)", "engines": { "node": ">=6" @@ -6826,8 +5905,6 @@ }, "node_modules/express": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -6869,8 +5946,6 @@ }, "node_modules/express-rate-limit": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.2.tgz", - "integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==", "license": "MIT", "dependencies": { "ip-address": "10.1.0" @@ -6887,8 +5962,6 @@ }, "node_modules/ext-list": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", "dev": true, "license": "MIT", "dependencies": { @@ -6900,8 +5973,6 @@ }, "node_modules/ext-name": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6914,8 +5985,6 @@ }, "node_modules/extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" @@ -6926,21 +5995,15 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, "node_modules/fast-fifo": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", "dev": true, "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", "dependencies": { @@ -6956,8 +6019,6 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { @@ -6969,22 +6030,16 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -6999,8 +6054,6 @@ }, "node_modules/fastq": { "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, "license": "ISC", "dependencies": { @@ -7009,15 +6062,11 @@ }, "node_modules/fflate": { "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", "dev": true, "license": "MIT" }, "node_modules/figures": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "license": "MIT", "dependencies": { @@ -7032,8 +6081,6 @@ }, "node_modules/figures/node_modules/escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "license": "MIT", "engines": { @@ -7042,8 +6089,6 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "license": "MIT", "dependencies": { @@ -7055,8 +6100,6 @@ }, "node_modules/file-type": { "version": "20.5.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-20.5.0.tgz", - "integrity": "sha512-BfHZtG/l9iMm4Ecianu7P8HRD2tBHLtjXinm4X62XBOYzi7CYA7jyqfJzOvXHqzVrVPYqBo2/GvbARMaaJkKVg==", "dev": true, "license": "MIT", "dependencies": { @@ -7074,14 +6117,10 @@ }, "node_modules/file-uri-to-path": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "license": "MIT" }, "node_modules/filename-reserved-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", - "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", "dev": true, "license": "MIT", "engines": { @@ -7093,8 +6132,6 @@ }, "node_modules/filenamify": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-6.0.0.tgz", - "integrity": "sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7109,8 +6146,6 @@ }, "node_modules/fill-range": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { @@ -7122,8 +6157,6 @@ }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -7143,8 +6176,6 @@ }, "node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { @@ -7160,8 +6191,6 @@ }, "node_modules/find-versions": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", "dev": true, "license": "MIT", "dependencies": { @@ -7176,8 +6205,6 @@ }, "node_modules/flat": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, "license": "BSD-3-Clause", "bin": { @@ -7186,8 +6213,6 @@ }, "node_modules/flat-cache": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", "dependencies": { @@ -7201,15 +6226,11 @@ }, "node_modules/flatted": { "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true, "funding": [ { @@ -7259,8 +6280,6 @@ }, "node_modules/form-data": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "license": "MIT", "dependencies": { @@ -7276,8 +6295,6 @@ }, "node_modules/form-data-encoder": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", "dev": true, "license": "MIT", "engines": { @@ -7286,8 +6303,6 @@ }, "node_modules/form-data/node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", "engines": { @@ -7296,8 +6311,6 @@ }, "node_modules/form-data/node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", "dependencies": { @@ -7309,8 +6322,6 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -7318,8 +6329,6 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -7327,8 +6336,6 @@ }, "node_modules/front-matter": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", - "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", "dev": true, "license": "MIT", "dependencies": { @@ -7337,8 +6344,6 @@ }, "node_modules/front-matter/node_modules/argparse": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", "dependencies": { @@ -7347,8 +6352,6 @@ }, "node_modules/front-matter/node_modules/js-yaml": { "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -7361,14 +6364,10 @@ }, "node_modules/fs-constants": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "license": "MIT" }, "node_modules/fs-extra": { "version": "11.3.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", - "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -7381,17 +6380,12 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, "license": "ISC" }, "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": [ @@ -7403,8 +6397,6 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7412,8 +6404,6 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", "engines": { @@ -7422,8 +6412,6 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, "license": "ISC", "engines": { @@ -7444,8 +6432,6 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -7468,8 +6454,6 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -7481,8 +6465,6 @@ }, "node_modules/get-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "license": "MIT", "engines": { @@ -7494,15 +6476,10 @@ }, "node_modules/github-from-package": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "license": "MIT" }, "node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -7522,8 +6499,6 @@ }, "node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", "dependencies": { @@ -7535,8 +6510,6 @@ }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -7546,8 +6519,6 @@ }, "node_modules/glob/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -7559,8 +6530,6 @@ }, "node_modules/globals": { "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7575,8 +6544,6 @@ }, "node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "license": "MIT", "dependencies": { @@ -7596,8 +6563,6 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -7608,8 +6573,6 @@ }, "node_modules/got": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", - "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", "dev": true, "license": "MIT", "dependencies": { @@ -7634,21 +6597,15 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, "license": "MIT" }, "node_modules/gray-matter": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", "license": "MIT", "dependencies": { "js-yaml": "^3.13.1", @@ -7662,8 +6619,6 @@ }, "node_modules/gray-matter/node_modules/argparse": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -7671,8 +6626,6 @@ }, "node_modules/gray-matter/node_modules/js-yaml": { "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -7684,8 +6637,6 @@ }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", "engines": { "node": ">=8" @@ -7693,8 +6644,6 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -7705,8 +6654,6 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { @@ -7721,8 +6668,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -7733,8 +6678,6 @@ }, "node_modules/hono": { "version": "4.12.12", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.12.tgz", - "integrity": "sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -7742,22 +6685,16 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, "license": "MIT" }, "node_modules/http-cache-semantics": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true, "license": "BSD-2-Clause" }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -7776,8 +6713,6 @@ }, "node_modules/http2-wrapper": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", - "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7790,8 +6725,6 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -7800,8 +6733,6 @@ }, "node_modules/husky": { "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true, "license": "MIT", "bin": { @@ -7811,106 +6742,336 @@ "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/typicode" + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.0", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "license": "ISC" + }, + "node_modules/ink": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/ink/-/ink-7.0.4.tgz", + "integrity": "sha512-4wsM/gMKOT2ZANNTJibI6I9IcwBfobqv/CgaDcwvOaCREZIQxo3iGQS7qPHa2hmA67NYltZWCMtBDELB/mcbJQ==", + "license": "MIT", + "dependencies": { + "@alcalzone/ansi-tokenize": "^0.3.0", + "ansi-escapes": "^7.3.0", + "ansi-styles": "^6.2.3", + "auto-bind": "^5.0.1", + "chalk": "^5.6.2", + "cli-boxes": "^4.0.1", + "cli-cursor": "^4.0.0", + "cli-truncate": "^6.0.0", + "code-excerpt": "^4.0.0", + "es-toolkit": "^1.45.1", + "indent-string": "^5.0.0", + "is-in-ci": "^2.0.0", + "patch-console": "^2.0.0", + "react-reconciler": "^0.33.0", + "scheduler": "^0.27.0", + "signal-exit": "^3.0.7", + "slice-ansi": "^9.0.0", + "stack-utils": "^2.0.6", + "string-width": "^8.2.0", + "terminal-size": "^4.0.1", + "type-fest": "^5.5.0", + "widest-line": "^6.0.0", + "wrap-ansi": "^10.0.0", + "ws": "^8.20.0", + "yoga-layout": "~3.2.1" + }, + "engines": { + "node": ">=22" + }, + "peerDependencies": { + "@types/react": ">=19.2.0", + "react": ">=19.2.0", + "react-devtools-core": ">=6.1.2" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-devtools-core": { + "optional": true + } + } + }, + "node_modules/ink-text-input": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ink-text-input/-/ink-text-input-6.0.0.tgz", + "integrity": "sha512-Fw64n7Yha5deb1rHY137zHTAbSTNelUKuB5Kkk2HACXEtwIHBCf9OH2tP/LQ9fRYTl1F0dZgbW0zPnZk6FA9Lw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "type-fest": "^4.18.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "ink": ">=5", + "react": ">=18" + } + }, + "node_modules/ink-text-input/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ink-text-input/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ink/node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ink/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ink/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ink/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ink/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ink/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "node_modules/ink/node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=20" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, + "node_modules/ink/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, "engines": { - "node": ">= 4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", + "node_modules/ink/node_modules/type-fest": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.6.0.tgz", + "integrity": "sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==", + "license": "(MIT OR CC0-1.0)", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "tagged-tag": "^1.0.0" }, "engines": { - "node": ">=6" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, + "node_modules/ink/node_modules/wrap-ansi": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.0.tgz", + "integrity": "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==", "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "ansi-styles": "^6.2.3", + "string-width": "^8.2.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, "node_modules/inquirer": { "version": "9.3.8", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.8.tgz", @@ -7936,8 +7097,6 @@ }, "node_modules/inspect-with-kind": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/inspect-with-kind/-/inspect-with-kind-1.0.5.tgz", - "integrity": "sha512-MAQUJuIo7Xqk8EVNP+6d3CKq9c80hi4tjIbIAT6lmGW9W6WzlHiu9PS8uSuUYU+Do+j1baiFp3H25XEVxDIG2g==", "dev": true, "license": "ISC", "dependencies": { @@ -7946,8 +7105,6 @@ }, "node_modules/ip-address": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", "engines": { "node": ">= 12" @@ -7955,8 +7112,6 @@ }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -7964,15 +7119,11 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, "license": "MIT" }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", "dependencies": { @@ -7984,8 +7135,6 @@ }, "node_modules/is-core-module": { "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { @@ -8000,8 +7149,6 @@ }, "node_modules/is-docker": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "license": "MIT", "bin": { @@ -8016,8 +7163,6 @@ }, "node_modules/is-extendable": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8025,8 +7170,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", "engines": { @@ -8035,8 +7178,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { "node": ">=8" @@ -8044,8 +7185,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", "dependencies": { @@ -8055,10 +7194,23 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-in-ci/-/is-in-ci-2.0.0.tgz", + "integrity": "sha512-cFeerHriAnhrQSbpAxL37W1wcJKUUX07HyLWZCW1URJT/ra3GyUTzBgUnh24TMVfNTV2Hij2HLxkPHFZfOZy5w==", + "license": "MIT", + "bin": { + "is-in-ci": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "license": "MIT", "engines": { "node": ">=8" @@ -8066,8 +7218,6 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", "engines": { @@ -8076,8 +7226,6 @@ }, "node_modules/is-path-inside": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", "engines": { @@ -8086,8 +7234,6 @@ }, "node_modules/is-plain-obj": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true, "license": "MIT", "engines": { @@ -8096,14 +7242,10 @@ }, "node_modules/is-promise": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, "node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "license": "MIT", "engines": { @@ -8115,8 +7257,6 @@ }, "node_modules/is-unicode-supported": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "license": "MIT", "engines": { "node": ">=10" @@ -8127,8 +7267,6 @@ }, "node_modules/is-wsl": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", "dependencies": { @@ -8140,14 +7278,10 @@ }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -8156,8 +7290,6 @@ }, "node_modules/istanbul-lib-report": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8171,8 +7303,6 @@ }, "node_modules/istanbul-reports": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8201,8 +7331,6 @@ }, "node_modules/jest-diff": { "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", - "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, "license": "MIT", "dependencies": { @@ -8217,8 +7345,6 @@ }, "node_modules/jose": { "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -8226,15 +7352,11 @@ }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -8246,8 +7368,6 @@ }, "node_modules/jsesc": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", "bin": { @@ -8259,42 +7379,30 @@ }, "node_modules/json-buffer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, "node_modules/json-schema-typed": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", "license": "BSD-2-Clause" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, "license": "MIT" }, "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": { @@ -8306,15 +7414,11 @@ }, "node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true, "license": "MIT" }, "node_modules/jsonfile": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -8325,8 +7429,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": { @@ -8335,8 +7437,6 @@ }, "node_modules/kind-of": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8344,8 +7444,6 @@ }, "node_modules/levn": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8358,15 +7456,11 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true, "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { @@ -8381,22 +7475,16 @@ }, "node_modules/lodash.debounce": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true, "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "license": "MIT", "dependencies": { "chalk": "^4.1.0", @@ -8418,8 +7506,6 @@ }, "node_modules/lowercase-keys": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", "dev": true, "license": "MIT", "engines": { @@ -8431,8 +7517,6 @@ }, "node_modules/lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", "dependencies": { @@ -8463,8 +7547,6 @@ }, "node_modules/make-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { @@ -8479,15 +7561,11 @@ }, "node_modules/make-error": { "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, "license": "ISC" }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8495,8 +7573,6 @@ }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -8504,8 +7580,6 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { "node": ">=18" @@ -8516,15 +7590,11 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "license": "MIT", "engines": { @@ -8533,8 +7603,6 @@ }, "node_modules/micromatch": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { @@ -8547,8 +7615,6 @@ }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -8556,8 +7622,6 @@ }, "node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -8572,8 +7636,6 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "license": "MIT", "engines": { "node": ">=6" @@ -8593,8 +7655,6 @@ }, "node_modules/mimic-response": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "license": "MIT", "engines": { "node": ">=10" @@ -8605,8 +7665,6 @@ }, "node_modules/minimatch": { "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "license": "ISC", "dependencies": { @@ -8621,8 +7679,6 @@ }, "node_modules/minimist": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8640,14 +7696,10 @@ }, "node_modules/mkdirp-classic": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "license": "MIT" }, "node_modules/mri": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "license": "MIT", "engines": { "node": ">=4" @@ -8655,8 +7707,6 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/mute-stream": { @@ -8689,21 +7739,15 @@ }, "node_modules/napi-build-utils": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, "license": "MIT" }, "node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -8711,8 +7755,6 @@ }, "node_modules/node-abi": { "version": "3.87.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz", - "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", "license": "MIT", "dependencies": { "semver": "^7.3.5" @@ -8723,8 +7765,6 @@ }, "node_modules/node-fetch": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" @@ -8743,15 +7783,11 @@ }, "node_modules/node-releases": { "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", "engines": { @@ -8760,8 +7796,6 @@ }, "node_modules/normalize-url": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", - "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", "dev": true, "license": "MIT", "engines": { @@ -8773,8 +7807,6 @@ }, "node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "license": "MIT", "dependencies": { @@ -8786,8 +7818,6 @@ }, "node_modules/nx": { "version": "22.6.5", - "resolved": "https://registry.npmjs.org/nx/-/nx-22.6.5.tgz", - "integrity": "sha512-VRKhDAt684dXNSz9MNjE7MekkCfQF41P2PSx5jEWQjDEP1Z4jFZbyeygWs5ZyOroG7/n0MoWAJTe6ftvIcBOAg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -8860,8 +7890,6 @@ }, "node_modules/nx/node_modules/balanced-match": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", "engines": { @@ -8870,8 +7898,6 @@ }, "node_modules/nx/node_modules/brace-expansion": { "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8883,8 +7909,6 @@ }, "node_modules/nx/node_modules/cli-spinners": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", "dev": true, "license": "MIT", "engines": { @@ -8896,8 +7920,6 @@ }, "node_modules/nx/node_modules/ignore": { "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { @@ -8906,8 +7928,6 @@ }, "node_modules/nx/node_modules/lines-and-columns": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", - "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", "dev": true, "license": "MIT", "engines": { @@ -8916,8 +7936,6 @@ }, "node_modules/nx/node_modules/minimatch": { "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -8932,8 +7950,6 @@ }, "node_modules/nx/node_modules/ora": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", "dev": true, "license": "MIT", "dependencies": { @@ -8955,8 +7971,6 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8964,8 +7978,6 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -8976,8 +7988,6 @@ }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -8988,8 +7998,6 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -8997,8 +8005,6 @@ }, "node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -9012,8 +8018,6 @@ }, "node_modules/open": { "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9030,8 +8034,6 @@ }, "node_modules/optionator": { "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { @@ -9048,8 +8050,6 @@ }, "node_modules/ora": { "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "license": "MIT", "dependencies": { "bl": "^4.1.0", @@ -9071,8 +8071,6 @@ }, "node_modules/p-cancelable": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", "dev": true, "license": "MIT", "engines": { @@ -9081,8 +8079,6 @@ }, "node_modules/p-limit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9097,8 +8093,6 @@ }, "node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { @@ -9113,8 +8107,6 @@ }, "node_modules/p-timeout": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-4.1.0.tgz", - "integrity": "sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw==", "license": "MIT", "engines": { "node": ">=10" @@ -9129,8 +8121,6 @@ }, "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { @@ -9142,8 +8132,6 @@ }, "node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -9161,17 +8149,22 @@ }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/patch-console": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", + "integrity": "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", "engines": { @@ -9180,8 +8173,6 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", "engines": { @@ -9190,8 +8181,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" @@ -9199,8 +8188,6 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, "license": "MIT" }, @@ -9230,8 +8217,6 @@ }, "node_modules/path-to-regexp": { "version": "8.4.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.1.tgz", - "integrity": "sha512-fvU78fIjZ+SBM9YwCknCvKOUKkLVqtWDVctl0s7xIqfmfb38t2TT4ZU2gHm+Z8xGwgW+QWEU3oQSAzIbo89Ggw==", "license": "MIT", "funding": { "type": "opencollective", @@ -9240,8 +8225,6 @@ }, "node_modules/path-type": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, "license": "MIT", "engines": { @@ -9267,22 +8250,16 @@ }, "node_modules/pend": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -9294,8 +8271,6 @@ }, "node_modules/piscina": { "version": "4.9.2", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.9.2.tgz", - "integrity": "sha512-Fq0FERJWFEUpB4eSY59wSNwXD4RYqR+nR/WiEVcZW8IWfVBxJJafcgTEZDQo8k3w0sUarJ8RyVbbUF4GQ2LGbQ==", "dev": true, "license": "MIT", "optionalDependencies": { @@ -9304,8 +8279,6 @@ }, "node_modules/pkce-challenge": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "license": "MIT", "engines": { "node": ">=16.20.0" @@ -9342,8 +8315,6 @@ }, "node_modules/prebuild-install": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "license": "MIT", "dependencies": { "detect-libc": "^2.0.0", @@ -9368,8 +8339,6 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", "engines": { @@ -9378,8 +8347,6 @@ }, "node_modules/pretty-format": { "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -9393,8 +8360,6 @@ }, "node_modules/pretty-format/node_modules/@jest/schemas": { "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", "dev": true, "license": "MIT", "dependencies": { @@ -9406,15 +8371,11 @@ }, "node_modules/pretty-format/node_modules/@sinclair/typebox": { "version": "0.34.41", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", - "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", "dev": true, "license": "MIT" }, "node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -9426,8 +8387,6 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -9439,8 +8398,6 @@ }, "node_modules/proxy-from-env": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", "dev": true, "license": "MIT", "engines": { @@ -9449,8 +8406,6 @@ }, "node_modules/pump": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -9459,8 +8414,6 @@ }, "node_modules/punycode": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { @@ -9469,8 +8422,6 @@ }, "node_modules/qs": { "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -9484,8 +8435,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -9505,8 +8454,6 @@ }, "node_modules/quick-lru": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true, "license": "MIT", "engines": { @@ -9518,8 +8465,6 @@ }, "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -9527,8 +8472,6 @@ }, "node_modules/raw-body": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -9542,8 +8485,6 @@ }, "node_modules/rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", @@ -9557,8 +8498,15 @@ }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9566,15 +8514,26 @@ }, "node_modules/react-is": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, + "node_modules/react-reconciler": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.33.0.tgz", + "integrity": "sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -9587,8 +8546,6 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", "dependencies": { @@ -9600,15 +8557,11 @@ }, "node_modules/regenerate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true, "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "dev": true, "license": "MIT", "dependencies": { @@ -9620,8 +8573,6 @@ }, "node_modules/regexpu-core": { "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", "dev": true, "license": "MIT", "dependencies": { @@ -9638,15 +8589,11 @@ }, "node_modules/regjsgen": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", "dev": true, "license": "MIT" }, "node_modules/regjsparser": { "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -9658,8 +8605,6 @@ }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "license": "MIT", "engines": { @@ -9668,8 +8613,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9677,8 +8620,6 @@ }, "node_modules/resolve": { "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9698,15 +8639,11 @@ }, "node_modules/resolve-alpn": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", "dev": true, "license": "MIT" }, "node_modules/resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "engines": { @@ -9715,8 +8652,6 @@ }, "node_modules/resolve.exports": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", "dev": true, "license": "MIT", "engines": { @@ -9725,8 +8660,6 @@ }, "node_modules/responselike": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", "dev": true, "license": "MIT", "dependencies": { @@ -9741,8 +8674,6 @@ }, "node_modules/restore-cursor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "license": "MIT", "dependencies": { "onetime": "^5.1.0", @@ -9754,8 +8685,6 @@ }, "node_modules/reusify": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { @@ -9765,9 +8694,6 @@ }, "node_modules/rimraf": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -9834,8 +8760,6 @@ }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -9859,8 +8783,6 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -9883,8 +8805,6 @@ }, "node_modules/rxjs": { "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" @@ -9892,8 +8812,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -9912,8 +8830,6 @@ }, "node_modules/safe-compare": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/safe-compare/-/safe-compare-1.1.4.tgz", - "integrity": "sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ==", "license": "MIT", "dependencies": { "buffer-alloc": "^1.2.0" @@ -9921,23 +8837,23 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/sandwich-stream": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sandwich-stream/-/sandwich-stream-2.0.2.tgz", - "integrity": "sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ==", "license": "Apache-2.0", "engines": { "node": ">= 0.10" } }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, "node_modules/section-matter": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", @@ -9949,8 +8865,6 @@ }, "node_modules/seek-bzip": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-2.0.0.tgz", - "integrity": "sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg==", "dev": true, "license": "MIT", "dependencies": { @@ -9963,8 +8877,6 @@ }, "node_modules/seek-bzip/node_modules/commander": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true, "license": "MIT", "engines": { @@ -9973,8 +8885,6 @@ }, "node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -9985,8 +8895,6 @@ }, "node_modules/semver-regex": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", "dev": true, "license": "MIT", "engines": { @@ -9998,8 +8906,6 @@ }, "node_modules/semver-truncate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", - "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -10014,8 +8920,6 @@ }, "node_modules/send": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { "debug": "^4.4.3", @@ -10040,8 +8944,6 @@ }, "node_modules/serve-static": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -10059,14 +8961,10 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -10077,8 +8975,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" @@ -10086,8 +8982,6 @@ }, "node_modules/side-channel": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -10105,8 +8999,6 @@ }, "node_modules/side-channel-list": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -10121,8 +9013,6 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -10139,8 +9029,6 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -10165,14 +9053,10 @@ }, "node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, "node_modules/simple-concat": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", "funding": [ { "type": "github", @@ -10191,8 +9075,6 @@ }, "node_modules/simple-get": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "funding": [ { "type": "github", @@ -10216,18 +9098,57 @@ }, "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-9.0.0.tgz", + "integrity": "sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/smol-toml": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", - "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -10238,8 +9159,6 @@ }, "node_modules/sort-keys": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", "dev": true, "license": "MIT", "dependencies": { @@ -10251,8 +9170,6 @@ }, "node_modules/sort-keys-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", "dev": true, "license": "MIT", "dependencies": { @@ -10264,8 +9181,6 @@ }, "node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -10284,10 +9199,25 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, + "node_modules/stack-utils": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -10297,8 +9227,6 @@ }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -10325,8 +9253,6 @@ }, "node_modules/streamx": { "version": "2.23.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", - "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", "dev": true, "license": "MIT", "dependencies": { @@ -10337,8 +9263,6 @@ }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -10346,8 +9270,6 @@ }, "node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -10376,8 +9298,6 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -10402,8 +9322,6 @@ }, "node_modules/strip-bom-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10411,8 +9329,6 @@ }, "node_modules/strip-dirs": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-3.0.0.tgz", - "integrity": "sha512-I0sdgcFTfKQlUPZyAqPJmSG3HLO9rWDFnxonnIbskYNM3DwFOeTNB5KzVq3dA1GdRAc/25b5Y7UO2TQfKWw4aQ==", "dev": true, "license": "ISC", "dependencies": { @@ -10422,8 +9338,6 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "license": "MIT", "engines": { @@ -10432,8 +9346,6 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { @@ -10445,8 +9357,6 @@ }, "node_modules/strtok3": { "version": "10.3.4", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz", - "integrity": "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==", "dev": true, "license": "MIT", "dependencies": { @@ -10462,8 +9372,6 @@ }, "node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -10474,8 +9382,6 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", "engines": { @@ -10485,10 +9391,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tar-fs": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "license": "MIT", "dependencies": { "chownr": "^1.1.1", @@ -10499,8 +9415,6 @@ }, "node_modules/tar-stream": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -10515,8 +9429,6 @@ }, "node_modules/telegraf": { "version": "4.16.3", - "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.16.3.tgz", - "integrity": "sha512-yjEu2NwkHlXu0OARWoNhJlIjX09dRktiMQFsM678BAH/PEPVwctzL67+tvXqLCRQQvm3SDtki2saGO9hLlz68w==", "license": "MIT", "dependencies": { "@telegraf/types": "^7.1.0", @@ -10535,10 +9447,20 @@ "node": "^12.20.0 || >=14.13.1" } }, + "node_modules/terminal-size": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/terminal-size/-/terminal-size-4.0.1.tgz", + "integrity": "sha512-avMLDQpUI9I5XFrklECw1ZEUPJhqzcwSWsyyI8blhRLT+8N1jLJWLWWYQpB2q2xthq8xDvjZPISVh53T/+CLYQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/text-decoder": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -10547,15 +9469,11 @@ }, "node_modules/text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, "license": "MIT" }, "node_modules/through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true, "license": "MIT" }, @@ -10575,8 +9493,6 @@ }, "node_modules/tinyglobby": { "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10592,8 +9508,6 @@ }, "node_modules/tinyglobby/node_modules/fdir": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", "engines": { @@ -10610,8 +9524,6 @@ }, "node_modules/tinyglobby/node_modules/picomatch": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -10653,8 +9565,6 @@ }, "node_modules/tmp": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "license": "MIT", "engines": { @@ -10663,8 +9573,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10676,8 +9584,6 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" @@ -10685,8 +9591,6 @@ }, "node_modules/token-types": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", - "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", "dev": true, "license": "MIT", "dependencies": { @@ -10704,14 +9608,10 @@ }, "node_modules/tr46": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, "node_modules/tree-kill": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, "license": "MIT", "bin": { @@ -10720,8 +9620,6 @@ }, "node_modules/ts-api-utils": { "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "license": "MIT", "engines": { @@ -10733,8 +9631,6 @@ }, "node_modules/ts-node": { "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10777,8 +9673,6 @@ }, "node_modules/tsconfig-paths": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, "license": "MIT", "dependencies": { @@ -10792,8 +9686,6 @@ }, "node_modules/tsconfig-paths/node_modules/strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { @@ -10802,14 +9694,10 @@ }, "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/tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -10820,8 +9708,6 @@ }, "node_modules/type-check": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", "dependencies": { @@ -10833,8 +9719,6 @@ }, "node_modules/type-fest": { "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -10846,8 +9730,6 @@ }, "node_modules/type-is": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { "content-type": "^1.0.5", @@ -10860,8 +9742,6 @@ }, "node_modules/typescript": { "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -10874,8 +9754,6 @@ }, "node_modules/uint8array-extras": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", - "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", "dev": true, "license": "MIT", "engines": { @@ -10887,8 +9765,6 @@ }, "node_modules/unbzip2-stream": { "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dev": true, "license": "MIT", "dependencies": { @@ -10898,15 +9774,11 @@ }, "node_modules/undici-types": { "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/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "license": "MIT", "engines": { @@ -10915,8 +9787,6 @@ }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10929,8 +9799,6 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", "dev": true, "license": "MIT", "engines": { @@ -10939,8 +9807,6 @@ }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", "dev": true, "license": "MIT", "engines": { @@ -10949,8 +9815,6 @@ }, "node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -10958,8 +9822,6 @@ }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -10967,8 +9829,6 @@ }, "node_modules/update-browserslist-db": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -10998,8 +9858,6 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -11008,14 +9866,10 @@ }, "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==", "license": "MIT" }, "node_modules/uuid": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -11027,15 +9881,11 @@ }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, "license": "MIT" }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -11192,8 +10042,6 @@ }, "node_modules/wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "license": "MIT", "dependencies": { "defaults": "^1.0.3" @@ -11201,14 +10049,10 @@ }, "node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "license": "BSD-2-Clause" }, "node_modules/whatwg-url": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "license": "MIT", "dependencies": { "tr46": "~0.0.3", @@ -11217,8 +10061,6 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -11247,10 +10089,66 @@ "node": ">=8" } }, + "node_modules/widest-line": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-6.0.0.tgz", + "integrity": "sha512-U89AsyEeAsyoF0zVJBkG9zBgekjgjK7yk9sje3F4IQpXBJ10TF6ByLlIfjMhcmHMJgHZI4KHt4rdNfktzxIAMA==", + "license": "MIT", + "dependencies": { + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/word-wrap": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { @@ -11259,8 +10157,6 @@ }, "node_modules/wrap-ansi": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -11292,14 +10188,31 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "license": "ISC", "engines": { @@ -11308,15 +10221,11 @@ }, "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, "node_modules/yaml": { "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -11330,8 +10239,6 @@ }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", "dependencies": { @@ -11349,8 +10256,6 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", "engines": { @@ -11359,8 +10264,6 @@ }, "node_modules/yauzl": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.3.0.tgz", - "integrity": "sha512-PtGEvEP30p7sbIBJKUBjUnqgTVOyMURc4dLo9iNyAJnNIEz9pm88cCXF21w94Kg3k6RXkeZh5DHOGS0qEONvNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11373,8 +10276,6 @@ }, "node_modules/yn": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, "license": "MIT", "engines": { @@ -11383,8 +10284,6 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { @@ -11418,10 +10317,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoga-layout": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", + "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==", + "license": "MIT" + }, "node_modules/zod": { "version": "4.3.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", - "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -11429,8 +10332,6 @@ }, "node_modules/zod-to-json-schema": { "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", "license": "ISC", "peerDependencies": { "zod": "^3.25 || ^4" @@ -11480,8 +10381,6 @@ }, "packages/channel-connector/node_modules/marked": { "version": "15.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", - "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -11503,8 +10402,11 @@ "debug": "^4.4.3", "fs-extra": "^11.2.0", "gray-matter": "^4.0.3", + "ink": "^7.0.4", + "ink-text-input": "^6.0.0", "inquirer": "^9.3.0", "ora": "^9.0.0", + "react": "^19.2.0", "smol-toml": "^1.6.1", "yaml": "^2.3.4", "zod": "^3.25.76" @@ -11517,6 +10419,7 @@ "@types/fs-extra": "^11.0.4", "@types/inquirer": "^9.0.0", "@types/node": "^20.11.5", + "@types/react": "^19.2.0", "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.19.1", "@vitest/coverage-v8": "^2.1.0", @@ -11718,8 +10621,6 @@ }, "packages/cli/node_modules/zod": { "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/packages/agent-manager/src/AgentManager.ts b/packages/agent-manager/src/AgentManager.ts index 7800c208..e7d98fcc 100644 --- a/packages/agent-manager/src/AgentManager.ts +++ b/packages/agent-manager/src/AgentManager.ts @@ -11,7 +11,15 @@ import type { SessionSummary, ListSessionsOptions, } from './adapters/AgentAdapter.js'; -import { AgentStatus } from './adapters/AgentAdapter.js'; +import { sortAgents, type AgentSortKey } from './utils/sortAgents.js'; + +export interface ListAgentsOptions { + /** + * Sort key for the returned list. Defaults to `status`, which orders + * waiting → running → idle → unknown, then by name for stability. + */ + sortBy?: AgentSortKey; +} /** * Agent Manager Class @@ -108,7 +116,7 @@ export class AgentManager { * }); * ``` */ - async listAgents(): Promise { + async listAgents(options?: ListAgentsOptions): Promise { const allAgents: AgentInfo[] = []; const errors: Array<{ type: string; error: Error }> = []; @@ -142,8 +150,8 @@ export class AgentManager { }); } - // Sort by status priority (waiting first, then running, then idle) - return this.sortAgentsByStatus(allAgents); + const sortKey: AgentSortKey = options?.sortBy ?? 'status'; + return sortAgents(allAgents, sortKey); } /** @@ -193,29 +201,6 @@ export class AgentManager { return merged; } - /** - * Sort agents by status priority - * - * Priority order: waiting > running > idle > unknown - * This ensures agents that need attention appear first. - * - * @param agents Array of agents to sort - * @returns Sorted array of agents - */ - private sortAgentsByStatus(agents: AgentInfo[]): AgentInfo[] { - const statusPriority: Record = { - [AgentStatus.WAITING]: 0, - [AgentStatus.RUNNING]: 1, - [AgentStatus.IDLE]: 2, - [AgentStatus.UNKNOWN]: 3, - }; - - return agents.sort((a, b) => { - const priorityA = statusPriority[a.status] ?? 999; - const priorityB = statusPriority[b.status] ?? 999; - return priorityA - priorityB; - }); - } /** * Get count of registered adapters diff --git a/packages/agent-manager/src/index.ts b/packages/agent-manager/src/index.ts index d80e19e0..6aa0991c 100644 --- a/packages/agent-manager/src/index.ts +++ b/packages/agent-manager/src/index.ts @@ -20,3 +20,5 @@ export type { TerminalLocation } from './terminal/TerminalFocusManager.js'; export { TtyWriter } from './terminal/TtyWriter.js'; export { getProcessTty } from './utils/process.js'; +export type { AgentSortKey } from './utils/sortAgents.js'; +export type { ListAgentsOptions } from './AgentManager.js'; diff --git a/packages/agent-manager/src/utils/sortAgents.ts b/packages/agent-manager/src/utils/sortAgents.ts new file mode 100644 index 00000000..cc0bacd3 --- /dev/null +++ b/packages/agent-manager/src/utils/sortAgents.ts @@ -0,0 +1,52 @@ +import { AgentStatus, type AgentInfo } from '../adapters/AgentAdapter.js'; + +export type AgentSortKey = 'name' | 'status' | 'pid' | 'lastActive'; + +const STATUS_PRIORITY: Record = { + [AgentStatus.WAITING]: 0, + [AgentStatus.RUNNING]: 1, + [AgentStatus.IDLE]: 2, + [AgentStatus.UNKNOWN]: 3, +}; + +function compareByName(a: AgentInfo, b: AgentInfo): number { + return a.name.localeCompare(b.name); +} + +function compareByStatus(a: AgentInfo, b: AgentInfo): number { + const pa = STATUS_PRIORITY[a.status] ?? 999; + const pb = STATUS_PRIORITY[b.status] ?? 999; + if (pa !== pb) return pa - pb; + return compareByName(a, b); +} + +function compareByPid(a: AgentInfo, b: AgentInfo): number { + if (a.pid !== b.pid) return a.pid - b.pid; + return compareByName(a, b); +} + +function compareByLastActive(a: AgentInfo, b: AgentInfo): number { + const ta = a.lastActive instanceof Date ? a.lastActive.getTime() : new Date(a.lastActive).getTime(); + const tb = b.lastActive instanceof Date ? b.lastActive.getTime() : new Date(b.lastActive).getTime(); + if (tb !== ta) return tb - ta; // most recent first + return compareByName(a, b); +} + +export function sortAgents(agents: AgentInfo[], by: AgentSortKey): AgentInfo[] { + const copy = agents.slice(); + switch (by) { + case 'name': + copy.sort(compareByName); + break; + case 'status': + copy.sort(compareByStatus); + break; + case 'pid': + copy.sort(compareByPid); + break; + case 'lastActive': + copy.sort(compareByLastActive); + break; + } + return copy; +} diff --git a/packages/cli/package.json b/packages/cli/package.json index db041db1..1c88f15a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -36,8 +36,11 @@ "debug": "^4.4.3", "fs-extra": "^11.2.0", "gray-matter": "^4.0.3", + "ink": "^7.0.4", + "ink-text-input": "^6.0.0", "inquirer": "^9.3.0", "ora": "^9.0.0", + "react": "^19.2.0", "smol-toml": "^1.6.1", "yaml": "^2.3.4", "zod": "^3.25.76" @@ -47,6 +50,7 @@ "@types/fs-extra": "^11.0.4", "@types/inquirer": "^9.0.0", "@types/node": "^20.11.5", + "@types/react": "^19.2.0", "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.19.1", "@vitest/coverage-v8": "^2.1.0", diff --git a/packages/cli/src/commands/agent.ts b/packages/cli/src/commands/agent.ts index 3371f89f..608ceb21 100644 --- a/packages/cli/src/commands/agent.ts +++ b/packages/cli/src/commands/agent.ts @@ -1,7 +1,9 @@ import os from 'os'; +import { createElement } from 'react'; import { Command } from 'commander'; import chalk from 'chalk'; import inquirer from 'inquirer'; +import { render } from 'ink'; import { AgentManager, type AgentAdapter, @@ -27,6 +29,8 @@ import { } from '../util/sessions.js'; import { waitForAgentResponse } from '../services/agent/agent.service.js'; import { parseMilliseconds } from '../util/time.js'; +import { WatchApp } from '../tui/watch/WatchApp.js'; +import { runAction } from '../tui/watch/actions/runAction.js'; const AGENT_SEND_WAIT_POLL_INTERVAL_MS = 2000; const AGENT_SEND_WAIT_MAX_WAIT_MS = 10 * 60 * 1000; @@ -673,4 +677,49 @@ export function registerAgentCommand(program: Command): void { ui.breakline(); renderConversationDetail(displayMessages, conversation.length, isTruncated); })); + + agentCommand + .command('watch') + .description('Live multi-agent monitor (interactive TUI)') + .action(withErrorHandler('agent watch', async () => { + if (!process.stdout.isTTY) { + ui.error('agent watch requires an interactive terminal (TTY).'); + process.exit(1); + } + const manager = createAgentManager(); + + let lastSelection: string | null = null; + let pendingAction: { type: 'open' | 'send'; agentName: string; message?: string } | null = null; + let transient: { kind: 'info' | 'error'; text: string } | null = null; + + // Loop: render TUI → user triggers action → TUI exits with pendingAction → + // run action (stdio inherit) → re-enter TUI with preserved selection. + // Ink 7 manages alt-screen and stdin lifecycle via alternateScreen: true. + // eslint-disable-next-line no-constant-condition + while (true) { + pendingAction = null; + const onIntent = (intent: { type: 'open' | 'send'; agentName: string; message?: string }) => { + pendingAction = intent; + lastSelection = intent.agentName; + }; + const { waitUntilExit } = render( + createElement(WatchApp, { + manager, + initialSelection: lastSelection, + onIntent, + transientMessage: transient, + }), + { alternateScreen: true, exitOnCtrlC: true }, + ); + await waitUntilExit(); + transient = null; + if (!pendingAction) break; + const result = await runAction(pendingAction); + if (result.error) { + transient = { kind: 'error', text: `action failed: ${result.error}` }; + } else if (result.exitCode !== 0 && result.exitCode !== null) { + transient = { kind: 'error', text: `action exited ${result.exitCode}` }; + } + } + })); } diff --git a/packages/cli/src/lib/Config.ts b/packages/cli/src/lib/Config.ts index 10204bd0..75ec43a2 100644 --- a/packages/cli/src/lib/Config.ts +++ b/packages/cli/src/lib/Config.ts @@ -94,7 +94,7 @@ export class ConfigManager { } async getMemoryDbPath(): Promise { - const config = await this.read() as any; + const config = await this.read(); const configuredPath = config?.memory?.path; if (typeof configuredPath !== 'string') { diff --git a/packages/cli/src/lib/SkillManager.ts b/packages/cli/src/lib/SkillManager.ts index 6ff81529..bbcb5349 100644 --- a/packages/cli/src/lib/SkillManager.ts +++ b/packages/cli/src/lib/SkillManager.ts @@ -13,6 +13,7 @@ import { validateRegistryId, validateSkillName, extractSkillDescription, isValid import { isInteractiveTerminal } from '../util/terminal.js'; import { ui } from '../util/terminal-ui.js'; import { ConfigNotFoundError, NotFoundError, ValidationError } from '../util/errors.js'; +import type { EnvironmentCode } from '../types.js'; import type { UpdateSummary } from './SkillRegistry.js'; import type { SkillEntry } from './SkillIndex.js'; @@ -258,7 +259,7 @@ export class SkillManager { const capableEnvironments: string[] = []; for (const env of environments) { - const skillPath = isGlobal ? getGlobalSkillPath(env as any) : getSkillPath(env as any); + const skillPath = isGlobal ? getGlobalSkillPath(env as EnvironmentCode) : getSkillPath(env as EnvironmentCode); if (skillPath) { targets.push(skillPath); capableEnvironments.push(env); diff --git a/packages/cli/src/services/install/install.service.ts b/packages/cli/src/services/install/install.service.ts index 05813510..28b95104 100644 --- a/packages/cli/src/services/install/install.service.ts +++ b/packages/cli/src/services/install/install.service.ts @@ -5,6 +5,7 @@ import { SkillManager } from '../../lib/SkillManager.js'; import { TemplateManager } from '../../lib/TemplateManager.js'; import { InstallConfigData } from '../../util/config.js'; import { installMcpServers, McpInstallReport } from './mcp/index.js'; +import type { DevKitConfig } from '../../types.js'; export interface InstallRunOptions { overwrite?: boolean; @@ -130,7 +131,7 @@ export async function reconcileAndInstall( } } - const updates: Record = {}; + const updates: Partial = {}; if (successfulEnvironments.length > 0) { updates.environments = successfulEnvironments; } @@ -146,7 +147,7 @@ export async function reconcileAndInstall( if (config.mcpServers && Object.keys(config.mcpServers).length > 0) { updates.mcpServers = config.mcpServers; } - await configManager.update(updates as any); + await configManager.update(updates); return report; } diff --git a/packages/cli/src/tui/watch/AgentListPane.tsx b/packages/cli/src/tui/watch/AgentListPane.tsx new file mode 100644 index 00000000..7e9c85f9 --- /dev/null +++ b/packages/cli/src/tui/watch/AgentListPane.tsx @@ -0,0 +1,128 @@ +import React, { useEffect } from 'react'; +import { Box, Text } from 'ink'; +import type { AgentInfo } from '@ai-devkit/agent-manager'; +import { FormatStatus } from './render/formatStatus.js'; + +interface AgentListPaneProps { + agents: AgentInfo[]; + selectedName: string | null; + onSelect: (name: string | null) => void; + width?: number; + error?: string | null; + focused?: boolean; +} + +function clip(s: string | undefined, max: number): string { + const text = (s ?? '').replace(/\n/g, ' ').trimEnd(); + if (max <= 0) return ''; + if (text.length <= max) return text; + return text.slice(0, max - 1) + '…'; +} + +function shortPath(p: string): string { + const home = process.env.HOME ?? ''; + return home && p.startsWith(home) ? '~' + p.slice(home.length) : p; +} + +// Fixed column widths inside each row (excluding outer marker). +const MARKER_W = 2; // "▶ " or " " +const STATUS_W = 7; // "● run " — glyph(1) + space(1) + label(4) + trailing space(1) +const ROW_CHROME = MARKER_W + STATUS_W; + +interface AgentRowProps { + agent: AgentInfo; + isSelected: boolean; + innerWidth: number; +} + +const AgentRow: React.FC = ({ agent, isSelected, innerWidth }) => { + const nameW = Math.max(4, innerWidth - ROW_CHROME); + const summaryW = Math.max(4, innerWidth - MARKER_W); // summary indented by marker only + + const rawSummary = agent.summary?.trim() + ? agent.summary + : shortPath(agent.projectPath); + const summary = clip(rawSummary, summaryW); + const name = clip(agent.name, nameW); + + const accent = isSelected ? 'cyan' : undefined; + + return ( + + {/* Line 1: marker · status · name */} + + + {isSelected ? '▶ ' : ' '} + + + + + + {name} + + + {/* Line 2: summary / project path, indented under status */} + + + + {summary} + + + + ); +}; + +const AgentListPaneInner: React.FC = ({ + agents, + selectedName, + onSelect, + width, + error, +}) => { + useEffect(() => { + if (agents.length === 0) { + if (selectedName !== null) onSelect(null); + return; + } + const exists = agents.some(a => a.name === selectedName); + if (!exists) onSelect(agents[0].name); + }, [agents, selectedName, onSelect]); + + const innerWidth = Math.max(16, width ?? 44); + + if (error && agents.length === 0) { + return ( + + AGENTS + {clip(error, innerWidth)} + + ); + } + + if (agents.length === 0) { + return ( + + AGENTS + No running agents. + + ); + } + + return ( + + + AGENTS ({agents.length}) + + {agents.map((agent) => ( + + ))} + + ); +}; + +export const AgentListPane = React.memo(AgentListPaneInner); diff --git a/packages/cli/src/tui/watch/ChatInput.tsx b/packages/cli/src/tui/watch/ChatInput.tsx new file mode 100644 index 00000000..511fbe72 --- /dev/null +++ b/packages/cli/src/tui/watch/ChatInput.tsx @@ -0,0 +1,82 @@ +import { memo, useEffect, useRef } from 'react'; +import type { FC } from 'react'; +import { Box, Text } from 'ink'; +import TextInput from 'ink-text-input'; + +interface ChatInputProps { + focused: boolean; + value: string; + onChange: (value: string) => void; + onSubmit: (text: string) => void; + onCancel: () => void; + /** Inner width available for text content (after borders + padding + "> "). */ + innerWidth: number; + /** Called with the rendered line count whenever it changes. */ + onLineCountChange: (lines: number) => void; +} + +const MIN_LINES = 1; +const MAX_LINES = 6; + +function computeLines(value: string, usableWidth: number): number { + if (usableWidth <= 0) return MIN_LINES; + const len = Math.max(1, value.length + 1); + return Math.min(MAX_LINES, Math.max(MIN_LINES, Math.ceil(len / usableWidth))); +} + +const ChatInputInner: FC = ({ + focused, + value, + onChange, + onSubmit, + onCancel, + innerWidth, + onLineCountChange, +}) => { + const lastLinesRef = useRef(MIN_LINES); + const onLineCountChangeRef = useRef(onLineCountChange); + onLineCountChangeRef.current = onLineCountChange; + + useEffect(() => { + const promptWidth = 2; // "> " + const usable = Math.max(1, innerWidth - promptWidth); + const lines = computeLines(value, usable); + if (lines !== lastLinesRef.current) { + lastLinesRef.current = lines; + onLineCountChangeRef.current(lines); + } + }, [value, innerWidth]); + + const handleSubmit = (text: string): void => { + const trimmed = text.trim(); + onChange(''); + if (trimmed.length === 0) { + onCancel(); + return; + } + onSubmit(trimmed); + }; + + if (!focused) { + return ( + + {'> '} + press i to type a message + + ); + } + + return ( + + {'> '} + + + ); +}; + +export const ChatInput = memo(ChatInputInner); diff --git a/packages/cli/src/tui/watch/FooterSection.tsx b/packages/cli/src/tui/watch/FooterSection.tsx new file mode 100644 index 00000000..a4ed1267 --- /dev/null +++ b/packages/cli/src/tui/watch/FooterSection.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { StatusFooter } from './StatusFooter.js'; +import { useWatchContext } from './state/WatchContext.js'; + +interface FooterSectionProps { + selectedName: string | null; + narrowNote: string | null; + transient: { kind: 'info' | 'error'; text: string } | null; +} + +const FooterSectionInner: React.FC = ({ selectedName, narrowNote, transient }) => { + const { agents, lastUpdated, isLoading } = useWatchContext(); + const selected = agents.find(a => a.name === selectedName) ?? null; + return ( + + ); +}; + +export const FooterSection = React.memo(FooterSectionInner); diff --git a/packages/cli/src/tui/watch/HeaderBar.tsx b/packages/cli/src/tui/watch/HeaderBar.tsx new file mode 100644 index 00000000..d88ebae1 --- /dev/null +++ b/packages/cli/src/tui/watch/HeaderBar.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Box, Text } from 'ink'; +import { useWatchContext } from './state/WatchContext.js'; + +const HeaderBarInner: React.FC = () => { + const { agents, isLoading } = useWatchContext(); + const totalLabel = isLoading && agents.length === 0 ? 'scanning…' : `${agents.length} agent${agents.length === 1 ? '' : 's'}`; + return ( + + ai-devkit + · + agent watch + {totalLabel} + + ); +}; + +export const HeaderBar = React.memo(HeaderBarInner); diff --git a/packages/cli/src/tui/watch/ListSection.tsx b/packages/cli/src/tui/watch/ListSection.tsx new file mode 100644 index 00000000..f688f22b --- /dev/null +++ b/packages/cli/src/tui/watch/ListSection.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { Box } from 'ink'; +import { AgentListPane } from './AgentListPane.js'; +import { useWatchContext } from './state/WatchContext.js'; + +interface ListSectionProps { + selectedName: string | null; + onSelect: (name: string | null) => void; + focused: boolean; + width: number; + height: number; +} + +const ListSectionInner: React.FC = ({ selectedName, onSelect, focused, width, height }) => { + const { agents, error } = useWatchContext(); + return ( + + + + ); +}; + +export const ListSection = React.memo(ListSectionInner); diff --git a/packages/cli/src/tui/watch/PreviewPane.tsx b/packages/cli/src/tui/watch/PreviewPane.tsx new file mode 100644 index 00000000..eb558d9b --- /dev/null +++ b/packages/cli/src/tui/watch/PreviewPane.tsx @@ -0,0 +1,140 @@ +import React from 'react'; +import { Box, Text } from 'ink'; +import type { AgentInfo, ConversationMessage } from '@ai-devkit/agent-manager'; +import type { ConversationFetchError } from './hooks/useAgentConversation.js'; + +interface PreviewPaneProps { + agent: AgentInfo | null; + messages: ConversationMessage[]; + error: ConversationFetchError | null; + isLoading: boolean; + maxLines?: number; +} + +const ROLE_COLOR: Record = { + user: 'green', + assistant: 'cyan', + system: 'yellow', +}; + +const TYPE_LABEL: Record = { + claude: 'Claude', + codex: 'Codex', + gemini_cli: 'Gemini', + opencode: 'OpenCode', +}; + +function formatTime(ts: string | undefined): string { + if (!ts) return ''; + try { + return new Date(ts).toLocaleTimeString(); + } catch { + return ''; + } +} + +function formatRelative(date: Date | string | undefined): string { + if (!date) return '—'; + const d = typeof date === 'string' ? new Date(date) : date; + const diffMs = Date.now() - d.getTime(); + const sec = Math.max(0, Math.floor(diffMs / 1000)); + if (sec < 5) return 'now'; + if (sec < 60) return `${sec}s ago`; + const min = Math.floor(sec / 60); + if (min < 60) return `${min}m ago`; + const hr = Math.floor(min / 60); + if (hr < 24) return `${hr}h ago`; + return `${Math.floor(hr / 24)}d ago`; +} + +function shortPath(p: string): string { + const home = process.env.HOME ?? ''; + if (home && p.startsWith(home)) return '~' + p.slice(home.length); + return p; +} + +const MetadataHeader: React.FC<{ agent: AgentInfo }> = ({ agent }) => ( + + PREVIEW + · + {agent.name} + · + {TYPE_LABEL[agent.type] ?? agent.type} + · + {formatRelative(agent.lastActive)} + · + {shortPath(agent.projectPath)} + +); + +const PreviewPaneInner: React.FC = ({ + agent, + messages, + error, + isLoading, + maxLines = 22, +}) => { + if (!agent) { + return ( + + PREVIEW + No agent selected. + + ); + } + + const messageBudget = Math.max(4, maxLines); + + let body: React.ReactNode; + if (error) { + const detail = error.kind === 'no-session-file' + ? 'No session file available for this agent yet.' + : error.kind === 'no-adapter' + ? `Unsupported agent type: ${agent.type}.` + : `Could not read session file: ${error.message}`; + body = {detail}; + } else if (isLoading && messages.length === 0) { + body = loading…; + } else if (messages.length === 0) { + body = No messages yet.; + } else { + const rendered: React.ReactNode[] = []; + let usedLines = 0; + for (let i = messages.length - 1; i >= 0; i--) { + const msg = messages[i]; + const contentLines = msg.content.split('\n'); + const headerLine = 1; + if (usedLines + headerLine > messageBudget) break; + const remaining = messageBudget - usedLines - headerLine; + const trimmed = contentLines.length > remaining + ? [...contentLines.slice(0, Math.max(0, remaining - 1)), `… (${contentLines.length - Math.max(0, remaining - 1)} more lines)`] + : contentLines; + const time = formatTime(msg.timestamp); + rendered.unshift( + + + {time ? [{time}] : null} + {msg.role}: + + {trimmed.map((line: string, idx: number) => ( + {line} + ))} + , + ); + usedLines += headerLine + trimmed.length + 1; + if (usedLines >= messageBudget) break; + } + body = <>{rendered}; + } + + return ( + + + + {body} + + + ); +}; + +export const PreviewPane = React.memo(PreviewPaneInner); diff --git a/packages/cli/src/tui/watch/PreviewSection.tsx b/packages/cli/src/tui/watch/PreviewSection.tsx new file mode 100644 index 00000000..0f55a299 --- /dev/null +++ b/packages/cli/src/tui/watch/PreviewSection.tsx @@ -0,0 +1,44 @@ +import React, { useMemo } from 'react'; +import { Box } from 'ink'; +import { PreviewPane } from './PreviewPane.js'; +import { useWatchContext } from './state/WatchContext.js'; +import { useAgentConversation } from './hooks/useAgentConversation.js'; + +interface PreviewSectionProps { + selectedName: string | null; + height: number; +} + +const PreviewSectionInner: React.FC = ({ selectedName, height }) => { + const { agents, manager, inputFocused } = useWatchContext(); + const selectedAgent = useMemo( + () => agents.find(a => a.name === selectedName) ?? null, + [agents, selectedName], + ); + const { messages, error, isLoading } = useAgentConversation({ + manager, + agent: selectedAgent, + paused: inputFocused, + }); + + return ( + + + + ); +}; + +export const PreviewSection = React.memo(PreviewSectionInner); diff --git a/packages/cli/src/tui/watch/StatusFooter.tsx b/packages/cli/src/tui/watch/StatusFooter.tsx new file mode 100644 index 00000000..412e0fc0 --- /dev/null +++ b/packages/cli/src/tui/watch/StatusFooter.tsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { Box, Text } from 'ink'; +import { AgentStatus, type AgentInfo } from '@ai-devkit/agent-manager'; + +interface StatusFooterProps { + agents: AgentInfo[]; + selected: AgentInfo | null; + lastUpdated: Date | null; + isLoading: boolean; + narrowNote: string | null; + transient: { kind: 'info' | 'error'; text: string } | null; +} + +function formatRelative(date: Date | string | undefined): string { + if (!date) return '—'; + const d = typeof date === 'string' ? new Date(date) : date; + const diffMs = Date.now() - d.getTime(); + const sec = Math.max(0, Math.floor(diffMs / 1000)); + if (sec < 5) return 'now'; + if (sec < 60) return `${sec}s ago`; + const min = Math.floor(sec / 60); + if (min < 60) return `${min}m ago`; + const hr = Math.floor(min / 60); + if (hr < 24) return `${hr}h ago`; + return `${Math.floor(hr / 24)}d ago`; +} + +const StatusFooterInner: React.FC = ({ + agents, + selected, + lastUpdated, + isLoading, + narrowNote, + transient, +}) => { + const counts: Record = { + [AgentStatus.RUNNING]: 0, + [AgentStatus.WAITING]: 0, + [AgentStatus.IDLE]: 0, + [AgentStatus.UNKNOWN]: 0, + }; + for (const a of agents) counts[a.status] = (counts[a.status] ?? 0) + 1; + + const summary = [ + `${counts[AgentStatus.RUNNING]} run`, + `${counts[AgentStatus.WAITING]} wait`, + `${counts[AgentStatus.IDLE]} idle`, + ].join(' · '); + + const updated = isLoading && !lastUpdated + ? 'loading…' + : `updated ${lastUpdated ? formatRelative(lastUpdated) : '—'}`; + + return ( + + + + {summary}{' · '}{updated}{' · '}↑/↓ nav · ⏎ open · i message · q quit + + + {selected ? ( + + + sel: {selected.name} · {selected.projectPath} · {selected.status} + + + ) : null} + {narrowNote ? ( + + {narrowNote} + + ) : null} + {transient ? ( + + {transient.text} + + ) : null} + + ); +}; + +export const StatusFooter = React.memo(StatusFooterInner); diff --git a/packages/cli/src/tui/watch/WatchApp.tsx b/packages/cli/src/tui/watch/WatchApp.tsx new file mode 100644 index 00000000..4ee5a16a --- /dev/null +++ b/packages/cli/src/tui/watch/WatchApp.tsx @@ -0,0 +1,207 @@ +import React, { useState, useEffect, useCallback, useRef } from 'react'; +import { Box, useApp, useInput } from 'ink'; +import type { AgentManager } from '@ai-devkit/agent-manager'; +import { WatchProvider, useWatchContext } from './state/WatchContext.js'; +import { useTerminalSize } from './hooks/useTerminalSize.js'; +import { ListSection } from './ListSection.js'; +import { PreviewSection } from './PreviewSection.js'; +import { FooterSection } from './FooterSection.js'; +import { ChatInput } from './ChatInput.js'; +import { HeaderBar } from './HeaderBar.js'; +import type { WatchAction } from './actions/types.js'; + +interface WatchAppProps { + manager: AgentManager; + initialSelection?: string | null; + onIntent?: (action: WatchAction) => void; + transientMessage?: { kind: 'info' | 'error'; text: string } | null; +} + +const NARROW_THRESHOLD_COLS = 120; +const LIST_PANE_WIDTH = 48; +const FOOTER_HEIGHT = 2; +const HEADER_HEIGHT = 1; +const MIN_CONTENT_HEIGHT = 12; +const INPUT_BOX_CHROME_ROWS = 2; + +type Focus = 'list' | 'input'; + +const WatchAppShell: React.FC<{ + initialSelection: string | null; + onIntent?: (action: WatchAction) => void; + transientMessage: { kind: 'info' | 'error'; text: string } | null; + setInputFocused: (v: boolean) => void; +}> = ({ initialSelection, onIntent, transientMessage, setInputFocused }) => { + const { exit } = useApp(); + const [selectedName, setSelectedName] = useState(initialSelection); + const [focus, setFocus] = useState('list'); + const [inputLines, setInputLines] = useState(1); + const [inputValue, setInputValue] = useState(''); + const inputFocused = focus === 'input'; + + useEffect(() => { + if (!inputFocused) setInputLines(1); + }, [inputFocused]); + + useEffect(() => { setInputFocused(inputFocused); }, [inputFocused, setInputFocused]); + + const onIntentRef = useRef(onIntent); + onIntentRef.current = onIntent; + const exitRef = useRef(exit); + exitRef.current = exit; + const selectedNameRef = useRef(selectedName); + selectedNameRef.current = selectedName; + const { agents } = useWatchContext(); + const agentsRef = useRef(agents); + agentsRef.current = agents; + + const handleInputSubmit = useCallback((text: string) => { + setFocus('list'); + const name = selectedNameRef.current; + const agent = name ? agentsRef.current.find(a => a.name === name) : null; + const intent = onIntentRef.current; + if (agent && intent) { + intent({ type: 'send', agentName: agent.name, message: text }); + exitRef.current(); + } + }, []); + + const handleInputCancel = useCallback(() => { + setFocus('list'); + }, []); + + // All keyboard handling lives here — useInput inside React.memo components + // does not fire reliably in Ink 7 + React 19. + useInput((input, key) => { + if (focus === 'input') { + if (key.escape) { + setInputValue(''); + setFocus('list'); + } + return; + } + + if (input === 'q') { + exit(); + return; + } + if (input === 'o') { + const name = selectedNameRef.current; + const agent = name ? agentsRef.current.find(a => a.name === name) : null; + if (agent && onIntent) { + onIntent({ type: 'open', agentName: agent.name }); + exit(); + } + return; + } + if (input === 'i' || input === 'm') { + const name = selectedNameRef.current; + if (name) setFocus('input'); + return; + } + if (key.downArrow || input === 'j') { + const list = agentsRef.current; + if (list.length === 0) return; + const idx = Math.max(0, list.findIndex(a => a.name === selectedNameRef.current)); + setSelectedName(list[(idx + 1) % list.length].name); + return; + } + if (key.upArrow || input === 'k') { + const list = agentsRef.current; + if (list.length === 0) return; + const idx = Math.max(0, list.findIndex(a => a.name === selectedNameRef.current)); + setSelectedName(list[(idx - 1 + list.length) % list.length].name); + return; + } + }); + + const [, forceTick] = useState(0); + useEffect(() => { + if (!transientMessage) return; + const handle = setTimeout(() => forceTick(t => t + 1), 4000); + return () => clearTimeout(handle); + }, [transientMessage]); + + const { cols, rows } = useTerminalSize(); + const narrow = cols < NARROW_THRESHOLD_COLS; + const inputBoxHeight = inputLines + INPUT_BOX_CHROME_ROWS; + const totalHeight = Math.max( + MIN_CONTENT_HEIGHT + inputBoxHeight + FOOTER_HEIGHT + HEADER_HEIGHT, + rows - 1, + ); + const contentHeight = Math.max(MIN_CONTENT_HEIGHT, totalHeight - FOOTER_HEIGHT - HEADER_HEIGHT); + const previewHeight = contentHeight - inputBoxHeight; + const listHeight = contentHeight; + + const listPaneWidth = narrow ? cols - 2 : LIST_PANE_WIDTH; + // marginLeft(1) + border(2) accounted for; right col fills the rest exactly. + const rightColWidth = Math.max(20, cols - listPaneWidth - 1); + const inputInnerWidth = Math.max(4, rightColWidth - 4); + + return ( + + + + + + + {!narrow && ( + + + + + + + )} + + + + ); +}; + +export const WatchApp: React.FC = ({ + manager, + initialSelection = null, + onIntent, + transientMessage = null, +}) => { + const [inputFocused, setInputFocused] = useState(false); + return ( + + + + ); +}; diff --git a/packages/cli/src/tui/watch/actions/runAction.ts b/packages/cli/src/tui/watch/actions/runAction.ts new file mode 100644 index 00000000..e45a9d55 --- /dev/null +++ b/packages/cli/src/tui/watch/actions/runAction.ts @@ -0,0 +1,36 @@ +import { spawn } from 'child_process'; +import type { WatchAction } from './types.js'; + +export interface ActionResult { + exitCode: number | null; + error?: string; +} + +function resolveCliEntry(): { command: string; baseArgs: string[] } { + // Re-invoke the exact same process (works in both dev/ts-node and prod/compiled). + // process.execArgv carries loader flags (e.g. --loader ts-node/esm). + // process.argv[1] is the entry script (src/cli.ts in dev, dist/cli.js in prod). + return { command: process.execPath, baseArgs: [...process.execArgv, process.argv[1]] }; +} + +export async function runAction(action: WatchAction): Promise { + const { command, baseArgs } = resolveCliEntry(); + const argv = (() => { + switch (action.type) { + case 'open': + return [...baseArgs, 'agent', 'open', action.agentName]; + case 'send': + return [...baseArgs, 'agent', 'send', action.message, '--id', action.agentName]; + } + })(); + + return new Promise((resolve) => { + const child = spawn(command, argv, { stdio: 'inherit' }); + child.once('error', (err) => { + resolve({ exitCode: null, error: err.message }); + }); + child.once('exit', (code) => { + resolve({ exitCode: code }); + }); + }); +} diff --git a/packages/cli/src/tui/watch/actions/types.ts b/packages/cli/src/tui/watch/actions/types.ts new file mode 100644 index 00000000..1a8cd3ac --- /dev/null +++ b/packages/cli/src/tui/watch/actions/types.ts @@ -0,0 +1,3 @@ +export type WatchAction = + | { type: 'open'; agentName: string } + | { type: 'send'; agentName: string; message: string }; diff --git a/packages/cli/src/tui/watch/hooks/useAgentConversation.ts b/packages/cli/src/tui/watch/hooks/useAgentConversation.ts new file mode 100644 index 00000000..534aadc1 --- /dev/null +++ b/packages/cli/src/tui/watch/hooks/useAgentConversation.ts @@ -0,0 +1,164 @@ +import fs from 'fs'; +import { useEffect, useRef, useState } from 'react'; +import type { AgentInfo, AgentManager, ConversationMessage } from '@ai-devkit/agent-manager'; + +export interface ConversationFetchError { + kind: 'no-session-file' | 'no-adapter' | 'parse-error' | 'agent-not-found'; + message: string; +} + +export interface UseAgentConversationResult { + messages: ConversationMessage[]; + error: ConversationFetchError | null; + lastUpdated: Date | null; + isLoading: boolean; +} + +export const PREVIEW_POLL_INTERVAL_MS = 3000; +export const PREVIEW_TAIL = 20; +export const SELECTION_DEBOUNCE_MS = 150; + +interface Params { + manager: AgentManager; + agent: AgentInfo | null; + intervalMs?: number; + tail?: number; + paused?: boolean; +} + +function messagesEqual(a: ConversationMessage[], b: ConversationMessage[]): boolean { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) { + if (a[i].role !== b[i].role) return false; + if (a[i].content !== b[i].content) return false; + if (a[i].timestamp !== b[i].timestamp) return false; + } + return true; +} + +const EMPTY_STATE: UseAgentConversationResult = { + messages: [], + error: null, + lastUpdated: null, + isLoading: false, +}; + +export function useAgentConversation({ + manager, + agent, + intervalMs = PREVIEW_POLL_INTERVAL_MS, + tail = PREVIEW_TAIL, + paused = false, +}: Params): UseAgentConversationResult { + const [state, setState] = useState(EMPTY_STATE); + + const runTokenRef = useRef(0); + const mountedRef = useRef(true); + const lastMtimeRef = useRef(null); + + useEffect(() => { + mountedRef.current = true; + + if (!agent) { + setState(prev => prev === EMPTY_STATE ? prev : EMPTY_STATE); + lastMtimeRef.current = null; + return () => { mountedRef.current = false; }; + } + + // Selection change → fresh state, single render. + setState({ messages: [], error: null, lastUpdated: null, isLoading: true }); + lastMtimeRef.current = null; + + const fetchOnce = (): void => { + const token = ++runTokenRef.current; + + if (!agent.sessionFilePath) { + if (token !== runTokenRef.current || !mountedRef.current) return; + setState(prev => prev.error?.kind === 'no-session-file' && !prev.isLoading + ? prev + : { + messages: [], + error: { kind: 'no-session-file', message: `No session file for "${agent.name}".` }, + lastUpdated: prev.lastUpdated, + isLoading: false, + }); + return; + } + + const adapter = manager.getAdapter(agent.type); + if (!adapter) { + if (token !== runTokenRef.current || !mountedRef.current) return; + setState(prev => prev.error?.kind === 'no-adapter' && !prev.isLoading + ? prev + : { + messages: [], + error: { kind: 'no-adapter', message: `Unsupported agent type: ${agent.type}` }, + lastUpdated: prev.lastUpdated, + isLoading: false, + }); + return; + } + + try { + let mtime: number | null = null; + try { + mtime = fs.statSync(agent.sessionFilePath).mtimeMs; + } catch { + mtime = null; + } + // mtime didn't change → no need to re-parse. Skip state update. + if (mtime !== null && lastMtimeRef.current === mtime) { + if (token !== runTokenRef.current || !mountedRef.current) return; + setState(prev => prev.isLoading || prev.error + ? { ...prev, isLoading: false, error: null } + : prev); + return; + } + + const conversation = adapter.getConversation(agent.sessionFilePath, { verbose: false }); + if (token !== runTokenRef.current || !mountedRef.current) return; + + const sliced = tail > 0 && conversation.length > tail + ? conversation.slice(-tail) + : conversation; + lastMtimeRef.current = mtime; + setState(prev => { + const changed = !messagesEqual(prev.messages, sliced); + if (!changed && prev.error === null && !prev.isLoading && prev.lastUpdated !== null) { + return prev; + } + return { + messages: changed ? sliced : prev.messages, + error: null, + lastUpdated: new Date(), + isLoading: false, + }; + }); + } catch (err) { + if (token !== runTokenRef.current || !mountedRef.current) return; + const message = err instanceof Error ? err.message : String(err); + setState(prev => ({ ...prev, error: { kind: 'parse-error', message }, isLoading: false })); + } + }; + + // Debounce the immediate fetch on selection change so rapid arrow-key + // navigation doesn't fire a synchronous getConversation() per keystroke. + const debounceHandle = setTimeout(fetchOnce, SELECTION_DEBOUNCE_MS); + + if (paused) { + return () => { + mountedRef.current = false; + clearTimeout(debounceHandle); + }; + } + + const intervalHandle = setInterval(fetchOnce, intervalMs); + return () => { + mountedRef.current = false; + clearTimeout(debounceHandle); + clearInterval(intervalHandle); + }; + }, [manager, agent?.name, agent?.type, agent?.sessionFilePath, intervalMs, tail, paused]); + + return state; +} diff --git a/packages/cli/src/tui/watch/hooks/useAgentList.ts b/packages/cli/src/tui/watch/hooks/useAgentList.ts new file mode 100644 index 00000000..fd779129 --- /dev/null +++ b/packages/cli/src/tui/watch/hooks/useAgentList.ts @@ -0,0 +1,99 @@ +import { useEffect, useRef, useState } from 'react'; +import type { AgentInfo, AgentManager } from '@ai-devkit/agent-manager'; + +export interface UseAgentListResult { + agents: AgentInfo[]; + error: string | null; + lastUpdated: Date | null; + isLoading: boolean; +} + +export const LIST_POLL_INTERVAL_MS = 3000; + +function agentsEqual(a: AgentInfo[], b: AgentInfo[]): boolean { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) { + const x = a[i]; + const y = b[i]; + if ( + x.name !== y.name + || x.status !== y.status + || x.type !== y.type + || x.summary !== y.summary + || x.sessionFilePath !== y.sessionFilePath + ) return false; + const tx = x.lastActive instanceof Date ? x.lastActive.getTime() : new Date(x.lastActive).getTime(); + const ty = y.lastActive instanceof Date ? y.lastActive.getTime() : new Date(y.lastActive).getTime(); + if (tx !== ty) return false; + } + return true; +} + +export function useAgentList( + manager: AgentManager, + intervalMs: number = LIST_POLL_INTERVAL_MS, + paused: boolean = false, +): UseAgentListResult { + // Single state object so multiple updates within one fetch produce + // exactly one render (React 17 doesn't batch async setState). + const [state, setState] = useState({ + agents: [], + error: null, + lastUpdated: null, + isLoading: true, + }); + + const runTokenRef = useRef(0); + const inFlightRef = useRef(false); + const mountedRef = useRef(true); + + useEffect(() => { + mountedRef.current = true; + + const fetchOnce = async (): Promise => { + if (inFlightRef.current) return; + inFlightRef.current = true; + const token = ++runTokenRef.current; + try { + const next = await manager.listAgents({ sortBy: 'name' }); + if (!mountedRef.current || token !== runTokenRef.current) return; + setState(prev => { + const isFirst = prev.lastUpdated === null; + const changed = !agentsEqual(prev.agents, next); + // Quiet poll: nothing changed, no error to clear, not first + // load. Skip state update entirely → zero re-renders. + if (!changed && prev.error === null && !prev.isLoading && !isFirst) { + return prev; + } + return { + agents: changed ? next : prev.agents, + error: null, + lastUpdated: new Date(), + isLoading: false, + }; + }); + } catch (err) { + if (!mountedRef.current || token !== runTokenRef.current) return; + const message = err instanceof Error ? err.message : String(err); + setState(prev => prev.error === message && !prev.isLoading + ? prev + : { ...prev, error: message, isLoading: false }); + } finally { + inFlightRef.current = false; + } + }; + + if (paused) { + return () => { mountedRef.current = false; }; + } + void fetchOnce(); + const handle = setInterval(() => { void fetchOnce(); }, intervalMs); + + return () => { + mountedRef.current = false; + clearInterval(handle); + }; + }, [manager, intervalMs, paused]); + + return state; +} diff --git a/packages/cli/src/tui/watch/hooks/useTerminalSize.ts b/packages/cli/src/tui/watch/hooks/useTerminalSize.ts new file mode 100644 index 00000000..de58ae33 --- /dev/null +++ b/packages/cli/src/tui/watch/hooks/useTerminalSize.ts @@ -0,0 +1,37 @@ +import { useEffect, useState, useRef } from 'react'; + +interface TerminalSize { + cols: number; + rows: number; +} + +const RESIZE_DEBOUNCE_MS = 80; + +function readSize(): TerminalSize { + return { + cols: process.stdout.columns ?? 120, + rows: process.stdout.rows ?? 30, + }; +} + +export function useTerminalSize(): TerminalSize { + const [size, setSize] = useState(readSize); + const debounceRef = useRef(null); + + useEffect(() => { + const onResize = (): void => { + if (debounceRef.current) clearTimeout(debounceRef.current); + debounceRef.current = setTimeout(() => { + const next = readSize(); + setSize(prev => (prev.cols === next.cols && prev.rows === next.rows) ? prev : next); + }, RESIZE_DEBOUNCE_MS); + }; + process.stdout.on('resize', onResize); + return () => { + if (debounceRef.current) clearTimeout(debounceRef.current); + process.stdout.off('resize', onResize); + }; + }, []); + + return size; +} diff --git a/packages/cli/src/tui/watch/render/formatStatus.tsx b/packages/cli/src/tui/watch/render/formatStatus.tsx new file mode 100644 index 00000000..08f99fa8 --- /dev/null +++ b/packages/cli/src/tui/watch/render/formatStatus.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Text } from 'ink'; +import { AgentStatus } from '@ai-devkit/agent-manager'; + +interface StatusGlyph { + glyph: string; + label: string; + color: 'green' | 'yellow' | 'gray' | 'red'; +} + +const STATUS_DISPLAY: Record = { + [AgentStatus.RUNNING]: { glyph: '●', label: 'run', color: 'green' }, + [AgentStatus.WAITING]: { glyph: '◐', label: 'wait', color: 'yellow' }, + [AgentStatus.IDLE]: { glyph: '○', label: 'idle', color: 'gray' }, + [AgentStatus.UNKNOWN]: { glyph: '?', label: 'unk', color: 'red' }, +}; + +export interface FormatStatusProps { + status: AgentStatus; +} + +const FormatStatusInner: React.FC = ({ status }) => { + const { glyph, label, color } = STATUS_DISPLAY[status] ?? STATUS_DISPLAY[AgentStatus.UNKNOWN]; + return {glyph} {label}; +}; + +export const FormatStatus = React.memo(FormatStatusInner); + +export function statusDisplayWidth(): number { + // glyph (1) + space (1) + longest label ("idle"/"wait"/"run"/"unk" = 4) + return 6; +} diff --git a/packages/cli/src/tui/watch/state/WatchContext.tsx b/packages/cli/src/tui/watch/state/WatchContext.tsx new file mode 100644 index 00000000..75cefdd0 --- /dev/null +++ b/packages/cli/src/tui/watch/state/WatchContext.tsx @@ -0,0 +1,30 @@ +import React, { createContext, useContext } from 'react'; +import type { AgentManager } from '@ai-devkit/agent-manager'; +import { useAgentList, type UseAgentListResult } from '../hooks/useAgentList.js'; + +interface WatchContextValue extends UseAgentListResult { + manager: AgentManager; + inputFocused: boolean; +} + +const WatchContext = createContext(null); + +export const useWatchContext = (): WatchContextValue => { + const ctx = useContext(WatchContext); + if (!ctx) throw new Error('useWatchContext must be used inside '); + return ctx; +}; + +interface WatchProviderProps { + manager: AgentManager; + inputFocused: boolean; + children: React.ReactNode; +} + +export const WatchProvider: React.FC = ({ manager, inputFocused, children }) => { + // Pause list poll while user is composing a message: removes a source of + // re-renders that compete with the controlled TextInput. + const list = useAgentList(manager, undefined, inputFocused); + const value: WatchContextValue = { ...list, manager, inputFocused }; + return {children}; +}; diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index 652dd497..b95adae3 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -4,7 +4,8 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "rootDir": "./src", - "outDir": "./dist" + "outDir": "./dist", + "jsx": "react-jsx" }, "include": [ "src/**/*" From 1b5ee1cc9f503430262c57c4f66e985a290d35ff Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Thu, 28 May 2026 11:35:17 +0200 Subject: [PATCH 2/7] feat(cli): update to agent console --- .../design/2026-05-28-feature-agent-watch.md | 122 +++++++++++++++ .../2026-05-28-feature-agent-watch.md | 71 +++++++++ .../2026-05-28-feature-agent-watch.md | 53 +++++++ .../2026-05-28-feature-agent-watch.md | 47 ++++++ .../testing/2026-05-28-feature-agent-watch.md | 89 +++++++++++ .../tui/watch/actions/runAction.test.ts | 85 +++++++++++ .../__tests__/tui/watch/computeLayout.test.ts | 75 ++++++++++ .../tui/watch/hooks/agentsEqual.test.ts | 74 ++++++++++ .../tui/watch/hooks/conversationCache.test.ts | 87 +++++++++++ .../tui/watch/render/formatRelative.test.ts | 48 ++++++ packages/cli/src/commands/agent.ts | 48 ++---- packages/cli/src/tui/watch/AgentListPane.tsx | 52 ++++--- packages/cli/src/tui/watch/FooterSection.tsx | 26 ---- packages/cli/src/tui/watch/HeaderBar.tsx | 2 +- packages/cli/src/tui/watch/ListSection.tsx | 37 ----- packages/cli/src/tui/watch/PreviewPane.tsx | 32 +--- packages/cli/src/tui/watch/StatusFooter.tsx | 26 +--- packages/cli/src/tui/watch/WatchApp.tsx | 139 ++++++++++-------- .../cli/src/tui/watch/actions/runAction.ts | 15 +- .../tui/watch/hooks/useAgentConversation.ts | 49 ++++-- .../cli/src/tui/watch/hooks/useAgentList.ts | 9 +- .../src/tui/watch/render/agentTypeLabel.ts | 15 ++ .../src/tui/watch/render/formatRelative.ts | 13 ++ .../cli/src/tui/watch/render/formatStatus.tsx | 5 - .../cli/src/tui/watch/state/WatchContext.tsx | 7 +- 25 files changed, 955 insertions(+), 271 deletions(-) create mode 100644 docs/ai/design/2026-05-28-feature-agent-watch.md create mode 100644 docs/ai/implementation/2026-05-28-feature-agent-watch.md create mode 100644 docs/ai/planning/2026-05-28-feature-agent-watch.md create mode 100644 docs/ai/requirements/2026-05-28-feature-agent-watch.md create mode 100644 docs/ai/testing/2026-05-28-feature-agent-watch.md create mode 100644 packages/cli/src/__tests__/tui/watch/actions/runAction.test.ts create mode 100644 packages/cli/src/__tests__/tui/watch/computeLayout.test.ts create mode 100644 packages/cli/src/__tests__/tui/watch/hooks/agentsEqual.test.ts create mode 100644 packages/cli/src/__tests__/tui/watch/hooks/conversationCache.test.ts create mode 100644 packages/cli/src/__tests__/tui/watch/render/formatRelative.test.ts delete mode 100644 packages/cli/src/tui/watch/FooterSection.tsx delete mode 100644 packages/cli/src/tui/watch/ListSection.tsx create mode 100644 packages/cli/src/tui/watch/render/agentTypeLabel.ts create mode 100644 packages/cli/src/tui/watch/render/formatRelative.ts diff --git a/docs/ai/design/2026-05-28-feature-agent-watch.md b/docs/ai/design/2026-05-28-feature-agent-watch.md new file mode 100644 index 00000000..10412cfc --- /dev/null +++ b/docs/ai/design/2026-05-28-feature-agent-watch.md @@ -0,0 +1,122 @@ +--- +phase: design +title: System Design & Architecture +description: Define the technical architecture, components, and data models +--- + +# System Design & Architecture + +## Architecture Overview + +```mermaid +graph TD + CLI["agent console (commands/agent.ts)"] + CLI --> WatchApp + + WatchApp --> WatchProvider + WatchProvider --> useAgentList + useAgentList --> AgentManager + + WatchApp --> WatchAppShell + WatchAppShell --> HeaderBar + WatchAppShell --> AgentListPane + WatchAppShell --> PreviewSection + WatchAppShell --> StatusFooter + WatchAppShell --> ChatInput + + PreviewSection --> useAgentConversation + useAgentConversation --> conversationCache["LRU cache (module-level)"] + useAgentConversation --> AgentAdapter["AgentAdapter.getConversation()"] + + WatchAppShell --> runAction + runAction -->|subprocess| CLIAgentOpen["agent open "] + runAction -->|subprocess| CLIAgentSend["agent send --id "] +``` + +**Key architectural decisions:** +- All keyboard handling (`useInput`) centralised in `WatchAppShell` (non-memo) — Ink 7 + React 19 silently drops `useInput` inside `React.memo` components +- Actions dispatch via `spawn()` re-invoking the CLI with `stdio: pipe` so the TUI never yields the terminal +- Context value stabilised with `useMemo` so quiet polls don't re-render all consumers + +## Data Models + +**AgentInfo** (from `@ai-devkit/agent-manager`) +```typescript +{ name, type, status, projectPath, summary, lastActive, sessionFilePath } +``` + +**ConversationMessage** +```typescript +{ role: 'user' | 'assistant' | 'system', content: string, timestamp?: string } +``` + +**WatchContextValue** +```typescript +{ agents, error, lastUpdated, isLoading, manager, inputFocused } +``` + +**CacheEntry** (module-level LRU, max 50) +```typescript +{ mtime: number, messages: ConversationMessage[] } +``` + +## Component Breakdown + +| Component | File | Responsibility | +|-----------|------|----------------| +| `WatchApp` | `WatchApp.tsx` | Context provider wrapper | +| `WatchAppShell` | `WatchApp.tsx` | All state, keyboard handling, layout math | +| `HeaderBar` | `HeaderBar.tsx` | Agent count + app label | +| `AgentListPane` | `AgentListPane.tsx` | 2-line agent rows with status/name/type/summary | +| `PreviewSection` | `PreviewSection.tsx` | Runs `useAgentConversation`, wraps `PreviewPane` | +| `PreviewPane` | `PreviewPane.tsx` | Renders last N messages with role/timestamp | +| `StatusFooter` | `StatusFooter.tsx` | Status counts + updated time + keybinding hints | +| `ChatInput` | `ChatInput.tsx` | Controlled text input for sending messages | +| `FormatStatus` | `render/formatStatus.tsx` | Status glyph + label | +| `WatchProvider` | `state/WatchContext.tsx` | Provides agent list via context | +| `useAgentList` | `hooks/useAgentList.ts` | Polls `manager.listAgents()` every 3s | +| `useAgentConversation` | `hooks/useAgentConversation.ts` | Polls conversation with debounce + LRU cache | +| `useTerminalSize` | `hooks/useTerminalSize.ts` | Debounced terminal resize listener | +| `runAction` | `actions/runAction.ts` | Spawns CLI subprocess for open/send | +| `computeLayout` | `WatchApp.tsx` | Pure function: cols/rows → layout dimensions | + +## Layout Design + +``` +┌─ ai-devkit · agent console 3 agents ──────────────────────────────┐ +├──────────────────────┬─────────────────────────────────────────────┤ +│ AGENTS (3) │ PREVIEW · jarvis · claude · 2m ago · ~/code │ +│ ● run jarvis claude│ user: │ +│ ~/projects/jarvis │ can you fix the login bug? │ +│ ─────────────────────│ assistant: │ +│ ◐ wait titan codex │ Sure, looking at auth.ts now… │ +│ ~/projects/titan │─────────────────────────────────────────────│ +│ ─────────────────────│ ╭─────────────────────────────────────────╮ │ +│ ○ idle scout gemini│ │ > press i to type a message │ │ +│ ~/projects/scout │ ╰─────────────────────────────────────────╯ │ +├──────────────────────┴─────────────────────────────────────────────┤ +│ 1 run · 1 wait · 1 idle · updated 2s ago · j/k · o · i · q │ +└────────────────────────────────────────────────────────────────────┘ +``` + +- Narrow mode (< 120 cols): only left pane shown, preview hidden +- Left pane fixed at 48 cols; right column fills remaining space + +## Design Decisions + +| Decision | Choice | Rationale | +|----------|--------|-----------| +| Keyboard handler location | Single non-memo `WatchAppShell` | Ink 7 + React 19: `useInput` silently fails in `React.memo` | +| Action execution | Subprocess re-invoking CLI | TUI stays alive; no terminal handoff complexity | +| Conversation data | Sync `statSync` + JSONL parse | Session files are local; async adds race complexity without benefit | +| Cache | Module-level LRU Map (max 50) | Survives selection changes; evicts old entries; no library needed | +| Context stabilisation | `useMemo` on context value | Quiet polls (`setState` returns `prev`) don't re-render consumers | +| Poll interval | 3s for both list and conversation | Balances freshness vs CPU; paused during input focus | +| `inFlightRef` reset | At top of each effect run | Prevents blocked fetch after dependency change | + +## Non-Functional Requirements + +- Layout must not shift when selecting a different agent (all boxes use fixed widths + `flexShrink={0}`) +- Conversation cache must not grow unbounded (LRU eviction at 50 entries) +- Actions must not unmount the TUI (subprocess with `stdio: pipe`) +- Terminal resize must be debounced (80ms) to avoid render storms diff --git a/docs/ai/implementation/2026-05-28-feature-agent-watch.md b/docs/ai/implementation/2026-05-28-feature-agent-watch.md new file mode 100644 index 00000000..d41532ab --- /dev/null +++ b/docs/ai/implementation/2026-05-28-feature-agent-watch.md @@ -0,0 +1,71 @@ +--- +phase: implementation +title: Implementation Guide +description: Technical implementation notes, patterns, and code guidelines +--- + +# Implementation Guide + +## Code Structure + +``` +packages/cli/src/ +├── commands/agent.ts # CLI command registration; renders WatchApp +└── tui/watch/ + ├── WatchApp.tsx # WatchProvider + WatchAppShell (all state + keyboard) + ├── AgentListPane.tsx # 2-line agent rows + ├── PreviewPane.tsx # Last-N message renderer + ├── PreviewSection.tsx # Runs useAgentConversation, wraps PreviewPane + ├── StatusFooter.tsx # Status counts + keybinding hints + ├── ChatInput.tsx # Controlled text input + ├── HeaderBar.tsx # App label + agent count + ├── actions/ + │ ├── runAction.ts # Subprocess dispatcher + │ └── types.ts # WatchAction discriminated union + ├── hooks/ + │ ├── useAgentList.ts # 3s poll for agent list + │ ├── useAgentConversation.ts # 3s poll for conversation + LRU cache + │ └── useTerminalSize.ts # Debounced terminal resize + ├── render/ + │ ├── formatStatus.tsx # FormatStatus component + │ ├── formatRelative.ts # Shared relative-time formatter + │ └── agentTypeLabel.ts # AGENT_TYPE_LABEL / AGENT_TYPE_LABEL_DISPLAY + └── state/ + └── WatchContext.tsx # WatchProvider + useWatchContext +``` + +## Key Implementation Notes + +### Ink 7 + React 19 keyboard handling +`useInput` silently fails inside `React.memo` components. All keyboard handling lives in `WatchAppShell` (non-memo). Refs (`exitRef`, `selectedNameRef`, `agentsRef`) capture current values for use inside `useInput` closures without stale closure bugs. + +### Layout stability +Every `` has explicit `width` + `flexShrink={0}`. Without this, Yoga recalculates and shifts layout on every selection change. `computeLayout()` is a pure function — easy to verify and test independently. + +### Conversation cache +`conversationCache` is a module-level `Map` with LRU eviction via `cacheSet()` (max 50). On selection change, cached messages are shown immediately while the debounced fetch checks `statSync().mtimeMs`. If mtime matches cache, no JSONL parse occurs. + +### Action dispatch +`runAction` resolves the CLI entry as `process.execPath + process.execArgv + process.argv[1]` — works in both dev (tsx/ts-node) and production. Subprocess uses `stdio: ['ignore', 'pipe', 'pipe']` so it never seizes the TUI terminal. + +### Quiet poll optimization +Both hooks use `setState(prev => prev)` return to skip re-renders on unchanged data: +- `useAgentList`: `agentsEqual()` compares all fields; uses `Date.parse()` not `new Date()` to avoid GC pressure +- `useAgentConversation`: `messagesEqual()` compares role + content + timestamp + +### Context stability +`WatchContext` wraps the value in `useMemo([list, manager, inputFocused])`. Since `useAgentList` returns `prev` when nothing changed, `list` is a stable reference across quiet polls — the `useMemo` dependency doesn't trigger, so consumers don't re-render. + +## Error Handling + +- `useAgentList` catches `listAgents()` errors and surfaces them via `error` in context; `AgentListPane` shows the error message +- `useAgentConversation` handles: no session file, no adapter, JSONL parse error — each shown in `PreviewPane` +- `runAction` captures stderr from subprocess; resolves with `{ exitCode, error }` never rejects +- All `setState` calls in async hooks guard with `mountedRef.current && token === runTokenRef.current` + +## Performance Considerations + +- Poll paused during input focus (`paused: inputFocused`) to reduce competing re-renders +- Terminal resize debounced at 80ms +- `React.memo` on all leaf components (`AgentListPane`, `PreviewPane`, `StatusFooter`, `ChatInput`, `FormatStatus`, `HeaderBar`) +- `inFlightRef` prevents concurrent `listAgents()` calls when interval fires before previous fetch completes; reset at start of each effect run to prevent blocked fetch after dependency change diff --git a/docs/ai/planning/2026-05-28-feature-agent-watch.md b/docs/ai/planning/2026-05-28-feature-agent-watch.md new file mode 100644 index 00000000..2ee234d7 --- /dev/null +++ b/docs/ai/planning/2026-05-28-feature-agent-watch.md @@ -0,0 +1,53 @@ +--- +phase: planning +title: Project Planning & Task Breakdown +description: Break down work into actionable tasks and estimate timeline +--- + +# Project Planning & Task Breakdown + +## Task Breakdown + +### Phase 1: Core Shell & Data Hooks +- [x] Task 1.1: `useAgentList` hook — polls `manager.listAgents()` every 3s, equality-checks to skip quiet re-renders, guards stale setState with run token +- [x] Task 1.2: `WatchProvider` / `WatchContext` — provides agent list + manager via context; `useMemo` on value object +- [x] Task 1.3: `useTerminalSize` — debounced resize listener on `process.stdout` +- [x] Task 1.4: `WatchApp` shell — `WatchProvider` wrapper + `WatchAppShell` with all keyboard handling via `useInput` + +### Phase 2: Agent List Pane +- [x] Task 2.1: `AgentListPane` — 2-line rows (status+name+type / summary), fixed widths to prevent layout shift, dividers between agents +- [x] Task 2.2: `FormatStatus` — status glyph + label with colour coding +- [x] Task 2.3: Sort agents by status (WAITING → RUNNING → IDLE → UNKNOWN) via `sortBy: 'status'` + +### Phase 3: Conversation Preview +- [x] Task 3.1: `useAgentConversation` hook — polls every 3s, 150ms selection debounce, LRU module-level cache (max 50 entries), run-token race guard +- [x] Task 3.2: `PreviewPane` — renders last 20 messages with role colour + timestamp; each line wrapped in `` to guarantee row breaks in Ink 7 +- [x] Task 3.3: `PreviewSection` — reads context + runs `useAgentConversation`, paused during input focus + +### Phase 4: Chat Input & Actions +- [x] Task 4.1: `ChatInput` — fully controlled (value/onChange lifted to `WatchAppShell`); dynamic line-count reporting for layout +- [x] Task 4.2: `runAction` — spawns CLI subprocess (`agent open` / `agent send`) with `stdio: pipe`; resolves via `process.execPath + execArgv + argv[1]` +- [x] Task 4.3: Transient feedback messages — 4s auto-clear; shown in `StatusFooter` + +### Phase 5: Header, Footer & Layout +- [x] Task 5.1: `HeaderBar` — agent count + app label +- [x] Task 5.2: `StatusFooter` — status counts, updated time, keybinding hints +- [x] Task 5.3: `computeLayout` — pure function mapping cols/rows/inputLines → all layout dimensions +- [x] Task 5.4: Narrow mode — hides preview pane when terminal < 120 cols; shows resize hint in footer + +## Dependencies + +- `@ai-devkit/agent-manager` — `AgentManager`, `AgentInfo`, `ConversationMessage`, `AgentStatus` +- `ink` 7.x — TUI rendering; `useInput`, `useApp`, `Box`, `Text` +- `ink-text-input` — controlled text input component +- `react` 19.x + +## Risks & Mitigation + +| Risk | Mitigation | +|------|-----------| +| `useInput` silent failure in memo components | All keyboard handling in single non-memo `WatchAppShell` | +| Layout shift on selection change | Fixed widths + `flexShrink={0}` on all boxes | +| Unbounded conversation cache | LRU eviction at 50 entries via `cacheSet()` | +| Subprocess blocking TUI terminal | `stdio: ['ignore', 'pipe', 'pipe']` | +| Stale fetch after effect re-run | `inFlightRef.current = false` reset at start of each effect | diff --git a/docs/ai/requirements/2026-05-28-feature-agent-watch.md b/docs/ai/requirements/2026-05-28-feature-agent-watch.md new file mode 100644 index 00000000..9f734e8d --- /dev/null +++ b/docs/ai/requirements/2026-05-28-feature-agent-watch.md @@ -0,0 +1,47 @@ +--- +phase: requirements +title: Requirements & Problem Understanding +description: Clarify the problem space, gather requirements, and define success criteria +--- + +# Requirements & Problem Understanding + +## Problem Statement + +Developers running multiple AI agents (Claude Code, Codex, Gemini CLI, OpenCode) have no unified view of what those agents are doing. They must switch terminal windows to check status, find logs, or send messages. This creates context-switching overhead and makes it easy to miss stuck or waiting agents. + +## Goals & Objectives + +**Primary goals** +- Provide a real-time TUI dashboard (`agent console`) that lists all detected running agents with live status +- Allow the user to inspect an agent's recent conversation without leaving the console +- Allow the user to send a message to a selected agent from within the TUI +- Allow the user to open a selected agent's terminal session + +**Non-goals** +- Full conversation history (preview shows last 20 messages only) +- Multi-agent message broadcast +- Managing agent lifecycle (start/stop) + +## User Stories & Use Cases + +- As a developer, I want to see all my agents' statuses at a glance so I can detect stuck or idle agents quickly +- As a developer, I want to read the last few messages of any agent's conversation without switching windows +- As a developer, I want to send a message to an agent from the console so I can unblock it without interrupting my current context +- As a developer, I want to open an agent's full terminal UI from the console + +## Success Criteria + +- `agent console` renders within 1s of launch +- Agent list refreshes every 3s without noticeable layout shifts +- Keyboard navigation (j/k/o/i/q) works immediately on launch +- Conversation preview updates every 3s; fast cursor movement does not cause excessive I/O +- Action feedback (open/send) is displayed without unmounting the TUI +- Works in terminals ≥ 80 cols; preview pane shown when terminal ≥ 120 cols + +## Constraints & Assumptions + +- Terminal must support at least 80 columns and 24 rows for usable layout +- Ink 7 + React 19 ESM — `useInput` must live in a single non-memo component to avoid silent failures +- Agent session files are JSONL on disk; parsing happens synchronously per selection +- Actions (open/send) are dispatched by re-invoking the CLI as a subprocess so the TUI stays alive diff --git a/docs/ai/testing/2026-05-28-feature-agent-watch.md b/docs/ai/testing/2026-05-28-feature-agent-watch.md new file mode 100644 index 00000000..7c3160a2 --- /dev/null +++ b/docs/ai/testing/2026-05-28-feature-agent-watch.md @@ -0,0 +1,89 @@ +--- +phase: testing +title: Testing Strategy & Coverage +description: Test coverage plan, test file locations, and results +--- + +# Testing Strategy & Coverage + +## Scope + +React components and hooks cannot be tested without `@testing-library/react` or `ink-testing-library` (not available in this project). Coverage targets all pure TypeScript logic: layout calculation, equality checks, LRU cache, time formatting, and subprocess dispatch. + +## Test Files + +| File | Covers | Tests | +|------|--------|-------| +| `src/__tests__/tui/watch/computeLayout.test.ts` | `computeLayout()` in `WatchApp.tsx` | 10 | +| `src/__tests__/tui/watch/render/formatRelative.test.ts` | `render/formatRelative.ts` | 8 | +| `src/__tests__/tui/watch/hooks/conversationCache.test.ts` | `cacheSet`, `conversationCache`, `messagesEqual` | 11 | +| `src/__tests__/tui/watch/hooks/agentsEqual.test.ts` | `agentsEqual` in `useAgentList.ts` | 11 | +| `src/__tests__/tui/watch/actions/runAction.test.ts` | `runAction.ts` | 7 | + +**Total new tests: 47** | **All passing** + +## What Each Suite Validates + +### `computeLayout` +- Fixed 48-col list pane in wide mode +- Right column fills remaining width minus separator +- Narrow mode uses `cols − 2` for list pane +- `contentHeight` never drops below `MIN_CONTENT_HEIGHT` (12) even on tiny terminals +- `inputBoxHeight` scales with `inputLines` +- `rightColWidth` clamped to 20 minimum; `inputInnerWidth` clamped to 4 minimum + +### `formatRelative` +- All time buckets: now (< 5s), seconds, minutes, hours, days +- Future timestamps clamped to "now" +- String and Date inputs both accepted +- `undefined` returns `"—"` + +### LRU Cache +- Store and retrieve +- Re-insert moves key to most-recent position (LRU refresh) +- Oldest key evicted when size hits `CACHE_MAX` (50) +- Never exceeds `CACHE_MAX` under sustained inserts + +### `messagesEqual` +- Empty arrays equal +- Length mismatch → false +- role / content / timestamp field comparison +- Undefined timestamps handled + +### `agentsEqual` +- Empty arrays equal +- Field-level comparison: name, status, type, summary, sessionFilePath, lastActive +- String `lastActive` compared correctly against `Date` (via `Date.parse()`) +- Order-sensitive multi-agent comparison + +### `runAction` +- Success: exitCode 0, no error +- Non-zero exit + stderr → error string captured +- Non-zero exit + empty stderr → error undefined +- Spawn error (`ENOENT`) → exitCode null + error message +- `open` action argv shape: `['agent', 'open', '']` +- `send` action argv shape: `['agent', 'send', '', '--id', '']` +- `stdio: ['ignore', 'pipe', 'pipe']` verified (TUI terminal not seized) + +## Coverage Notes + +**Not covered by automated tests** (require ink-testing-library or manual QA): +- React component rendering: `AgentListPane`, `PreviewPane`, `StatusFooter`, `ChatInput`, `HeaderBar` +- Hook behaviour: `useAgentList`, `useAgentConversation`, `useTerminalSize` +- Keyboard navigation: j/k, o, i, q in `WatchAppShell` +- Narrow/wide layout transition on terminal resize + +**Recommended manual QA scenarios:** +1. Rapid j/k navigation — verify 150ms debounce prevents excessive `statSync` calls +2. Resize terminal from < 120 cols to ≥ 120 cols — preview pane appears +3. Delete an agent mid-session — list resets to first agent without crash +4. Send message to agent — transient "Message sent" appears for 4s +5. Open action with bad agent name — transient error shown + +## Results + +``` +Test Files 41 passed (41) + Tests 621 passed (621) ← includes 47 new agent-console tests + Duration 2.65s +``` diff --git a/packages/cli/src/__tests__/tui/watch/actions/runAction.test.ts b/packages/cli/src/__tests__/tui/watch/actions/runAction.test.ts new file mode 100644 index 00000000..1f394ea1 --- /dev/null +++ b/packages/cli/src/__tests__/tui/watch/actions/runAction.test.ts @@ -0,0 +1,85 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { EventEmitter } from 'events'; + +// Mock child_process before importing runAction +vi.mock('child_process', () => ({ + spawn: vi.fn(), +})); + +import { spawn } from 'child_process'; +import { runAction } from '../../../../tui/watch/actions/runAction.js'; + +function makeChild(exitCode: number | null, stderr = '') { + const child = new EventEmitter() as EventEmitter & { + stderr: EventEmitter; + once: (event: string, cb: (...args: unknown[]) => void) => typeof child; + }; + child.stderr = new EventEmitter(); + + // Emit stderr data then exit asynchronously + setTimeout(() => { + if (stderr) child.stderr.emit('data', Buffer.from(stderr)); + child.emit('exit', exitCode); + }, 0); + + return child; +} + +describe('runAction', () => { + beforeEach(() => { + vi.mocked(spawn).mockReset(); + }); + + it('resolves with exitCode 0 on success', async () => { + vi.mocked(spawn).mockReturnValue(makeChild(0) as ReturnType); + const result = await runAction({ type: 'open', agentName: 'jarvis' }); + expect(result.exitCode).toBe(0); + expect(result.error).toBeUndefined(); + }); + + it('includes stderr in error when exit code is non-zero', async () => { + vi.mocked(spawn).mockReturnValue(makeChild(1, 'agent not found') as ReturnType); + const result = await runAction({ type: 'open', agentName: 'jarvis' }); + expect(result.exitCode).toBe(1); + expect(result.error).toBe('agent not found'); + }); + + it('does not set error when exit code is non-zero but stderr is empty', async () => { + vi.mocked(spawn).mockReturnValue(makeChild(1, '') as ReturnType); + const result = await runAction({ type: 'open', agentName: 'jarvis' }); + expect(result.exitCode).toBe(1); + expect(result.error).toBeUndefined(); + }); + + it('resolves with null exitCode and error message on spawn error', async () => { + const child = new EventEmitter() as EventEmitter & { stderr: EventEmitter }; + child.stderr = new EventEmitter(); + setTimeout(() => child.emit('error', new Error('ENOENT')), 0); + vi.mocked(spawn).mockReturnValue(child as ReturnType); + + const result = await runAction({ type: 'send', agentName: 'jarvis', message: 'hello' }); + expect(result.exitCode).toBeNull(); + expect(result.error).toBe('ENOENT'); + }); + + it('passes correct argv for open action', async () => { + vi.mocked(spawn).mockReturnValue(makeChild(0) as ReturnType); + await runAction({ type: 'open', agentName: 'my-agent' }); + const [, argv] = vi.mocked(spawn).mock.calls[0]; + expect(argv).toEqual(expect.arrayContaining(['agent', 'open', 'my-agent'])); + }); + + it('passes correct argv for send action', async () => { + vi.mocked(spawn).mockReturnValue(makeChild(0) as ReturnType); + await runAction({ type: 'send', agentName: 'my-agent', message: 'hello world' }); + const [, argv] = vi.mocked(spawn).mock.calls[0]; + expect(argv).toEqual(expect.arrayContaining(['agent', 'send', 'hello world', '--id', 'my-agent'])); + }); + + it('spawns with stdio pipe to avoid seizing the TUI terminal', async () => { + vi.mocked(spawn).mockReturnValue(makeChild(0) as ReturnType); + await runAction({ type: 'open', agentName: 'x' }); + const [, , opts] = vi.mocked(spawn).mock.calls[0]; + expect(opts?.stdio).toEqual(['ignore', 'pipe', 'pipe']); + }); +}); diff --git a/packages/cli/src/__tests__/tui/watch/computeLayout.test.ts b/packages/cli/src/__tests__/tui/watch/computeLayout.test.ts new file mode 100644 index 00000000..8cf3604c --- /dev/null +++ b/packages/cli/src/__tests__/tui/watch/computeLayout.test.ts @@ -0,0 +1,75 @@ +import { describe, it, expect } from 'vitest'; +// computeLayout is a pure function exported from WatchApp — import only the function, +// not the React component tree, to avoid JSX in the test environment. +import { computeLayout } from '../../../tui/watch/WatchApp.js'; + +// Constants mirrored from WatchApp.tsx for assertions +const LIST_PANE_WIDTH = 48; +const MIN_CONTENT_HEIGHT = 12; +const INPUT_BOX_CHROME_ROWS = 2; + +describe('computeLayout', () => { + describe('wide mode (narrow=false)', () => { + it('uses fixed LIST_PANE_WIDTH', () => { + const layout = computeLayout(160, 40, 1, false); + expect(layout.listPaneWidth).toBe(LIST_PANE_WIDTH); + }); + + it('right col fills remaining space minus separator', () => { + const layout = computeLayout(160, 40, 1, false); + expect(layout.rightColWidth).toBe(160 - LIST_PANE_WIDTH - 1); + }); + + it('inputInnerWidth is rightColWidth minus 4 (border + padding)', () => { + const layout = computeLayout(160, 40, 1, false); + expect(layout.inputInnerWidth).toBe(layout.rightColWidth - 4); + }); + + it('previewHeight is contentHeight minus inputBoxHeight', () => { + const layout = computeLayout(160, 40, 1, false); + expect(layout.previewHeight).toBe(layout.contentHeight - layout.inputBoxHeight); + }); + + it('inputBoxHeight grows with inputLines', () => { + const single = computeLayout(160, 40, 1, false); + const triple = computeLayout(160, 40, 3, false); + expect(triple.inputBoxHeight).toBe(single.inputBoxHeight + 2); + }); + }); + + describe('narrow mode (narrow=true)', () => { + it('list pane is cols − 2', () => { + const layout = computeLayout(80, 30, 1, true); + expect(layout.listPaneWidth).toBe(78); + }); + }); + + describe('contentHeight floor', () => { + it('never goes below MIN_CONTENT_HEIGHT', () => { + // Very small terminal + const layout = computeLayout(40, 1, 1, true); + expect(layout.contentHeight).toBeGreaterThanOrEqual(MIN_CONTENT_HEIGHT); + }); + }); + + describe('inputBoxHeight', () => { + it('is inputLines + INPUT_BOX_CHROME_ROWS', () => { + expect(computeLayout(160, 40, 1, false).inputBoxHeight).toBe(1 + INPUT_BOX_CHROME_ROWS); + expect(computeLayout(160, 40, 4, false).inputBoxHeight).toBe(4 + INPUT_BOX_CHROME_ROWS); + }); + }); + + describe('minimum right col width', () => { + it('clamps rightColWidth to 20 on very narrow terminal', () => { + // cols=50: 50 - 48 - 1 = 1, clamped to 20 + const layout = computeLayout(50, 30, 1, false); + expect(layout.rightColWidth).toBe(20); + }); + + it('clamps inputInnerWidth to 4 minimum', () => { + const layout = computeLayout(50, 30, 1, false); + // rightColWidth=20, 20-4=16; but if clamped rightCol is exactly 20, inner is 16 + expect(layout.inputInnerWidth).toBeGreaterThanOrEqual(4); + }); + }); +}); diff --git a/packages/cli/src/__tests__/tui/watch/hooks/agentsEqual.test.ts b/packages/cli/src/__tests__/tui/watch/hooks/agentsEqual.test.ts new file mode 100644 index 00000000..c9ff37e2 --- /dev/null +++ b/packages/cli/src/__tests__/tui/watch/hooks/agentsEqual.test.ts @@ -0,0 +1,74 @@ +import { describe, it, expect } from 'vitest'; +import { agentsEqual } from '../../../../tui/watch/hooks/useAgentList.js'; +import type { AgentInfo } from '@ai-devkit/agent-manager'; +import { AgentStatus } from '@ai-devkit/agent-manager'; + +const agent = (overrides: Partial = {}): AgentInfo => ({ + name: 'test-agent', + type: 'claude', + status: AgentStatus.IDLE, + projectPath: '/home/user/project', + summary: 'working on auth', + lastActive: new Date('2026-01-01T12:00:00Z'), + sessionFilePath: '/home/user/.sessions/test.jsonl', + ...overrides, +} as AgentInfo); + +describe('agentsEqual', () => { + it('returns true for two empty arrays', () => { + expect(agentsEqual([], [])).toBe(true); + }); + + it('returns false when lengths differ', () => { + expect(agentsEqual([agent()], [])).toBe(false); + }); + + it('returns true when all fields match', () => { + expect(agentsEqual([agent()], [agent()])).toBe(true); + }); + + it('returns false when name differs', () => { + expect(agentsEqual([agent({ name: 'a' })], [agent({ name: 'b' })])).toBe(false); + }); + + it('returns false when status differs', () => { + expect(agentsEqual( + [agent({ status: AgentStatus.RUNNING })], + [agent({ status: AgentStatus.IDLE })], + )).toBe(false); + }); + + it('returns false when type differs', () => { + expect(agentsEqual([agent({ type: 'claude' })], [agent({ type: 'codex' })])).toBe(false); + }); + + it('returns false when summary differs', () => { + expect(agentsEqual([agent({ summary: 'a' })], [agent({ summary: 'b' })])).toBe(false); + }); + + it('returns false when sessionFilePath differs', () => { + expect(agentsEqual( + [agent({ sessionFilePath: '/a.jsonl' })], + [agent({ sessionFilePath: '/b.jsonl' })], + )).toBe(false); + }); + + it('accepts string lastActive and compares correctly', () => { + const a = agent({ lastActive: '2026-01-01T12:00:00Z' as unknown as Date }); + const b = agent({ lastActive: new Date('2026-01-01T12:00:00Z') }); + expect(agentsEqual([a], [b])).toBe(true); + }); + + it('returns false when lastActive timestamps differ', () => { + expect(agentsEqual( + [agent({ lastActive: new Date('2026-01-01T12:00:00Z') })], + [agent({ lastActive: new Date('2026-01-01T12:00:01Z') })], + )).toBe(false); + }); + + it('compares multiple agents in order', () => { + const list = [agent({ name: 'a' }), agent({ name: 'b' })]; + expect(agentsEqual(list, [agent({ name: 'a' }), agent({ name: 'b' })])).toBe(true); + expect(agentsEqual(list, [agent({ name: 'b' }), agent({ name: 'a' })])).toBe(false); + }); +}); diff --git a/packages/cli/src/__tests__/tui/watch/hooks/conversationCache.test.ts b/packages/cli/src/__tests__/tui/watch/hooks/conversationCache.test.ts new file mode 100644 index 00000000..dc1bc779 --- /dev/null +++ b/packages/cli/src/__tests__/tui/watch/hooks/conversationCache.test.ts @@ -0,0 +1,87 @@ +import { describe, it, expect, beforeEach } from 'vitest'; +import { + cacheSet, + conversationCache, + CACHE_MAX, + messagesEqual, +} from '../../../../tui/watch/hooks/useAgentConversation.js'; +import type { ConversationMessage } from '@ai-devkit/agent-manager'; + +const msg = (role: ConversationMessage['role'], content: string, timestamp?: string): ConversationMessage => + ({ role, content, timestamp } as ConversationMessage); + +describe('LRU conversation cache', () => { + beforeEach(() => { conversationCache.clear(); }); + + it('stores and retrieves an entry', () => { + cacheSet('/path/a', { mtime: 1, messages: [msg('user', 'hi')] }); + expect(conversationCache.get('/path/a')).toEqual({ mtime: 1, messages: [msg('user', 'hi')] }); + }); + + it('re-inserting an existing key moves it to most-recent (LRU refresh)', () => { + cacheSet('/path/a', { mtime: 1, messages: [] }); + cacheSet('/path/b', { mtime: 2, messages: [] }); + // refresh /path/a so it becomes most-recent + cacheSet('/path/a', { mtime: 3, messages: [] }); + // fill to capacity, pushing /path/b out first + for (let i = 0; i < CACHE_MAX - 1; i++) { + cacheSet(`/path/${i + 10}`, { mtime: i, messages: [] }); + } + expect(conversationCache.has('/path/b')).toBe(false); + expect(conversationCache.has('/path/a')).toBe(true); + }); + + it('evicts oldest entry when size reaches CACHE_MAX', () => { + for (let i = 0; i < CACHE_MAX; i++) { + cacheSet(`/path/${i}`, { mtime: i, messages: [] }); + } + expect(conversationCache.size).toBe(CACHE_MAX); + // adding one more evicts the oldest (/path/0) + cacheSet('/path/new', { mtime: 99, messages: [] }); + expect(conversationCache.size).toBe(CACHE_MAX); + expect(conversationCache.has('/path/0')).toBe(false); + expect(conversationCache.has('/path/new')).toBe(true); + }); + + it('never exceeds CACHE_MAX even under repeated inserts', () => { + for (let i = 0; i < CACHE_MAX * 3; i++) { + cacheSet(`/path/${i}`, { mtime: i, messages: [] }); + } + expect(conversationCache.size).toBe(CACHE_MAX); + }); +}); + +describe('messagesEqual', () => { + it('returns true for two empty arrays', () => { + expect(messagesEqual([], [])).toBe(true); + }); + + it('returns false when lengths differ', () => { + expect(messagesEqual([msg('user', 'a')], [])).toBe(false); + }); + + it('returns true when role, content and timestamp match', () => { + const a = [msg('user', 'hello', '2026-01-01T00:00:00Z')]; + const b = [msg('user', 'hello', '2026-01-01T00:00:00Z')]; + expect(messagesEqual(a, b)).toBe(true); + }); + + it('returns false when role differs', () => { + expect(messagesEqual([msg('user', 'x')], [msg('assistant', 'x')])).toBe(false); + }); + + it('returns false when content differs', () => { + expect(messagesEqual([msg('user', 'a')], [msg('user', 'b')])).toBe(false); + }); + + it('returns false when timestamp differs', () => { + expect(messagesEqual( + [msg('user', 'x', '2026-01-01T00:00:00Z')], + [msg('user', 'x', '2026-01-01T00:00:01Z')], + )).toBe(false); + }); + + it('returns true when both timestamps are undefined', () => { + expect(messagesEqual([msg('user', 'x')], [msg('user', 'x')])).toBe(true); + }); +}); diff --git a/packages/cli/src/__tests__/tui/watch/render/formatRelative.test.ts b/packages/cli/src/__tests__/tui/watch/render/formatRelative.test.ts new file mode 100644 index 00000000..bbf1383b --- /dev/null +++ b/packages/cli/src/__tests__/tui/watch/render/formatRelative.test.ts @@ -0,0 +1,48 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { formatRelative } from '../../../../tui/watch/render/formatRelative.js'; + +describe('formatRelative', () => { + beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(new Date('2026-01-01T12:00:00Z')); + }); + afterEach(() => { vi.useRealTimers(); }); + + it('returns "—" for undefined', () => { + expect(formatRelative(undefined)).toBe('—'); + }); + + it('returns "now" for timestamps within 5 seconds', () => { + expect(formatRelative(new Date('2026-01-01T11:59:56Z'))).toBe('now'); + expect(formatRelative(new Date('2026-01-01T12:00:00Z'))).toBe('now'); + }); + + it('returns seconds for 5–59s ago', () => { + expect(formatRelative(new Date('2026-01-01T11:59:55Z'))).toBe('5s ago'); + expect(formatRelative(new Date('2026-01-01T11:59:01Z'))).toBe('59s ago'); + }); + + it('returns minutes for 1–59m ago', () => { + expect(formatRelative(new Date('2026-01-01T11:59:00Z'))).toBe('1m ago'); + expect(formatRelative(new Date('2026-01-01T11:01:00Z'))).toBe('59m ago'); + }); + + it('returns hours for 1–23h ago', () => { + expect(formatRelative(new Date('2026-01-01T11:00:00Z'))).toBe('1h ago'); + expect(formatRelative(new Date('2025-12-31T13:00:00Z'))).toBe('23h ago'); + }); + + it('returns days for ≥24h ago', () => { + expect(formatRelative(new Date('2025-12-31T12:00:00Z'))).toBe('1d ago'); + expect(formatRelative(new Date('2025-12-25T12:00:00Z'))).toBe('7d ago'); + }); + + it('accepts a string timestamp', () => { + expect(formatRelative('2026-01-01T11:59:55Z')).toBe('5s ago'); + }); + + it('clamps negative diff to now', () => { + // future date — diff is negative, clamped to 0 → "now" + expect(formatRelative(new Date('2026-01-01T12:00:01Z'))).toBe('now'); + }); +}); diff --git a/packages/cli/src/commands/agent.ts b/packages/cli/src/commands/agent.ts index 608ceb21..03666d9c 100644 --- a/packages/cli/src/commands/agent.ts +++ b/packages/cli/src/commands/agent.ts @@ -30,7 +30,6 @@ import { import { waitForAgentResponse } from '../services/agent/agent.service.js'; import { parseMilliseconds } from '../util/time.js'; import { WatchApp } from '../tui/watch/WatchApp.js'; -import { runAction } from '../tui/watch/actions/runAction.js'; const AGENT_SEND_WAIT_POLL_INTERVAL_MS = 2000; const AGENT_SEND_WAIT_MAX_WAIT_MS = 10 * 60 * 1000; @@ -679,47 +678,18 @@ export function registerAgentCommand(program: Command): void { })); agentCommand - .command('watch') - .description('Live multi-agent monitor (interactive TUI)') - .action(withErrorHandler('agent watch', async () => { + .command('console') + .description('Interactive multi-agent console (open, message, monitor)') + .action(withErrorHandler('agent console', async () => { if (!process.stdout.isTTY) { - ui.error('agent watch requires an interactive terminal (TTY).'); + ui.error('agent console requires an interactive terminal (TTY).'); process.exit(1); } const manager = createAgentManager(); - - let lastSelection: string | null = null; - let pendingAction: { type: 'open' | 'send'; agentName: string; message?: string } | null = null; - let transient: { kind: 'info' | 'error'; text: string } | null = null; - - // Loop: render TUI → user triggers action → TUI exits with pendingAction → - // run action (stdio inherit) → re-enter TUI with preserved selection. - // Ink 7 manages alt-screen and stdin lifecycle via alternateScreen: true. - // eslint-disable-next-line no-constant-condition - while (true) { - pendingAction = null; - const onIntent = (intent: { type: 'open' | 'send'; agentName: string; message?: string }) => { - pendingAction = intent; - lastSelection = intent.agentName; - }; - const { waitUntilExit } = render( - createElement(WatchApp, { - manager, - initialSelection: lastSelection, - onIntent, - transientMessage: transient, - }), - { alternateScreen: true, exitOnCtrlC: true }, - ); - await waitUntilExit(); - transient = null; - if (!pendingAction) break; - const result = await runAction(pendingAction); - if (result.error) { - transient = { kind: 'error', text: `action failed: ${result.error}` }; - } else if (result.exitCode !== 0 && result.exitCode !== null) { - transient = { kind: 'error', text: `action exited ${result.exitCode}` }; - } - } + const { waitUntilExit } = render( + createElement(WatchApp, { manager }), + { alternateScreen: true, exitOnCtrlC: true }, + ); + await waitUntilExit(); })); } diff --git a/packages/cli/src/tui/watch/AgentListPane.tsx b/packages/cli/src/tui/watch/AgentListPane.tsx index 7e9c85f9..a7d8e25f 100644 --- a/packages/cli/src/tui/watch/AgentListPane.tsx +++ b/packages/cli/src/tui/watch/AgentListPane.tsx @@ -2,6 +2,7 @@ import React, { useEffect } from 'react'; import { Box, Text } from 'ink'; import type { AgentInfo } from '@ai-devkit/agent-manager'; import { FormatStatus } from './render/formatStatus.js'; +import { AGENT_TYPE_LABEL } from './render/agentTypeLabel.js'; interface AgentListPaneProps { agents: AgentInfo[]; @@ -9,7 +10,6 @@ interface AgentListPaneProps { onSelect: (name: string | null) => void; width?: number; error?: string | null; - focused?: boolean; } function clip(s: string | undefined, max: number): string { @@ -24,10 +24,10 @@ function shortPath(p: string): string { return home && p.startsWith(home) ? '~' + p.slice(home.length) : p; } -// Fixed column widths inside each row (excluding outer marker). -const MARKER_W = 2; // "▶ " or " " -const STATUS_W = 7; // "● run " — glyph(1) + space(1) + label(4) + trailing space(1) -const ROW_CHROME = MARKER_W + STATUS_W; +const MARKER_W = 2; +const STATUS_W = 7; +const TYPE_W = 9; // space(1) + label up to 8 chars ("opencode") +const ROW_CHROME = MARKER_W + STATUS_W + TYPE_W; interface AgentRowProps { agent: AgentInfo; @@ -37,19 +37,13 @@ interface AgentRowProps { const AgentRow: React.FC = ({ agent, isSelected, innerWidth }) => { const nameW = Math.max(4, innerWidth - ROW_CHROME); - const summaryW = Math.max(4, innerWidth - MARKER_W); // summary indented by marker only - - const rawSummary = agent.summary?.trim() - ? agent.summary - : shortPath(agent.projectPath); - const summary = clip(rawSummary, summaryW); - const name = clip(agent.name, nameW); - + const summaryW = Math.max(4, innerWidth - MARKER_W); + const rawSummary = agent.summary?.trim() ? agent.summary : shortPath(agent.projectPath); const accent = isSelected ? 'cyan' : undefined; + const typeLabel = AGENT_TYPE_LABEL[agent.type] ?? agent.type; return ( - {/* Line 1: marker · status · name */} {isSelected ? '▶ ' : ' '} @@ -58,14 +52,16 @@ const AgentRow: React.FC = ({ agent, isSelected, innerWidth }) => - {name} + {clip(agent.name, nameW)} + + + {typeLabel} - {/* Line 2: summary / project path, indented under status */} - {summary} + {clip(rawSummary, summaryW)} @@ -108,18 +104,26 @@ const AgentListPaneInner: React.FC = ({ ); } + const divider = '─'.repeat(innerWidth); + return ( AGENTS ({agents.length}) - {agents.map((agent) => ( - + {agents.map((agent, i) => ( + + {i > 0 && ( + + {divider} + + )} + + ))} ); diff --git a/packages/cli/src/tui/watch/FooterSection.tsx b/packages/cli/src/tui/watch/FooterSection.tsx deleted file mode 100644 index a4ed1267..00000000 --- a/packages/cli/src/tui/watch/FooterSection.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import { StatusFooter } from './StatusFooter.js'; -import { useWatchContext } from './state/WatchContext.js'; - -interface FooterSectionProps { - selectedName: string | null; - narrowNote: string | null; - transient: { kind: 'info' | 'error'; text: string } | null; -} - -const FooterSectionInner: React.FC = ({ selectedName, narrowNote, transient }) => { - const { agents, lastUpdated, isLoading } = useWatchContext(); - const selected = agents.find(a => a.name === selectedName) ?? null; - return ( - - ); -}; - -export const FooterSection = React.memo(FooterSectionInner); diff --git a/packages/cli/src/tui/watch/HeaderBar.tsx b/packages/cli/src/tui/watch/HeaderBar.tsx index d88ebae1..18911e2a 100644 --- a/packages/cli/src/tui/watch/HeaderBar.tsx +++ b/packages/cli/src/tui/watch/HeaderBar.tsx @@ -9,7 +9,7 @@ const HeaderBarInner: React.FC = () => { ai-devkit · - agent watch + agent console {totalLabel} ); diff --git a/packages/cli/src/tui/watch/ListSection.tsx b/packages/cli/src/tui/watch/ListSection.tsx deleted file mode 100644 index f688f22b..00000000 --- a/packages/cli/src/tui/watch/ListSection.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import { Box } from 'ink'; -import { AgentListPane } from './AgentListPane.js'; -import { useWatchContext } from './state/WatchContext.js'; - -interface ListSectionProps { - selectedName: string | null; - onSelect: (name: string | null) => void; - focused: boolean; - width: number; - height: number; -} - -const ListSectionInner: React.FC = ({ selectedName, onSelect, focused, width, height }) => { - const { agents, error } = useWatchContext(); - return ( - - - - ); -}; - -export const ListSection = React.memo(ListSectionInner); diff --git a/packages/cli/src/tui/watch/PreviewPane.tsx b/packages/cli/src/tui/watch/PreviewPane.tsx index eb558d9b..cfa4c841 100644 --- a/packages/cli/src/tui/watch/PreviewPane.tsx +++ b/packages/cli/src/tui/watch/PreviewPane.tsx @@ -2,6 +2,8 @@ import React from 'react'; import { Box, Text } from 'ink'; import type { AgentInfo, ConversationMessage } from '@ai-devkit/agent-manager'; import type { ConversationFetchError } from './hooks/useAgentConversation.js'; +import { formatRelative } from './render/formatRelative.js'; +import { AGENT_TYPE_LABEL_DISPLAY } from './render/agentTypeLabel.js'; interface PreviewPaneProps { agent: AgentInfo | null; @@ -17,12 +19,6 @@ const ROLE_COLOR: Record = { - claude: 'Claude', - codex: 'Codex', - gemini_cli: 'Gemini', - opencode: 'OpenCode', -}; function formatTime(ts: string | undefined): string { if (!ts) return ''; @@ -33,20 +29,6 @@ function formatTime(ts: string | undefined): string { } } -function formatRelative(date: Date | string | undefined): string { - if (!date) return '—'; - const d = typeof date === 'string' ? new Date(date) : date; - const diffMs = Date.now() - d.getTime(); - const sec = Math.max(0, Math.floor(diffMs / 1000)); - if (sec < 5) return 'now'; - if (sec < 60) return `${sec}s ago`; - const min = Math.floor(sec / 60); - if (min < 60) return `${min}m ago`; - const hr = Math.floor(min / 60); - if (hr < 24) return `${hr}h ago`; - return `${Math.floor(hr / 24)}d ago`; -} - function shortPath(p: string): string { const home = process.env.HOME ?? ''; if (home && p.startsWith(home)) return '~' + p.slice(home.length); @@ -59,7 +41,7 @@ const MetadataHeader: React.FC<{ agent: AgentInfo }> = ({ agent }) => ( · {agent.name} · - {TYPE_LABEL[agent.type] ?? agent.type} + {AGENT_TYPE_LABEL_DISPLAY[agent.type] ?? agent.type} · {formatRelative(agent.lastActive)} · @@ -112,12 +94,14 @@ const PreviewPaneInner: React.FC = ({ const time = formatTime(msg.timestamp); rendered.unshift( - + {time ? [{time}] : null} {msg.role}: - + {trimmed.map((line: string, idx: number) => ( - {line} + + {line} + ))} , ); diff --git a/packages/cli/src/tui/watch/StatusFooter.tsx b/packages/cli/src/tui/watch/StatusFooter.tsx index 412e0fc0..84e21ad9 100644 --- a/packages/cli/src/tui/watch/StatusFooter.tsx +++ b/packages/cli/src/tui/watch/StatusFooter.tsx @@ -1,33 +1,18 @@ import React from 'react'; import { Box, Text } from 'ink'; import { AgentStatus, type AgentInfo } from '@ai-devkit/agent-manager'; +import { formatRelative } from './render/formatRelative.js'; interface StatusFooterProps { agents: AgentInfo[]; - selected: AgentInfo | null; lastUpdated: Date | null; isLoading: boolean; narrowNote: string | null; transient: { kind: 'info' | 'error'; text: string } | null; } -function formatRelative(date: Date | string | undefined): string { - if (!date) return '—'; - const d = typeof date === 'string' ? new Date(date) : date; - const diffMs = Date.now() - d.getTime(); - const sec = Math.max(0, Math.floor(diffMs / 1000)); - if (sec < 5) return 'now'; - if (sec < 60) return `${sec}s ago`; - const min = Math.floor(sec / 60); - if (min < 60) return `${min}m ago`; - const hr = Math.floor(min / 60); - if (hr < 24) return `${hr}h ago`; - return `${Math.floor(hr / 24)}d ago`; -} - const StatusFooterInner: React.FC = ({ agents, - selected, lastUpdated, isLoading, narrowNote, @@ -55,16 +40,9 @@ const StatusFooterInner: React.FC = ({ - {summary}{' · '}{updated}{' · '}↑/↓ nav · ⏎ open · i message · q quit + {summary}{' · '}{updated}{' · '}j/k nav · o open · i message · q quit - {selected ? ( - - - sel: {selected.name} · {selected.projectPath} · {selected.status} - - - ) : null} {narrowNote ? ( {narrowNote} diff --git a/packages/cli/src/tui/watch/WatchApp.tsx b/packages/cli/src/tui/watch/WatchApp.tsx index 4ee5a16a..24816283 100644 --- a/packages/cli/src/tui/watch/WatchApp.tsx +++ b/packages/cli/src/tui/watch/WatchApp.tsx @@ -3,18 +3,16 @@ import { Box, useApp, useInput } from 'ink'; import type { AgentManager } from '@ai-devkit/agent-manager'; import { WatchProvider, useWatchContext } from './state/WatchContext.js'; import { useTerminalSize } from './hooks/useTerminalSize.js'; -import { ListSection } from './ListSection.js'; +import { AgentListPane } from './AgentListPane.js'; import { PreviewSection } from './PreviewSection.js'; -import { FooterSection } from './FooterSection.js'; +import { StatusFooter } from './StatusFooter.js'; import { ChatInput } from './ChatInput.js'; import { HeaderBar } from './HeaderBar.js'; -import type { WatchAction } from './actions/types.js'; +import { runAction } from './actions/runAction.js'; interface WatchAppProps { manager: AgentManager; initialSelection?: string | null; - onIntent?: (action: WatchAction) => void; - transientMessage?: { kind: 'info' | 'error'; text: string } | null; } const NARROW_THRESHOLD_COLS = 120; @@ -26,17 +24,35 @@ const INPUT_BOX_CHROME_ROWS = 2; type Focus = 'list' | 'input'; +export function computeLayout(cols: number, rows: number, inputLines: number, narrow: boolean) { + const inputBoxHeight = inputLines + INPUT_BOX_CHROME_ROWS; + const totalHeight = Math.max( + MIN_CONTENT_HEIGHT + inputBoxHeight + FOOTER_HEIGHT + HEADER_HEIGHT, + rows - 1, + ); + const contentHeight = Math.max(MIN_CONTENT_HEIGHT, totalHeight - FOOTER_HEIGHT - HEADER_HEIGHT); + const listPaneWidth = narrow ? cols - 2 : LIST_PANE_WIDTH; + const rightColWidth = Math.max(20, cols - listPaneWidth - 1); + return { + inputBoxHeight, + contentHeight, + previewHeight: contentHeight - inputBoxHeight, + listPaneWidth, + rightColWidth, + inputInnerWidth: Math.max(4, rightColWidth - 4), + }; +} + const WatchAppShell: React.FC<{ initialSelection: string | null; - onIntent?: (action: WatchAction) => void; - transientMessage: { kind: 'info' | 'error'; text: string } | null; setInputFocused: (v: boolean) => void; -}> = ({ initialSelection, onIntent, transientMessage, setInputFocused }) => { +}> = ({ initialSelection, setInputFocused }) => { const { exit } = useApp(); const [selectedName, setSelectedName] = useState(initialSelection); const [focus, setFocus] = useState('list'); const [inputLines, setInputLines] = useState(1); const [inputValue, setInputValue] = useState(''); + const [transient, setTransient] = useState<{ kind: 'info' | 'error'; text: string } | null>(null); const inputFocused = focus === 'input'; useEffect(() => { @@ -45,13 +61,15 @@ const WatchAppShell: React.FC<{ useEffect(() => { setInputFocused(inputFocused); }, [inputFocused, setInputFocused]); - const onIntentRef = useRef(onIntent); - onIntentRef.current = onIntent; - const exitRef = useRef(exit); - exitRef.current = exit; + useEffect(() => { + if (!transient) return; + const t = setTimeout(() => setTransient(null), 4000); + return () => clearTimeout(t); + }, [transient]); + const selectedNameRef = useRef(selectedName); selectedNameRef.current = selectedName; - const { agents } = useWatchContext(); + const { agents, error, lastUpdated, isLoading } = useWatchContext(); const agentsRef = useRef(agents); agentsRef.current = agents; @@ -59,19 +77,20 @@ const WatchAppShell: React.FC<{ setFocus('list'); const name = selectedNameRef.current; const agent = name ? agentsRef.current.find(a => a.name === name) : null; - const intent = onIntentRef.current; - if (agent && intent) { - intent({ type: 'send', agentName: agent.name, message: text }); - exitRef.current(); - } + if (!agent) return; + void runAction({ type: 'send', agentName: agent.name, message: text }).then(result => { + if (result.error || (result.exitCode !== 0 && result.exitCode !== null)) { + setTransient({ kind: 'error', text: result.error ?? `send exited ${result.exitCode}` }); + } else { + setTransient({ kind: 'info', text: `Message sent to ${agent.name}` }); + } + }); }, []); const handleInputCancel = useCallback(() => { setFocus('list'); }, []); - // All keyboard handling lives here — useInput inside React.memo components - // does not fire reliably in Ink 7 + React 19. useInput((input, key) => { if (focus === 'input') { if (key.escape) { @@ -81,75 +100,67 @@ const WatchAppShell: React.FC<{ return; } - if (input === 'q') { - exit(); - return; - } + if (input === 'q') { exit(); return; } + if (input === 'o') { const name = selectedNameRef.current; const agent = name ? agentsRef.current.find(a => a.name === name) : null; - if (agent && onIntent) { - onIntent({ type: 'open', agentName: agent.name }); - exit(); - } + if (!agent) return; + void runAction({ type: 'open', agentName: agent.name }).then(result => { + if (result.error || (result.exitCode !== 0 && result.exitCode !== null)) { + setTransient({ kind: 'error', text: result.error ?? `open exited ${result.exitCode}` }); + } + }); return; } + if (input === 'i' || input === 'm') { - const name = selectedNameRef.current; - if (name) setFocus('input'); + if (selectedNameRef.current) setFocus('input'); return; } + if (key.downArrow || input === 'j') { const list = agentsRef.current; - if (list.length === 0) return; + if (!list.length) return; const idx = Math.max(0, list.findIndex(a => a.name === selectedNameRef.current)); setSelectedName(list[(idx + 1) % list.length].name); return; } + if (key.upArrow || input === 'k') { const list = agentsRef.current; - if (list.length === 0) return; + if (!list.length) return; const idx = Math.max(0, list.findIndex(a => a.name === selectedNameRef.current)); setSelectedName(list[(idx - 1 + list.length) % list.length].name); return; } }); - const [, forceTick] = useState(0); - useEffect(() => { - if (!transientMessage) return; - const handle = setTimeout(() => forceTick(t => t + 1), 4000); - return () => clearTimeout(handle); - }, [transientMessage]); - const { cols, rows } = useTerminalSize(); const narrow = cols < NARROW_THRESHOLD_COLS; - const inputBoxHeight = inputLines + INPUT_BOX_CHROME_ROWS; - const totalHeight = Math.max( - MIN_CONTENT_HEIGHT + inputBoxHeight + FOOTER_HEIGHT + HEADER_HEIGHT, - rows - 1, - ); - const contentHeight = Math.max(MIN_CONTENT_HEIGHT, totalHeight - FOOTER_HEIGHT - HEADER_HEIGHT); - const previewHeight = contentHeight - inputBoxHeight; - const listHeight = contentHeight; - - const listPaneWidth = narrow ? cols - 2 : LIST_PANE_WIDTH; - // marginLeft(1) + border(2) accounted for; right col fills the rest exactly. - const rightColWidth = Math.max(20, cols - listPaneWidth - 1); - const inputInnerWidth = Math.max(4, rightColWidth - 4); + const { inputBoxHeight, contentHeight, previewHeight, listPaneWidth, rightColWidth, inputInnerWidth } = computeLayout(cols, rows, inputLines, narrow); return ( - + height={contentHeight} + borderStyle="round" + borderColor={focus === 'list' ? 'cyan' : 'gray'} + paddingX={1} + flexDirection="column" + > + + {!narrow && ( @@ -178,10 +189,12 @@ const WatchAppShell: React.FC<{ )} - ); @@ -190,16 +203,12 @@ const WatchAppShell: React.FC<{ export const WatchApp: React.FC = ({ manager, initialSelection = null, - onIntent, - transientMessage = null, }) => { const [inputFocused, setInputFocused] = useState(false); return ( diff --git a/packages/cli/src/tui/watch/actions/runAction.ts b/packages/cli/src/tui/watch/actions/runAction.ts index e45a9d55..e037b052 100644 --- a/packages/cli/src/tui/watch/actions/runAction.ts +++ b/packages/cli/src/tui/watch/actions/runAction.ts @@ -7,9 +7,6 @@ export interface ActionResult { } function resolveCliEntry(): { command: string; baseArgs: string[] } { - // Re-invoke the exact same process (works in both dev/ts-node and prod/compiled). - // process.execArgv carries loader flags (e.g. --loader ts-node/esm). - // process.argv[1] is the entry script (src/cli.ts in dev, dist/cli.js in prod). return { command: process.execPath, baseArgs: [...process.execArgv, process.argv[1]] }; } @@ -25,12 +22,14 @@ export async function runAction(action: WatchAction): Promise { })(); return new Promise((resolve) => { - const child = spawn(command, argv, { stdio: 'inherit' }); - child.once('error', (err) => { - resolve({ exitCode: null, error: err.message }); - }); + // Use pipe so the subprocess never takes over the TUI's terminal. + const child = spawn(command, argv, { stdio: ['ignore', 'pipe', 'pipe'] }); + const stderrChunks: Buffer[] = []; + child.stderr?.on('data', (chunk: Buffer) => stderrChunks.push(chunk)); + child.once('error', (err) => resolve({ exitCode: null, error: err.message })); child.once('exit', (code) => { - resolve({ exitCode: code }); + const stderr = Buffer.concat(stderrChunks).toString().trim(); + resolve({ exitCode: code, error: code !== 0 && stderr ? stderr : undefined }); }); }); } diff --git a/packages/cli/src/tui/watch/hooks/useAgentConversation.ts b/packages/cli/src/tui/watch/hooks/useAgentConversation.ts index 534aadc1..1aa95c55 100644 --- a/packages/cli/src/tui/watch/hooks/useAgentConversation.ts +++ b/packages/cli/src/tui/watch/hooks/useAgentConversation.ts @@ -26,7 +26,7 @@ interface Params { paused?: boolean; } -function messagesEqual(a: ConversationMessage[], b: ConversationMessage[]): boolean { +export function messagesEqual(a: ConversationMessage[], b: ConversationMessage[]): boolean { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i].role !== b[i].role) return false; @@ -43,6 +43,23 @@ const EMPTY_STATE: UseAgentConversationResult = { isLoading: false, }; +interface CacheEntry { + mtime: number; + messages: ConversationMessage[]; +} + +export const CACHE_MAX = 50; +// Module-level LRU cache: re-inserting a key moves it to most-recent position. +export const conversationCache = new Map(); + +export function cacheSet(key: string, entry: CacheEntry): void { + conversationCache.delete(key); + if (conversationCache.size >= CACHE_MAX) { + conversationCache.delete(conversationCache.keys().next().value!); + } + conversationCache.set(key, entry); +} + export function useAgentConversation({ manager, agent, @@ -54,20 +71,22 @@ export function useAgentConversation({ const runTokenRef = useRef(0); const mountedRef = useRef(true); - const lastMtimeRef = useRef(null); useEffect(() => { mountedRef.current = true; if (!agent) { setState(prev => prev === EMPTY_STATE ? prev : EMPTY_STATE); - lastMtimeRef.current = null; return () => { mountedRef.current = false; }; } - // Selection change → fresh state, single render. - setState({ messages: [], error: null, lastUpdated: null, isLoading: true }); - lastMtimeRef.current = null; + // If we have a cached result for this agent, show it immediately while + // the debounced fetch confirms whether the file has changed. + const cached = agent.sessionFilePath ? conversationCache.get(agent.sessionFilePath) : undefined; + setState(cached + ? { messages: cached.messages, error: null, lastUpdated: new Date(), isLoading: false } + : { messages: [], error: null, lastUpdated: null, isLoading: true }, + ); const fetchOnce = (): void => { const token = ++runTokenRef.current; @@ -106,12 +125,16 @@ export function useAgentConversation({ } catch { mtime = null; } - // mtime didn't change → no need to re-parse. Skip state update. - if (mtime !== null && lastMtimeRef.current === mtime) { + + const cached = conversationCache.get(agent.sessionFilePath); + if (mtime !== null && cached && cached.mtime === mtime) { + // File unchanged — serve from cache, no JSONL parse needed. if (token !== runTokenRef.current || !mountedRef.current) return; - setState(prev => prev.isLoading || prev.error - ? { ...prev, isLoading: false, error: null } - : prev); + setState(prev => { + const changed = !messagesEqual(prev.messages, cached.messages); + if (!changed && prev.error === null && !prev.isLoading && prev.lastUpdated !== null) return prev; + return { messages: changed ? cached.messages : prev.messages, error: null, lastUpdated: new Date(), isLoading: false }; + }); return; } @@ -121,7 +144,9 @@ export function useAgentConversation({ const sliced = tail > 0 && conversation.length > tail ? conversation.slice(-tail) : conversation; - lastMtimeRef.current = mtime; + if (mtime !== null) { + cacheSet(agent.sessionFilePath, { mtime, messages: sliced }); + } setState(prev => { const changed = !messagesEqual(prev.messages, sliced); if (!changed && prev.error === null && !prev.isLoading && prev.lastUpdated !== null) { diff --git a/packages/cli/src/tui/watch/hooks/useAgentList.ts b/packages/cli/src/tui/watch/hooks/useAgentList.ts index fd779129..6fa2fecb 100644 --- a/packages/cli/src/tui/watch/hooks/useAgentList.ts +++ b/packages/cli/src/tui/watch/hooks/useAgentList.ts @@ -10,7 +10,7 @@ export interface UseAgentListResult { export const LIST_POLL_INTERVAL_MS = 3000; -function agentsEqual(a: AgentInfo[], b: AgentInfo[]): boolean { +export function agentsEqual(a: AgentInfo[], b: AgentInfo[]): boolean { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { const x = a[i]; @@ -22,8 +22,8 @@ function agentsEqual(a: AgentInfo[], b: AgentInfo[]): boolean { || x.summary !== y.summary || x.sessionFilePath !== y.sessionFilePath ) return false; - const tx = x.lastActive instanceof Date ? x.lastActive.getTime() : new Date(x.lastActive).getTime(); - const ty = y.lastActive instanceof Date ? y.lastActive.getTime() : new Date(y.lastActive).getTime(); + const tx = x.lastActive instanceof Date ? x.lastActive.getTime() : Date.parse(x.lastActive as string); + const ty = y.lastActive instanceof Date ? y.lastActive.getTime() : Date.parse(y.lastActive as string); if (tx !== ty) return false; } return true; @@ -49,13 +49,14 @@ export function useAgentList( useEffect(() => { mountedRef.current = true; + inFlightRef.current = false; const fetchOnce = async (): Promise => { if (inFlightRef.current) return; inFlightRef.current = true; const token = ++runTokenRef.current; try { - const next = await manager.listAgents({ sortBy: 'name' }); + const next = await manager.listAgents({ sortBy: 'status' }); if (!mountedRef.current || token !== runTokenRef.current) return; setState(prev => { const isFirst = prev.lastUpdated === null; diff --git a/packages/cli/src/tui/watch/render/agentTypeLabel.ts b/packages/cli/src/tui/watch/render/agentTypeLabel.ts new file mode 100644 index 00000000..3e6f0a9f --- /dev/null +++ b/packages/cli/src/tui/watch/render/agentTypeLabel.ts @@ -0,0 +1,15 @@ +/** Compact lowercase label for list rows. */ +export const AGENT_TYPE_LABEL: Record = { + claude: 'claude', + codex: 'codex', + gemini_cli: 'gemini', + opencode: 'opencode', +}; + +/** Display-cased label for headers and preview panes. */ +export const AGENT_TYPE_LABEL_DISPLAY: Record = { + claude: 'Claude', + codex: 'Codex', + gemini_cli: 'Gemini', + opencode: 'OpenCode', +}; diff --git a/packages/cli/src/tui/watch/render/formatRelative.ts b/packages/cli/src/tui/watch/render/formatRelative.ts new file mode 100644 index 00000000..60e5f594 --- /dev/null +++ b/packages/cli/src/tui/watch/render/formatRelative.ts @@ -0,0 +1,13 @@ +export function formatRelative(date: Date | string | undefined): string { + if (!date) return '—'; + const d = typeof date === 'string' ? new Date(date) : date; + const diffMs = Date.now() - d.getTime(); + const sec = Math.max(0, Math.floor(diffMs / 1000)); + if (sec < 5) return 'now'; + if (sec < 60) return `${sec}s ago`; + const min = Math.floor(sec / 60); + if (min < 60) return `${min}m ago`; + const hr = Math.floor(min / 60); + if (hr < 24) return `${hr}h ago`; + return `${Math.floor(hr / 24)}d ago`; +} diff --git a/packages/cli/src/tui/watch/render/formatStatus.tsx b/packages/cli/src/tui/watch/render/formatStatus.tsx index 08f99fa8..43221c05 100644 --- a/packages/cli/src/tui/watch/render/formatStatus.tsx +++ b/packages/cli/src/tui/watch/render/formatStatus.tsx @@ -25,8 +25,3 @@ const FormatStatusInner: React.FC = ({ status }) => { }; export const FormatStatus = React.memo(FormatStatusInner); - -export function statusDisplayWidth(): number { - // glyph (1) + space (1) + longest label ("idle"/"wait"/"run"/"unk" = 4) - return 6; -} diff --git a/packages/cli/src/tui/watch/state/WatchContext.tsx b/packages/cli/src/tui/watch/state/WatchContext.tsx index 75cefdd0..40ee2045 100644 --- a/packages/cli/src/tui/watch/state/WatchContext.tsx +++ b/packages/cli/src/tui/watch/state/WatchContext.tsx @@ -1,4 +1,4 @@ -import React, { createContext, useContext } from 'react'; +import React, { createContext, useContext, useMemo } from 'react'; import type { AgentManager } from '@ai-devkit/agent-manager'; import { useAgentList, type UseAgentListResult } from '../hooks/useAgentList.js'; @@ -25,6 +25,9 @@ export const WatchProvider: React.FC = ({ manager, inputFocu // Pause list poll while user is composing a message: removes a source of // re-renders that compete with the controlled TextInput. const list = useAgentList(manager, undefined, inputFocused); - const value: WatchContextValue = { ...list, manager, inputFocused }; + const value = useMemo( + () => ({ ...list, manager, inputFocused }), + [list, manager, inputFocused], + ); return {children}; }; From e2c92776866628e2575f3472925801fcfe18fa59 Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Thu, 28 May 2026 11:38:52 +0200 Subject: [PATCH 3/7] remove stale docs --- .../design/2026-05-27-feature-agent-watch.md | 216 ------------------ .../2026-05-27-feature-agent-watch.md | 65 ------ .../2026-05-27-feature-agent-watch.md | 100 -------- .../2026-05-27-feature-agent-watch.md | 99 -------- .../testing/2026-05-27-feature-agent-watch.md | 81 ------- 5 files changed, 561 deletions(-) delete mode 100644 docs/ai/design/2026-05-27-feature-agent-watch.md delete mode 100644 docs/ai/implementation/2026-05-27-feature-agent-watch.md delete mode 100644 docs/ai/planning/2026-05-27-feature-agent-watch.md delete mode 100644 docs/ai/requirements/2026-05-27-feature-agent-watch.md delete mode 100644 docs/ai/testing/2026-05-27-feature-agent-watch.md diff --git a/docs/ai/design/2026-05-27-feature-agent-watch.md b/docs/ai/design/2026-05-27-feature-agent-watch.md deleted file mode 100644 index 633318cc..00000000 --- a/docs/ai/design/2026-05-27-feature-agent-watch.md +++ /dev/null @@ -1,216 +0,0 @@ ---- -phase: design -title: System Design & Architecture -description: Define the technical architecture, components, and data models ---- - -# System Design & Architecture — Agent Watch - -## Architecture Overview - -`ai-devkit agent watch` is a new CLI subcommand that launches an Ink-based React TUI inside the user's terminal. The TUI reads agent state in-process via the existing `AgentManager` and adapter APIs, renders a two-pane master-detail view, and shells out to existing `ai-devkit agent open` / `ai-devkit agent send` commands for user actions. - -```mermaid -graph TD - CLI["packages/cli
agent watch command"] -->|render| TUI["Ink App
WatchApp.tsx"] - TUI --> ListPane["AgentListPane
(left, ~35%)"] - TUI --> PreviewPane["PreviewPane
(right, ~65%)"] - TUI --> Footer["StatusFooter"] - TUI --> MessageModal["SendMessageModal
(overlay)"] - - ListPane -->|poll 2s| ListPoller["useAgentList hook"] - PreviewPane -->|poll 1s| PreviewPoller["useAgentConversation hook"] - - ListPoller -->|manager.listAgents| Manager["AgentManager
(in-process)"] - PreviewPoller -->|adapter.getConversation| Manager - Manager --> ClaudeAdapter - Manager --> CodexAdapter - Manager --> GeminiAdapter - Manager --> OpenCodeAdapter - - TUI -->|Enter| OpenSpawn["spawn ai-devkit agent open name
(suspend + resume)"] - TUI -->|m + submit| SendSpawn["spawn ai-devkit agent send --id name msg"] -``` - -### Key components and responsibilities - -- **`agent watch` command** (`packages/cli/src/commands/agent.ts`): Registers the subcommand, verifies stdout is a TTY, instantiates `AgentManager`, and renders the Ink app with `render()`. -- **`WatchApp`**: Root Ink component. Owns selection state, modal state, "ended-agent" banner state. Wires polling hooks to panes. -- **`AgentListPane`**: Renders the live agent table, handles `↑↓`/`j k` selection, exposes the selected `AgentInfo` to parent. -- **`PreviewPane`**: Renders the selected agent's recent conversation messages with collapsible tool calls. Auto-scrolls to bottom unless user scrolls up. -- **`StatusFooter`**: Renders agent counts, selected agent metadata, keybinding hints, transient error/info lines. -- **`SendMessageModal`**: Overlay text input; on submit, spawns `ai-devkit agent send --id `. On cancel, returns to list. -- **Polling hooks** (`useAgentList`, `useAgentConversation`): Encapsulate the polling state machine — setInterval, in-flight cancellation, error capture, "data freshness" timestamps. -- **Action runners** (`runAgentOpen`, `runAgentSend`): Suspend Ink, spawn the child CLI via `tea.ExecProcess`-equivalent (Ink supports this via stdin/stdout takeover), wait for exit, resume. - -### Technology stack - -| Choice | Rationale | -|---|---| -| **Ink 5** (`ink`, `ink-text-input`, `ink-spinner`) | React for terminals; matches existing TS codebase; ecosystem covers list/input/spinner widgets. Ink 5 supports ESM-only deps and aligns with current Node ≥18 target. | -| **In-process `AgentManager`** | Avoids fork/parse overhead of `ai-devkit agent list --json` polling; preview reads session files via the adapter directly. Trade-off: TUI depends on `@ai-devkit/agent-manager` package internals. | -| **`child_process.spawn` for `open`/`send`** | Keep the existing CLI as the source of truth for these verbs. No duplication of terminal-focus or send logic. | -| **No new persistent state, no daemon** | v1 is a pure viewer; closing the TUI loses nothing. Polling is sufficient at the stated cadence. | - -## Data Models - -The TUI does not introduce new persistent data. It consumes existing types from `@ai-devkit/agent-manager`: - -### From `manager.listAgents()` -```ts -type AgentInfo = { - name: string; - type: 'claude' | 'codex' | 'gemini_cli' | 'opencode'; - status: AgentStatus; // RUNNING | WAITING | IDLE | UNKNOWN - projectPath: string; - summary?: string; // "working on" line - lastActive: Date; - sessionId?: string; - sessionFilePath?: string; -} -``` - -### From `adapter.getConversation(sessionFilePath, opts)` -```ts -type ConversationMessage = { - role: 'user' | 'assistant' | 'tool_use' | 'tool_result'; - content: string; - timestamp?: string; - // tool-call specific fields when verbose -} -``` - -### TUI-local view models - -- `WatchState`: `{ agents: AgentInfo[], selectedName: string | null, lastListUpdate: Date, listError: string | null, view: 'list' | 'sendModal' }` -- `PreviewState`: `{ messages: ConversationMessage[], expandedToolIndexes: Set, autoScroll: boolean, lastPreviewUpdate: Date, previewError: string | null }` - -### Sort order - -The TUI uses the order returned by `AgentManager.listAgents()` directly: WAITING → RUNNING → IDLE → UNKNOWN, then `lastActive` desc within each group. Waiting agents bubble to the top for free; the non-color row cue (requirement #4) is reinforcement. No client-side re-sort, no upstream change. - -## API Design - -### New CLI surface -``` -ai-devkit agent watch -``` -No flags in v1. Constants in code: list poll = 2000ms, preview poll = 1000ms, preview tail = 20 messages. No JSON output mode (interactive only). Exits 0 on `q`, 1 on fatal init error (no TTY, manager init failure). - -### Internal interfaces - -- `WatchApp` consumes `{ manager: AgentManager }` as prop. -- Polling hooks take the manager + cadence and return `{ data, error, isLoading, lastUpdated }`. They handle their own intervals and cancellation; React unmount stops the loop. -- Action runners take `{ name, message? }` and return `Promise<{ exitCode: number, stderr: string }>` after the child process exits. - -### Suspend / resume for `agent open` - -Ink's `useApp().exit()` returns control to the parent process. The runner uses Ink's documented "exec external command" pattern: -1. Capture current screen state (cursor position, alt-screen). -2. Call `app.unmount()` to release stdin/stdout. -3. `spawn('ai-devkit', ['agent', 'open', name], { stdio: 'inherit' })`. -4. Await exit. -5. Re-`render()`, restoring the prior `selectedName`. - -For `agent send`, the child's stdio is also inherited so any prompts (e.g., the existing "agent not waiting" warning) display in-place; the user sees normal CLI output then is returned to the TUI. - -## Component Breakdown - -### File layout -``` -packages/cli/src/commands/agent.ts # add .command('watch') -packages/cli/src/tui/watch/ - WatchApp.tsx # root component - AgentListPane.tsx - PreviewPane.tsx - StatusFooter.tsx - SendMessageModal.tsx - hooks/ - useAgentList.ts - useAgentConversation.ts - useTerminalSize.ts - actions/ - runAgentOpen.ts - runAgentSend.ts - render/ - formatStatus.tsx # color + glyph + label (no-color cue) - formatMessage.tsx # assistant / tool_use / tool_result rendering - state/ - watchReducer.ts # selection, modal, banner state -``` - -### Polling state machine - -Single hook handles both panes (parameterized): - -``` -state: idle | loading | success | error -on mount → start interval -each tick → if not loading: fetch; on resolve → setState success; on reject → setState error (keep stale data visible) -selection change (preview only) → cancel in-flight, refetch immediately -unmount → clear interval, abort in-flight -``` - -Cancellation: hold a `runToken` ref, bump on every fetch start, only commit results matching the current token. - -### Narrow-terminal fallback - -Detect via `useTerminalSize` (listens on `process.stdout` `resize`). Below 100 columns, hide the preview pane and show a footer line: `resize ≥100 cols to show preview`. Selection still works. - -## Design Decisions - -### D1. In-process manager vs shell-out -**Chosen:** in-process import of `@ai-devkit/agent-manager`. -**Alternative:** spawn `ai-devkit agent list --json` / `agent detail --json --tail 20`. -**Trade-off:** in-process is ~10–20ms faster per tick and avoids JSON parse + process startup cost (Node CLI cold start is ~150–300ms). The cost is tighter coupling: a manager API rename will break the TUI. Accepted because both packages ship together and the manager is internal to ai-devkit. - -### D2. Polling vs streaming -**Chosen:** polling (2s list, 1s preview). -**Alternative:** add `--watch` NDJSON to `agent list`, subscribe via stdin. -**Trade-off:** polling ships now without modifying the manager. Worst-case staleness is 2s for the list, which satisfies success criterion #3 (3s). Streaming can be added later behind the same hook interface. - -### D3. Use the manager's native sort -**Chosen:** consume `listAgents()` order as-is (status priority, then `lastActive` desc within each group). -**Alternative:** re-sort client-side or change the manager. -**Trade-off:** native order already surfaces waiting agents first, which is the actual UX goal behind the requirement; client-side re-sort would have hidden that signal. Zero new code, zero coupling. - -### D4. Inherited stdio vs captured stdio for `agent open` / `send` -**Chosen:** inherited (`stdio: 'inherit'`). -**Alternative:** capture stdout/stderr and render inside the TUI. -**Trade-off:** capturing requires re-implementing prompts and color handling. Inherited just hands the terminal over; for `open`, that's required anyway since it focuses another terminal window. Inherited stdio also makes it impossible to leak the parent's TUI state — the child sees a clean terminal. - -### D5. Single window vs multi-window -**Chosen:** single window, two panes. -**Alternative:** Ink-supported tabs/windows. -**Trade-off:** Single window matches requirements (no splits in v1) and keeps the mental model simple. Tabs can be added later without restructuring. - -### D6. Tool-call rendering: collapsed by default -**Chosen:** Render `tool_use` / `tool_result` as one-liners (`→ read src/auth/mw.ts`); `v` toggles expansion on the focused message. -**Alternative:** Always expand (more context, but a single 50-line file read dominates the preview). -**Trade-off:** Collapsed default preserves the "what is the agent doing right now" signal. Expansion stays available. - -### D7. Pure viewer, no kill action -**Chosen:** No destructive verbs in v1. Confirms non-goal from requirements. -**Alternative:** Add a `k` keybinding + new `ai-devkit agent kill` CLI verb. -**Trade-off:** Out of scope by requirement. Worth revisiting in a follow-up once the CLI verb exists. - -## Non-Functional Requirements - -| Property | Target | How | -|---|---|---| -| **Launch latency** | <1s on ≤10 agents | First render before first poll completes (skeleton row); manager init is sync. | -| **Selection-to-preview latency** | <1s | Preview poll fires immediately on selection change, not on next interval. | -| **State-change visibility** | ≤3s | 2s list poll cadence + 1 frame render < 3s ceiling. | -| **Input latency** | <100ms | Ink renders on state change; keystrokes never wait for I/O (in-flight fetches don't block input). | -| **CPU at idle (20 agents)** | <5% of one core on M-series Mac | Polling at 2s × `listAgents` (which already runs in parallel across adapters); preview reads only one session file per second. | -| **Memory** | <50 MB resident | One Node process; no transcript buffering beyond current `--tail`. | -| **Compatibility** | macOS, Linux | Inherits from agent module. Windows: explicitly unsupported in v1. | -| **Security** | No new attack surface | TUI does not parse user input as code; `agent send` payload is passed as an argv element, not shell-interpreted. | -| **Failure isolation** | Adapter errors don't crash the TUI | `listAgents()` already swallows per-adapter errors; the TUI surfaces them as a footer line, not a crash. | - -## Open Items Resolved from Requirements Phase - -- **Preview rendering (req open item):** collapsed tool calls, `v` to expand (D6). -- **Narrow-terminal fallback:** threshold 100 cols, list-only below. -- **Resize behavior:** redraw on `SIGWINCH`/`stdout.resize`; preview re-wraps to new width; selection preserved. -- **Empty / missing session file:** preview shows distinct messages — "No messages yet" vs "Session file unreadable: " with the cause; list keeps polling. diff --git a/docs/ai/implementation/2026-05-27-feature-agent-watch.md b/docs/ai/implementation/2026-05-27-feature-agent-watch.md deleted file mode 100644 index d1c0729c..00000000 --- a/docs/ai/implementation/2026-05-27-feature-agent-watch.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -phase: implementation -title: Implementation Guide -description: Technical implementation notes, patterns, and code guidelines ---- - -# Implementation Guide - -## Development Setup -**How do we get started?** - -- Prerequisites and dependencies -- Environment setup steps -- Configuration needed - -## Code Structure -**How is the code organized?** - -- Directory structure -- Module organization -- Naming conventions - -## Implementation Notes -**Key technical details to remember:** - -### Core Features -- Feature 1: Implementation approach -- Feature 2: Implementation approach -- Feature 3: Implementation approach - -### Patterns & Best Practices -- Design patterns being used -- Code style guidelines -- Common utilities/helpers - -## Integration Points -**How do pieces connect?** - -- API integration details -- Database connections -- Third-party service setup - -## Error Handling -**How do we handle failures?** - -- Error handling strategy -- Logging approach -- Retry/fallback mechanisms - -## Performance Considerations -**How do we keep it fast?** - -- Optimization strategies -- Caching approach -- Query optimization -- Resource management - -## Security Notes -**What security measures are in place?** - -- Authentication/authorization -- Input validation -- Data encryption -- Secrets management - diff --git a/docs/ai/planning/2026-05-27-feature-agent-watch.md b/docs/ai/planning/2026-05-27-feature-agent-watch.md deleted file mode 100644 index 29d91c0d..00000000 --- a/docs/ai/planning/2026-05-27-feature-agent-watch.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -phase: planning -title: Project Planning & Task Breakdown -description: Break down work into actionable tasks and estimate timeline ---- - -# Project Planning & Task Breakdown — Agent Watch - -## Milestones - -- [ ] **M1 — Skeleton runs**: `ai-devkit agent watch` launches an Ink app that lists agents (no preview, no actions). -- [ ] **M2 — Preview works**: selecting an agent renders its recent conversation, refreshes automatically. -- [ ] **M3 — Actions work**: `⏎` opens an agent (suspend/resume), `m` sends a message. -- [ ] **M4 — Polish + tests**: narrow-terminal fallback, error states, unit tests, manual smoke against Claude + Codex. - -## Task Breakdown - -### Phase 1 — Foundation -- [x] **T1.1** Add `ink`, `ink-text-input` to `packages/cli` dependencies; verify build still passes. _(Picked Ink 3.2.0 + React 17 because the CLI compiles to CommonJS and Ink 4+ is ESM-only. Added `jsx: "react"` to `packages/cli/tsconfig.json`.)_ -- [x] **T1.2** Create directory scaffold under `packages/cli/src/tui/watch/` per design file layout. Empty placeholder files only. _(Created subdirs `hooks/`, `actions/`, `render/`, `state/`. Files added incrementally per later tasks.)_ -- [x] **T1.3** Register `agent watch` subcommand in `packages/cli/src/commands/agent.ts`. TTY guard: if `!process.stdout.isTTY`, print error and exit 1. Instantiate `AgentManager`, call `render()`. _(Verified `--help` renders and TTY guard fires under non-TTY stdin. Lazy-require Ink/React/WatchApp so they only load when this command runs.)_ - -### Phase 2 — Core Features -- [x] **T2.1** Implement `useAgentList` polling hook: 2s interval, in-flight cancellation via `runToken`, returns `{ agents, error, lastUpdated }`. Errors keep stale data visible. _(`hooks/useAgentList.ts`. Tracks `mountedRef` + `runTokenRef` so stale fetches don't commit. Errors set `error` but leave `agents` intact. Exports `LIST_POLL_INTERVAL_MS = 2000`. Build passes.)_ -- [x] **T2.2** Implement `useAgentConversation` hook: 1s interval for the selected agent; refetch immediately on selection change; same `runToken` discipline. _(`hooks/useAgentConversation.ts`. Fetches via `manager.getAdapter(type).getConversation(sessionFilePath)`. mtime cache skips re-parse when the session file hasn't changed. Classifies errors as `no-session-file`/`no-adapter`/`parse-error` for distinct preview copy later.)_ -- [x] **T2.3** Implement `AgentListPane` — table render of name, type, status (color + glyph + label), summary, lastActive (relative). Keyboard nav `↑↓`/`j k`. Uses native `listAgents()` order (no client-side sort). _(`AgentListPane.tsx`. Auto-selects first agent and re-selects on list change if the previous selection disappeared. Empty-state copy shipped. Wired into `WatchApp` — `agent watch` now renders the live list. M1 milestone reached.)_ -- [x] **T2.4** Implement `formatStatus` render helper: per-status color + non-color glyph (e.g., `● run`, `◐ wait`, `○ idle`, `? unk`). _(`render/formatStatus.tsx`. Glyph + short label, color is reinforcement not the sole signal. Exports `statusDisplayWidth()` for column sizing.)_ -- [x] **T2.5** Implement `PreviewPane` — render messages by role (user/assistant/system). _(`PreviewPane.tsx`. `ConversationMessage` is `{role, content, timestamp}` only — no separate tool_use/tool_result, tool calls already embedded in content. So the `v`-to-expand keybinding and auto-scroll/`G` complexity are out: instead we render from most-recent backward into a fixed line budget (~`rows-8`), guaranteeing the latest message is always visible. Master-detail layout wired into WatchApp with 40%/60% split. Narrow-terminal fallback already present (<100 cols hides preview, footer note shown). M2 milestone reached.)_ -- [x] **T2.6** Implement `StatusFooter` — agent counts (running / waiting / idle), selected agent metadata (cwd, message count, last active), keybinding hints, transient error/info line. _(`StatusFooter.tsx`. Shows counts, last-updated relative time, keybinding hint, selected agent meta. Accepts a `transient` prop for action feedback.)_ -- [x] **T2.7** Implement `WatchApp` root: owns selection, modal flag, error banner; wires hooks to panes; handles global keys (`q`, `r`, `v`). _(`WatchApp.tsx`. Owns `selectedName`, derives `selectedAgent`, computes narrow layout. Modal flag will be added in T3.2.)_ - -### Phase 3 — Integration & Polish -- [x] **T3.1** Implement `runAgentOpen` action: `app.unmount()` → `spawn('ai-devkit', ['agent', 'open', name], { stdio: 'inherit' })` → await exit → re-`render()` with `initialSelection` prop. Preserve selection across the round trip. _(`actions/runAction.ts`. Resolves CLI entry via `process.execPath` + `path.resolve(__dirname, ../../../cli.js)` so it works regardless of PATH. The render/exit loop lives in the `agent watch` command and re-mounts with `lastSelection` and a `transient` message on action failure. Requires manual TTY smoke to verify suspend/resume cleanliness — deferred to T4.4.)_ -- [x] **T3.2** Implement `SendMessageModal` overlay (`ink-text-input`): captures text, on submit calls `runAgentSend` (same spawn pattern, `agent send --id `), on cancel returns to list. Empty input is a no-op cancel. _(`SendMessageModal.tsx`. `m` toggles open, Enter submits, Esc cancels. Submit triggers a `send` intent which routes through the same suspend/resume loop in the command. M3 milestone reached.)_ -- [x] **T3.3** Implement narrow-terminal fallback (<100 cols hides preview, footer shows `resize ≥100 cols to show preview`). _(Completed inside T2.5/T2.6 — `WatchApp` reads `process.stdout.columns` once per render, hides preview pane below 100 cols, footer shows the resize hint. No dedicated `useTerminalSize` hook needed yet; can be added if dynamic resize feels janky during smoke testing.)_ -- [x] **T3.4** Empty-state copy: zero agents, missing session file, empty conversation, action error. _(Implemented across `AgentListPane` ("No running agents detected"), `PreviewPane` ("No messages yet" / "No session file available" / typed `parse-error` copy), `StatusFooter` (transient error line). No separate "ended agent banner" — when an agent disappears the list auto-selects another; preview shows "No messages yet" if the new selection's session is bare. Acceptable for v1.)_ -- [ ] **T3.5** Document the command in `web/content/docs/8-agent-management.md` under a new "Watch Agents" section. Mark experimental. - -### Phase 4 — Verification (handed to Phases 6–8 of dev-lifecycle) -- [ ] **T4.1** Unit tests for `useAgentList` / `useAgentConversation` polling/cancellation (mock manager). -- [ ] **T4.2** Unit tests for `formatMessage` render helper (assistant text, tool_use one-liner, tool_result one-liner, expansion). -- [ ] **T4.3** Snapshot tests for `AgentListPane` and `PreviewPane` via `ink-testing-library` — happy path, empty, error. -- [ ] **T4.4** Manual smoke on macOS: one Claude Code + one Codex agent running concurrently; verify launch <1s, selection-to-preview <1s, `⏎`/`m` round trips, narrow-terminal fallback, ended-agent banner. - -## Dependencies - -| Task | Depends on | -|---|---| -| T1.3 | T1.1, T1.2 | -| T2.1, T2.2 | T1.3 | -| T2.3 | T2.1, T2.4 | -| T2.5 | T2.2 | -| T2.6, T2.7 | T2.3, T2.5 | -| T3.1, T3.2 | T2.7 | -| T3.3 | T2.7 | -| T3.4 | T2.7 | -| T3.5 | T3.1, T3.2 done (so doc reflects shipped behavior) | -| T4.1–T4.3 | their corresponding implementation tasks | -| T4.4 | all of Phase 1–3 | - -External dependencies: `@ai-devkit/agent-manager` (existing, internal). `ai-devkit agent open` / `agent send` (existing CLI verbs). - -## Implementation order (linear) - -1. T1.1 → T1.2 → T1.3 (skeleton compiles and runs, prints "TUI placeholder") -2. T2.1 → T2.4 → T2.3 (M1: list renders and updates) -3. T2.2 → T2.5 (M2: preview renders and updates) -4. T2.6 → T2.7 (footer + global keys wired) -5. T3.1 → T3.2 (M3: actions work) -6. T3.3 → T3.4 (polish) -7. T3.5 (docs) -8. T4.1–T4.4 (verification; Phase 7 of dev-lifecycle) - -## Timeline & Estimates - -| Phase | Effort | Notes | -|---|---|---| -| Foundation | 0.5d | Mostly dependency wiring + boilerplate. | -| Core Features | 2d | Bulk of the work; hooks + three pane components. | -| Integration & Polish | 1d | Suspend/resume is the only risky bit; tested early via T3.1. | -| Verification | 1d | Unit + snapshot + manual smoke. | -| **Total** | **~4.5d** | Within the single-developer-week target from requirements. | - -## Risks & Mitigation - -| Risk | Likelihood | Impact | Mitigation | -|---|---|---|---| -| Ink suspend/resume leaves terminal in a bad state (alt-screen artifacts) after `agent open` | Medium | High — kills the "feels like a hub" UX | Build T3.1 early (immediately after T2.7). If broken, fall back to TUI-exits-on-open pattern documented as known limitation. | -| `getConversation()` is slow on large session files at 1Hz | Medium | Medium — preview lags | Use `--tail 20` semantics (already supported by adapter); cache by session-file mtime so unchanged files don't re-parse. | -| Inputs collide with Ink built-in raw-mode quirks (e.g., Ctrl-C handling) | Low | Medium | Use Ink's `useInput` hook conventionally; let Ctrl-C exit normally; document `q` as the standard exit. | -| `ink-text-input` ergonomics for the send modal feel cramped | Low | Low | If problematic, switch to `ink-multi-select-input`-style or roll a minimal input using `useInput`. | -| `child_process.spawn` cannot find `ai-devkit` in PATH when invoked from inside a worktree's `node_modules/.bin` | Low | High — actions fail silently | Resolve the path explicitly: `process.execPath` + the absolute CLI entry script, or use `npm bin` resolution. Validate in T3.1. | -| Adapter parse error (e.g., session file mid-write) crashes a fetch | Medium | Low | Manager already swallows per-adapter errors; the TUI surfaces them as a footer line and keeps polling. | - -## Resources Needed - -- One developer (TypeScript + React familiarity). -- Local Claude Code and Codex agents for smoke testing. -- macOS dev machine (iTerm2 or Apple Terminal for `agent open` verification). -- Existing CI pipeline (no infra changes). diff --git a/docs/ai/requirements/2026-05-27-feature-agent-watch.md b/docs/ai/requirements/2026-05-27-feature-agent-watch.md deleted file mode 100644 index c7acb12e..00000000 --- a/docs/ai/requirements/2026-05-27-feature-agent-watch.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -phase: requirements -title: Requirements & Problem Understanding -description: Clarify the problem space, gather requirements, and define success criteria ---- - -# Requirements & Problem Understanding — Agent Watch - -## Problem Statement - -Users running multiple AI coding agents (Claude Code, Codex, OpenCode, Gemini CLI) have no live, single-pane view of what each agent is doing. Today they must repeatedly run `ai-devkit agent list` to see status, then `ai-devkit agent detail --id ` to inspect any single agent's recent activity. Switching attention between agents requires re-running commands and mentally diffing snapshots. - -Adjacent products (cmux and similar terminal "mission control" tools) are gaining traction, signalling real user demand for an always-on monitor. AI DevKit already has the data sources (`agent list`, `agent detail`) and an `agent open` verb to hand control to the live session. What is missing is a thin viewer that ties them together. - -**Affected users:** developers running 2+ agents in parallel during refactors, feature work, or comparative experiments. Especially relevant for ai-devkit users on macOS who already invoke `agent open`/`agent send` from their shell. - -**Current workaround:** alternating between `agent list` and `agent detail`, or keeping a tmux window per agent. Both lose the "all agents at a glance" view. - -## Goals & Objectives - -### Primary goals -1. Provide a single TUI command (`ai-devkit agent watch`) that shows all running agents and a live preview of the selected agent's recent activity, refreshing automatically. -2. Make hand-off to existing verbs frictionless: one keystroke to `agent open`, one to `agent send`. -3. Reuse existing data sources — no new long-lived daemon, no new persistent state. - -### Secondary goals -- Establish an Ink-based TUI foundation that future surfaces (history browser, multi-agent diff view) can build on without an architectural rewrite. -- Keep the watch UI fully stateless: closing it loses nothing; reopening picks up live state. - -### Non-goals (v1) -- Pane splitting or multi-agent side-by-side preview. -- Killing agents from the TUI (no `kill` verb exists; would require new destructive CLI surface). -- Creating new agents from the TUI. -- Browsing historical sessions (`agent sessions` stays a separate command). -- An NDJSON `--watch` stream on `agent list` (polling is sufficient for v1; can be added later without changing the TUI shape). -- Windows support (inherits macOS/Linux constraint from the existing agent module). -- Mouse interaction. - -## User Stories & Use Cases - -- **As a developer running multiple agents,** I want to open one command and see every agent's status update live, so I can tell at a glance which agent needs my attention. -- **As a developer reviewing what an agent is doing,** I want to select an agent and see its last ~20 conversation messages refresh automatically, so I can decide whether to intervene without context-switching to its terminal. -- **As a developer who decides an agent needs input,** I want to press one key to jump into that agent's live terminal (via `agent open`), so the watch view feels like a hub I return to. -- **As a developer who wants to nudge an agent,** I want to press one key, type a message, and have it sent via `agent send`, so I don't need to focus the agent's terminal to dispatch a short instruction. -- **As a developer with one agent waiting for input,** I want the watch UI to surface that state visibly (e.g., highlighted row), so I notice immediately. -- **As a developer scanning the agent list,** I want the most recently active agents at the top, so the agents I'm currently working with are always visible without scrolling. - -### List ordering - -The TUI uses the order returned by `AgentManager.listAgents()`: status priority (WAITING → RUNNING → IDLE → UNKNOWN), then `lastActive` descending within each group. This bubbles waiting agents to the top automatically; the non-color visual cue is reinforcement, not the sole signal. - -### Edge cases -- Selected agent finishes / disappears mid-session → preview greys out with an "ended" banner; cursor does not auto-jump. -- Zero agents running → empty-state hint pointing at `agent list` and the docs. -- Session file unreadable / `agent detail` fails → preview shows an error line, list continues to refresh. -- Terminal too narrow to render two panes → fall back to list-only with a footer note (`resize ≥ N cols to show preview`). -- `agent open` fails (terminal not supported) → show the error in the TUI footer, do not crash. - -## Success Criteria - -1. `ai-devkit agent watch` launches and displays the agent list in under 1 second on a machine with ≤10 agents running. -2. Selecting a different agent updates the preview pane in under 1 second. -3. The list reflects underlying status changes (new agent, status transition, agent ended) within 3 seconds of the change, without user input. -4. An agent in the `waiting` state is surfaced first in the list (existing `AgentManager.listAgents()` ordering: WAITING → RUNNING → IDLE → UNKNOWN, then `lastActive` desc within each group) and rendered with a non-color cue (label, glyph, or weight) in addition to color so it remains distinguishable in a monochrome terminal. -5. `⏎` cleanly suspends the TUI, executes `agent open` for the selected agent, and returns to the watch view on detach without losing selection. -6. `m` opens a prompt, captures a message, and dispatches `ai-devkit agent send --id ` with the captured text, returning to the watch view afterward. The prompt always targets the currently selected agent; there is no agent picker inside the prompt. -7. Existing `agent list`, `agent detail`, `agent open`, and `agent send` commands continue to work unchanged — verified via manual smoke after the change lands. -8. Manual smoke test passes with at least one Claude Code agent and one Codex agent running concurrently on macOS. -9. Performance target: the TUI remains responsive (input latency <100ms, no visible frame drops) with up to 20 concurrent agents. Behavior beyond 20 agents is best-effort and not part of v1 acceptance. - -## Constraints & Assumptions - -### Technical constraints -- Must run in standard macOS/Linux terminals (iTerm2, Terminal.app, tmux, common Linux emulators). No Windows support in v1. -- Must integrate cleanly with the existing TypeScript CLI in `packages/cli`. -- Hand-off to `agent open` must suspend/resume; nested-tmux behavior must not break the parent shell. -- Polling cadence (1–2s) must not noticeably degrade CPU or session-file I/O for users with many agents. - -### Business / scope constraints -- Single-developer-week effort target for v1. -- No new long-running daemon; no new persistent state on disk. -- No new destructive CLI verbs (no `kill`). - -### Assumptions -- `createAgentManager()` is callable in-process from the watch command, returning the same `AgentInfo[]` shape `agent list` uses today. -- Adapter `getConversation(sessionFilePath, opts)` is callable in-process and returns the same shape `agent detail` renders. -- Ink (`ink` + `ink-text-input` + `ink-select-input` or equivalent) can be added as a dependency to `packages/cli` without breaking existing builds. -- Users running the watch command have a TTY (the command refuses to start under a non-TTY stdout). - -## Questions & Open Items - -No material open questions at requirements time. Items deferred to design: - -- Exact Ink component decomposition (list widget choice, viewport for preview). -- Whether the preview pane reads session files directly via the adapter or shells out to `agent detail --json` (perf vs boundary cleanliness). -- Footer status content and exact column widths. -- Behavior when the user resizes the terminal during a session. - -These are design-phase decisions and do not block Phase 1 sign-off. diff --git a/docs/ai/testing/2026-05-27-feature-agent-watch.md b/docs/ai/testing/2026-05-27-feature-agent-watch.md deleted file mode 100644 index 50958b29..00000000 --- a/docs/ai/testing/2026-05-27-feature-agent-watch.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -phase: testing -title: Testing Strategy -description: Define testing approach, test cases, and quality assurance ---- - -# Testing Strategy - -## Test Coverage Goals -**What level of testing do we aim for?** - -- Unit test coverage target (default: 100% of new/changed code) -- Integration test scope (critical paths + error handling) -- End-to-end test scenarios (key user journeys) -- Alignment with requirements/design acceptance criteria - -## Unit Tests -**What individual components need testing?** - -### Component/Module 1 -- [ ] Test case 1: [Description] (covers scenario / branch) -- [ ] Test case 2: [Description] (covers edge case / error handling) -- [ ] Additional coverage: [Description] - -### Component/Module 2 -- [ ] Test case 1: [Description] -- [ ] Test case 2: [Description] -- [ ] Additional coverage: [Description] - -## Integration Tests -**How do we test component interactions?** - -- [ ] Integration scenario 1 -- [ ] Integration scenario 2 -- [ ] API endpoint tests -- [ ] Integration scenario 3 (failure mode / rollback) - -## End-to-End Tests -**What user flows need validation?** - -- [ ] User flow 1: [Description] -- [ ] User flow 2: [Description] -- [ ] Critical path testing -- [ ] Regression of adjacent features - -## Test Data -**What data do we use for testing?** - -- Test fixtures and mocks -- Seed data requirements -- Test database setup - -## Test Reporting & Coverage -**How do we verify and communicate test results?** - -- Coverage commands and thresholds (`npm run test -- --coverage`) -- Coverage gaps (files/functions below 100% and rationale) -- Links to test reports or dashboards -- Manual testing outcomes and sign-off - -## Manual Testing -**What requires human validation?** - -- UI/UX testing checklist (include accessibility) -- Browser/device compatibility -- Smoke tests after deployment - -## Performance Testing -**How do we validate performance?** - -- Load testing scenarios -- Stress testing approach -- Performance benchmarks - -## Bug Tracking -**How do we manage issues?** - -- Issue tracking process -- Bug severity levels -- Regression testing strategy - From 2941bb48d67df50cdb5047da5ebc3f6185322f7b Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Thu, 28 May 2026 11:51:45 +0200 Subject: [PATCH 4/7] feat(cli): update naming --- .../actions/runAction.test.ts | 2 +- .../{watch => console}/computeLayout.test.ts | 6 +++--- .../hooks/agentsEqual.test.ts | 2 +- .../hooks/conversationCache.test.ts | 2 +- .../render/formatRelative.test.ts | 2 +- packages/cli/src/commands/agent.ts | 4 ++-- .../tui/{watch => console}/AgentListPane.tsx | 0 .../src/tui/{watch => console}/ChatInput.tsx | 0 .../WatchApp.tsx => console/ConsoleApp.tsx} | 16 ++++++++-------- .../src/tui/{watch => console}/HeaderBar.tsx | 4 ++-- .../src/tui/{watch => console}/PreviewPane.tsx | 0 .../tui/{watch => console}/PreviewSection.tsx | 4 ++-- .../tui/{watch => console}/StatusFooter.tsx | 0 .../{watch => console}/actions/runAction.ts | 4 ++-- .../tui/{watch => console}/actions/types.ts | 2 +- .../hooks/useAgentConversation.ts | 0 .../{watch => console}/hooks/useAgentList.ts | 0 .../hooks/useTerminalSize.ts | 0 .../render/agentTypeLabel.ts | 0 .../render/formatRelative.ts | 0 .../{watch => console}/render/formatStatus.tsx | 0 .../state/ConsoleContext.tsx} | 18 +++++++++--------- 22 files changed, 33 insertions(+), 33 deletions(-) rename packages/cli/src/__tests__/tui/{watch => console}/actions/runAction.test.ts (97%) rename packages/cli/src/__tests__/tui/{watch => console}/computeLayout.test.ts (93%) rename packages/cli/src/__tests__/tui/{watch => console}/hooks/agentsEqual.test.ts (97%) rename packages/cli/src/__tests__/tui/{watch => console}/hooks/conversationCache.test.ts (98%) rename packages/cli/src/__tests__/tui/{watch => console}/render/formatRelative.test.ts (95%) rename packages/cli/src/tui/{watch => console}/AgentListPane.tsx (100%) rename packages/cli/src/tui/{watch => console}/ChatInput.tsx (100%) rename packages/cli/src/tui/{watch/WatchApp.tsx => console/ConsoleApp.tsx} (95%) rename packages/cli/src/tui/{watch => console}/HeaderBar.tsx (81%) rename packages/cli/src/tui/{watch => console}/PreviewPane.tsx (100%) rename packages/cli/src/tui/{watch => console}/PreviewSection.tsx (90%) rename packages/cli/src/tui/{watch => console}/StatusFooter.tsx (100%) rename packages/cli/src/tui/{watch => console}/actions/runAction.ts (90%) rename packages/cli/src/tui/{watch => console}/actions/types.ts (78%) rename packages/cli/src/tui/{watch => console}/hooks/useAgentConversation.ts (100%) rename packages/cli/src/tui/{watch => console}/hooks/useAgentList.ts (100%) rename packages/cli/src/tui/{watch => console}/hooks/useTerminalSize.ts (100%) rename packages/cli/src/tui/{watch => console}/render/agentTypeLabel.ts (100%) rename packages/cli/src/tui/{watch => console}/render/formatRelative.ts (100%) rename packages/cli/src/tui/{watch => console}/render/formatStatus.tsx (100%) rename packages/cli/src/tui/{watch/state/WatchContext.tsx => console/state/ConsoleContext.tsx} (53%) diff --git a/packages/cli/src/__tests__/tui/watch/actions/runAction.test.ts b/packages/cli/src/__tests__/tui/console/actions/runAction.test.ts similarity index 97% rename from packages/cli/src/__tests__/tui/watch/actions/runAction.test.ts rename to packages/cli/src/__tests__/tui/console/actions/runAction.test.ts index 1f394ea1..3d66cb64 100644 --- a/packages/cli/src/__tests__/tui/watch/actions/runAction.test.ts +++ b/packages/cli/src/__tests__/tui/console/actions/runAction.test.ts @@ -7,7 +7,7 @@ vi.mock('child_process', () => ({ })); import { spawn } from 'child_process'; -import { runAction } from '../../../../tui/watch/actions/runAction.js'; +import { runAction } from '../../../../tui/console/actions/runAction.js'; function makeChild(exitCode: number | null, stderr = '') { const child = new EventEmitter() as EventEmitter & { diff --git a/packages/cli/src/__tests__/tui/watch/computeLayout.test.ts b/packages/cli/src/__tests__/tui/console/computeLayout.test.ts similarity index 93% rename from packages/cli/src/__tests__/tui/watch/computeLayout.test.ts rename to packages/cli/src/__tests__/tui/console/computeLayout.test.ts index 8cf3604c..ef45f2a5 100644 --- a/packages/cli/src/__tests__/tui/watch/computeLayout.test.ts +++ b/packages/cli/src/__tests__/tui/console/computeLayout.test.ts @@ -1,9 +1,9 @@ import { describe, it, expect } from 'vitest'; -// computeLayout is a pure function exported from WatchApp — import only the function, +// computeLayout is a pure function exported from ConsoleApp — import only the function, // not the React component tree, to avoid JSX in the test environment. -import { computeLayout } from '../../../tui/watch/WatchApp.js'; +import { computeLayout } from '../../../tui/console/ConsoleApp.js'; -// Constants mirrored from WatchApp.tsx for assertions +// Constants mirrored from ConsoleApp.tsx for assertions const LIST_PANE_WIDTH = 48; const MIN_CONTENT_HEIGHT = 12; const INPUT_BOX_CHROME_ROWS = 2; diff --git a/packages/cli/src/__tests__/tui/watch/hooks/agentsEqual.test.ts b/packages/cli/src/__tests__/tui/console/hooks/agentsEqual.test.ts similarity index 97% rename from packages/cli/src/__tests__/tui/watch/hooks/agentsEqual.test.ts rename to packages/cli/src/__tests__/tui/console/hooks/agentsEqual.test.ts index c9ff37e2..62613dee 100644 --- a/packages/cli/src/__tests__/tui/watch/hooks/agentsEqual.test.ts +++ b/packages/cli/src/__tests__/tui/console/hooks/agentsEqual.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest'; -import { agentsEqual } from '../../../../tui/watch/hooks/useAgentList.js'; +import { agentsEqual } from '../../../../tui/console/hooks/useAgentList.js'; import type { AgentInfo } from '@ai-devkit/agent-manager'; import { AgentStatus } from '@ai-devkit/agent-manager'; diff --git a/packages/cli/src/__tests__/tui/watch/hooks/conversationCache.test.ts b/packages/cli/src/__tests__/tui/console/hooks/conversationCache.test.ts similarity index 98% rename from packages/cli/src/__tests__/tui/watch/hooks/conversationCache.test.ts rename to packages/cli/src/__tests__/tui/console/hooks/conversationCache.test.ts index dc1bc779..6188bc8d 100644 --- a/packages/cli/src/__tests__/tui/watch/hooks/conversationCache.test.ts +++ b/packages/cli/src/__tests__/tui/console/hooks/conversationCache.test.ts @@ -4,7 +4,7 @@ import { conversationCache, CACHE_MAX, messagesEqual, -} from '../../../../tui/watch/hooks/useAgentConversation.js'; +} from '../../../../tui/console/hooks/useAgentConversation.js'; import type { ConversationMessage } from '@ai-devkit/agent-manager'; const msg = (role: ConversationMessage['role'], content: string, timestamp?: string): ConversationMessage => diff --git a/packages/cli/src/__tests__/tui/watch/render/formatRelative.test.ts b/packages/cli/src/__tests__/tui/console/render/formatRelative.test.ts similarity index 95% rename from packages/cli/src/__tests__/tui/watch/render/formatRelative.test.ts rename to packages/cli/src/__tests__/tui/console/render/formatRelative.test.ts index bbf1383b..3d9f1a68 100644 --- a/packages/cli/src/__tests__/tui/watch/render/formatRelative.test.ts +++ b/packages/cli/src/__tests__/tui/console/render/formatRelative.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import { formatRelative } from '../../../../tui/watch/render/formatRelative.js'; +import { formatRelative } from '../../../../tui/console/render/formatRelative.js'; describe('formatRelative', () => { beforeEach(() => { diff --git a/packages/cli/src/commands/agent.ts b/packages/cli/src/commands/agent.ts index 03666d9c..81ee1fd5 100644 --- a/packages/cli/src/commands/agent.ts +++ b/packages/cli/src/commands/agent.ts @@ -29,7 +29,7 @@ import { } from '../util/sessions.js'; import { waitForAgentResponse } from '../services/agent/agent.service.js'; import { parseMilliseconds } from '../util/time.js'; -import { WatchApp } from '../tui/watch/WatchApp.js'; +import { ConsoleApp } from '../tui/console/ConsoleApp.js'; const AGENT_SEND_WAIT_POLL_INTERVAL_MS = 2000; const AGENT_SEND_WAIT_MAX_WAIT_MS = 10 * 60 * 1000; @@ -687,7 +687,7 @@ export function registerAgentCommand(program: Command): void { } const manager = createAgentManager(); const { waitUntilExit } = render( - createElement(WatchApp, { manager }), + createElement(ConsoleApp, { manager }), { alternateScreen: true, exitOnCtrlC: true }, ); await waitUntilExit(); diff --git a/packages/cli/src/tui/watch/AgentListPane.tsx b/packages/cli/src/tui/console/AgentListPane.tsx similarity index 100% rename from packages/cli/src/tui/watch/AgentListPane.tsx rename to packages/cli/src/tui/console/AgentListPane.tsx diff --git a/packages/cli/src/tui/watch/ChatInput.tsx b/packages/cli/src/tui/console/ChatInput.tsx similarity index 100% rename from packages/cli/src/tui/watch/ChatInput.tsx rename to packages/cli/src/tui/console/ChatInput.tsx diff --git a/packages/cli/src/tui/watch/WatchApp.tsx b/packages/cli/src/tui/console/ConsoleApp.tsx similarity index 95% rename from packages/cli/src/tui/watch/WatchApp.tsx rename to packages/cli/src/tui/console/ConsoleApp.tsx index 24816283..d50bbb8d 100644 --- a/packages/cli/src/tui/watch/WatchApp.tsx +++ b/packages/cli/src/tui/console/ConsoleApp.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; import { Box, useApp, useInput } from 'ink'; import type { AgentManager } from '@ai-devkit/agent-manager'; -import { WatchProvider, useWatchContext } from './state/WatchContext.js'; +import { ConsoleProvider, useConsoleContext } from './state/ConsoleContext.js'; import { useTerminalSize } from './hooks/useTerminalSize.js'; import { AgentListPane } from './AgentListPane.js'; import { PreviewSection } from './PreviewSection.js'; @@ -10,7 +10,7 @@ import { ChatInput } from './ChatInput.js'; import { HeaderBar } from './HeaderBar.js'; import { runAction } from './actions/runAction.js'; -interface WatchAppProps { +interface ConsoleAppProps { manager: AgentManager; initialSelection?: string | null; } @@ -43,7 +43,7 @@ export function computeLayout(cols: number, rows: number, inputLines: number, na }; } -const WatchAppShell: React.FC<{ +const ConsoleAppShell: React.FC<{ initialSelection: string | null; setInputFocused: (v: boolean) => void; }> = ({ initialSelection, setInputFocused }) => { @@ -69,7 +69,7 @@ const WatchAppShell: React.FC<{ const selectedNameRef = useRef(selectedName); selectedNameRef.current = selectedName; - const { agents, error, lastUpdated, isLoading } = useWatchContext(); + const { agents, error, lastUpdated, isLoading } = useConsoleContext(); const agentsRef = useRef(agents); agentsRef.current = agents; @@ -200,17 +200,17 @@ const WatchAppShell: React.FC<{ ); }; -export const WatchApp: React.FC = ({ +export const ConsoleApp: React.FC = ({ manager, initialSelection = null, }) => { const [inputFocused, setInputFocused] = useState(false); return ( - - + - + ); }; diff --git a/packages/cli/src/tui/watch/HeaderBar.tsx b/packages/cli/src/tui/console/HeaderBar.tsx similarity index 81% rename from packages/cli/src/tui/watch/HeaderBar.tsx rename to packages/cli/src/tui/console/HeaderBar.tsx index 18911e2a..b6d2edbf 100644 --- a/packages/cli/src/tui/watch/HeaderBar.tsx +++ b/packages/cli/src/tui/console/HeaderBar.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { Box, Text } from 'ink'; -import { useWatchContext } from './state/WatchContext.js'; +import { useConsoleContext } from './state/ConsoleContext.js'; const HeaderBarInner: React.FC = () => { - const { agents, isLoading } = useWatchContext(); + const { agents, isLoading } = useConsoleContext(); const totalLabel = isLoading && agents.length === 0 ? 'scanning…' : `${agents.length} agent${agents.length === 1 ? '' : 's'}`; return ( diff --git a/packages/cli/src/tui/watch/PreviewPane.tsx b/packages/cli/src/tui/console/PreviewPane.tsx similarity index 100% rename from packages/cli/src/tui/watch/PreviewPane.tsx rename to packages/cli/src/tui/console/PreviewPane.tsx diff --git a/packages/cli/src/tui/watch/PreviewSection.tsx b/packages/cli/src/tui/console/PreviewSection.tsx similarity index 90% rename from packages/cli/src/tui/watch/PreviewSection.tsx rename to packages/cli/src/tui/console/PreviewSection.tsx index 0f55a299..cb148ac2 100644 --- a/packages/cli/src/tui/watch/PreviewSection.tsx +++ b/packages/cli/src/tui/console/PreviewSection.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import { Box } from 'ink'; import { PreviewPane } from './PreviewPane.js'; -import { useWatchContext } from './state/WatchContext.js'; +import { useConsoleContext } from './state/ConsoleContext.js'; import { useAgentConversation } from './hooks/useAgentConversation.js'; interface PreviewSectionProps { @@ -10,7 +10,7 @@ interface PreviewSectionProps { } const PreviewSectionInner: React.FC = ({ selectedName, height }) => { - const { agents, manager, inputFocused } = useWatchContext(); + const { agents, manager, inputFocused } = useConsoleContext(); const selectedAgent = useMemo( () => agents.find(a => a.name === selectedName) ?? null, [agents, selectedName], diff --git a/packages/cli/src/tui/watch/StatusFooter.tsx b/packages/cli/src/tui/console/StatusFooter.tsx similarity index 100% rename from packages/cli/src/tui/watch/StatusFooter.tsx rename to packages/cli/src/tui/console/StatusFooter.tsx diff --git a/packages/cli/src/tui/watch/actions/runAction.ts b/packages/cli/src/tui/console/actions/runAction.ts similarity index 90% rename from packages/cli/src/tui/watch/actions/runAction.ts rename to packages/cli/src/tui/console/actions/runAction.ts index e037b052..d3f8bf12 100644 --- a/packages/cli/src/tui/watch/actions/runAction.ts +++ b/packages/cli/src/tui/console/actions/runAction.ts @@ -1,5 +1,5 @@ import { spawn } from 'child_process'; -import type { WatchAction } from './types.js'; +import type { ConsoleAction } from './types.js'; export interface ActionResult { exitCode: number | null; @@ -10,7 +10,7 @@ function resolveCliEntry(): { command: string; baseArgs: string[] } { return { command: process.execPath, baseArgs: [...process.execArgv, process.argv[1]] }; } -export async function runAction(action: WatchAction): Promise { +export async function runAction(action: ConsoleAction): Promise { const { command, baseArgs } = resolveCliEntry(); const argv = (() => { switch (action.type) { diff --git a/packages/cli/src/tui/watch/actions/types.ts b/packages/cli/src/tui/console/actions/types.ts similarity index 78% rename from packages/cli/src/tui/watch/actions/types.ts rename to packages/cli/src/tui/console/actions/types.ts index 1a8cd3ac..1ba8a898 100644 --- a/packages/cli/src/tui/watch/actions/types.ts +++ b/packages/cli/src/tui/console/actions/types.ts @@ -1,3 +1,3 @@ -export type WatchAction = +export type ConsoleAction = | { type: 'open'; agentName: string } | { type: 'send'; agentName: string; message: string }; diff --git a/packages/cli/src/tui/watch/hooks/useAgentConversation.ts b/packages/cli/src/tui/console/hooks/useAgentConversation.ts similarity index 100% rename from packages/cli/src/tui/watch/hooks/useAgentConversation.ts rename to packages/cli/src/tui/console/hooks/useAgentConversation.ts diff --git a/packages/cli/src/tui/watch/hooks/useAgentList.ts b/packages/cli/src/tui/console/hooks/useAgentList.ts similarity index 100% rename from packages/cli/src/tui/watch/hooks/useAgentList.ts rename to packages/cli/src/tui/console/hooks/useAgentList.ts diff --git a/packages/cli/src/tui/watch/hooks/useTerminalSize.ts b/packages/cli/src/tui/console/hooks/useTerminalSize.ts similarity index 100% rename from packages/cli/src/tui/watch/hooks/useTerminalSize.ts rename to packages/cli/src/tui/console/hooks/useTerminalSize.ts diff --git a/packages/cli/src/tui/watch/render/agentTypeLabel.ts b/packages/cli/src/tui/console/render/agentTypeLabel.ts similarity index 100% rename from packages/cli/src/tui/watch/render/agentTypeLabel.ts rename to packages/cli/src/tui/console/render/agentTypeLabel.ts diff --git a/packages/cli/src/tui/watch/render/formatRelative.ts b/packages/cli/src/tui/console/render/formatRelative.ts similarity index 100% rename from packages/cli/src/tui/watch/render/formatRelative.ts rename to packages/cli/src/tui/console/render/formatRelative.ts diff --git a/packages/cli/src/tui/watch/render/formatStatus.tsx b/packages/cli/src/tui/console/render/formatStatus.tsx similarity index 100% rename from packages/cli/src/tui/watch/render/formatStatus.tsx rename to packages/cli/src/tui/console/render/formatStatus.tsx diff --git a/packages/cli/src/tui/watch/state/WatchContext.tsx b/packages/cli/src/tui/console/state/ConsoleContext.tsx similarity index 53% rename from packages/cli/src/tui/watch/state/WatchContext.tsx rename to packages/cli/src/tui/console/state/ConsoleContext.tsx index 40ee2045..4ff1e697 100644 --- a/packages/cli/src/tui/watch/state/WatchContext.tsx +++ b/packages/cli/src/tui/console/state/ConsoleContext.tsx @@ -2,32 +2,32 @@ import React, { createContext, useContext, useMemo } from 'react'; import type { AgentManager } from '@ai-devkit/agent-manager'; import { useAgentList, type UseAgentListResult } from '../hooks/useAgentList.js'; -interface WatchContextValue extends UseAgentListResult { +interface ConsoleContextValue extends UseAgentListResult { manager: AgentManager; inputFocused: boolean; } -const WatchContext = createContext(null); +const ConsoleContext = createContext(null); -export const useWatchContext = (): WatchContextValue => { - const ctx = useContext(WatchContext); - if (!ctx) throw new Error('useWatchContext must be used inside '); +export const useConsoleContext = (): ConsoleContextValue => { + const ctx = useContext(ConsoleContext); + if (!ctx) throw new Error('useConsoleContext must be used inside '); return ctx; }; -interface WatchProviderProps { +interface ConsoleProviderProps { manager: AgentManager; inputFocused: boolean; children: React.ReactNode; } -export const WatchProvider: React.FC = ({ manager, inputFocused, children }) => { +export const ConsoleProvider: React.FC = ({ manager, inputFocused, children }) => { // Pause list poll while user is composing a message: removes a source of // re-renders that compete with the controlled TextInput. const list = useAgentList(manager, undefined, inputFocused); - const value = useMemo( + const value = useMemo( () => ({ ...list, manager, inputFocused }), [list, manager, inputFocused], ); - return {children}; + return {children}; }; From 9acf2c4bdabb78a020bea0bde4eb82c794bf3295 Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Thu, 28 May 2026 11:56:27 +0200 Subject: [PATCH 5/7] feat(cli): update naming --- .../design/2026-05-28-feature-agent-watch.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/ai/design/2026-05-28-feature-agent-watch.md b/docs/ai/design/2026-05-28-feature-agent-watch.md index 10412cfc..84b2b3ff 100644 --- a/docs/ai/design/2026-05-28-feature-agent-watch.md +++ b/docs/ai/design/2026-05-28-feature-agent-watch.md @@ -11,30 +11,30 @@ description: Define the technical architecture, components, and data models ```mermaid graph TD CLI["agent console (commands/agent.ts)"] - CLI --> WatchApp + CLI --> ConsoleApp - WatchApp --> WatchProvider - WatchProvider --> useAgentList + ConsoleApp --> ConsoleProvider + ConsoleProvider --> useAgentList useAgentList --> AgentManager - WatchApp --> WatchAppShell - WatchAppShell --> HeaderBar - WatchAppShell --> AgentListPane - WatchAppShell --> PreviewSection - WatchAppShell --> StatusFooter - WatchAppShell --> ChatInput + ConsoleApp --> ConsoleAppShell + ConsoleAppShell --> HeaderBar + ConsoleAppShell --> AgentListPane + ConsoleAppShell --> PreviewSection + ConsoleAppShell --> StatusFooter + ConsoleAppShell --> ChatInput PreviewSection --> useAgentConversation useAgentConversation --> conversationCache["LRU cache (module-level)"] useAgentConversation --> AgentAdapter["AgentAdapter.getConversation()"] - WatchAppShell --> runAction + ConsoleAppShell --> runAction runAction -->|subprocess| CLIAgentOpen["agent open "] runAction -->|subprocess| CLIAgentSend["agent send --id "] ``` **Key architectural decisions:** -- All keyboard handling (`useInput`) centralised in `WatchAppShell` (non-memo) — Ink 7 + React 19 silently drops `useInput` inside `React.memo` components +- All keyboard handling (`useInput`) centralised in `ConsoleAppShell` (non-memo) — Ink 7 + React 19 silently drops `useInput` inside `React.memo` components - Actions dispatch via `spawn()` re-invoking the CLI with `stdio: pipe` so the TUI never yields the terminal - Context value stabilised with `useMemo` so quiet polls don't re-render all consumers @@ -50,7 +50,7 @@ graph TD { role: 'user' | 'assistant' | 'system', content: string, timestamp?: string } ``` -**WatchContextValue** +**ConsoleContextValue** ```typescript { agents, error, lastUpdated, isLoading, manager, inputFocused } ``` @@ -64,8 +64,8 @@ graph TD | Component | File | Responsibility | |-----------|------|----------------| -| `WatchApp` | `WatchApp.tsx` | Context provider wrapper | -| `WatchAppShell` | `WatchApp.tsx` | All state, keyboard handling, layout math | +| `ConsoleApp` | `ConsoleApp.tsx` | Context provider wrapper | +| `ConsoleAppShell` | `ConsoleApp.tsx` | All state, keyboard handling, layout math | | `HeaderBar` | `HeaderBar.tsx` | Agent count + app label | | `AgentListPane` | `AgentListPane.tsx` | 2-line agent rows with status/name/type/summary | | `PreviewSection` | `PreviewSection.tsx` | Runs `useAgentConversation`, wraps `PreviewPane` | @@ -73,12 +73,12 @@ graph TD | `StatusFooter` | `StatusFooter.tsx` | Status counts + updated time + keybinding hints | | `ChatInput` | `ChatInput.tsx` | Controlled text input for sending messages | | `FormatStatus` | `render/formatStatus.tsx` | Status glyph + label | -| `WatchProvider` | `state/WatchContext.tsx` | Provides agent list via context | +| `ConsoleProvider` | `state/ConsoleContext.tsx` | Provides agent list via context | | `useAgentList` | `hooks/useAgentList.ts` | Polls `manager.listAgents()` every 3s | | `useAgentConversation` | `hooks/useAgentConversation.ts` | Polls conversation with debounce + LRU cache | | `useTerminalSize` | `hooks/useTerminalSize.ts` | Debounced terminal resize listener | | `runAction` | `actions/runAction.ts` | Spawns CLI subprocess for open/send | -| `computeLayout` | `WatchApp.tsx` | Pure function: cols/rows → layout dimensions | +| `computeLayout` | `ConsoleApp.tsx` | Pure function: cols/rows → layout dimensions | ## Layout Design @@ -106,7 +106,7 @@ graph TD | Decision | Choice | Rationale | |----------|--------|-----------| -| Keyboard handler location | Single non-memo `WatchAppShell` | Ink 7 + React 19: `useInput` silently fails in `React.memo` | +| Keyboard handler location | Single non-memo `ConsoleAppShell` | Ink 7 + React 19: `useInput` silently fails in `React.memo` | | Action execution | Subprocess re-invoking CLI | TUI stays alive; no terminal handoff complexity | | Conversation data | Sync `statSync` + JSONL parse | Session files are local; async adds race complexity without benefit | | Cache | Module-level LRU Map (max 50) | Survives selection changes; evicts old entries; no library needed | From c950e575913b1d9d3cbdceceb92c242f6ddcd245 Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Thu, 28 May 2026 11:58:40 +0200 Subject: [PATCH 6/7] feat(cli): update naming --- .../2026-05-28-feature-agent-watch.md | 14 +++++++------- docs/ai/planning/2026-05-28-feature-agent-watch.md | 8 ++++---- docs/ai/testing/2026-05-28-feature-agent-watch.md | 12 ++++++------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/ai/implementation/2026-05-28-feature-agent-watch.md b/docs/ai/implementation/2026-05-28-feature-agent-watch.md index d41532ab..b77fa99c 100644 --- a/docs/ai/implementation/2026-05-28-feature-agent-watch.md +++ b/docs/ai/implementation/2026-05-28-feature-agent-watch.md @@ -10,9 +10,9 @@ description: Technical implementation notes, patterns, and code guidelines ``` packages/cli/src/ -├── commands/agent.ts # CLI command registration; renders WatchApp -└── tui/watch/ - ├── WatchApp.tsx # WatchProvider + WatchAppShell (all state + keyboard) +├── commands/agent.ts # CLI command registration; renders ConsoleApp +└── tui/console/ + ├── ConsoleApp.tsx # ConsoleProvider + ConsoleAppShell (all state + keyboard) ├── AgentListPane.tsx # 2-line agent rows ├── PreviewPane.tsx # Last-N message renderer ├── PreviewSection.tsx # Runs useAgentConversation, wraps PreviewPane @@ -21,7 +21,7 @@ packages/cli/src/ ├── HeaderBar.tsx # App label + agent count ├── actions/ │ ├── runAction.ts # Subprocess dispatcher - │ └── types.ts # WatchAction discriminated union + │ └── types.ts # ConsoleAction discriminated union ├── hooks/ │ ├── useAgentList.ts # 3s poll for agent list │ ├── useAgentConversation.ts # 3s poll for conversation + LRU cache @@ -31,13 +31,13 @@ packages/cli/src/ │ ├── formatRelative.ts # Shared relative-time formatter │ └── agentTypeLabel.ts # AGENT_TYPE_LABEL / AGENT_TYPE_LABEL_DISPLAY └── state/ - └── WatchContext.tsx # WatchProvider + useWatchContext + └── ConsoleContext.tsx # ConsoleProvider + useConsoleContext ``` ## Key Implementation Notes ### Ink 7 + React 19 keyboard handling -`useInput` silently fails inside `React.memo` components. All keyboard handling lives in `WatchAppShell` (non-memo). Refs (`exitRef`, `selectedNameRef`, `agentsRef`) capture current values for use inside `useInput` closures without stale closure bugs. +`useInput` silently fails inside `React.memo` components. All keyboard handling lives in `ConsoleAppShell` (non-memo). Refs (`selectedNameRef`, `agentsRef`) capture current values for use inside `useInput` closures without stale closure bugs. ### Layout stability Every `` has explicit `width` + `flexShrink={0}`. Without this, Yoga recalculates and shifts layout on every selection change. `computeLayout()` is a pure function — easy to verify and test independently. @@ -54,7 +54,7 @@ Both hooks use `setState(prev => prev)` return to skip re-renders on unchanged d - `useAgentConversation`: `messagesEqual()` compares role + content + timestamp ### Context stability -`WatchContext` wraps the value in `useMemo([list, manager, inputFocused])`. Since `useAgentList` returns `prev` when nothing changed, `list` is a stable reference across quiet polls — the `useMemo` dependency doesn't trigger, so consumers don't re-render. +`ConsoleContext` wraps the value in `useMemo([list, manager, inputFocused])`. Since `useAgentList` returns `prev` when nothing changed, `list` is a stable reference across quiet polls — the `useMemo` dependency doesn't trigger, so consumers don't re-render. ## Error Handling diff --git a/docs/ai/planning/2026-05-28-feature-agent-watch.md b/docs/ai/planning/2026-05-28-feature-agent-watch.md index 2ee234d7..edc3692c 100644 --- a/docs/ai/planning/2026-05-28-feature-agent-watch.md +++ b/docs/ai/planning/2026-05-28-feature-agent-watch.md @@ -10,9 +10,9 @@ description: Break down work into actionable tasks and estimate timeline ### Phase 1: Core Shell & Data Hooks - [x] Task 1.1: `useAgentList` hook — polls `manager.listAgents()` every 3s, equality-checks to skip quiet re-renders, guards stale setState with run token -- [x] Task 1.2: `WatchProvider` / `WatchContext` — provides agent list + manager via context; `useMemo` on value object +- [x] Task 1.2: `ConsoleProvider` / `ConsoleContext` — provides agent list + manager via context; `useMemo` on value object - [x] Task 1.3: `useTerminalSize` — debounced resize listener on `process.stdout` -- [x] Task 1.4: `WatchApp` shell — `WatchProvider` wrapper + `WatchAppShell` with all keyboard handling via `useInput` +- [x] Task 1.4: `ConsoleApp` shell — `ConsoleProvider` wrapper + `ConsoleAppShell` with all keyboard handling via `useInput` ### Phase 2: Agent List Pane - [x] Task 2.1: `AgentListPane` — 2-line rows (status+name+type / summary), fixed widths to prevent layout shift, dividers between agents @@ -25,7 +25,7 @@ description: Break down work into actionable tasks and estimate timeline - [x] Task 3.3: `PreviewSection` — reads context + runs `useAgentConversation`, paused during input focus ### Phase 4: Chat Input & Actions -- [x] Task 4.1: `ChatInput` — fully controlled (value/onChange lifted to `WatchAppShell`); dynamic line-count reporting for layout +- [x] Task 4.1: `ChatInput` — fully controlled (value/onChange lifted to `ConsoleAppShell`); dynamic line-count reporting for layout - [x] Task 4.2: `runAction` — spawns CLI subprocess (`agent open` / `agent send`) with `stdio: pipe`; resolves via `process.execPath + execArgv + argv[1]` - [x] Task 4.3: Transient feedback messages — 4s auto-clear; shown in `StatusFooter` @@ -46,7 +46,7 @@ description: Break down work into actionable tasks and estimate timeline | Risk | Mitigation | |------|-----------| -| `useInput` silent failure in memo components | All keyboard handling in single non-memo `WatchAppShell` | +| `useInput` silent failure in memo components | All keyboard handling in single non-memo `ConsoleAppShell` | | Layout shift on selection change | Fixed widths + `flexShrink={0}` on all boxes | | Unbounded conversation cache | LRU eviction at 50 entries via `cacheSet()` | | Subprocess blocking TUI terminal | `stdio: ['ignore', 'pipe', 'pipe']` | diff --git a/docs/ai/testing/2026-05-28-feature-agent-watch.md b/docs/ai/testing/2026-05-28-feature-agent-watch.md index 7c3160a2..4f113815 100644 --- a/docs/ai/testing/2026-05-28-feature-agent-watch.md +++ b/docs/ai/testing/2026-05-28-feature-agent-watch.md @@ -14,11 +14,11 @@ React components and hooks cannot be tested without `@testing-library/react` or | File | Covers | Tests | |------|--------|-------| -| `src/__tests__/tui/watch/computeLayout.test.ts` | `computeLayout()` in `WatchApp.tsx` | 10 | -| `src/__tests__/tui/watch/render/formatRelative.test.ts` | `render/formatRelative.ts` | 8 | -| `src/__tests__/tui/watch/hooks/conversationCache.test.ts` | `cacheSet`, `conversationCache`, `messagesEqual` | 11 | -| `src/__tests__/tui/watch/hooks/agentsEqual.test.ts` | `agentsEqual` in `useAgentList.ts` | 11 | -| `src/__tests__/tui/watch/actions/runAction.test.ts` | `runAction.ts` | 7 | +| `src/__tests__/tui/console/computeLayout.test.ts` | `computeLayout()` in `ConsoleApp.tsx` | 10 | +| `src/__tests__/tui/console/render/formatRelative.test.ts` | `render/formatRelative.ts` | 8 | +| `src/__tests__/tui/console/hooks/conversationCache.test.ts` | `cacheSet`, `conversationCache`, `messagesEqual` | 11 | +| `src/__tests__/tui/console/hooks/agentsEqual.test.ts` | `agentsEqual` in `useAgentList.ts` | 11 | +| `src/__tests__/tui/console/actions/runAction.test.ts` | `runAction.ts` | 7 | **Total new tests: 47** | **All passing** @@ -70,7 +70,7 @@ React components and hooks cannot be tested without `@testing-library/react` or **Not covered by automated tests** (require ink-testing-library or manual QA): - React component rendering: `AgentListPane`, `PreviewPane`, `StatusFooter`, `ChatInput`, `HeaderBar` - Hook behaviour: `useAgentList`, `useAgentConversation`, `useTerminalSize` -- Keyboard navigation: j/k, o, i, q in `WatchAppShell` +- Keyboard navigation: j/k, o, i, q in `ConsoleAppShell` - Narrow/wide layout transition on terminal resize **Recommended manual QA scenarios:** From 0b9ba8bde8a169a1d48d86f29b337c4d492915a9 Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Thu, 28 May 2026 13:31:35 +0200 Subject: [PATCH 7/7] update package lock --- package-lock.json | 173 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 169 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e3a14e8..cc414eca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3346,6 +3346,171 @@ "node": ">=10" } }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.10.tgz", + "integrity": "sha512-NZpDXtwHH083L40xdyj1sY31MIwLgOxKfZEAGCI8xHXdHa+GWvEiVdGiu4qhkJctoHFzAEc7ZX3GN5phuJcPuQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.10.tgz", + "integrity": "sha512-ioieF5iuRziUF1HkH1gg1r93e055dAdeBAPGAk40VjqpL5/igPJ/WxFHGvc6WMLhUubSJI4S0AiZAAhEAp1jDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.10.tgz", + "integrity": "sha512-tD6BClOrxSsNus9cJL7Gxdv7z7Y2hlyvZd9l0NQz+YXzmTWqnfzLpg16ovEI7gknH2AgDBB5ywOsqu8hUgSeEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.10.tgz", + "integrity": "sha512-4uAHO3nbfbrTcmO/9YcVweTQdx5fN3l7ewwl5AEK4yoC4wXmoBTEPHAVdKNe4r9+xrTgd4BgyPsy0409OjjlMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.10.tgz", + "integrity": "sha512-W0h9ONNw1pVIA0cN7wtboOSTl4Jk3tHq+w2cMPQudu9/+3xoCxpFb9ZdehwCAk29IsvdWzGzY6P7dDVTyFwoqg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.10.tgz", + "integrity": "sha512-XQNZlLZB62S8nAbw7pqoqwy91Ldy2RpaMRqdRN3T+tAg6Xg6FywXRKCsLh6IQOadr4p1+lGnqM/Wn35z5a/0Vw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.10.tgz", + "integrity": "sha512-qnAGrRv5Nj/DATxAmCnJQRXXQqnJwR0trxLndhoHoxGci9MuguNIjWahS0gw8YZFjgTinbTxOwzatkoySihnmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.10.tgz", + "integrity": "sha512-i4X/q8QSvzVlaRtv1xfnfl+hVKpCfiJ+9th484rh937fiEZKxZGf51C+uO0lfKDP1FfnT6C1yBYwHy7FLBVXFw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.10.tgz", + "integrity": "sha512-HvY8XUFuoTXn6lSccDLYFlXv1SU/PzYi4PyUqGT++WfTnbw/68N/7BdUZqglGRwiSqr0qhYt/EhmBpULj0J9rA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "node_modules/@swc/counter": { "version": "0.1.3", "dev": true, @@ -3492,7 +3657,7 @@ }, "node_modules/@types/node": { "version": "20.19.21", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -3507,7 +3672,7 @@ "version": "19.2.15", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -5273,7 +5438,7 @@ }, "node_modules/csstype": { "version": "3.2.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/debug": { @@ -9774,7 +9939,7 @@ }, "node_modules/undici-types": { "version": "6.21.0", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": {