From 9923635dbaa718fe39017ba870e01f35466dbde4 Mon Sep 17 00:00:00 2001 From: Son Nguyen Date: Fri, 17 Jul 2026 22:13:03 -0700 Subject: [PATCH 1/6] fix(setup): make a bare root npm install produce a buildable tree on Node 24 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three related install/setup fixes so `npm install` at the repo root "just works" on a fresh clone — the trigger was `npm run build` failing to resolve "@fontsource/inter/latin-400.css". 1. Client deps on root install. The client's fonts (@fontsource/*) and build toolchain live in client/package.json, which a plain root `npm install` never installed. Add a root `postinstall` hook (scripts/postinstall.js) that installs them. It is a guarded no-op when client/ is absent, so the multi-stage Dockerfiles (root server-deps stage, mcp `file:..` link) and the published tarball still install cleanly; it uses shell:true so npm's Windows .cmd shim resolves. Skipped under --ignore-scripts. 2. better-sqlite3 ^11 -> ^12. 11.x ships no prebuilt binary for Node 24, so on Node 24 it falls back to a source build that needs the MSVC C++ toolchain and fails; the optional dep is then skipped. 12.x has Node 24 prebuilds and installs with no compiler. Bump engines to node >=20 (better-sqlite3 12's floor; the node:sqlite fallback already needs 22+). The app still runs on the node:sqlite fallback when the native driver is absent. 3. Two Windows-only path-semantics test failures (green on macOS/Linux, so never seen there; identical behavior on POSIX after the fix): - scripts/import-history.js classifyJsonl split on path.sep ("\\" on Windows) turned a POSIX "/a/b/subagents/x.jsonl" path into one segment that never equals "subagents", misclassifying subagents as sessions. Split on both separators instead. - server/routes/hooks.js livenessReap used the platform-sensitive path.isAbsolute; the tests mock the probe to run this reaper on Windows, where "D:\..." reads as absolute and wrongly reaps a forwarded remote session. Use path.posix.isAbsolute to match the documented intent. Docs: sync the Node floor (18 -> 20) and the client-install note across README (+VN/CN/KO), INSTALL, SETUP, ARCHITECTURE, server/client READMEs, docs/*, the landing page, and the wiki (badges + cache bump). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/CONTRIBUTING.md | 2 +- ARCHITECTURE.md | 4 ++-- INSTALL.md | 15 ++++++++----- README-CN.md | 4 ++-- README-KO.md | 4 ++-- README-VN.md | 4 ++-- README.md | 4 ++-- SETUP.md | 2 +- client/README.md | 4 ++-- docs/DEPLOYMENT.md | 6 ++--- docs/README.md | 4 ++-- index.html | 2 +- package-lock.json | 17 ++++++++++----- package.json | 5 +++-- scripts/import-history.js | 7 +++++- scripts/postinstall.js | 46 +++++++++++++++++++++++++++++++++++++++ server/README.md | 4 ++-- server/routes/hooks.js | 14 +++++++----- wiki/index.html | 8 +++---- wiki/sw.js | 2 +- 20 files changed, 112 insertions(+), 46 deletions(-) create mode 100644 scripts/postinstall.js diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a1d3492c..67c20d91 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -45,7 +45,7 @@ You sign **once** — the signature covers all of your current and future contri ### Prerequisites -- Node.js 18+ (22+ recommended for automatic SQLite fallback) +- Node.js 20+ (22+ recommended for automatic SQLite fallback) - npm 9+ ### Setup diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 75318a00..9d6d74f9 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -5,7 +5,7 @@ Architectural overview and technical reference for the Agent Dashboard system, c ![Claude Code](https://img.shields.io/badge/Claude_Code-orange?style=flat-square&logo=claude&logoColor=white) ![Claude Code Plugins](https://img.shields.io/badge/Claude_Code-Plugins_&_Skills-orange?style=flat-square&logo=anthropic&logoColor=white) ![Model Context Protocol](https://img.shields.io/badge/Model_Context_Protocol-1.0-0f766e?style=flat-square&logo=modelcontextprotocol&logoColor=white) -![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white) ![Python](https://img.shields.io/badge/Python-%3E%3D3.6-3776AB?style=flat-square&logo=python&logoColor=white) ![Express](https://img.shields.io/badge/Express-4.21-000000?style=flat-square&logo=express&logoColor=white) ![ws](https://img.shields.io/badge/ws-WebSocket_server-010101?style=flat-square&logo=socketdotio&logoColor=white) @@ -122,7 +122,7 @@ C4Context - Zero-config operation -- auto-discovers sessions from hook events - Never block Claude Code -- hooks fail silently with timeouts - Instant feedback -- WebSocket push, no polling -- Portable -- SQLite, no external services, runs on any OS with Node.js 18+ +- Portable -- SQLite, no external services, runs on any OS with Node.js 20+ - Extensible -- plugin marketplace with 10 plugins (53 skills, 14 agents, 30 slash commands, 3 CLI tools) --- diff --git a/INSTALL.md b/INSTALL.md index f5edaf15..cae4aa8c 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -6,7 +6,7 @@ A step-by-step guide to get the Claude Code Agent Monitor up and running on your | Requirement | Version | Notes | |---|---|---| -| Node.js | 18+ (22+ recommended) | Required for server and client | +| Node.js | 20+ (22+ recommended) | Required for server and client | | npm | 9+ | Comes with Node.js | | Claude Code | 2.x+ | Required for hook integration | | Python | 3.6+ | Optional — statusline utility only | @@ -29,13 +29,16 @@ cd Claude-Code-Agent-Monitor npm run setup ``` -This installs all server and client dependencies in a single command. It is equivalent to: +This installs all server and client dependencies, plus the VS Code extension, and links the `ccam` CLI. + +A plain root install already covers server **and** client — a `postinstall` hook installs the client dependencies automatically, so this alone is enough to build and run the dashboard: ```bash npm install -cd client && npm install ``` +`npm run setup` additionally installs the VS Code extension and links the `ccam` CLI. (If you install with `--ignore-scripts`, the `postinstall` hook is skipped — run `cd client && npm install` manually in that case.) + Or via Makefile (also installs MCP dependencies): ```bash @@ -180,8 +183,8 @@ If you'd rather not keep a terminal window open, the project also ships an Elect |---|---| | Downloading a pre-built installer (macOS) | macOS — nothing else | | Downloading a pre-built installer (Windows) | Windows 10/11 (x64) — nothing else | -| Building the DMG locally (macOS) | macOS, Node.js 18+ (22+ recommended), npm 9+, and **Xcode command-line tools** (`xcode-select --install`) so the native `better-sqlite3` module can be rebuilt for Electron's ABI | -| Building the `.exe` locally (Windows) | Windows, Node.js 18+ (22+ recommended), npm 9+. `better-sqlite3` is fetched as a **prebuilt Electron binary** by `npm run desktop:install`, so no Visual Studio C++ toolchain is needed in the common case. If the build _does_ fail, `npm run desktop:install` prints the exact fix (Visual Studio Build Tools + "Desktop development with C++") plus a no-toolchain alternative and exits non-zero rather than failing silently | +| Building the DMG locally (macOS) | macOS, Node.js 20+ (22+ recommended), npm 9+, and **Xcode command-line tools** (`xcode-select --install`) so the native `better-sqlite3` module can be rebuilt for Electron's ABI | +| Building the `.exe` locally (Windows) | Windows, Node.js 20+ (22+ recommended), npm 9+. `better-sqlite3` is fetched as a **prebuilt Electron binary** by `npm run desktop:install`, so no Visual Studio C++ toolchain is needed in the common case. If the build _does_ fail, `npm run desktop:install` prints the exact fix (Visual Studio Build Tools + "Desktop development with C++") plus a no-toolchain alternative and exits non-zero rather than failing silently | ### Way 1 — Download a pre-built installer @@ -460,7 +463,7 @@ This is expected and **non-fatal**. `better-sqlite3` is a native C++ module list At runtime the server uses this fallback chain: -1. **`better-sqlite3`** — used when prebuilt binaries are available (Node 18/20/22 on Windows x64, macOS arm64/x64, Linux x64/arm64) +1. **`better-sqlite3`** — used when prebuilt binaries are available (Node 20/22/24 on Windows x64, macOS arm64/x64, Linux x64/arm64) 2. **`node:sqlite`** — Node.js built-in SQLite module, used automatically on Node 22+ when `better-sqlite3` is unavailable If you see an error box at startup saying *"SQLite backend not available"*, either: diff --git a/README-CN.md b/README-CN.md index 6b61d149..37b5fe09 100644 --- a/README-CN.md +++ b/README-CN.md @@ -7,7 +7,7 @@ ![Claude Code](https://img.shields.io/badge/Claude_Code-orange?style=flat-square&logo=claude&logoColor=white) ![Claude Code Plugins](https://img.shields.io/badge/Claude_Code-Plugins_&_Skills-orange?style=flat-square&logo=anthropic&logoColor=white) ![Model Context Protocol](https://img.shields.io/badge/Model_Context_Protocol-1.0-0f766e?style=flat-square&logo=modelcontextprotocol&logoColor=white) -![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white) ![Python](https://img.shields.io/badge/Python-%3E%3D3.6-3776AB?style=flat-square&logo=python&logoColor=white) ![Express](https://img.shields.io/badge/Express-4.21-000000?style=flat-square&logo=express&logoColor=white) ![ws](https://img.shields.io/badge/ws-WebSocket_server-010101?style=flat-square&logo=socketdotio&logoColor=white) @@ -321,7 +321,7 @@ Dashboard 提供全面的功能来监控和分析你的 Claude Code 会话和 Ag ### 前置条件 -- **Node.js** >= 18.0.0(推荐 22+) +- **Node.js** >= 20.0.0(推荐 22+) - **npm** >= 9.0.0 ### 1. 安装 diff --git a/README-KO.md b/README-KO.md index 97e3db53..c9dfb332 100644 --- a/README-KO.md +++ b/README-KO.md @@ -7,7 +7,7 @@ Claude Code 에이전트 세션, 도구 사용, 서브에이전트 오케스트 ![Claude Code](https://img.shields.io/badge/Claude_Code-orange?style=flat-square&logo=claude&logoColor=white) ![Claude Code Plugins](https://img.shields.io/badge/Claude_Code-Plugins_&_Skills-orange?style=flat-square&logo=anthropic&logoColor=white) ![Model Context Protocol](https://img.shields.io/badge/Model_Context_Protocol-1.0-0f766e?style=flat-square&logo=modelcontextprotocol&logoColor=white) -![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white) ![Python](https://img.shields.io/badge/Python-%3E%3D3.6-3776AB?style=flat-square&logo=python&logoColor=white) ![Express](https://img.shields.io/badge/Express-4.21-000000?style=flat-square&logo=express&logoColor=white) ![ws](https://img.shields.io/badge/ws-WebSocket_server-010101?style=flat-square&logo=socketdotio&logoColor=white) @@ -319,7 +319,7 @@ flowchart LR ### 사전 요구 사항 -- **Node.js** >= 18.0.0 (22+ 권장) +- **Node.js** >= 20.0.0 (22+ 권장) - **npm** >= 9.0.0 ### 1. 설치 diff --git a/README-VN.md b/README-VN.md index 0a6ae089..d862ddb9 100644 --- a/README-VN.md +++ b/README-VN.md @@ -7,7 +7,7 @@ Bảng điều khiển chuyên nghiệp để theo dõi và trực quan hóa cá ![Claude Code](https://img.shields.io/badge/Claude_Code-orange?style=flat-square&logo=claude&logoColor=white) ![Claude Code Plugins](https://img.shields.io/badge/Claude_Code-Plugins_&_Skills-orange?style=flat-square&logo=anthropic&logoColor=white) ![Model Context Protocol](https://img.shields.io/badge/Model_Context_Protocol-1.0-0f766e?style=flat-square&logo=modelcontextprotocol&logoColor=white) -![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white) ![Python](https://img.shields.io/badge/Python-%3E%3D3.6-3776AB?style=flat-square&logo=python&logoColor=white) ![Express](https://img.shields.io/badge/Express-4.21-000000?style=flat-square&logo=express&logoColor=white) ![ws](https://img.shields.io/badge/ws-WebSocket_server-010101?style=flat-square&logo=socketdotio&logoColor=white) @@ -319,7 +319,7 @@ Bảng điều khiển cung cấp một bộ tính năng toàn diện để giá ### Điều kiện tiên quyết -- **Node.js** >= 18.0.0 (khuyến nghị 22+) +- **Node.js** >= 20.0.0 (khuyến nghị 22+) - **npm** >= 9.0.0 ### 1. Cài đặt diff --git a/README.md b/README.md index d9f3e2d1..4bd65bbb 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A professional dashboard to track and visualize your Claude Code agent sessions, ![Claude Code](https://img.shields.io/badge/Claude_Code-orange?style=flat-square&logo=claude&logoColor=white) ![Claude Code Plugins](https://img.shields.io/badge/Claude_Code-Plugins_&_Skills-orange?style=flat-square&logo=anthropic&logoColor=white) ![Model Context Protocol](https://img.shields.io/badge/Model_Context_Protocol-1.0-0f766e?style=flat-square&logo=modelcontextprotocol&logoColor=white) -![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white) ![Python](https://img.shields.io/badge/Python-%3E%3D3.6-3776AB?style=flat-square&logo=python&logoColor=white) ![Express](https://img.shields.io/badge/Express-4.21-000000?style=flat-square&logo=express&logoColor=white) ![ws](https://img.shields.io/badge/ws-WebSocket_server-010101?style=flat-square&logo=socketdotio&logoColor=white) @@ -319,7 +319,7 @@ The dashboard offers a comprehensive set of features to monitor and analyze your ### Prerequisites -- **Node.js** >= 18.0.0 (22+ recommended) +- **Node.js** >= 20.0.0 (22+ recommended) - **npm** >= 9.0.0 ### 1. Install diff --git a/SETUP.md b/SETUP.md index 677b83f1..99ad8e62 100644 --- a/SETUP.md +++ b/SETUP.md @@ -484,7 +484,7 @@ These warnings are **harmless**. `better-sqlite3` is an optional dependency — You do **not** need Python, Visual Studio Build Tools, or any C++ compiler to run this project on Node 22+. -If you are on Node 18 or 20 and `better-sqlite3` prebuilds are not available for your platform, you have two options: +If you are on Node 20 or 21 and `better-sqlite3` prebuilds are not available for your platform (there is no `node:sqlite` fallback below Node 22), you have two options: 1. **Upgrade to Node.js 22+** — the built-in `node:sqlite` fallback requires no native compilation at all 2. **Install build tools** and run `npm rebuild better-sqlite3`: diff --git a/client/README.md b/client/README.md index cfbea6b4..045720ba 100644 --- a/client/README.md +++ b/client/README.md @@ -3,7 +3,7 @@ Enterprise-grade React + TypeScript dashboard for real-time Claude Code agent monitoring. ![Claude Code](https://img.shields.io/badge/Claude_Code-orange?style=flat-square&logo=claude&logoColor=white) -![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white) ![React](https://img.shields.io/badge/React-18.3-61DAFB?style=flat-square&logo=react&logoColor=white) ![TypeScript](https://img.shields.io/badge/TypeScript-5.7-3178C6?style=flat-square&logo=typescript&logoColor=white) ![Javascript](https://img.shields.io/badge/JavaScript-ES6-F7DF1E?style=flat-square&logo=javascript&logoColor=white) @@ -958,7 +958,7 @@ graph TB ### Prerequisites -- Node.js >= 18.0.0 +- Node.js >= 20.0.0 - npm >= 9.0.0 ### Setup diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index d7168f22..06a3b2ba 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -142,7 +142,7 @@ graph TB ### Prerequisites -- Node.js >= 18.0.0 +- Node.js >= 20.0.0 - npm >= 9.0.0 ### Setup @@ -311,7 +311,7 @@ docker compose down ```dockerfile # Build stage -FROM node:18-alpine AS builder +FROM node:22-alpine AS builder WORKDIR /app @@ -325,7 +325,7 @@ COPY client ./client RUN cd client && npm run build # Production stage -FROM node:18-alpine +FROM node:22-alpine WORKDIR /app diff --git a/docs/README.md b/docs/README.md index 15dd1f40..74b5236f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -176,7 +176,7 @@ graph TB end subgraph "Backend" - Express[Express Server
Node.js 18+] + Express[Express Server
Node.js 20+] DB[(SQLite Database)] WS[WebSocket Server] end @@ -214,7 +214,7 @@ graph TB | Layer | Technology | |-------|------------| | **Frontend** | React 18, TypeScript 5.7, Vite 6, Tailwind CSS | -| **Backend** | Node.js 18+, Express 4.21, WebSocket | +| **Backend** | Node.js 20+, Express 4.21, WebSocket | | **Database** | SQLite 3 (better-sqlite3 or node:sqlite) | | **Integration** | Claude Code Hooks, MCP Server | diff --git a/index.html b/index.html index 57677b82..eff09320 100644 --- a/index.html +++ b/index.html @@ -3775,7 +3775,7 @@

A focused stack.

⚛️
React 18
+ TypeScript 5
Vite 6
HMR + bundle
-
🚂
Express 4
Node.js 18+
+
🚂
Express 4
Node.js 20+
🗃️
SQLite
better-sqlite3 + WAL
🔌
WebSocket
RFC 6455 push
📡
MCP 1.0
stdio / HTTP / REPL
diff --git a/package-lock.json b/package-lock.json index f3e98e04..8f9c070b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "agent-dashboard", "version": "1.3.0", + "hasInstallScript": true, "license": "MIT", "dependencies": { "adm-zip": "^0.5.16", @@ -20,19 +21,22 @@ "web-push": "^3.6.7", "ws": "^8.18.0" }, + "bin": { + "ccam": "bin/ccam.js" + }, "devDependencies": { "concurrently": "^9.1.2", "js-yaml": "^4.1.0", "prettier": "^3.8.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "funding": { "url": "https://github.com/sponsors/hoangsonww" }, "optionalDependencies": { - "better-sqlite3": "^11.7.0" + "better-sqlite3": "^12.0.0" } }, "node_modules/@babel/runtime": { @@ -279,15 +283,18 @@ "optional": true }, "node_modules/better-sqlite3": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz", - "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==", + "version": "12.11.1", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.11.1.tgz", + "integrity": "sha512-dq9AtApgg5PGFtBzPFSBl3HZQjHok5gaQCM6zh2Yk0aSmDCs1CbnVI8/HgASQkNKsWFpseIO9beg5xxpYhbIfA==", "hasInstallScript": true, "license": "MIT", "optional": true, "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "20.x || 22.x || 23.x || 24.x || 25.x || 26.x" } }, "node_modules/bindings": { diff --git a/package.json b/package.json index 8f4ea86b..2d02885d 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ ], "scripts": { "prepare": "git config core.hooksPath .husky || true", + "postinstall": "node scripts/postinstall.js", "dev": "node scripts/dev.js", "dev:raw": "concurrently -n server,client -c blue,green \"npm run dev:server\" \"npm run dev:client\"", "dev:server": "node --watch server/index.js", @@ -108,7 +109,7 @@ "ws": "^8.18.0" }, "optionalDependencies": { - "better-sqlite3": "^11.7.0" + "better-sqlite3": "^12.0.0" }, "devDependencies": { "concurrently": "^9.1.2", @@ -116,6 +117,6 @@ "prettier": "^3.8.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } } diff --git a/scripts/import-history.js b/scripts/import-history.js index e3a9581b..fc1a4290 100644 --- a/scripts/import-history.js +++ b/scripts/import-history.js @@ -2280,7 +2280,12 @@ function classifyJsonl(filePath) { // ancestor chain (rather than just parent/grandparent) stops workflow // inner-agent files from being misimported as bogus top-level sessions when a // user points the directory importer at a tree that contains workflow runs. - const segments = path.dirname(filePath).split(path.sep); + // Split on BOTH separators rather than the platform-specific path.sep: + // transcript paths can arrive in POSIX form even on Windows (forwarded + // household hooks, imported trees, the unit tests), and splitting a + // "/a/b/subagents/x.jsonl" path on "\\" would yield one giant segment that + // never equals "subagents", misclassifying every subagent as a session. + const segments = path.dirname(filePath).split(/[\\/]/); if (segments.includes("subagents")) return "subagent"; return "session"; } diff --git a/scripts/postinstall.js b/scripts/postinstall.js new file mode 100644 index 00000000..1b1525d9 --- /dev/null +++ b/scripts/postinstall.js @@ -0,0 +1,46 @@ +#!/usr/bin/env node +/** + * @file postinstall.js + * @description Root `postinstall` hook: after a bare `npm install` at the repo + * root, install the React client's dependencies too, so a single root install + * yields a buildable/runnable tree (the client's fonts and build deps live in + * `client/package.json`). The step is a safe no-op when the `client/` workspace + * is absent — production/Docker stages that copy only the root manifest, the + * MCP image's `file:..` link, and the published tarball all install without a + * client checkout, and must not fail here. Skipped entirely under + * `npm install --ignore-scripts` (run `cd client && npm install` manually then). + * @author Son Nguyen + */ + +const { spawnSync } = require("child_process"); +const fs = require("fs"); +const path = require("path"); + +const clientDir = path.join(__dirname, "..", "client"); +const clientManifest = path.join(clientDir, "package.json"); + +// No client checkout in this context (Docker server/MCP stages, packed tarball, +// server-only installs). Nothing to do — succeed quietly so the parent install +// is not broken. +if (!fs.existsSync(clientManifest)) { + console.log("[postinstall] client/ not present — skipping client dependency install."); + process.exit(0); +} + +console.log("[postinstall] installing client dependencies (client/)..."); + +// `shell: true` is required on Windows so npm's `.cmd` shim resolves (Node +// rejects spawning `.cmd`/`.bat` directly since 18.20 / CVE-2024-27980); the +// fixed arg list has no shell-significant characters, so this stays safe. +const result = spawnSync("npm", ["install"], { + cwd: clientDir, + stdio: "inherit", + shell: true, +}); + +if (result.error) { + console.error("[postinstall] failed to launch npm for the client install:", result.error.message); + process.exit(1); +} + +process.exit(result.status === null ? 1 : result.status); diff --git a/server/README.md b/server/README.md index ab853666..03065b8d 100644 --- a/server/README.md +++ b/server/README.md @@ -3,7 +3,7 @@ Enterprise-grade Node.js backend for Claude Code agent monitoring with real-time WebSocket updates. ![Claude Code](https://img.shields.io/badge/Claude_Code-orange?style=flat-square&logo=claude&logoColor=white) -![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white) ![Express](https://img.shields.io/badge/Express-4.21-000000?style=flat-square&logo=express&logoColor=white) ![Javascript](https://img.shields.io/badge/JavaScript-ES6-F7DF1E?style=flat-square&logo=javascript&logoColor=white) ![SQLite](https://img.shields.io/badge/SQLite-3-003B57?style=flat-square&logo=sqlite&logoColor=white) @@ -1340,7 +1340,7 @@ sudo systemctl start agent-dashboard ```dockerfile # Dockerfile (root of project) -FROM node:18-alpine +FROM node:22-alpine WORKDIR /app diff --git a/server/routes/hooks.js b/server/routes/hooks.js index b07b0f90..6093ffd6 100644 --- a/server/routes/hooks.js +++ b/server/routes/hooks.js @@ -1358,11 +1358,15 @@ function livenessReap({ ignoreIdleGate = false } = {}) { // deployment (this host has BOTH local sessions the probe should keep // reaping, AND remote household-hook sessions it must leave alone) // without sacrificing local crash detection via DASHBOARD_LIVENESS_PROBE=0. - // path.isAbsolute() resolves with POSIX semantics here (this function - // never reaches this point on win32 — probe.available is only true once - // probeLiveCwds() has already ruled that out), so it's equivalent to a - // leading-"/" check but self-documenting rather than a raw string test. - if (!path.isAbsolute(sess.cwd)) continue; + // The probe only ever reports POSIX cwds (/proc + lsof, and it bails out + // entirely on win32), so "could this cwd be local?" is precisely "is it + // POSIX-absolute?" — a leading-"/" check. Use path.posix.isAbsolute() + // explicitly rather than the platform-sensitive path.isAbsolute(): in + // production this only runs on POSIX hosts so the two are identical, but + // the unit tests mock probeLiveCwds() to exercise this reaper on a Windows + // host too, where bare path.isAbsolute("D:\\Git\\ai-deck") would be true + // and wrongly reap a forwarded remote session. posix keeps it host-agnostic. + if (!path.posix.isAbsolute(sess.cwd)) continue; let resolvedCwd; try { diff --git a/wiki/index.html b/wiki/index.html index 2bcdb645..cec16323 100644 --- a/wiki/index.html +++ b/wiki/index.html @@ -673,7 +673,7 @@

Claude Code Agent Monitor

- Node.js ≥ 18 + Node.js ≥ 20 Express 4.21 React 18.3 TypeScript 5.7 @@ -687,7 +687,7 @@

Claude Code Agent Monitor

Swagger 3.0 i18next 22.4 Mermaid 10.2 - better-sqlite3 11.7 + better-sqlite3 12 React Router 6.28 Lucide Icons D3.js 7 @@ -739,7 +739,7 @@

Claude Code Agent Monitor

MIT License