cc-viewer 0.1.3 → 0.1.6

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # CC Viewer
1
+ # CC-Viewer
2
2
 
3
3
  Claude Code API 请求监控系统,实时捕获并可视化展示 Claude Code 的所有 API 请求与响应。
4
4
 
@@ -11,7 +11,7 @@ npm install -g cc-viewer
11
11
  安装完成后运行:
12
12
 
13
13
  ```bash
14
- ccviewer
14
+ ccv
15
15
  ```
16
16
 
17
17
  该命令会自动将监控脚本注入到本地安装的 Claude Code 中。之后正常使用 Claude Code,打开浏览器访问 `http://localhost:7008` 即可查看监控界面。
@@ -31,35 +31,54 @@ ccviewer
31
31
 
32
32
  ### 对话模式
33
33
 
34
- 点击右上角「打开对话模式」按钮,将最新 Main Agent 请求的 messages 解析为聊天界面:
34
+ 点击右上角「对话模式」按钮,将 Main Agent 的完整对话历史解析为聊天界面:
35
35
 
36
- - 用户消息右对齐(蓝色气泡)
36
+ - 用户消息左对齐(蓝色气泡)
37
37
  - Main Agent 回复左对齐(深灰气泡),支持 Markdown 渲染
38
- - Sub Agent 工具返回左对齐(灰色边框气泡),关联显示工具名称
38
+ - 工具调用结果内联显示在对应的 Assistant 消息内部
39
39
  - `thinking` 块默认折叠,点击展开查看思考过程
40
- - `tool_use` 显示为紧凑的工具调用卡片,包含工具名和参数预览
41
- - 系统注入标签(`<system-reminder>`、`<project-reminder>` 等)自动折叠,点击标签名展开内容
40
+ - `tool_use` 显示为紧凑的工具调用卡片(Bash、Read、Edit、Write、Glob、Grep、Task 等均有专属展示)
41
+ - 用户选择型消息(AskUserQuestion)以问答形式展示
42
+ - 系统注入标签(`<system-reminder>`、`<project-reminder>` 等)自动折叠
42
43
  - 自动过滤系统注入文本,只展示用户的真实输入
44
+ - 支持多 session 分段展示(`/compact`、`/clear` 等操作后自动分段)
45
+ - 每条消息显示精确到秒的时间戳
46
+
47
+ ### Token 消耗统计
48
+
49
+ Header 区域的「Token 消耗统计」悬浮面板:
50
+
51
+ - 按模型分组统计 input/output token 数量
52
+ - 显示 cache creation/read 数量及缓存命中率
53
+ - Main Agent 缓存失效倒计时
54
+
55
+ ### 日志管理
56
+
57
+ 通过左上角 CC-Viewer 下拉菜单:
58
+
59
+ - 导入本地日志:浏览历史日志文件,按项目分组,在新窗口打开
60
+ - 当前日志另存为:下载当前监控的 JSONL 日志文件
61
+ - 导出用户 Prompt:提取并展示所有用户输入,支持 system-reminder 折叠查看
43
62
 
44
63
  ### 数据解析
45
64
 
46
65
  | 消息类型 | 识别方式 | 展示 |
47
66
  |---------|---------|------|
48
- | 用户输入 | `role: "user"` + 非系统标签文本 | 右对齐蓝色气泡 |
49
- | Agent 文本回复 | `role: "assistant"` + `type: "text"` | 左对齐 Markdown 渲染 |
50
- | Agent 工具调用 | `role: "assistant"` + `type: "tool_use"` | 工具调用卡片 |
67
+ | 用户输入 | `role: "user"` + 非系统标签文本 | 蓝色气泡 |
68
+ | 用户选择 | `[SUGGESTION MODE:]` + `tool_result` | 问答卡片 |
69
+ | Agent 文本回复 | `role: "assistant"` + `type: "text"` | Markdown 渲染 |
70
+ | Agent 工具调用 | `role: "assistant"` + `type: "tool_use"` | 工具调用卡片 + 内联结果 |
51
71
  | Agent 思考 | `role: "assistant"` + `type: "thinking"` | 可折叠思考块 |
52
- | 工具返回 | `role: "user"` + `type: "tool_result"` | 关联到对应 tool_use |
53
72
 
54
73
  对于 `Task` 类型的工具调用,会从 `input` 中提取 `subagent_type` 和 `description` 来标识具体的 Sub Agent。
55
74
 
56
75
  ## 技术栈
57
76
 
58
- - 前端:原生 HTML/CSS/JS,暗色主题
59
- - JSON 渲染:[@alenaksu/json-viewer](https://github.com/nicolo-ribaudo/json-viewer)
77
+ - 前端:React + Ant Design,暗色主题
60
78
  - Markdown 渲染:[marked](https://github.com/markedjs/marked)
61
79
  - 后端:Node.js 原生 HTTP 服务 + SSE 实时推送
62
80
  - 请求拦截:通过 `globalThis.fetch` 拦截,支持流式响应组装
81
+ - 构建:Vite
63
82
 
64
83
  ## License
65
84
 
package/cli.js CHANGED
@@ -1,11 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readFileSync, writeFileSync } from 'node:fs';
3
+ import { readFileSync, writeFileSync, unlinkSync } from 'node:fs';
4
4
  import { resolve } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
 
7
7
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
8
8
 
9
+ const INJECT_START = '// >>> Start CC Viewer Web Service >>>';
10
+ const INJECT_END = '// <<< Start CC Viewer Web Service <<<';
11
+ const INJECT_IMPORT = "import '../../cc-viewer/interceptor.js';";
12
+ const INJECT_BLOCK = `${INJECT_START}\n${INJECT_IMPORT}\n${INJECT_END}`;
13
+ const SHOW_ALL_FILE = '/tmp/cc-viewer-show-all';
14
+
15
+ // 解析 --all 参数
16
+ const showAll = process.argv.includes('--all');
17
+ if (showAll) {
18
+ try { writeFileSync(SHOW_ALL_FILE, '1'); } catch {}
19
+ } else {
20
+ try { unlinkSync(SHOW_ALL_FILE); } catch {}
21
+ }
22
+
9
23
  const INJECT_START = '// >>> Start CC Viewer Web Service >>>';
10
24
  const INJECT_END = '// <<< Start CC Viewer Web Service <<<';
11
25
  const INJECT_IMPORT = "import '../../cc-viewer/interceptor.js';";
package/interceptor.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // LLM Request Interceptor
2
2
  // 拦截并记录所有Claude API请求
3
3
  import { appendFileSync, mkdirSync } from 'node:fs';
4
+ import { homedir } from 'node:os';
4
5
  import { fileURLToPath } from 'node:url';
5
6
  import { dirname, join, basename } from 'node:path';
6
7
 
@@ -18,7 +19,7 @@ function generateLogFilePath() {
18
19
  + String(now.getMinutes()).padStart(2, '0')
19
20
  + String(now.getSeconds()).padStart(2, '0');
20
21
  const projectName = basename(process.cwd()).replace(/[^a-zA-Z0-9_\-\.]/g, '_');
21
- const dir = '/tmp/claude-requests';
22
+ const dir = join(homedir(), '.claude', 'cc-viewer');
22
23
  try { mkdirSync(dir, { recursive: true }); } catch {}
23
24
  return join(dir, `${projectName}_${ts}.jsonl`);
24
25
  }
@@ -215,6 +216,7 @@ export function setupInterceptor() {
215
216
  response: null,
216
217
  duration: 0,
217
218
  isStream: body?.stream === true,
219
+ isHeartbeat: /\/api\/eval\/sdk-/.test(urlStr),
218
220
  mainAgent: !!body?.system && Array.isArray(body?.tools) && body.tools.length > 10 &&
219
221
  ['Task', 'Edit', 'Bash'].every(n => body.tools.some(t => t.name === n))
220
222
  };