@kylindc/ccxray 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ### Fixed
6
+
7
+ - **Orphan hub detection**: When `hub.json` lockfile is missing but a hub is still running, clients now probe the default port and reconnect automatically instead of failing with EADDRINUSE
8
+ - **Browser auto-open**: First client connecting to a hub now opens the dashboard, regardless of whether the client forked the hub or discovered an existing one
9
+ - **ECONNRESET handling**: Upstream socket destruction mid-response no longer leaves the client hanging; added `proxyRes` error handler for both SSE and non-SSE paths
10
+ - **OOM on long-running hub**: In-memory entries capped at 5000 (configurable via `CCXRAY_MAX_ENTRIES`), oldest evicted first; disk logs unaffected
11
+
12
+ ### Added
13
+
14
+ - `CCXRAY_MAX_ENTRIES` environment variable to configure in-memory entry limit (default: 5000)
15
+ - Hub status endpoint includes `app: 'ccxray'` marker for identity verification
16
+ - 57 new tests (98 → 155) covering proxy E2E, SSE streaming, intercept lifecycle, error paths, concurrency, and hub crash recovery
17
+
18
+ ## 1.1.0
19
+
20
+ ### Added
21
+
22
+ - **Multi-project hub**: Multiple `ccxray claude` instances automatically share a single proxy server and dashboard. No configuration needed — the first instance starts a hub, subsequent ones connect to it.
23
+ - **`ccxray status`**: New subcommand showing hub info and connected clients.
24
+ - **Hub crash auto-recovery**: If the hub process dies, connected clients detect and restart it within ~5 seconds.
25
+ - **Version compatibility check**: Clients with different major versions are rejected with a clear error message.
26
+
27
+ ### Changed
28
+
29
+ - **Logs location**: Moved from `./logs/` (package-relative) to `~/.ccxray/logs/` (user home). Existing logs are automatically migrated on first run.
30
+ - **`--port` behavior**: Explicitly specifying `--port` now opts out of hub mode, running an independent server instead.
31
+
32
+ ### Migration from 1.0.0
33
+
34
+ - Logs are automatically migrated from the old `logs/` directory to `~/.ccxray/logs/` on first startup. No manual action needed.
35
+ - If you use `AUTH_TOKEN`, hub discovery endpoints (`/_api/health`, `/_api/hub/*`) bypass authentication since they are local IPC.
36
+
37
+ ## 1.0.0
38
+
39
+ Initial release.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Justin Lee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.ja.md ADDED
@@ -0,0 +1,144 @@
1
+ # ccxray
2
+
3
+ [English](README.md) | [正體中文](README.zh-TW.md) | **日本語**
4
+
5
+ AIエージェントセッションのX線ビュー。ゼロ設定のHTTPプロキシで、Claude CodeとAnthropic API間のすべてのAPI呼び出しを記録し、エージェント内部で実際に何が起きているかを確認できるリアルタイムダッシュボードを提供します。
6
+
7
+ ![License](https://img.shields.io/badge/license-MIT-blue)
8
+
9
+ ![ccxrayダッシュボード](https://raw.githubusercontent.com/lis186/ccxray/main/docs/dashboard.png)
10
+
11
+ ## なぜ必要か
12
+
13
+ Claude Codeはブラックボックスです。以下が見えません:
14
+ - どんなシステムプロンプトを送信しているか(バージョン間の変更も含む)
15
+ - 各ツール呼び出しのコスト
16
+ - なぜ30秒も思考しているのか
17
+ - 200Kトークンのコンテキストウィンドウを何が消費しているのか
18
+
19
+ ccxrayはそれをガラス箱に変えます。
20
+
21
+ ## クイックスタート
22
+
23
+ ```bash
24
+ npx @kylindc/ccxray claude
25
+ ```
26
+
27
+ これだけです。プロキシが起動し、Claude Codeがプロキシ経由で接続し、ダッシュボードが自動的にブラウザで開きます。複数のターミナルで実行すると、自動的に一つのダッシュボードを共有します。
28
+
29
+ ### その他の実行方法
30
+
31
+ ```bash
32
+ ccxray # プロキシ + ダッシュボードのみ
33
+ ccxray claude --continue # すべてのclaude引数がそのまま渡される
34
+ ccxray --port 8080 claude # カスタムポート(独立モード、hub共有なし)
35
+ ccxray claude --no-browser # ブラウザの自動オープンをスキップ
36
+ ccxray status # hubの情報と接続中のクライアントを表示
37
+ ANTHROPIC_BASE_URL=http://localhost:5577 claude # 手動設定(既存セッション)
38
+ ```
39
+
40
+ ### マルチプロジェクト
41
+
42
+ 複数のターミナルで `ccxray claude` を実行すると、自動的に単一のプロキシとダッシュボードを共有します。設定は不要です。
43
+
44
+ ```bash
45
+ # Terminal 1
46
+ cd ~/project-a && ccxray claude # hubを起動 + claude
47
+
48
+ # Terminal 2
49
+ cd ~/project-b && ccxray claude # 既存のhubに接続
50
+
51
+ # 両プロジェクトが http://localhost:5577 のダッシュボードに表示
52
+ ```
53
+
54
+ Hubプロセスがクラッシュした場合、接続中のクライアントは数秒以内に自動的に復旧します。
55
+
56
+ ```bash
57
+ $ ccxray status
58
+ Hub: http://localhost:5577 (pid 12345, uptime 3600s, v1.1.0)
59
+ Connected clients (2):
60
+ [1] pid 23456 — ~/dev/project-a
61
+ [2] pid 34567 — ~/dev/project-b
62
+ ```
63
+
64
+ `--port` を使用すると独立モードで実行できます。
65
+
66
+ ## 機能
67
+
68
+ ### タイムライン
69
+
70
+ エージェントの思考をリアルタイムで観察。各ターンを思考ブロック(所要時間付き)、ツール呼び出しのインラインプレビュー、アシスタント応答に分解します。
71
+
72
+ ![タイムラインビュー](https://raw.githubusercontent.com/lis186/ccxray/main/docs/timeline.png)
73
+
74
+ ### 使用量とコスト
75
+
76
+ 実際の支出を把握。セッションヒートマップ、消費レート、ROI計算 — トークンの行き先を正確に把握できます。
77
+
78
+ ![使用量分析](https://raw.githubusercontent.com/lis186/ccxray/main/docs/usage.png)
79
+
80
+ ### システムプロンプト追跡
81
+
82
+ バージョンの自動検出とdiffビューア。Claude Codeのアップデートで何が変わったかを正確に把握 — プロンプトの変更を見逃しません。
83
+
84
+ ![システムプロンプト追跡](https://raw.githubusercontent.com/lis186/ccxray/main/docs/system-prompt.png)
85
+
86
+ ### その他
87
+
88
+ - **セッション検出** — Claude Codeセッションごとに自動グループ化。プロジェクト/作業ディレクトリの抽出付き
89
+ - **トークン会計** — ターンごとの内訳:input/output/cache-read/cache-createトークン、USD単位のコスト、コンテキストウィンドウ使用率バー
90
+
91
+ ## 仕組み
92
+
93
+ ```
94
+ Claude Code ──► ccxray (:5577) ──► api.anthropic.com
95
+
96
+
97
+ ~/.ccxray/logs/ (JSON)
98
+
99
+
100
+ ダッシュボード(同じポート)
101
+ ```
102
+
103
+ ccxrayは透過型HTTPプロキシです。リクエストをそのままAnthropicに転送し、リクエストとレスポンスの両方をJSONファイルとして記録し、同じポートでWebダッシュボードを提供します。APIキーは不要です — Claude Codeが送信する内容をそのまま通過させます。
104
+
105
+ ## 設定
106
+
107
+ ### CLIフラグ
108
+
109
+ | フラグ | 説明 |
110
+ |---|---|
111
+ | `--port <number>` | プロキシ + ダッシュボードのポート(デフォルト: 5577)。hub共有を無効化 |
112
+ | `--no-browser` | ダッシュボードをブラウザで自動オープンしない |
113
+
114
+ ### 環境変数
115
+
116
+ | 変数 | デフォルト | 説明 |
117
+ |---|---|---|
118
+ | `PROXY_PORT` | `5577` | プロキシ + ダッシュボードのポート(`--port`で上書き) |
119
+ | `BROWSER` | — | `none`に設定すると自動オープンを無効化 |
120
+ | `AUTH_TOKEN` | _(なし)_ | アクセス制御用APIキー(未設定時は無効) |
121
+ | `CCXRAY_HOME` | `~/.ccxray` | hubロックファイル、ログ、hub.logの基本ディレクトリ |
122
+
123
+ ログは`~/.ccxray/logs/`に`{timestamp}_req.json`と`{timestamp}_res.json`として保存されます。v1.0からアップグレードする場合、`./logs/`のログは初回起動時に自動的に移行されます。
124
+
125
+ ## Docker
126
+
127
+ ```bash
128
+ docker build -t ccxray .
129
+ docker run -p 5577:5577 ccxray
130
+ ```
131
+
132
+ ## 要件
133
+
134
+ - Node.js 18+
135
+
136
+ ## 作者の他のプロジェクト
137
+
138
+ - [SourceAtlas](https://sourceatlas.io/) — あらゆるコードベースへのマップ
139
+ - [AskRoundtable](https://github.com/AskRoundtable/expert-skills) — AIをMunger、Feynman、Paul Grahamのように思考させる
140
+ - Xで [@lis186](https://x.com/lis186) をフォローして最新情報をチェック
141
+
142
+ ## ライセンス
143
+
144
+ MIT
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # ccxray
2
+
3
+ **English** | [正體中文](README.zh-TW.md) | [日本語](README.ja.md)
4
+
5
+ X-ray vision for AI agent sessions. A zero-config HTTP proxy that records every API call between Claude Code and Anthropic, with a real-time dashboard to inspect what's actually happening inside your agent.
6
+
7
+ ![License](https://img.shields.io/badge/license-MIT-blue)
8
+
9
+ ![ccxray dashboard](https://raw.githubusercontent.com/lis186/ccxray/main/docs/dashboard.png)
10
+
11
+ ## Why
12
+
13
+ Claude Code is a black box. You can't see:
14
+ - What system prompts it sends (and how they change between versions)
15
+ - How much each tool call costs
16
+ - Why it's thinking for 30 seconds
17
+ - What context is eating your 200K token window
18
+
19
+ ccxray makes it a glass box.
20
+
21
+ ## Quick Start
22
+
23
+ ```bash
24
+ npx @kylindc/ccxray claude
25
+ ```
26
+
27
+ That's it. Proxy starts, Claude Code launches through it, and the dashboard opens automatically in your browser. Run it in multiple terminals — they automatically share one dashboard.
28
+
29
+ ### Other ways to run
30
+
31
+ ```bash
32
+ ccxray # Proxy + dashboard only
33
+ ccxray claude --continue # All claude args pass through
34
+ ccxray --port 8080 claude # Custom port (independent, no hub sharing)
35
+ ccxray claude --no-browser # Skip auto-open browser
36
+ ccxray status # Show hub info and connected clients
37
+ ANTHROPIC_BASE_URL=http://localhost:5577 claude # Manual setup (existing sessions)
38
+ ```
39
+
40
+ ### Multi-project
41
+
42
+ Running `ccxray claude` in multiple terminals automatically shares a single proxy and dashboard — no configuration needed.
43
+
44
+ ```bash
45
+ # Terminal 1
46
+ cd ~/project-a && ccxray claude # Starts hub + claude
47
+
48
+ # Terminal 2
49
+ cd ~/project-b && ccxray claude # Connects to existing hub
50
+
51
+ # Both projects visible in one dashboard at http://localhost:5577
52
+ ```
53
+
54
+ If the hub process crashes, connected clients automatically recover within seconds.
55
+
56
+ ```bash
57
+ $ ccxray status
58
+ Hub: http://localhost:5577 (pid 12345, uptime 3600s, v1.1.0)
59
+ Connected clients (2):
60
+ [1] pid 23456 — ~/dev/project-a
61
+ [2] pid 34567 — ~/dev/project-b
62
+ ```
63
+
64
+ Use `--port` to opt out and run an independent server instead.
65
+
66
+ ## Features
67
+
68
+ ### Timeline
69
+
70
+ Watch your agent think in real-time. Every turn broken down into thinking blocks (with duration), tool calls with inline previews, and assistant responses.
71
+
72
+ ![Timeline view](https://raw.githubusercontent.com/lis186/ccxray/main/docs/timeline.png)
73
+
74
+ ### Usage & Cost
75
+
76
+ Track your real spending. Session heatmap, burn rate, ROI calculator — know exactly where your tokens go.
77
+
78
+ ![Usage analytics](https://raw.githubusercontent.com/lis186/ccxray/main/docs/usage.png)
79
+
80
+ ### System Prompt Tracking
81
+
82
+ Automatic version detection with diff viewer. See exactly what changed between Claude Code updates — never miss a prompt change again.
83
+
84
+ ![System prompt tracking](https://raw.githubusercontent.com/lis186/ccxray/main/docs/system-prompt.png)
85
+
86
+ ### More
87
+
88
+ - **Session Detection** — Automatically groups turns by Claude Code session, with project/cwd extraction
89
+ - **Token Accounting** — Per-turn breakdown: input/output/cache-read/cache-create tokens, cost in USD, context window usage bar
90
+
91
+ ## How It Works
92
+
93
+ ```
94
+ Claude Code ──► ccxray (:5577) ──► api.anthropic.com
95
+
96
+
97
+ ~/.ccxray/logs/ (JSON)
98
+
99
+
100
+ Dashboard (same port)
101
+ ```
102
+
103
+ ccxray is a transparent HTTP proxy. It forwards requests to Anthropic unchanged, records both request and response as JSON files, and serves a web dashboard on the same port. No API key needed — it passes through whatever Claude Code sends.
104
+
105
+ ## Configuration
106
+
107
+ ### CLI flags
108
+
109
+ | Flag | Description |
110
+ |---|---|
111
+ | `--port <number>` | Port for proxy + dashboard (default: 5577). Opts out of hub sharing. |
112
+ | `--no-browser` | Don't auto-open the dashboard in your browser |
113
+
114
+ ### Environment variables
115
+
116
+ | Variable | Default | Description |
117
+ |---|---|---|
118
+ | `PROXY_PORT` | `5577` | Port for proxy + dashboard (overridden by `--port`) |
119
+ | `BROWSER` | — | Set to `none` to disable auto-open |
120
+ | `AUTH_TOKEN` | _(none)_ | API key for access control (disabled when unset) |
121
+ | `CCXRAY_HOME` | `~/.ccxray` | Base directory for hub lockfile, logs, and hub.log |
122
+ | `CCXRAY_MAX_ENTRIES` | `5000` | Max in-memory entries (oldest evicted; disk logs unaffected) |
123
+
124
+ Logs are stored in `~/.ccxray/logs/` as `{timestamp}_req.json` and `{timestamp}_res.json`. Upgrading from v1.0? Logs previously in `./logs/` are automatically migrated on first run.
125
+
126
+ ## Docker
127
+
128
+ ```bash
129
+ docker build -t ccxray .
130
+ docker run -p 5577:5577 ccxray
131
+ ```
132
+
133
+ ## Requirements
134
+
135
+ - Node.js 18+
136
+
137
+ ## Also by the author
138
+
139
+ - [SourceAtlas](https://sourceatlas.io/) — Your map to any codebase
140
+ - [AskRoundtable](https://github.com/AskRoundtable/expert-skills) — Make your AI think like Munger, Feynman, or Paul Graham
141
+ - Follow [@lis186](https://x.com/lis186) on X for updates
142
+
143
+ ## License
144
+
145
+ MIT
@@ -0,0 +1,144 @@
1
+ # ccxray
2
+
3
+ [English](README.md) | **正體中文** | [日本語](README.ja.md)
4
+
5
+ AI 代理工作階段的透視鏡。零設定的 HTTP 代理,記錄 Claude Code 與 Anthropic API 之間的每一次呼叫,搭配即時儀表板,讓你看清代理內部到底在做什麼。
6
+
7
+ ![License](https://img.shields.io/badge/license-MIT-blue)
8
+
9
+ ![ccxray 儀表板](https://raw.githubusercontent.com/lis186/ccxray/main/docs/dashboard.png)
10
+
11
+ ## 為什麼需要
12
+
13
+ Claude Code 是個黑盒子。你看不到:
14
+ - 它送出了什麼 system prompt(以及版本間的變化)
15
+ - 每次 tool call 花了多少錢
16
+ - 為什麼它思考了 30 秒
17
+ - 什麼東西吃掉了你的 200K token 上下文窗口
18
+
19
+ ccxray 讓它變成透明的。
20
+
21
+ ## 快速開始
22
+
23
+ ```bash
24
+ npx @kylindc/ccxray claude
25
+ ```
26
+
27
+ 就這樣。代理啟動、Claude Code 透過代理連線、儀表板自動在瀏覽器中開啟。在多個終端機執行時會自動共用同一個 dashboard。
28
+
29
+ ### 其他執行方式
30
+
31
+ ```bash
32
+ ccxray # 只啟動代理 + 儀表板
33
+ ccxray claude --continue # 所有 claude 參數直接穿透
34
+ ccxray --port 8080 claude # 自訂 port(獨立模式,不共用 hub)
35
+ ccxray claude --no-browser # 不自動開啟瀏覽器
36
+ ccxray status # 顯示 hub 資訊及已連線的 client
37
+ ANTHROPIC_BASE_URL=http://localhost:5577 claude # 手動設定(現有工作階段)
38
+ ```
39
+
40
+ ### 多專案
41
+
42
+ 在多個終端機執行 `ccxray claude` 會自動共用同一個 proxy 和 dashboard — 無需任何設定。
43
+
44
+ ```bash
45
+ # Terminal 1
46
+ cd ~/project-a && ccxray claude # 啟動 hub + claude
47
+
48
+ # Terminal 2
49
+ cd ~/project-b && ccxray claude # 連線至現有 hub
50
+
51
+ # 兩個專案都顯示在 http://localhost:5577 的 dashboard
52
+ ```
53
+
54
+ 如果 hub 意外終止,已連線的 client 會在數秒內自動恢復。
55
+
56
+ ```bash
57
+ $ ccxray status
58
+ Hub: http://localhost:5577 (pid 12345, uptime 3600s, v1.1.0)
59
+ Connected clients (2):
60
+ [1] pid 23456 — ~/dev/project-a
61
+ [2] pid 34567 — ~/dev/project-b
62
+ ```
63
+
64
+ 使用 `--port` 可改為獨立模式。
65
+
66
+ ## 功能
67
+
68
+ ### 時間軸
69
+
70
+ 即時觀看代理的思考過程。每個回合拆解為思考區塊(含時長)、tool call 內聯預覽、助手回應。
71
+
72
+ ![時間軸檢視](https://raw.githubusercontent.com/lis186/ccxray/main/docs/timeline.png)
73
+
74
+ ### 用量與成本
75
+
76
+ 追蹤你的實際花費。工作階段熱力圖、消耗速率、ROI 計算 — 精確掌握 token 流向。
77
+
78
+ ![用量分析](https://raw.githubusercontent.com/lis186/ccxray/main/docs/usage.png)
79
+
80
+ ### System Prompt 追蹤
81
+
82
+ 自動偵測版本變更,內建 diff 檢視器。精確掌握 Claude Code 更新時改了什麼 — 不再遺漏任何 prompt 變動。
83
+
84
+ ![System Prompt 追蹤](https://raw.githubusercontent.com/lis186/ccxray/main/docs/system-prompt.png)
85
+
86
+ ### 其他功能
87
+
88
+ - **工作階段偵測** — 自動依 Claude Code session 分組,含專案/工作目錄擷取
89
+ - **Token 記帳** — 每回合明細:input/output/cache-read/cache-create tokens、美元成本、上下文窗口使用率
90
+
91
+ ## 運作原理
92
+
93
+ ```
94
+ Claude Code ──► ccxray (:5577) ──► api.anthropic.com
95
+
96
+
97
+ ~/.ccxray/logs/ (JSON)
98
+
99
+
100
+ 儀表板(同一連接埠)
101
+ ```
102
+
103
+ ccxray 是透明的 HTTP 代理。它將請求原封不動地轉發到 Anthropic,將請求與回應記錄為 JSON 檔案,並在同一連接埠提供網頁儀表板。不需要 API 金鑰 — 它直接傳遞 Claude Code 送出的內容。
104
+
105
+ ## 設定
106
+
107
+ ### CLI 參數
108
+
109
+ | 參數 | 說明 |
110
+ |---|---|
111
+ | `--port <number>` | 代理 + 儀表板的連接埠(預設:5577)。使用後不共用 hub。 |
112
+ | `--no-browser` | 不自動在瀏覽器中開啟儀表板 |
113
+
114
+ ### 環境變數
115
+
116
+ | 變數 | 預設值 | 說明 |
117
+ |---|---|---|
118
+ | `PROXY_PORT` | `5577` | 代理 + 儀表板的連接埠(`--port` 會覆蓋此值) |
119
+ | `BROWSER` | — | 設為 `none` 可停用自動開啟 |
120
+ | `AUTH_TOKEN` | _(無)_ | 存取控制用 API 金鑰(未設定時停用) |
121
+ | `CCXRAY_HOME` | `~/.ccxray` | 基底目錄,存放 hub lockfile、logs、hub.log |
122
+
123
+ 日誌儲存在 `~/.ccxray/logs/`,格式為 `{timestamp}_req.json` 和 `{timestamp}_res.json`。從 v1.0 升級?`./logs/` 中的日誌會在首次啟動時自動遷移。
124
+
125
+ ## Docker
126
+
127
+ ```bash
128
+ docker build -t ccxray .
129
+ docker run -p 5577:5577 ccxray
130
+ ```
131
+
132
+ ## 系統需求
133
+
134
+ - Node.js 18+
135
+
136
+ ## 作者的其他作品
137
+
138
+ - [SourceAtlas](https://sourceatlas.io/) — 任何 codebase 的導航地圖
139
+ - [AskRoundtable](https://github.com/AskRoundtable/expert-skills) — 讓你的 AI 像 Munger、Feynman、Paul Graham 一樣思考
140
+ - 在 X 上追蹤 [@lis186](https://x.com/lis186) 獲取最新動態
141
+
142
+ ## 授權
143
+
144
+ MIT
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@kylindc/ccxray",
3
+ "version": "1.2.0",
4
+ "description": "X-ray vision for AI agent sessions — a transparent HTTP proxy and dashboard for Claude Code",
5
+ "main": "server/index.js",
6
+ "bin": {
7
+ "ccxray": "server/index.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node server/index.js",
11
+ "dev": "node --watch-path=server --watch-path=public server/index.js",
12
+ "test": "node --test test/*.test.js"
13
+ },
14
+ "keywords": [
15
+ "claude",
16
+ "claude-code",
17
+ "proxy",
18
+ "dashboard",
19
+ "anthropic",
20
+ "ai-agent",
21
+ "debugging",
22
+ "observability"
23
+ ],
24
+ "author": "KylinDC",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/KylinDC/ccxray.git"
29
+ },
30
+ "homepage": "https://github.com/KylinDC/ccxray",
31
+ "bugs": {
32
+ "url": "https://github.com/KylinDC/ccxray/issues"
33
+ },
34
+ "type": "commonjs",
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "dependencies": {
39
+ "@anthropic-ai/tokenizer": "^0.0.4",
40
+ "ws": "^8.19.0"
41
+ },
42
+ "devDependencies": {
43
+ "@fission-ai/openspec": "^1.2.0",
44
+ "puppeteer": "^24.39.1"
45
+ }
46
+ }
package/public/app.js ADDED
@@ -0,0 +1,99 @@
1
+ // ── Global Config ────────────────────────────────────────────────────
2
+ const DEFAULT_MAX_CTX = window.__PROXY_CONFIG__?.DEFAULT_CONTEXT || 200000;
3
+
4
+ // ── Active Tab State ─────────────────────────────────────────────────
5
+ let activeTab = 'dashboard';
6
+
7
+ function switchTab(tab, forceDiff) {
8
+ if (activeTab === tab) return;
9
+ activeTab = tab;
10
+
11
+ // Update tab buttons
12
+ document.querySelectorAll('.topbar-tab').forEach(btn => {
13
+ btn.classList.toggle('active', btn.dataset.tab === tab);
14
+ });
15
+
16
+ // Show/hide content areas
17
+ document.getElementById('columns').style.display = tab === 'dashboard' ? '' : 'none';
18
+ const costPage = document.getElementById('cost-page');
19
+ const diffOverlay = document.getElementById('diff-overlay');
20
+ if (tab === 'usage') {
21
+ costPage.classList.add('open');
22
+ diffOverlay.classList.remove('open');
23
+ loadCostPage();
24
+ } else {
25
+ costPage.classList.remove('open');
26
+ }
27
+ if (tab === 'sysprompt') {
28
+ diffOverlay.classList.add('open');
29
+ costPage.classList.remove('open');
30
+ openSystemPromptPanel(forceDiff);
31
+ } else if (tab !== 'sysprompt') {
32
+ diffOverlay.classList.remove('open');
33
+ }
34
+
35
+ // Update Row 2 contextual content
36
+ document.getElementById('row2-dashboard').style.display = tab === 'dashboard' ? '' : 'none';
37
+ document.getElementById('row2-usage').style.display = tab === 'usage' ? '' : 'none';
38
+ document.getElementById('row2-sysprompt').style.display = tab === 'sysprompt' ? '' : 'none';
39
+
40
+ // Sync URL
41
+ syncViewParam();
42
+ }
43
+
44
+ function syncViewParam() {
45
+ // Use syncUrlFromState if available (miller-columns.js loaded), otherwise fallback
46
+ if (typeof syncUrlFromState === 'function') {
47
+ syncUrlFromState();
48
+ } else {
49
+ const params = new URLSearchParams(window.location.search);
50
+ if (activeTab === 'dashboard') params.delete('view');
51
+ else params.set('view', activeTab);
52
+ const qs = params.toString();
53
+ history.replaceState(null, '', window.location.pathname + (qs ? '?' + qs : ''));
54
+ }
55
+ }
56
+
57
+ // Capture view param early before deep-link resolution rewrites URL
58
+ const _savedViewParam = new URLSearchParams(window.location.search).get('view');
59
+
60
+ function restoreTabFromUrl() {
61
+ const view = _savedViewParam;
62
+ if (view === 'usage' || view === 'sysprompt') {
63
+ switchTab(view);
64
+ }
65
+ }
66
+
67
+ // ── Theme Toggle ─────────────────────────────────────────────────────
68
+ function toggleTheme() {
69
+ const isLight = document.documentElement.getAttribute('data-theme') === 'light';
70
+ const next = isLight ? 'dark' : 'light';
71
+ document.documentElement.setAttribute('data-theme', next);
72
+ localStorage.setItem('theme', next);
73
+ updateThemeIcon();
74
+ }
75
+ function updateThemeIcon() {
76
+ const btn = document.getElementById('theme-toggle');
77
+ if (!btn) return;
78
+ btn.textContent = document.documentElement.getAttribute('data-theme') === 'light' ? '🌙' : '☀️';
79
+ }
80
+ updateThemeIcon();
81
+
82
+ // ── Unified Escape + tab switching handler ──────────────────────────
83
+ document.addEventListener('keydown', (e) => {
84
+ if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) return;
85
+ // Don't intercept when miller-columns focused mode is active
86
+ if (typeof isFocusedMode !== 'undefined' && isFocusedMode) return;
87
+
88
+ // Escape → switch to dashboard
89
+ if (e.key === 'Escape' && activeTab !== 'dashboard') {
90
+ switchTab('dashboard');
91
+ e.preventDefault();
92
+ return;
93
+ }
94
+
95
+ // Tab switching: 1/2/3
96
+ if (e.key === '1') { switchTab('dashboard'); e.preventDefault(); return; }
97
+ if (e.key === '2') { switchTab('usage'); e.preventDefault(); return; }
98
+ if (e.key === '3') { switchTab('sysprompt'); e.preventDefault(); return; }
99
+ });