diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 6f9b0fcd..e16c3205 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,7 +1,7 @@ # Optional dev-container image for AgentHub. -# Node 22 to match the production Dockerfile and the project's engines. +# Node 22 to match the project's engines. # Adds the native-addon toolchain (better-sqlite3 builds via node-gyp) plus -# Python 3 (statusline.py and helper scripts) and the sqlite3 CLI. +# Python 3 (scripts/expand-ts-module-docs.py) and the sqlite3 CLI. # # This image is ONLY used by Dev Containers / Codespaces. Host-based development # (npm run dev / npm start) is unaffected. diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 87fbcf4c..8e0f67be 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -22,13 +22,13 @@ dependencies (`npm run setup`). | Component | Detail | | ---------------- | ------------------------------------------------------------------- | -| Base image | `mcr.microsoft.com/devcontainers/javascript-node:22` (matches prod) | +| Base image | `mcr.microsoft.com/devcontainers/javascript-node:22` | | Native toolchain | `build-essential` + `python3` so `better-sqlite3` compiles | -| Python | `python3` / `python` for `statusline.py` and helper scripts | +| Python | `python3` / `python` for `scripts/expand-ts-module-docs.py` | | sqlite3 CLI | inspect the dashboard DB during development | -| Features | GitHub CLI, Docker-in-Docker (build/run the project's own Dockerfile) | +| Features | GitHub CLI | | Forwarded ports | `4820` (server API + WebSocket), `5173` (Vite client) | -| Editor | ESLint + Prettier (format on save), Vitest, Docker, YAML, Tailwind | +| Editor | ESLint + Prettier (format on save), Vitest, YAML, Tailwind | ## Everyday commands diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 8f4312c2..d36be71c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,9 +4,9 @@ // Used only when you choose "Dev Containers: Reopen in Container" (VS Code) or // open the repo in a GitHub Codespace. It changes nothing for host-based dev. // - // Covers the full project: the Express server (4820), the React/Vite client - // (5173) and the VS Code extension. The native `better-sqlite3` - // addon builds here (build-essential + python3 are installed in the Dockerfile). + // Covers the full project: the Express server (4820) and the React/Vite + // client (5173). The native `better-sqlite3` addon builds here + // (build-essential + python3 are installed in the Dockerfile). // // NOTE (issue #193): Claude Code hooks are a HOST-side concern. This container // intentionally does NOT bind-mount ~/.claude and does NOT install hooks — the @@ -20,10 +20,7 @@ }, "features": { - "ghcr.io/devcontainers/features/github-cli:1": {}, - // Lets you build/run the project's own production Dockerfile + docker-compose - // from inside the dev container (e.g. to reproduce issue #193 deliberately). - "ghcr.io/devcontainers/features/docker-in-docker:2": {} + "ghcr.io/devcontainers/features/github-cli:1": {} }, // Server (API + WebSocket) and the Vite client dev server. VS Code forwards @@ -40,7 +37,7 @@ } }, - // Install root + client + vscode-extension deps. + // Install root + client deps. // Never installs Claude Code hooks (host-only — see note above). "postCreateCommand": "bash .devcontainer/post-create.sh", "waitFor": "postCreateCommand", @@ -59,7 +56,6 @@ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "vitest.explorer", - "ms-azuretools.vscode-docker", "redhat.vscode-yaml", "yzhang.markdown-all-in-one", "ms-python.python", diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index f9b9765f..4b529ee1 100755 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -7,7 +7,7 @@ # @author Nguyễn Ngọc Trí Vĩ set -euo pipefail -echo "▶ Installing server + client + vscode-extension dependencies (npm run setup)…" +echo "▶ Installing server + client dependencies (npm run setup)…" npm run setup cat <<'EOF' diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index a8e9e6d8..00000000 --- a/.dockerignore +++ /dev/null @@ -1,15 +0,0 @@ -node_modules/ -client/node_modules/ -client/dist/ -data/ -.git/ -.github/ -*.md -!README.md -images/ -wiki/ -index.html -og-image.svg -favicon.svg -.prettierrc -.prettierignore diff --git a/.gitattributes b/.gitattributes index 278b1269..e3cc17fe 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,13 +13,3 @@ *.ttf binary *.eot binary *.db binary - -# ── GitHub Linguist overrides — keep language stats honest ────────────────── -# wiki/mermaid.min.js is a vendored, minified third-party library (Mermaid); -# it is not project source code and must not count toward language stats. -wiki/mermaid.min.js linguist-vendored - -# wiki/i18n-content.js is machine-assembled translation data (see its header: -# "AUTO-GENERATED wiki body-content translations ... Do not hand-edit"). -# It is a data bundle keyed by English innerHTML, not hand-written JavaScript. -wiki/i18n-content.js linguist-generated diff --git a/.prettierignore b/.prettierignore index 4ae3a44a..897a6bb5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,17 +9,5 @@ package-lock.json client/package-lock.json .vs/ *.md -index.html -wiki/index.html *.yml *.yaml -desktop/out/ -desktop/release/ -desktop/node_modules/ -desktop/package-lock.json -desktop/assets/*.svg -desktop/assets/*.png -desktop/assets/*.icns -desktop/assets/icon.iconset/ -wiki/mermaid.min.js -fonts/*.woff2 diff --git a/.superpowers/README.md b/.superpowers/README.md deleted file mode 100644 index 616b09d3..00000000 --- a/.superpowers/README.md +++ /dev/null @@ -1,130 +0,0 @@ -# Superpowers Workspace - -This directory contains project-specific configuration and artifacts for the Superpowers workflow. - -It acts as the working memory layer for agent-driven development, enabling structured planning, execution, and iteration across sessions. - ---- - -## Purpose - -Superpowers transforms coding agents into structured, process-driven collaborators. Instead of jumping straight into code, the agent: - -1. Clarifies intent -2. Produces a design -3. Breaks work into executable steps -4. Executes via subagents -5. Verifies and iterates - -This directory stores the outputs of that workflow so progress is persistent, inspectable, and reproducible. - ---- - -## Directory Structure - -Typical contents may include: - -``` -.superpowers/ -├── brainstorm/ # Design explorations and refined specs -├── plans/ # Task breakdowns and execution plans -├── reviews/ # Code review outputs and feedback -├── runs/ # Execution logs or agent traces -└── README.md # This file -``` - -> Exact structure may evolve depending on which skills are triggered. - ---- - -## Workflow Overview - -Superpowers operates through automatic skill activation: - -### 1. Brainstorming - -* Refines vague ideas into concrete specs -* Explores alternatives -* Produces structured, reviewable design docs - -### 2. Planning - -* Converts approved designs into granular tasks -* Each task is: - - * Small (2–5 min) - * Explicit (exact file paths + code) - * Verifiable - -### 3. Execution - -* Tasks are executed by subagents -* Includes: - - * Spec compliance checks - * Code quality review -* Can run sequentially or in parallel - -### 4. Verification - -* Enforces test-first development (TDD) -* Ensures correctness before completion -* Prevents silent regressions - -### 5. Completion - -* Validates final state -* Offers merge / PR / discard options -* Cleans up working branches - ---- - -## Key Principles - -* **Test-first development** (RED → GREEN → REFACTOR) -* **Small, deterministic tasks** -* **Explicit over implicit** -* **Process over intuition** -* **Verification over assumption** - ---- - -## How to Use - -You don’t interact with this directory directly most of the time. - -Instead: - -* Start a task in your coding agent (Claude, Cursor, etc.) -* Let Superpowers skills activate automatically -* Review outputs when prompted (designs, plans, reviews) - -Artifacts will be written here as the workflow progresses. - ---- - -## When to Look Here - -Check this directory when you want to: - -* Review the current plan -* Inspect prior design decisions -* Debug agent behavior -* Resume interrupted work -* Audit what was executed - ---- - -## Notes - -* Files here are **source-of-truth for agent state** -* Safe to commit (recommended for team workflows) -* Avoid manual edits unless you understand the workflow implications - ---- - -## Related - -* Project root `CLAUDE.md` → global agent context -* `.claude/` → rules, skills, and subagents -* Superpowers upstream docs → diff --git a/.superpowers/brainstorm/1542-1774533799/content/workflows-page-wireframe.html b/.superpowers/brainstorm/1542-1774533799/content/workflows-page-wireframe.html deleted file mode 100644 index 33e0e6d6..00000000 --- a/.superpowers/brainstorm/1542-1774533799/content/workflows-page-wireframe.html +++ /dev/null @@ -1,2123 +0,0 @@ - - - - - - Workflows Page — Wireframe - - - - - - - -
-
-
3.2
-
Avg Agent Depth
-
▲ 0.4 this week
-
-
-
5.8
-
Avg Subagents / Session
-
▲ 1.2 this week
-
-
-
87%
-
Agent Success Rate
-
▼ 2% this week
-
-
-
R→E→B
-
Most Common Flow
-
Read → Edit → Bash
-
-
-
2.1
-
Avg Compactions
-
▲ 0.3 this week
-
-
-
4m 32s
-
Avg Session Duration
-
▼ 18s this week
-
-
- - -
-
-

- 1 Agent Orchestration Graph ? -

-
- Aggregate spawning patterns across all sessions · Click a node to filter page -
-
-
-
- -
-
Origin
-
● Session Start (142)
-
- -
-
-
- - -
-
Main Agent
-
■ Main Agent (142)
-
- -
-
-
-
-
-
-
- - -
-
Subagent Types
-
◆ Explore (89)
-
◆ code-reviewer (67)
-
- ◆ general-purpose (54) -
-
◆ Plan (43)
-
◆ tdd-assistant (38)
-
◆ +5 more...
-
- -
-
-
-
- - -
-
Nested (Depth 2+)
-
- ◆ debugger (12) -
-
- ◆ security-auditor (8) -
-
- ◆ compaction (23) -
-
- -
-
-
-
- - -
-
Outcomes
-
- ✓ Completed (298) -
-
✗ Error (18)
-
- ⚠ Abandoned (7) -
-
-
- -
-
-
- Session root -
-
-
- Main agent -
-
-
- Subagent type -
-
-
- High frequency -
-
-
- Low frequency -
-
- -
- 💡 - Interactive: Nodes are clickable. Selecting a node filters Sections 2-5 to only show data - involving that agent type. Edge thickness represents spawn frequency. Hover shows detailed - metrics. -
-
-
- - -
-
-

2 Tool Execution Flow ?

-
How tools chain together · Sankey-style directed flow
-
-
-
-
All Agents
-
Explore
-
code-reviewer
-
general-purpose
-
- -
- -
-
- Read 42% -
-
- Bash 18% -
-
- Grep 14% -
-
- Glob 10% -
-
- - -
-
-
-
-
-
-
- Flow bands connect
source → target tools
Band width = transition frequency -
-
- - -
-
- Edit 28% -
-
- Write 22% -
-
- Bash 18% -
-
- Read 16% -
-
- Agent 10% -
-
-
- -
- 💡 - Sankey diagram: left column = source tool, right column = next tool in sequence. Band - width shows how often one tool follows another. Filterable by agent type tabs above. -
-
-
- - -
- -
-
-

3 Subagent Effectiveness

-
Performance per agent type
-
-
-
- -
-
-
- Explore -
-
- - - - -
92%
-
-
-
-
89
-
Sessions
-
-
-
1.2m
-
Avg Tokens
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
-
-
- code-reviewer -
-
- - - - -
85%
-
-
-
-
67
-
Sessions
-
-
-
2.8m
-
Avg Tokens
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
-
-
- general-purpose -
-
- - - - -
80%
-
-
-
-
54
-
Sessions
-
-
-
3.4m
-
Avg Tokens
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
-
-
- tdd-assistant -
-
- - - - -
75%
-
-
-
-
38
-
Sessions
-
-
-
1.8m
-
Avg Tokens
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
-
-

4 Detected Workflow Patterns

-
Common agent orchestration sequences
-
-
-
-
-
🚀
-
-
Explore
-
→
-
Plan
-
→
-
code-reviewer
-
-
-
34x
-
24% of sessions
-
-
- -
-
🔧
-
-
Explore
-
→
-
general-purpose
-
→
-
tdd-assistant
-
-
-
28x
-
20% of sessions
-
-
- -
-
🛡
-
-
code-reviewer
-
→
-
security-auditor
-
-
-
19x
-
13% of sessions
-
-
- -
-
🐞
-
-
Explore
-
→
-
debugger
-
→
-
tdd-assistant
-
-
-
15x
-
11% of sessions
-
-
- -
-
📑
-
-
- Solo main -
-
→
-
- No subagents -
-
-
-
22x
-
15% of sessions
-
-
-
- -
- 💡 - Patterns detected by analyzing subagent spawn sequences within sessions. Click a pattern - to highlight it in the DAG above. -
-
-
-
- - -
- -
-
-

5 Model Delegation Flow

-
How models route through agent hierarchies
-
-
-
-
-
Opus 4.6
-
78% of main agents
-
$4.82 avg cost
-
-
-
delegates to
-
-
62%
-
-
-
-
Sonnet 4.6
-
48% of subagents
-
$1.24 avg cost
-
-
-
Haiku 4.5
-
14% of subagents
-
$0.18 avg cost
-
-
-
-
-
- - -
-
-

6 Error Propagation Map

-
Where errors cluster in agent hierarchy depth
-
-
-
-
-
-
3
-
-
- Depth 0
Main agent -
-
-
-
-
11
-
-
- Depth 1
Direct subagent -
-
-
-
-
4
-
-
- Depth 2
Nested -
-
-
-
-
1
-
-
- Depth 3+
Deep nested -
-
-
-
-
- Top error-prone types: -
-
- general-purpose (6) · - tdd-assistant (5) · - debugger (4) -
-
-
-
-
- - -
-
-

- 7 Agent Concurrency Timeline ? -

-
- Parallel agent execution patterns · Shows how agents overlap in time -
-
-
-
-
Aggregate (avg across sessions)
-
Selected Session
-
- -
-
-
Main Agent
-
-
-
-
-
-
Explore
-
-
-
-
-
-
-
Plan
-
-
-
-
-
-
code-reviewer
-
-
-
-
-
-
tdd-assistant
-
-
-
-
-
-
-
-
security-auditor
-
-
-
-
-
-
compaction
-
-
-
-
-
- -
-
0% — Start
-
25%
-
50%
-
75%
-
100% — End
-
-
- -
-
-
- Working -
-
-
- Error -
-
-
- Compaction event -
-
-
-
- - -
- -
-
-

8 Session Complexity Scatter

-
- Duration vs agent count vs tokens · Bubble size = token usage -
-
-
-
-
-
-
- Agent Count ↑ -
-
Duration →
- - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Completed -
-
-
- Error -
-
-
- Active -
-
-
- Abandoned -
-
-
-
- - -
-
-

9 Compaction Impact Analysis

-
Context compression events and token recovery
-
-
-
-
-
47
-
- Total Compactions -
-
-
-
38.2M
-
- Tokens Recovered -
-
-
- - -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- Session start - Session end -
- -
-
-
- Token growth -
-
-
- Compaction trigger -
-
-
- Post-compaction baseline -
-
-
-
-
- - -
-
-

10 Session Drill-In ?

-
- Select a session from the dropdown above or click a scatter dot to see its full execution - graph -
-
-
-
-
◆
-
No session selected
-
- Select a session to see its specific agent hierarchy tree, tool call timeline, and - execution flow as a horizontal node graph. -
-
-
◆ Agent Tree
-
⚙ Tool Timeline
-
☰ Event Sequence
-
-
- -
- 💡 - When a session is selected: shows the actual horizontal agent spawn tree for that session - (like the DAG above but for one session), a tool-call swim-lane timeline, and a scrollable - event sequence. All three sub-views in tabs. -
-
-
- - -
-

✍ Design Notes

-
-
- UX Principles -
    -
  • Cross-filtering: clicking nodes in DAG filters all other sections
  • -
  • Progressive disclosure: aggregate by default, drill into specifics
  • -
  • Consistent dark theme matching existing app (Tailwind surface levels)
  • -
  • Responsive: 2-col layouts collapse to single column on narrow screens
  • -
  • Tooltips on every metric for raw values and context
  • -
-
-
- Technical Approach -
    -
  • New /api/workflows endpoint with aggregation queries
  • -
  • D3.js or React Flow for DAG and Sankey rendering
  • -
  • WebSocket updates for real-time active session changes
  • -
  • No new database tables — all derived from existing schema
  • -
  • Server-side computation for patterns and aggregates
  • -
-
-
-
- - diff --git a/.superpowers/brainstorm/1542-1774533799/state/server-stopped b/.superpowers/brainstorm/1542-1774533799/state/server-stopped deleted file mode 100644 index 7f4b634a..00000000 --- a/.superpowers/brainstorm/1542-1774533799/state/server-stopped +++ /dev/null @@ -1 +0,0 @@ -{"reason":"idle timeout","timestamp":1774536800234} diff --git a/.superpowers/brainstorm/1542-1774533799/state/server.pid b/.superpowers/brainstorm/1542-1774533799/state/server.pid deleted file mode 100644 index 57c7c052..00000000 --- a/.superpowers/brainstorm/1542-1774533799/state/server.pid +++ /dev/null @@ -1 +0,0 @@ -1542 diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 2491530c..42ed2974 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -39,8 +39,6 @@ Architectural overview and technical reference for the Agent Dashboard system, c ![React Testing Library](https://img.shields.io/badge/React_Testing_Library-13.0-FF5733?style=flat-square&logo=testinglibrary&logoColor=white) ![ESLint](https://img.shields.io/badge/ESLint-8.44-4B32C3?style=flat-square&logo=eslint&logoColor=white) ![Prettier](https://img.shields.io/badge/Prettier-3.8-F7B93E?style=flat-square&logo=prettier&logoColor=white) -![Docker](https://img.shields.io/badge/Docker-20.10-2496ED?style=flat-square&logo=docker&logoColor=white) -![Podman](https://img.shields.io/badge/Podman-4.0-CC342D?style=flat-square&logo=podman&logoColor=white) ![Make](https://img.shields.io/badge/Make-4.3-000000?style=flat-square&logo=make&logoColor=white) --- @@ -63,11 +61,10 @@ Architectural overview and technical reference for the Agent Dashboard system, c - [Browser Notification System](#browser-notification-system) - [Update Notifier Subsystem](#update-notifier-subsystem) - [Sagi Companion Subsystem](#sagi-companion-subsystem) -- [VS Code Extension Architecture](#vs-code-extension-architecture) - [Security Considerations](#security-considerations) - [Performance Characteristics](#performance-characteristics) - [Deployment Modes](#deployment-modes) -- [Statusline Utility](#statusline-utility) +- [Model Name Formatting](#model-name-formatting-client) - [Technology Choices](#technology-choices) - [Build & Run Targets](#build--run-targets) @@ -473,57 +470,37 @@ graph TD ### Self-hosted assets (no external CDN) -Nothing the dashboard or docs render is fetched from a third-party CDN at runtime — all fonts and scripts are served locally, so every surface works fully offline and leaks nothing to external hosts. +Nothing the dashboard renders is fetched from a third-party CDN at runtime — fonts are served locally, so the UI works fully offline and leaks nothing to external hosts. - **React app fonts** — Inter + JetBrains Mono are imported from `@fontsource` (latin subset) in `client/src/main.tsx`. Vite bundles the per-weight WOFF2 into `client/dist/assets/` with content hashes at build time; there is no Google Fonts ``. Importing the `latin-*` subset entry points keeps the emitted set to one WOFF2 per weight. -- **Static pages (landing + wiki)** — load a self-hosted `@font-face` sheet at the repo-root `fonts/` directory (`fonts/fonts.css` + the `*.woff2` files). The root `index.html` references `fonts/fonts.css`; the wiki references `../fonts/fonts.css` (relative paths resolve under GitHub Pages). -- **Wiki Mermaid** — vendored as `wiki/mermaid.min.js` (the genuine minified `mermaid@10.9.6` from npm, with a provenance banner; `.prettierignore`d) and loaded via a local ` diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 4d2626c1..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,23 +0,0 @@ -services: - agent-monitor: - build: . - container_name: agent-monitor - ports: - # Publish on the host loopback only, so the dashboard is not reachable - # from the LAN out of the box (matches the server's default trust - # boundary — GHSA-gr74-4xfh-6jw9). To expose it on a LAN, change this to - # "${DASHBOARD_PORT:-4820}:4820" and set DASHBOARD_TOKEN below. - - "127.0.0.1:${DASHBOARD_PORT:-4820}:4820" - volumes: - # Same SQLite file as `npm start` / `npm run dev` on the host. - - ${CLAUDE_HOME:-~/.claude}/agenthub:/app/data - - ${CLAUDE_HOME:-~/.claude}:/root/.claude:ro - environment: - - NODE_ENV=production - - DASHBOARD_PORT=4820 - # Optional — required when a Prometheus-in-Docker scraper reaches this - # container as anything other than loopback (e.g. host.docker.internal). - - DASHBOARD_ALLOWED_HOSTS=${DASHBOARD_ALLOWED_HOSTS:-} - # DASHBOARD_HOST=0.0.0.0 and DASHBOARD_DATA_DIR=/app/data are baked into - # the image (see Dockerfile) so both `docker run` and Compose work as-is. - restart: unless-stopped diff --git a/docs/DATABASE.md b/docs/DATABASE.md index cbd01942..ed0740cf 100644 --- a/docs/DATABASE.md +++ b/docs/DATABASE.md @@ -64,7 +64,7 @@ graph TB ``` **Database Location:** -- **Canonical (default):** `~/.claude/agenthub/dashboard.db` — shared by `npm start`, `npm run dev`, Docker (bind mount), and the desktop app when it uses the same data dir +- **Canonical (default):** `~/.claude/agenthub/dashboard.db` — shared by `npm start`, `npm run dev`, and the desktop app when it uses the same data dir - **Override:** set `DASHBOARD_DATA_DIR` (directory) or `DASHBOARD_DB_PATH` (file path) for tests or custom deployments - **Legacy:** repo-local `./data/dashboard.db` is migrated into the canonical location on first launch (see `server/db.js`) - **Pre-rebrand:** an install that predates AgentHub keeps its data in `~/.claude/agent-dashboard/`. Server startup renames that directory to `~/.claude/agenthub/` once, before anything opens the database (`migrateLegacyDataDir()` in `server/lib/claude-home.js`). It is a same-filesystem rename, so it is instant even at multiple gigabytes and never leaves two copies. If the rename fails, or `DASHBOARD_DATA_DIR` is set, nothing moves and the old directory keeps being used. diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index df3fb12a..50a00dfd 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -10,7 +10,6 @@ Enterprise deployment strategies for Agent Dashboard across development, staging - [Deployment Architecture](#deployment-architecture) - [Local Development](#local-development) - [Production Deployment](#production-deployment) -- [Docker Deployment](#docker-deployment) - [Cloud Deployment](#cloud-deployment) - [Process Management](#process-management) - [Monitoring & Logging](#monitoring--logging) @@ -26,7 +25,6 @@ Enterprise deployment strategies for Agent Dashboard across development, staging Agent Dashboard supports multiple deployment modes: - **Local Development** - Hot reload for rapid iteration -- **Docker** - Containerized deployment with Docker/Podman - **PM2** - Process management for production - **Systemd** - System service on Linux - **Cloud** - Deploy to AWS, Azure, GCP, or other cloud providers @@ -35,7 +33,6 @@ Agent Dashboard supports multiple deployment modes: graph TB subgraph "Deployment Modes" Dev[Local Development
npm run dev] - Docker[Docker Container
docker compose up] PM2[PM2 Process Manager
pm2 start] Systemd[Systemd Service
systemctl start] Cloud[Cloud Platform
Kubernetes, ECS, etc.] @@ -48,8 +45,6 @@ graph TB end Dev --> DevEnv - Docker --> DevEnv - Docker --> StagingEnv PM2 --> ProdEnv Systemd --> ProdEnv Cloud --> ProdEnv @@ -260,118 +255,14 @@ CODEX_HOME= # where Codex keeps sessions/ (default ~ LOG_LEVEL=info # debug | info | warn | error ``` -> **Reverse-proxy / Docker exposure:** the app binds loopback, so publish it to a +> **Reverse-proxy / container exposure:** the app binds loopback, so publish it to a > network only through a proxy you control that adds TLS + auth, or set -> `DASHBOARD_HOST=0.0.0.0` **with** `DASHBOARD_TOKEN`. A `-p 4820:4820` Docker -> mapping assumes a trusted host network — do not expose it publicly without a +> `DASHBOARD_HOST=0.0.0.0` **with** `DASHBOARD_TOKEN`. A published `4820` port +> assumes a trusted host network — do not expose it publicly without a > token and a proxy. --- -## Docker Deployment - -### Docker Compose (Recommended) - -```yaml -# docker-compose.yml -version: '3.8' - -services: - agenthub: - build: . - ports: - - "4820:4820" - volumes: - - ./data:/app/data - environment: - - NODE_ENV=production - - PORT=4820 - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:4820/api/sessions"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s -``` - -### Build & Run - -```bash -# Build image -docker compose build - -# Start container -docker compose up -d - -# View logs -docker compose logs -f - -# Stop container -docker compose down -``` - -### Multi-Stage Dockerfile - -```dockerfile -# Build stage -FROM node:22-alpine AS builder - -WORKDIR /app - -# Install dependencies -COPY package*.json ./ -COPY client/package*.json ./client/ -RUN npm ci && cd client && npm ci - -# Build client -COPY client ./client -RUN cd client && npm run build - -# Production stage -FROM node:22-alpine - -WORKDIR /app - -# Copy built artifacts -COPY --from=builder /app/client/dist ./client/dist -COPY --from=builder /app/node_modules ./node_modules -COPY server ./server -COPY package.json ./ - -# Create data directory -RUN mkdir -p /app/data - -EXPOSE 4820 - -HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ - CMD node -e "require('http').get('http://localhost:4820/api/sessions', (res) => process.exit(res.statusCode === 200 ? 0 : 1))" - -CMD ["node", "server/index.js"] -``` - -### Container Architecture - -```mermaid -graph TB - subgraph "Docker Host" - subgraph "Container" - App[Node.js App
:4820] - Volume[Volume Mount
/app/data] - end - end - - Host[Host Filesystem
./data] -->|Bind Mount| Volume - App --> Volume - - Client[External Clients] -->|Port 4820| App - - style App fill:#2496ED,color:#fff - style Volume fill:#FFA500 -``` - ---- - ## Cloud Deployment ### AWS (Elastic Beanstalk) @@ -395,6 +286,9 @@ eb open ### Kubernetes +The repo ships no container image or `Dockerfile` — build your own from +`npm ci && npm run build` and push it to your registry, then reference it here. + ```yaml # k8s/deployment.yaml apiVersion: apps/v1 @@ -603,19 +497,16 @@ graph TB subgraph "Log Aggregation" Stdout --> PM2[PM2 Logs] Stdout --> Systemd[Systemd Journal] - Stdout --> Docker[Docker Logs] end subgraph "Monitoring Tools" PM2 --> File[Log Files] Systemd --> Journalctl[journalctl] - Docker --> DockerLogs[docker logs] end subgraph "Analysis" File --> Splunk[Splunk/ELK] Journalctl --> Splunk - DockerLogs --> Splunk end style App fill:#000000,color:#fff @@ -912,7 +803,7 @@ NODE_ENV=development node server/index.js This deployment guide covers: -- ✅ **Multiple deployment modes** - Local, Docker, PM2, Systemd, Cloud +- ✅ **Multiple deployment modes** - Local, PM2, Systemd, Cloud - ✅ **Production best practices** - Environment variables, health checks, logging - ✅ **Process management** - PM2, systemd service files - ✅ **Monitoring & logging** - Metrics endpoint, log aggregation diff --git a/docs/HOOKS.md b/docs/HOOKS.md index 78593853..cc7d7ff7 100644 --- a/docs/HOOKS.md +++ b/docs/HOOKS.md @@ -578,8 +578,8 @@ function sendToServer(hookType, payload) { > Each server appends its `{port, pid, startedAt, dataDir}` entry on > startup and removes it on a clean shutdown. The handler **prunes any > entry whose PID is no longer alive** and POSTs the hook payload to one -> port per **unique SQLite data directory** (lowest port wins when Docker -> and `npm run dev` share `~/.claude/agenthub`). +> port per **unique SQLite data directory** (lowest port wins when two +> instances share `~/.claude/agenthub`). > 3. If neither yields a target, the handler falls back to `4820`. > > Dashboards with **different** databases (e.g. the packaged desktop app using diff --git a/docs/README.md b/docs/README.md index 15601bc2..79bc710b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -429,7 +429,7 @@ This documentation covers: - ✅ **Complete architecture** - Frontend, backend, database, integrations - ✅ **API reference** - REST endpoints, WebSocket events -- ✅ **Deployment guides** - Docker, PM2, systemd, cloud +- ✅ **Deployment guides** - PM2, systemd, cloud - ✅ **Performance tuning** - Database, server, client optimizations - ✅ **Integration guides** - Hooks, MCP, custom clients - ✅ **Internationalization** - Language resources, switching flow, locale formatting, rollout checklist diff --git a/favicon.svg b/favicon.svg deleted file mode 100644 index 098f2401..00000000 --- a/favicon.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fonts/fonts.css b/fonts/fonts.css deleted file mode 100644 index 412aa306..00000000 --- a/fonts/fonts.css +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @file fonts.css - * @description Self-hosted Inter + JetBrains Mono @font-face declarations — no Google Fonts dependency. - * @author Nguyễn Ngọc Trí Vĩ - */ - -/* Inter */ -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url("inter-latin-400-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 500; - font-display: swap; - src: url("inter-latin-500-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 600; - font-display: swap; - src: url("inter-latin-600-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 700; - font-display: swap; - src: url("inter-latin-700-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 800; - font-display: swap; - src: url("inter-latin-800-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 900; - font-display: swap; - src: url("inter-latin-900-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} - -/* JetBrains Mono */ -@font-face { - font-family: "JetBrains Mono"; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url("jetbrains-mono-latin-400-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: "JetBrains Mono"; - font-style: normal; - font-weight: 500; - font-display: swap; - src: url("jetbrains-mono-latin-500-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: "JetBrains Mono"; - font-style: normal; - font-weight: 600; - font-display: swap; - src: url("jetbrains-mono-latin-600-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: "JetBrains Mono"; - font-style: normal; - font-weight: 700; - font-display: swap; - src: url("jetbrains-mono-latin-700-normal.woff2") format("woff2"); - unicode-range: - U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, - U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} diff --git a/fonts/inter-latin-400-normal.woff2 b/fonts/inter-latin-400-normal.woff2 deleted file mode 100644 index f15b025d..00000000 Binary files a/fonts/inter-latin-400-normal.woff2 and /dev/null differ diff --git a/fonts/inter-latin-500-normal.woff2 b/fonts/inter-latin-500-normal.woff2 deleted file mode 100644 index 54f0a595..00000000 Binary files a/fonts/inter-latin-500-normal.woff2 and /dev/null differ diff --git a/fonts/inter-latin-600-normal.woff2 b/fonts/inter-latin-600-normal.woff2 deleted file mode 100644 index d1897949..00000000 Binary files a/fonts/inter-latin-600-normal.woff2 and /dev/null differ diff --git a/fonts/inter-latin-700-normal.woff2 b/fonts/inter-latin-700-normal.woff2 deleted file mode 100644 index a68fb101..00000000 Binary files a/fonts/inter-latin-700-normal.woff2 and /dev/null differ diff --git a/fonts/inter-latin-800-normal.woff2 b/fonts/inter-latin-800-normal.woff2 deleted file mode 100644 index 74a16d45..00000000 Binary files a/fonts/inter-latin-800-normal.woff2 and /dev/null differ diff --git a/fonts/inter-latin-900-normal.woff2 b/fonts/inter-latin-900-normal.woff2 deleted file mode 100644 index 4db8333c..00000000 Binary files a/fonts/inter-latin-900-normal.woff2 and /dev/null differ diff --git a/fonts/jetbrains-mono-latin-400-normal.woff2 b/fonts/jetbrains-mono-latin-400-normal.woff2 deleted file mode 100644 index 58588733..00000000 Binary files a/fonts/jetbrains-mono-latin-400-normal.woff2 and /dev/null differ diff --git a/fonts/jetbrains-mono-latin-500-normal.woff2 b/fonts/jetbrains-mono-latin-500-normal.woff2 deleted file mode 100644 index be878e68..00000000 Binary files a/fonts/jetbrains-mono-latin-500-normal.woff2 and /dev/null differ diff --git a/fonts/jetbrains-mono-latin-600-normal.woff2 b/fonts/jetbrains-mono-latin-600-normal.woff2 deleted file mode 100644 index 59c24e7c..00000000 Binary files a/fonts/jetbrains-mono-latin-600-normal.woff2 and /dev/null differ diff --git a/fonts/jetbrains-mono-latin-700-normal.woff2 b/fonts/jetbrains-mono-latin-700-normal.woff2 deleted file mode 100644 index 3a4e333f..00000000 Binary files a/fonts/jetbrains-mono-latin-700-normal.woff2 and /dev/null differ diff --git a/manifest.json b/manifest.json deleted file mode 100644 index 3db94711..00000000 --- a/manifest.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "claude-code-agent-monitor-landing", - "name": "AgentHub", - "short_name": "AgentHub", - "description": "Local-first monitoring dashboard for Claude Code sessions.", - "author": "Nguyễn Ngọc Trí Vĩ", - "start_url": ".", - "scope": ".", - "display": "standalone", - "theme_color": "#6366f1", - "background_color": "#07070b", - "orientation": "any", - "categories": ["developer-tools", "productivity"], - "icons": [ - { - "src": "favicon.svg", - "sizes": "any", - "type": "image/svg+xml", - "purpose": "any" - }, - { - "src": "favicon.svg", - "sizes": "any", - "type": "image/svg+xml", - "purpose": "maskable" - } - ] -} diff --git a/og-image.svg b/og-image.svg deleted file mode 100644 index fc252883..00000000 --- a/og-image.svg +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Agent Dashboard - - - Real-time monitoring platform for Claude Code agent activity - - - - - - - - - Node.js 18+ - - - React 18 - - - TypeScript - - - SQLite - - - WebSocket - - - MIT - - - - github.com/SmartGift · smartgift.vn - diff --git a/package.json b/package.json index 33a6bd90..f93fa01b 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "dev:client": "cd client && npm run dev", "build": "cd client && npm run build", "start": "node server/index.js", - "setup": "npm install && (cd client && npm install) && (cd vscode-extension && npm install) && npm run link-cli", + "setup": "npm install && (cd client && npm install) && npm run link-cli", "update:pull-setup": "git pull --ff-only && npm run setup", "install-hooks": "node scripts/install-hooks.js", "seed": "node scripts/seed.js", @@ -68,9 +68,7 @@ "format": "prettier --write .", "format:check": "prettier --check .", "openapi:yaml": "node scripts/generate-openapi-yaml.js", - "link-cli": "npm link || node -e \"console.warn('agenthub CLI not linked globally (no permission?). Link manually with: npm link')\"", - "docker:up": "docker compose up -d --build", - "docker:down": "docker compose down" + "link-cli": "npm link || node -e \"console.warn('agenthub CLI not linked globally (no permission?). Link manually with: npm link')\"" }, "dependencies": { "@lydell/node-pty": "^1.2.0-beta.15", diff --git a/robots.txt b/robots.txt deleted file mode 100644 index bbf25618..00000000 --- a/robots.txt +++ /dev/null @@ -1,5 +0,0 @@ -# https://smartgift.github.io/Claude-Code-Agent-Monitor/ -User-agent: * -Allow: / - -Sitemap: https://smartgift.github.io/Claude-Code-Agent-Monitor/sitemap.xml diff --git a/server/README.md b/server/README.md index 6f4c3500..cc32150d 100644 --- a/server/README.md +++ b/server/README.md @@ -13,8 +13,6 @@ Enterprise-grade Node.js backend for Claude Code agent monitoring with real-time ![better--sqlite3](https://img.shields.io/badge/better--sqlite3-11.7-003B57?style=flat-square&logo=sqlite&logoColor=white) ![Autoprefixer](https://img.shields.io/badge/Autoprefixer-10.4-DD3735?style=flat-square&logo=autoprefixer&logoColor=white) ![ESLint](https://img.shields.io/badge/ESLint-8.44-4B32C3?style=flat-square&logo=eslint&logoColor=white) -![Docker](https://img.shields.io/badge/Docker-20.10-2496ED?style=flat-square&logo=docker&logoColor=white) -![Podman](https://img.shields.io/badge/Podman-4.0-CC342D?style=flat-square&logo=podman&logoColor=white) ![Prometheus](https://img.shields.io/badge/Prometheus-2.x-E6522C?style=flat-square&logo=prometheus&logoColor=white) ![Grafana](https://img.shields.io/badge/Grafana-10.x-F46800?style=flat-square&logo=grafana&logoColor=white) ![SSE](https://img.shields.io/badge/SSE-Server_Sent_Events-FF6600?style=flat-square&logo=googlechrome&logoColor=white) @@ -1532,38 +1530,6 @@ pm2 start server/index.js --name agenthub sudo systemctl start agenthub ``` -### Docker Deployment - -```dockerfile -# Dockerfile (root of project) -FROM node:22-alpine - -WORKDIR /app - -# Install dependencies -COPY package*.json ./ -COPY client/package*.json ./client/ -RUN npm ci --production && cd client && npm ci --production - -# Build client -COPY client ./client -RUN cd client && npm run build - -# Copy server -COPY server ./server -COPY data ./data - -EXPOSE 4820 - -CMD ["node", "server/index.js"] -``` - -```bash -# Build and run -docker build -t agenthub . -docker run -p 127.0.0.1:4820:4820 -v "$HOME/.claude/agenthub:/app/data" agenthub -``` - --- ## Configuration diff --git a/server/lib/server-info.js b/server/lib/server-info.js index 01cf87a6..0cfa2f6d 100644 --- a/server/lib/server-info.js +++ b/server/lib/server-info.js @@ -231,8 +231,8 @@ function resolveAllDashboardPorts() { /** * Ports that should receive hook POSTs. When several live servers share the * same SQLite data directory, only the lowest port per directory is returned - * so parallel instances (Docker + dev, two terminals on the same DB) never - * double-ingest events. + * so parallel instances (two terminals on the same DB) never double-ingest + * events. * * @returns {number[]} */ diff --git a/sitemap.xml b/sitemap.xml deleted file mode 100644 index 163ba01d..00000000 --- a/sitemap.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - https://smartgift.github.io/Claude-Code-Agent-Monitor/ - 2026-07-29 - daily - 1.0 - - diff --git a/skills/update-project-docs/references/doc-map.md b/skills/update-project-docs/references/doc-map.md index df5126ba..c868ca07 100644 --- a/skills/update-project-docs/references/doc-map.md +++ b/skills/update-project-docs/references/doc-map.md @@ -52,7 +52,6 @@ i18n architecture: **Supported languages** list, `supportedLngs`, the 15 namespa - `INSTALL.md`, `SETUP.md` — install/run commands. - `CLAUDE.md`, `AGENTS.md` — agent working guides; update when commands, file locations, or workflows change. - `docs/README.md` — docs index; add a link when a new `docs/*.md` is created. -- `vscode-extension/README.md`, `statusline/README.md` — surface-specific; update only when that surface changes. ## Consistency invariants diff --git a/statusline/README.md b/statusline/README.md deleted file mode 100644 index 9e0cefd0..00000000 --- a/statusline/README.md +++ /dev/null @@ -1,183 +0,0 @@ -# Claude Code Statusline - -A color-coded statusline for Claude Code showing model, user, working directory, git branch, context window usage, token counts, and session cost. - -## Preview - -Example statusline with all segments visible in a git repo and 24% context window usage: -| Segment | Color | Example | -| ----------- | -------------------- | -------------------------------------------------- | -| Model | Cyan | `Sonnet 4.6` | -| User | Green | `nguyens6` | -| CWD | Yellow | `~/agenthub/client` | -| Git branch | Magenta | `main` (hidden outside git repos) | -| Context bar | Green → Yellow → Red | `████████░░ 79%` | -| Tokens | Green / Cyan / Dim | `3↑ 2↓ 156586c` (green `↑` in, cyan `↓` out, dim `c` cache reads) | -| Cost (USD) | Green → Yellow → Red | `$0.4231` (session total — shown on API and subscription plans) | - -Context bar color thresholds: - -- **Green** — under 50% used -- **Yellow** — 50–79% used -- **Red** — 80%+ used - -Cost color thresholds: - -- **Green** — under $5 -- **Yellow** — $5–$20 -- **Red** — $20+ - -## Requirements - -- Python 3.6+ -- Git (for branch detection) -- Claude Code 2.x+ - -## Installation - -**1. Copy both files into your Claude config directory:** - -```bash -# macOS / Linux -cp statusline.py ~/.claude/statusline.py -cp statusline-command.sh ~/.claude/statusline-command.sh -chmod +x ~/.claude/statusline-command.sh - -# Windows (Git Bash) -cp statusline.py "$HOME/.claude/statusline.py" -cp statusline-command.sh "$HOME/.claude/statusline-command.sh" -``` - -**2. Update the path in `statusline-command.sh`:** - -Open `~/.claude/statusline-command.sh` and replace the path with your own home directory: - -```bash -#!/usr/bin/env bash -PYTHONUTF8=1 python3 "/your/home/.claude/statusline.py" -``` - -On Windows this looks like: - -```bash -#!/usr/bin/env bash -PYTHONUTF8=1 python3 "C:/Users/YOUR_USERNAME/.claude/statusline.py" -``` - -On macOS/Linux: - -```bash -#!/usr/bin/env bash -python3 "$HOME/.claude/statusline.py" -``` - -**3. Add to `~/.claude/settings.json`:** - -```json -{ - "statusLine": { - "type": "command", - "command": "bash \"/path/to/home/.claude/statusline-command.sh\"" - } -} -``` - -Windows example: - -```json -{ - "statusLine": { - "type": "command", - "command": "bash \"C:/Users/YOUR_USERNAME/.claude/statusline-command.sh\"" - } -} -``` - -macOS/Linux example: - -```json -{ - "statusLine": { - "type": "command", - "command": "bash \"/home/YOUR_USERNAME/.claude/statusline-command.sh\"" - } -} -``` - -**4. Restart Claude Code** — fully exit and relaunch. Claude Code does not hot-reload `settings.json`, so the new statusline will not show up until the process is restarted. - -## Troubleshooting - -**The statusline still shows the default (e.g. `[Model] 📁 cwd`) after restarting.** - -Claude Code resolves `statusLine` from multiple settings files, in this precedence (later wins): - -1. `~/.claude/settings.json` (user, global) -2. `~/.claude/settings.local.json` (user, local — **often overrides the global**) -3. `/.claude/settings.json` (project, shared) -4. `/.claude/settings.local.json` (project, local) - -If any of those later files defines its own `statusLine` block, it **replaces** the global one — yours will never run. Grep for it: - -```bash -grep -l statusLine ~/.claude/settings*.json $(find . -maxdepth 3 -name 'settings*.json' -path '*.claude*' 2>/dev/null) -``` - -For each file that defines a competing `statusLine`, either delete that block (to fall back to the global one) or point it at the same script: - -```json -{ - "statusLine": { - "type": "command", - "command": "bash \"/path/to/home/.claude/statusline-command.sh\"" - } -} -``` - -**The statusline is blank / missing segments.** - -Run the script manually with a sample payload to confirm it works: - -```bash -echo '{"model":{"display_name":"Sonnet 4.6"},"workspace":{"current_dir":"'"$HOME"'"},"context_window":{"used_percentage":25,"current_usage":{"input_tokens":1000,"output_tokens":500,"cache_read_input_tokens":200}},"cost":{"total_cost_usd":0.4231}}' \ - | sh ~/.claude/statusline-command.sh -``` - -If nothing prints, check that `python3` is on your `PATH` and `~/.claude/statusline.py` is readable. The script always exits 0 by design so Claude Code never blocks — errors are silent, so test from the shell first. - -## How It Works - -Claude Code pipes a JSON object to the statusline command's stdin on each update. The script reads that JSON, extracts the relevant fields, and prints a color-coded string using ANSI escape codes. - -Key fields used from the JSON payload: - -```json -{ - "model": { "display_name": "Sonnet 4.6" }, - "workspace": { "current_dir": "C:\\Users\\..." }, - "context_window": { - "used_percentage": 79, - "current_usage": { - "input_tokens": 3, - "output_tokens": 2, - "cache_read_input_tokens": 156586 - } - }, - "cost": { "total_cost_usd": 0.4231 } -} -``` - -## Customization - -Edit `statusline.py` directly to change colors, reorder segments, or remove ones you don't want. Each segment is clearly labeled with a comment. - -Color constants at the top of the file: - -```python -CYAN = '\033[0;36m' -GREEN = '\033[0;32m' -YELLOW = '\033[0;33m' -MAGENTA = '\033[0;35m' -RED = '\033[0;31m' -DIM = '\033[2m' -``` diff --git a/statusline/statusline-command.sh b/statusline/statusline-command.sh deleted file mode 100644 index df2ddf25..00000000 --- a/statusline/statusline-command.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -# -# @file statusline-command.sh — wrapper that Claude Code invokes for its custom statusline; -# pipes the JSON event payload into statusline.py (update the path to match your install). -# @author Nguyễn Ngọc Trí Vĩ -# -PYTHONUTF8=1 python3 "C:/Users/nguyens6/.claude/statusline.py" -# IMPORTANT: -# Put the statusline.py file in the .claude folder in your user directory (e.g. C:/Users/nguyens6/.claude/statusline.py) and make sure to update the path in the above command if you place it somewhere else. -# Change the above path to the location of your statusline.py file. You can also change the command to run a different script if you want to display something else in your status line. diff --git a/statusline/statusline.py b/statusline/statusline.py deleted file mode 100644 index 1ffd8cb6..00000000 --- a/statusline/statusline.py +++ /dev/null @@ -1,136 +0,0 @@ -""" -statusline.py — Claude Code custom statusline renderer. - -Reads a JSON event payload from stdin (emitted by Claude Code on every turn) -and prints a single ANSI-colored status line to stdout. Renders the model -display name, current user, working directory (with home collapsed to ``~``), -active git branch, a color-coded context window usage bar (green / yellow / -red thresholds), and token counts. Always exits 0 so it can never block -Claude Code — missing fields are silently skipped. - -Intended to be referenced from Claude Code's ``statusLine`` setting (see -``statusline-command.sh`` for the wrapper) or installed to -``~/.claude/statusline.py``. - -:file: statusline/statusline.py -:module: Claude-Code-Agent-Monitor.statusline -:author: Nguyễn Ngọc Trí Vĩ -:maintainer: Nguyễn Ngọc Trí Vĩ (a.k.a. David Nguyen, smartgift) -:copyright: (c) 2026 Nguyễn Ngọc Trí Vĩ -:license: MIT -:repository: https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor -:requires: Python 3.6+ -:encoding: utf-8 - -@author Nguyễn Ngọc Trí Vĩ -""" - -__file_name__ = "statusline.py" -__module__ = "Claude-Code-Agent-Monitor.statusline" -__author__ = "Nguyễn Ngọc Trí Vĩ" -__email__ = "vinnt@smartgift.vn" -__maintainer__ = "Nguyễn Ngọc Trí Vĩ" -__copyright__ = "Copyright (c) 2026 Nguyễn Ngọc Trí Vĩ" -__license__ = "MIT" -__version__ = "1.0.0" -__status__ = "Production" -__repository__ = "https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor" - -import sys -import json -import os -import subprocess - -sys.stdout.reconfigure(encoding='utf-8') - -CYAN = '\033[0;36m' -GREEN = '\033[0;32m' -YELLOW = '\033[0;33m' -MAGENTA = '\033[0;35m' -RED = '\033[0;31m' -DIM = '\033[2m' -RESET = '\033[0m' - -raw = sys.stdin.read().strip() -if not raw: - sys.exit(0) - -try: - data = json.loads(raw) -except Exception: - sys.exit(0) - -parts = [] - -# Model -model = (data.get('model') or {}).get('display_name', '') -if model: - parts.append(f"{CYAN}{model}{RESET}") - -# User -user = os.environ.get('USERNAME') or os.environ.get('USER', '') -if user: - parts.append(f"{GREEN}{user}{RESET}") - -# CWD — strip home prefix -cwd = (data.get('workspace') or {}).get('current_dir') or data.get('cwd', '') -if cwd: - home = os.path.expanduser('~') # C:\Users\nguyens6 - if cwd.startswith(home): - cwd = '~' + cwd[len(home):].replace('\\', '/') - else: - cwd = cwd.replace('\\', '/') - parts.append(f"{YELLOW}{cwd}{RESET}") - -# Git branch -git_dir = (data.get('workspace') or {}).get('current_dir') or data.get('cwd', '') -if git_dir: - try: - branch = subprocess.check_output( - ['git', '-C', git_dir, '--no-optional-locks', 'symbolic-ref', '--short', 'HEAD'], - stderr=subprocess.DEVNULL - ).decode().strip() - except Exception: - try: - branch = subprocess.check_output( - ['git', '-C', git_dir, '--no-optional-locks', 'rev-parse', '--short', 'HEAD'], - stderr=subprocess.DEVNULL - ).decode().strip() - except Exception: - branch = '' - if branch: - parts.append(f"{MAGENTA}{branch}{RESET}") - -# Context bar -ctx = data.get('context_window') or {} -used_pct = ctx.get('used_percentage') -if used_pct is not None: - bar_len = 10 - filled = round(bar_len * used_pct / 100) - bar = '█' * filled + '░' * (bar_len - filled) - color = RED if used_pct >= 80 else YELLOW if used_pct >= 50 else GREEN - parts.append(f"{color}{bar} {used_pct}%{RESET}") - -# Tokens -usage = ctx.get('current_usage') or {} -in_tok = usage.get('input_tokens') -out_tok = usage.get('output_tokens') -cache = usage.get('cache_read_input_tokens') -if in_tok is not None and out_tok is not None: - tok_parts = [f"{GREEN}{in_tok}↑{RESET}", f"{CYAN}{out_tok}↓{RESET}"] - if cache: - tok_parts.append(f"{DIM}{cache}c{RESET}") - parts.append(' '.join(tok_parts)) - -# Session cost (USD) — shown on both API and subscription plans -cost = (data.get('cost') or {}).get('total_cost_usd') -if cost is not None: - try: - cost_f = float(cost) - cost_color = RED if cost_f >= 20 else YELLOW if cost_f >= 5 else GREEN - parts.append(f"{cost_color}${cost_f:.4f}{RESET}") - except (TypeError, ValueError): - pass - -sep = f"{DIM} | {RESET}" -print(sep.join(parts)) diff --git a/sw.js b/sw.js deleted file mode 100644 index 92d8bd59..00000000 --- a/sw.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file sw.js - * @description Service worker for the project landing page — precaches the shell (index, favicon, OG image, manifest) and manages cache lifecycle for offline support. - * @author Nguyễn Ngọc Trí Vĩ - */ - -const CACHE_NAME = "landing-v1"; -const PRECACHE = ["./", "./index.html", "./favicon.svg", "./og-image.svg", "./manifest.json"]; - -self.addEventListener("install", (event) => { - event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.addAll(PRECACHE))); - self.skipWaiting(); -}); - -self.addEventListener("activate", (event) => { - event.waitUntil( - caches - .keys() - .then((keys) => - Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k))) - ) - ); - self.clients.claim(); -}); - -self.addEventListener("fetch", (event) => { - const { request } = event; - if (request.method !== "GET") return; - - if (request.mode === "navigate") { - // Network-first for HTML - event.respondWith(fetch(request).catch(() => caches.match("./index.html"))); - return; - } - - // Cache-first for assets, lazy-cache on miss - event.respondWith( - caches.match(request).then( - (cached) => - cached || - fetch(request).then((response) => { - if (response.ok) { - const clone = response.clone(); - caches.open(CACHE_NAME).then((cache) => cache.put(request, clone)); - } - return response; - }) - ) - ); -}); diff --git a/vscode-extension/.vscode/extensions.json b/vscode-extension/.vscode/extensions.json deleted file mode 100644 index 940260d8..00000000 --- a/vscode-extension/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["dbaeumer.vscode-eslint"] -} diff --git a/vscode-extension/.vscode/launch.json b/vscode-extension/.vscode/launch.json deleted file mode 100644 index bf4f6d10..00000000 --- a/vscode-extension/.vscode/launch.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Run Extension", - "type": "extensionHost", - "request": "launch", - "args": ["--extensionDevelopmentPath=${workspaceFolder}"], - "outFiles": [], - "presentation": { - "group": "1_extension", - "order": 1 - } - }, - { - "name": "Run Extension (clean profile)", - "type": "extensionHost", - "request": "launch", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}", - "--disable-extensions", - "--profile-temp" - ], - "presentation": { - "group": "1_extension", - "order": 2 - } - }, - { - "name": "Run Extension (open repo)", - "type": "extensionHost", - "request": "launch", - "args": ["--extensionDevelopmentPath=${workspaceFolder}", "${workspaceFolder}/.."], - "presentation": { - "group": "1_extension", - "order": 3 - } - } - ] -} diff --git a/vscode-extension/.vscode/tasks.json b/vscode-extension/.vscode/tasks.json deleted file mode 100644 index f976682a..00000000 --- a/vscode-extension/.vscode/tasks.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "package", - "type": "shell", - "command": "npx vsce package", - "problemMatcher": [], - "presentation": { - "reveal": "always", - "panel": "shared" - } - } - ] -} diff --git a/vscode-extension/README.md b/vscode-extension/README.md deleted file mode 100644 index 1f649a41..00000000 --- a/vscode-extension/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# AgentHub for VS Code - -**AgentHub** brings a high-fidelity, real-time dashboard for your Claude Code AI sessions directly into your VS Code workspace. Monitor token usage, track agent health, and view deep analytics without switching windows. - -![Extension Screenshot](https://git.smartgift.io.vn/Smartgift-AI/AgentHub/raw/branch/main/vscode-extension/vscode.png) - ---- - -## 🚀 Key Features - -### 📊 Integrated Dashboard -Open the full agent monitoring dashboard in a dedicated VS Code tab. Supports real-time updates via WebSockets and local-first data storage. - -### 🩺 Live Agent Health -Track all 5 agent states in your sidebar with color-coded status indicators: -- **Working**: Active subagents currently processing tasks. -- **Connected**: Agents initialized and ready. -- **Idle**: Standby agents. -- **Completed**: Successfully finished tasks. -- **Error/Failed**: Instantly spot where things went wrong. - -### 📈 Usage & Analytics -- **Token Tracking**: Real-time display of Billions (B) or Millions (M) of tokens consumed. -- **Cost Calculation**: Live estimate of total USD cost based on current model pricing. -- **Event Frequency**: High-signal stats on events per session and subagent spawning. - -### 🧭 Deep Navigation -Jump directly to specific views from the sidebar: -- **Main Dashboard**: Global overview. -- **Analytics Hub**: Deep dives into model performance. -- **Agent Board**: Kanban-style view of subagent progress. -- **Recent Sessions**: One-click access to your last 10 Claude sessions. - ---- - -## 🛠️ Getting Started - -### 1. Requirements -Ensure you have the AgentHub server running locally: -```bash -npm install -npm run dev -``` - -### 2. Installation -- Search for **"AgentHub"** in the VS Code Marketplace. -- Click **Install**. - -### 3. Usage -- Click the **Radar/Dashboard icon** in the Activity Bar. -- The extension automatically detects your local server on ports **5173** (dev) or **4820** (prod). -- Use the **Refresh** button in the sidebar to manually force an update. - ---- - -## 📦 Publishing & Development - -To generate a `.vsix` file for manual installation or marketplace upload: - -1. Install `vsce` globally: - ```bash - npm install -g @vscode/vsce - ``` -2. Navigate to the extension folder: - ```bash - cd vscode-extension - ``` -3. Run the package command: - ```bash - vsce package - ``` - *This will generate `claude-code-agent-monitor-1.0.0.vsix`.* - ---- - -## 📜 License -Internal SmartGift build — all rights reserved. - -Developed with ❤️ for the AI Engineer community. diff --git a/vscode-extension/android-chrome-192x192.png b/vscode-extension/android-chrome-192x192.png deleted file mode 100644 index e02d2ec5..00000000 Binary files a/vscode-extension/android-chrome-192x192.png and /dev/null differ diff --git a/vscode-extension/android-chrome-512x512.png b/vscode-extension/android-chrome-512x512.png deleted file mode 100644 index 5ae97878..00000000 Binary files a/vscode-extension/android-chrome-512x512.png and /dev/null differ diff --git a/vscode-extension/apple-touch-icon.png b/vscode-extension/apple-touch-icon.png deleted file mode 100644 index 1685f174..00000000 Binary files a/vscode-extension/apple-touch-icon.png and /dev/null differ diff --git a/vscode-extension/extension.js b/vscode-extension/extension.js deleted file mode 100644 index c4e97a5f..00000000 --- a/vscode-extension/extension.js +++ /dev/null @@ -1,338 +0,0 @@ -/** - * @file Main extension file for AgentHub VSCode extension - * Sets up the extension, registers commands, and manages the status bar item. - * Implements a dynamic dashboard view that checks for active servers on ports 5173 and 4820. - * Provides real-time status updates in the sidebar and status bar with background polling. - * - * @author Nguyễn Ngọc Trí Vĩ - */ - -const vscode = require("vscode"); -const http = require("http"); -const { DashboardWebviewProvider } = require("./sidebar"); - -let statusBarItem; -let outputChannel; - -function activate(context) { - outputChannel = vscode.window.createOutputChannel("Claude Code Monitor"); - outputChannel.appendLine("[activate] " + new Date().toISOString()); - context.subscriptions.push(outputChannel); - - const statusProvider = new DashboardWebviewProvider(context, outputChannel); - context.subscriptions.push( - vscode.window.registerWebviewViewProvider("claude-code-monitor-view", statusProvider, { - webviewOptions: { retainContextWhenHidden: true }, - }) - ); - - statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100); - statusBarItem.command = "claude-code-agent-monitor.openDashboard"; - context.subscriptions.push(statusBarItem); - - updateStatusBar(); - const statusInterval = setInterval(() => { - updateStatusBar(); - }, 5000); // Auto-refresh every 5 seconds - - let openDashboard = vscode.commands.registerCommand( - "claude-code-agent-monitor.openDashboard", - async (target) => { - const panel = vscode.window.createWebviewPanel( - "agentMonitor", - "AgentHub", - vscode.ViewColumn.One, - { enableScripts: true, retainContextWhenHidden: true } - ); - - const updateWebview = async () => { - const ports = [5173, 4820]; - let activePort = null; - for (const port of ports) { - if (await checkPort(port)) { - activePort = port; - break; - } - } - - if (activePort) { - let suffix = ""; - if (target) { - suffix = target.includes("-") ? `/sessions/${target}` : `/${target}`; - } - panel.webview.html = getDashboardHtml(activePort, suffix); - } else { - panel.webview.html = getErrorHtml(); - } - }; - - panel.webview.onDidReceiveMessage((m) => { - if (m.command === "retry") updateWebview(); - }); - await updateWebview(); - } - ); - - let openInBrowser = vscode.commands.registerCommand( - "claude-code-agent-monitor.openInBrowser", - async () => { - const isDevUp = await checkPort(5173); - const url = isDevUp ? "http://localhost:5173" : "http://localhost:4820"; - vscode.env.openExternal(vscode.Uri.parse(url)); - } - ); - - let refreshStatus = vscode.commands.registerCommand( - "claude-code-agent-monitor.refreshStatus", - () => { - statusProvider.refresh(); - updateStatusBar(); - vscode.window.showInformationMessage("Claude Code Monitor refreshed."); - } - ); - - let clearHistory = vscode.commands.registerCommand( - "claude-code-agent-monitor.clearHistory", - async () => { - if ( - (await vscode.window.showWarningMessage("Clear all history?", { modal: true }, "Yes")) === - "Yes" - ) { - try { - const res = await request("DELETE", 4820, "/api/sessions"); - if (res.statusCode === 200) { - statusProvider.refresh(); - updateStatusBar(); - vscode.window.showInformationMessage("History cleared."); - } - } catch (e) { - vscode.window.showErrorMessage("Failed to clear history."); - } - } - } - ); - - context.subscriptions.push(openDashboard, openInBrowser, refreshStatus, clearHistory); - context.subscriptions.push({ dispose: () => clearInterval(statusInterval) }); -} - -async function updateStatusBar() { - try { - const stats = await fetchJson(4820, "/api/stats"); - if (stats) { - statusBarItem.text = `$(pulse) Claude: ${stats.sessions || 0}s | ${stats.agents || 0}a`; - statusBarItem.show(); - } else statusBarItem.hide(); - } catch (e) { - statusBarItem.hide(); - } -} - -function checkPort(port) { - return new Promise((r) => { - const req = http.get({ hostname: "localhost", port, path: "/", timeout: 500 }, (res) => { - r(true); - res.resume(); - }); - req.on("error", () => r(false)); - }); -} - -function fetchJson(port, path) { - return new Promise((res, rej) => { - const req = http.get({ hostname: "localhost", port, path, timeout: 800 }, (r) => { - let d = ""; - r.on("data", (c) => (d += c)); - r.on("end", () => { - try { - res(JSON.parse(d)); - } catch (e) { - rej(e); - } - }); - }); - req.on("error", rej); - }); -} - -function request(method, port, path) { - return new Promise((res, rej) => { - const req = http.request({ hostname: "localhost", port, path, method }, res); - req.on("error", rej); - req.end(); - }); -} - -function getDashboardHtml(port, suffix) { - return ` - -
Live Dashboard: ${suffix || "/"}
localhost:${port}
- `; -} - -function getErrorHtml() { - return ` - - - - - - -
-
-
- - - -
-

Dashboard Offline

-
Unable to connect to the Claude Code Monitor server
-
- -
-
-

Quick Setup Guide

-
-
-
Initialize Repository
-
git clone https://git.smartgift.io.vn/Smartgift-AI/AgentHub.git -cd AgentHub -npm run setup
-
-
-
Launch Dashboard
-
npm run dev
-
-
-
- -
-
-

- - - - - - Troubleshooting -

-

Ensure no other services are occupying ports 5173 or 4820. If the problem persists, check the documentation.

-
- - - - - View Documentation - -
-
- - -
- -`; -} - -function deactivate() { - if (statusBarItem) statusBarItem.dispose(); -} -module.exports = { activate, deactivate }; diff --git a/vscode-extension/favicon-16x16.png b/vscode-extension/favicon-16x16.png deleted file mode 100644 index d4b8170a..00000000 Binary files a/vscode-extension/favicon-16x16.png and /dev/null differ diff --git a/vscode-extension/favicon-32x32.png b/vscode-extension/favicon-32x32.png deleted file mode 100644 index 617b13bc..00000000 Binary files a/vscode-extension/favicon-32x32.png and /dev/null differ diff --git a/vscode-extension/favicon.ico b/vscode-extension/favicon.ico deleted file mode 100644 index 0306539a..00000000 Binary files a/vscode-extension/favicon.ico and /dev/null differ diff --git a/vscode-extension/icon.svg b/vscode-extension/icon.svg deleted file mode 100644 index 6319caaa..00000000 --- a/vscode-extension/icon.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/vscode-extension/package-lock.json b/vscode-extension/package-lock.json deleted file mode 100644 index 30e1695f..00000000 --- a/vscode-extension/package-lock.json +++ /dev/null @@ -1,1612 +0,0 @@ -{ - "name": "claude-code-agent-monitor", - "version": "1.2.4", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "claude-code-agent-monitor", - "version": "1.2.4", - "license": "MIT", - "devDependencies": { - "@types/vscode": "^1.75.0", - "vsce": "^2.15.0" - }, - "engines": { - "vscode": "^1.75.0" - } - }, - "node_modules/@types/vscode": { - "version": "1.116.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.116.0.tgz", - "integrity": "sha512-sYHp4MO6BqJ2PD7Hjt0hlIS3tMaYsVPJrd0RUjDJ8HtOYnyJIEej0bLSccM8rE77WrC+Xox/kdBwEFDO8MsxNA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "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/azure-devops-node-api": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", - "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "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/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "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": "MIT" - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC" - }, - "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "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": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "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": { - "node": "*" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cheerio": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", - "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "encoding-sniffer": "^0.2.1", - "htmlparser2": "^10.1.0", - "parse5": "^7.3.0", - "parse5-htmlparser2-tree-adapter": "^7.1.0", - "parse5-parser-stream": "^7.1.2", - "undici": "^7.19.0", - "whatwg-mimetype": "^4.0.0" - }, - "engines": { - "node": ">=20.18.1" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "license": "ISC" - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "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": { - "node": ">= 6" - } - }, - "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/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "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==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/encoding-sniffer": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", - "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "^0.6.3", - "whatwg-encoding": "^3.1.1" - }, - "funding": { - "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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": { - "node": ">=0.8.0" - } - }, - "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==", - "dev": true, - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "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/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "dev": true, - "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": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/htmlparser2": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", - "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "entities": "^7.0.1" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "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/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" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it/node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true, - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true, - "license": "ISC" - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-abi": { - "version": "3.89.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", - "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^5.1.0" - } - }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", - "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "domhandler": "^5.0.3", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-parser-stream": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", - "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", - "dev": true, - "license": "MIT", - "dependencies": { - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "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": { - "node": ">=0.10.0" - } - }, - "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/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 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==", - "dev": true, - "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": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=11.0.0" - } - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "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": "MIT" - }, - "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==", - "dev": true, - "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": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=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": { - "node": ">=14.14" - } - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "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==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/typed-rest-client": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", - "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true, - "license": "MIT" - }, - "node_modules/underscore": { - "version": "1.13.8", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", - "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", - "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true, - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/vsce": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.15.0.tgz", - "integrity": "sha512-P8E9LAZvBCQnoGoizw65JfGvyMqNGlHdlUXD1VAuxtvYAaHBKLBdKPnpy60XKVDAkQCfmMu53g+gq9FM+ydepw==", - "deprecated": "vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead.", - "dev": true, - "license": "MIT", - "dependencies": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^12.3.2", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "bin": { - "vsce": "vsce" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3" - } - } - } -} diff --git a/vscode-extension/package.json b/vscode-extension/package.json deleted file mode 100644 index ca4f0ac6..00000000 --- a/vscode-extension/package.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "name": "claude-code-agent-monitor", - "displayName": "AgentHub", - "description": "Professional integrated dashboard for monitoring Claude Code AI agent activity, token usage, and costs directly in VS Code.", - "version": "1.2.4", - "publisher": "hoangsonw", - "engines": { - "vscode": "^1.75.0" - }, - "categories": [ - "Data Science", - "Machine Learning", - "Programming Languages", - "Other" - ], - "activationEvents": [ - "onView:claude-code-monitor-view" - ], - "main": "./extension.js", - "icon": "apple-touch-icon.png", - "galleryBanner": { - "color": "#0f111a", - "theme": "dark" - }, - "repository": { - "type": "git", - "url": "https://git.smartgift.io.vn/Smartgift-AI/AgentHub" - }, - "homepage": "https://git.smartgift.io.vn/Smartgift-AI/AgentHub/src/branch/main/vscode-extension/README.md", - "contributes": { - "commands": [ - { - "command": "claude-code-agent-monitor.openDashboard", - "title": "Open Agent Dashboard", - "category": "Claude Code", - "icon": "$(dashboard)" - }, - { - "command": "claude-code-agent-monitor.refreshStatus", - "title": "Refresh Dashboard Status", - "category": "Claude Code", - "icon": "$(refresh)" - }, - { - "command": "claude-code-agent-monitor.clearHistory", - "title": "Clear Monitor History", - "category": "Claude Code", - "icon": "$(trash)" - }, - { - "command": "claude-code-agent-monitor.openInBrowser", - "title": "Open Dashboard in Browser", - "category": "Claude Code", - "icon": "$(globe)" - } - ], - "viewsContainers": { - "activitybar": [ - { - "id": "claude-code-monitor", - "title": "AgentHub", - "icon": "icon.svg" - } - ] - }, - "views": { - "claude-code-monitor": [ - { - "id": "claude-code-monitor-view", - "name": "Monitor Control Center", - "type": "webview" - } - ] - }, - "menus": { - "view/title": [ - { - "command": "claude-code-agent-monitor.openDashboard", - "when": "view == claude-code-monitor-view", - "group": "navigation@1" - }, - { - "command": "claude-code-agent-monitor.refreshStatus", - "when": "view == claude-code-monitor-view", - "group": "navigation@2" - }, - { - "command": "claude-code-agent-monitor.openInBrowser", - "when": "view == claude-code-monitor-view", - "group": "navigation@3" - } - ] - } - }, - "devDependencies": { - "@types/vscode": "^1.75.0", - "vsce": "^2.15.0" - }, - "scripts": { - "package": "vsce package", - "publish": "vsce publish" - }, - "keywords": [ - "claude", - "anthropic", - "ai", - "agent", - "monitor", - "dashboard", - "tokens", - "llm" - ], - "author": "Nguyễn Ngọc Trí Vĩ", - "license": "MIT" -} diff --git a/vscode-extension/sidebar.js b/vscode-extension/sidebar.js deleted file mode 100644 index 29e7d2c0..00000000 --- a/vscode-extension/sidebar.js +++ /dev/null @@ -1,747 +0,0 @@ -/** - * @file Sidebar provider for AgentHub VSCode extension - * Renders a rich, real-time WebviewView showing backend status, live agent - * health, usage analytics, recent sessions, and quick navigation. - * - * Replaces the previous flat TreeDataProvider with a styled WebviewView that - * pushes JSON snapshots from background polling and receives action messages - * (open dashboard, open session, refresh, browser, clear history) back from - * the webview UI. - * - * @author Nguyễn Ngọc Trí Vĩ - */ - -const vscode = require("vscode"); -const http = require("http"); - -const POLL_INTERVAL_MS = 5000; -const SPARK_HISTORY = 20; - -class DashboardWebviewProvider { - constructor(context, output) { - this.context = context; - this.output = output; - this.view = null; - this.status = "Offline"; - this.data = {}; - this.history = { - sessions: [], - agents: [], - tokens: [], - cost: [], - }; - this._pollHandle = null; - this._fetching = null; - } - - log(msg) { - if (this.output) { - try { - this.output.appendLine("[" + new Date().toISOString() + "] " + msg); - } catch (_) {} - } - } - - resolveWebviewView(view) { - this.view = view; - view.webview.options = { - enableScripts: true, - localResourceRoots: [], - }; - view.webview.html = this.getHtml(); - - view.webview.onDidReceiveMessage((msg) => this.handleMessage(msg)); - view.onDidChangeVisibility(() => { - if (this.view && this.view.visible) this.refresh(); - }); - view.onDidDispose(() => { - this.view = null; - if (this._pollHandle) clearInterval(this._pollHandle); - this._pollHandle = null; - }); - - this.refresh(); - if (!this._pollHandle) { - this._pollHandle = setInterval(() => this.refresh(), POLL_INTERVAL_MS); - } - } - - refresh() { - return this.fetchAll() - .then(() => { - try { - this.pushSnapshot(); - } catch (e) { - this.log("pushSnapshot threw: " + e.message); - } - }) - .catch((e) => this.log("refresh threw: " + e.message)); - } - - handleMessage(msg) { - if (!msg || !msg.command) return; - switch (msg.command) { - case "openDashboard": - vscode.commands.executeCommand("claude-code-agent-monitor.openDashboard", msg.target || ""); - break; - case "openInBrowser": - vscode.commands.executeCommand("claude-code-agent-monitor.openInBrowser"); - break; - case "refresh": - vscode.commands.executeCommand("claude-code-agent-monitor.refreshStatus"); - break; - case "clearHistory": - vscode.commands.executeCommand("claude-code-agent-monitor.clearHistory"); - break; - case "ready": - this.log("webview READY"); - this.refresh(); - break; - case "log": - this.log("[webview] " + msg.text); - break; - case "error": - this.log("[webview ERROR] " + msg.text); - break; - } - } - - pushSnapshot() { - if (!this.view) { - this.log("pushSnapshot skipped: view is null"); - return; - } - const d = this.data || {}; - const t = (d.analytics && d.analytics.tokens) || {}; - const totalTokens = - (t.total_input || 0) + - (t.total_output || 0) + - (t.total_cache_read || 0) + - (t.total_cache_write || 0); - - const snapshot = { - status: this.status, - port: d.port || null, - stats: { - ws: (d.stats && d.stats.ws_connections) || 0, - sessions: (d.stats && d.stats.total_sessions) || 0, - events: (d.stats && d.stats.total_events) || 0, - agents_total: - (d.stats && - d.stats.agents_by_status && - Object.values(d.stats.agents_by_status).reduce((a, b) => a + b, 0)) || - 0, - agents_by_status: (d.stats && d.stats.agents_by_status) || {}, - }, - analytics: { - tokens: { - input: t.total_input || 0, - output: t.total_output || 0, - cache_read: t.total_cache_read || 0, - cache_write: t.total_cache_write || 0, - total: totalTokens, - }, - cost: (d.analytics && d.analytics.total_cost) || 0, - subagents: (d.analytics && d.analytics.total_subagents) || 0, - }, - sessions: (Array.isArray(d.sessions) ? d.sessions : []).slice(0, 12).map((s) => ({ - id: s.id, - name: s.name || s.id.substring(0, 8), - status: s.status || "unknown", - model: s.model || "unknown", - started_at: s.started_at, - })), - history: this.history, - ts: Date.now(), - }; - - this.view.webview.postMessage({ type: "snapshot", payload: snapshot }); - } - - pushHistory(snapshot) { - const cap = (arr, v) => { - arr.push(v); - if (arr.length > SPARK_HISTORY) arr.shift(); - }; - cap(this.history.sessions, snapshot.stats.sessions); - cap(this.history.agents, snapshot.stats.agents_total); - cap(this.history.tokens, snapshot.analytics.tokens.total); - cap(this.history.cost, snapshot.analytics.cost); - } - - async fetchAll() { - if (this._fetching) return this._fetching; - this._fetching = (async () => { - const ports = [4820, 5173]; - let foundActive = false; - - for (const p of ports) { - const up = await this.ping(p); - this.log("ping " + p + " => " + up); - if (up) { - this.status = "Online"; - this.data.port = p; - foundActive = true; - try { - this.data.stats = await this.f(4820, "/api/stats"); - this.data.analytics = await this.f(4820, "/api/analytics"); - const sess = await this.f(4820, "/api/sessions?limit=12"); - this.data.sessions = Array.isArray(sess) - ? sess - : (sess && (sess.sessions || sess.rows || sess.data)) || []; - if (!Array.isArray(this.data.sessions)) this.data.sessions = []; - this.log("fetched stats+analytics+sessions ok"); - } catch (e) { - this.log("fetch error: " + (e && e.message ? e.message : e)); - } - break; - } - } - - if (!foundActive) { - this.status = "Offline"; - this.data = {}; - } - this.log("fetchAll done, status=" + this.status); - })(); - try { - await this._fetching; - } finally { - this._fetching = null; - } - - // Update sparkline history off the freshest snapshot - const t = (this.data.analytics && this.data.analytics.tokens) || {}; - const totalTokens = - (t.total_input || 0) + - (t.total_output || 0) + - (t.total_cache_read || 0) + - (t.total_cache_write || 0); - this.pushHistory({ - stats: { - sessions: (this.data.stats && this.data.stats.total_sessions) || 0, - agents_total: - (this.data.stats && - this.data.stats.agents_by_status && - Object.values(this.data.stats.agents_by_status).reduce((a, b) => a + b, 0)) || - 0, - }, - analytics: { - tokens: { total: totalTokens }, - cost: (this.data.analytics && this.data.analytics.total_cost) || 0, - }, - }); - } - - ping(p) { - return new Promise((resolve) => { - let done = false; - const finish = (v) => { - if (done) return; - done = true; - try { - req.destroy(); - } catch (_) {} - resolve(v); - }; - const req = http.get( - { hostname: "127.0.0.1", port: p, path: p === 4820 ? "/api/health" : "/", timeout: 800 }, - (res) => { - res.resume(); - finish(true); - } - ); - req.on("error", () => finish(false)); - req.on("timeout", () => finish(false)); - }); - } - - f(p, path) { - return new Promise((resolve, reject) => { - let done = false; - const finish = (fn, v) => { - if (done) return; - done = true; - try { - req.destroy(); - } catch (_) {} - fn(v); - }; - const req = http.get({ hostname: "127.0.0.1", port: p, path, timeout: 1500 }, (r) => { - let d = ""; - r.on("data", (c) => (d += c)); - r.on("end", () => { - try { - finish(resolve, JSON.parse(d)); - } catch (e) { - finish(reject, e); - } - }); - }); - req.on("error", (e) => finish(reject, e)); - req.on("timeout", () => finish(reject, new Error("timeout"))); - }); - } - - getHtml() { - const nonce = makeNonce(); - return ` - - - - - - - - -
- -
-
Claude Code Monitor
-
Connecting…
-
-
Offline
-
- -
-
-
Loading…
- Polling backend for live data. -
-
- - - -`; - } -} - -function makeNonce() { - let s = ""; - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (let i = 0; i < 32; i++) s += chars[Math.floor(Math.random() * chars.length)]; - return s; -} - -module.exports = { DashboardWebviewProvider }; diff --git a/vscode-extension/vscode.png b/vscode-extension/vscode.png deleted file mode 100644 index dd30b644..00000000 Binary files a/vscode-extension/vscode.png and /dev/null differ