@myskyline_ai/ccdebug 0.2.17 → 0.2.18

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.en.md CHANGED
@@ -1,131 +1,141 @@
1
+
1
2
  # CCDebug - Claude Code Debugging Tool
2
3
 
3
- CCDebug is a debugging tool for Claude Code. It records and visualizes Claude Code execution traces, and also supports “edit & replay” for a single LLM request so you can quickly pinpoint deviations caused by prompts/context/tool calls.
4
+ CCDebug is a debugging tool for Claude Code. It records and visualizes Claude Code execution traces, and also supports “edit & replay” for a single LLM request to help you quickly pinpoint deviations caused by prompts/context/tool calls. (This project is a derivative work based on [lemmy/claude-trace](https://github.com/badlogic/lemmy/tree/main/apps/claude-trace).)
4
5
 
5
- This project is a derivative work based on [lemmy/claude-trace](https://github.com/badlogic/lemmy/tree/main/apps/claude-trace).
6
+ [>>中文 README](./README.md)
6
7
 
7
8
  ## ✨ Key Features
8
9
 
9
- ### 📊 Timeline view for Claude Code execution
10
+ ### **1. Timeline trace view**
11
+ - **Show by Claude Code execution steps**: distinguish different log types such as user input, LLM replies, and tool calls
12
+ - **Step details supported**: quickly inspect the raw Claude Code log content for any step
13
+
14
+ ![Timeline trace for Claude Code](./docs/img/1、日志以时间线形式展示.png)
15
+
16
+ ### **2. Quick log switching**
17
+ - **One-click jump to SubAgent logs**: jump to sub-agent logs to inspect the sub-agent execution trace
18
+ - **Quickly switch projects and sessions**: switch between different projects and sessions under `~/.claude/projects` without running the tool multiple times
19
+
20
+ ![Quickly switch projects and sessions](./docs/img/2、快速切换项目和会话.gif)
10
21
 
11
- ![Timeline](./docs/img/时间线.png)
22
+ ### **3. Fast search & pinpointing**
23
+ - **Global keyword search**: quickly locate logs containing a given keyword (searches all log files under the current session)
24
+ - **Step overview filtering**: the overview shows the whole execution; filter timeline nodes by type
25
+ - **Generate share links**: generate a share link for the current session for collaborative analysis
12
26
 
13
- - **Conversation timeline**: visualize the full conversation flow and tool call chain.
14
- - **Filter by step type**: filter timeline nodes by type (user message, assistant reply, tool call, etc.).
15
- - **Combined tool call + result**: tool input and its output are shown together for easier inspection.
16
- - **Session selector & sub-agent labels**: choose a main session log; sub-agent logs are shown using agent name/description.
17
- - **Project switching**: switch projects under `~/.claude/projects` in the Web UI to avoid running multiple servers.
27
+ ![Fast search & pinpointing](./docs/img/3、快速搜索定位.gif)
18
28
 
19
- ### 🛠️ Step-level LLM request debugging
29
+ ### **4. Quick latency analysis**
30
+ - **Show step start time**: each log node displays the start time of the step
31
+ - **Show tool-call duration**: for tool calls and SubAgent steps, nodes display the duration
32
+ - **Measure time between steps**: mark two step nodes to automatically calculate and display the elapsed time between them
20
33
 
21
- ![LLM Request Debug](./docs/img/LLM请求调试.png)
34
+ ![Quick latency analysis](./docs/img/4、快速分析耗时.gif)
22
35
 
23
- ![Send Modified Request](./docs/img/发送修改后的LLM请求.png)
36
+ ### **5. Step-level debugging for Claude Code**
37
+ > Note: the debugging feature only supports Claude Code installed via the NPM script form, and does not support the native binary version.
24
38
 
25
- - **Track LLM requests**: record all LLM request/response logs made by Claude Code.
26
- - **Replay requests**: edit the request payload and resend it to validate the response repeatedly.
39
+ ![Step-level debugging for Claude Code](./docs/img/LLM请求调试.png)
40
+ - **Track LLM requests**: record all Claude Code request logs to the LLM in detail
41
+ - **Resend LLM requests**: edit the LLM request payload and resend it, making it easy to repeatedly validate whether the response meets expectations
27
42
 
28
43
  ## 🚀 Quick Start
29
44
 
30
45
  ### Install
31
46
 
32
47
  ```bash
33
- # Recommended: install from npm
48
+ # Recommended: install globally from npm
34
49
  npm install -g @myskyline_ai/ccdebug
35
50
 
36
- # Or install from a local tgz artifact
51
+ # Or: install a local/released tgz artifact
37
52
  # npm install -g /path/to/@myskyline_ai-ccdebug-x.y.z.tgz
38
53
  ```
39
54
 
40
55
  ### Basic usage
41
56
 
42
- #### 1) Launch Claude and record traffic
57
+ #### 1. Launch Claude and record interactions
43
58
 
44
59
  ```bash
45
- # Basic usage - start Claude and record logs
60
+ # Basic usage - start Claude and record automatically
46
61
  ccdebug
47
62
 
48
- # Include all requests (not only /v1/messages)
63
+ # Include all requests (not only conversations)
49
64
  ccdebug --include-all-requests
50
65
 
51
- # Pass all subsequent arguments to Claude (example)
52
- ccdebug --run-with -p "Do the work as requested" --verbose
66
+ # Pass subsequent args to the Claude process (example)
67
+ ccdebug --run-with -p "Please work as requested" --verbose
53
68
  ```
54
69
 
55
- #### 2) Start the Web timeline server
70
+ #### 2. Start the Web site to view the timeline trace
56
71
 
57
72
  ```bash
58
- # Start the Web server (default port: 3001, default project dir: current working directory)
59
- ccdebug --serve
73
+ # Start the Web server for the timeline (default port: 3001; default project dir: current directory)
74
+ ccdebug -l
60
75
 
61
- # Custom port
62
- ccdebug --serve --port 3001
76
+ # Start on a custom port
77
+ ccdebug -l --port 3001
63
78
 
64
- # Specify project directory
65
- ccdebug --serve --project /path/to/your/cc_workdir
79
+ # Start with a specified project directory
80
+ ccdebug -l --project /path/to/your/cc_workdir
66
81
  ```
67
82
 
68
83
  ### Log output directories
69
84
 
70
85
  - **Claude Code standard logs (for timeline)**: `.claude-trace/cclog/*.jsonl` (includes main logs and `agent-*.jsonl` sub-agent logs)
71
- - **Claude API tracing logs (for LLM debugging)**: `.claude-trace/tracelog/*.jsonl`
72
- - **Saved LLM request overrides (for replay)**: `.claude-trace/tracelog/llm_requests/*.json`
86
+ - **Claude Code API tracing logs (for LLM request debugging)**: `.claude-trace/tracelog/*.jsonl`
87
+ - **Saved LLM requests (for override/replay)**: `.claude-trace/tracelog/llm_requests/*.json`
73
88
 
74
89
  Notes:
75
90
 
76
- - After a `ccdebug`-launched Claude session ends, CCDebug automatically copies the corresponding Claude Code standard logs into `.claude-trace/cclog/`, and renames the API tracing log to `{sessionId}.jsonl`.
77
- - If you are using the **native Claude Code binary** (not the npm script version), CCDebug cannot intercept API requests, so LLM request debugging won’t work. You can still use the Web UI to view existing standard logs.
91
+ - After you run `ccdebug` to start a Claude session, CCDebug automatically copies the corresponding Claude Code standard logs into `.claude-trace/cclog/`, and renames the API tracing log to `{sessionId}.jsonl`.
92
+ - If you are using the **native Claude Code binary version** (not the NPM script form), CCDebug cannot intercept API requests, and LLM request debugging will be unavailable (you can still view existing Claude Code standard logs via the Web site).
78
93
 
79
94
  ## 📋 CLI Options
80
95
 
81
96
  | Option | Description |
82
97
  |------|------|
83
- | `--serve` | Start the Web timeline server |
84
- | `--log, -l` | Start the Web timeline server (`--log` without a value behaves like `--serve`; prefer `-l` to avoid confusion with `--log <name>`) |
98
+ | `--log, -l` | Start the Web timeline server (when `--log` is used without a value, it is equivalent to `--serve`; prefer `-l` to avoid confusion with `--log <name>`) |
85
99
  | `--port <number>` | Web server port (default: 3001) |
86
- | `--project <path>` | Project directory |
100
+ | `--project <path>` | Project directory path |
87
101
  | `--run-with <args>` | Pass subsequent args to the Claude process |
88
- | `--include-all-requests` | Capture all Claude-related requests, not only chat requests |
89
- | `--no-open` | Do not auto-open the generated HTML in a browser (currently only effective for `--generate-html`) |
90
- | `--claude-path <path>` | Custom path to the Claude binary or `cli.js` |
91
- | `--log <name>` | Base name for API tracing logs (affects files under `.claude-trace/tracelog/`) |
92
- | `--generate-html <input.jsonl> [output.html]` | Generate an HTML report from a JSONL file |
93
- | `--index` | Generate conversation summaries & an index under `.claude-trace/` (will call Claude and incur token usage) |
94
- | `--extract-token` | Extract OAuth token and exit |
95
- | `--version, -v` | Print version |
102
+ | `--include-all-requests` | Include all fetch requests, not only conversations |
103
+ | `--claude-path <path>` | Custom path to the Claude binary |
104
+ | `--index` | Generate conversation summaries and an index for the `.claude-trace/` directory (will call Claude and incur extra token usage) |
105
+ | `--version, -v` | Show version information |
96
106
  | `--help, -h` | Show help |
97
107
 
98
108
  ## 🏗️ Architecture
99
109
 
100
110
  ### Core components
101
111
 
102
- - **HTTP/API interceptor**: intercepts Node.js HTTP/HTTPS + fetch to capture Anthropic/Bedrock requests and responses.
103
- - **Standard log collection**: on exit, copies main and sub-agent Claude Code logs into `.claude-trace/cclog/`.
104
- - **Web server**: Express provides APIs for file listing, session management, project switching, and LLM request read/save/replay.
105
- - **Frontend**: Vue 3 + Vite + Pinia + Arco Design.
112
+ - **HTTP/API interceptor**: based on Node.js HTTP/HTTPS + fetch interception, recording requests and responses to Anthropic/Bedrock
113
+ - **Claude Code standard log consolidation**: on session exit, automatically copies Claude Code standard logs (main and sub-agent logs) into `.claude-trace/cclog/`
114
+ - **Web server**: Express.js provides APIs for file listing, session management, project switching, and LLM request read/save/replay
115
+ - **Frontend UI**: Vue 3 + Vite + Pinia + Arco Design
106
116
 
107
117
  ### Data flow
108
118
 
109
119
  ```
110
- HTTP request/response → interceptor → raw JSONL → processors → structured data → Web UI
120
+ HTTP request/response → interceptor → raw data (JSONL)data processor → structured data → Web UI
111
121
  ```
112
122
 
113
123
  ## 📁 Project Structure
114
124
 
115
125
  ```
116
126
  ccdebug/
117
- ├── src/ # CLI & interceptors
127
+ ├── src/ # CLI and interceptors
118
128
  │ ├── cli.ts # CLI entry
119
129
  │ ├── interceptor.ts # API interception and tracelog recording
120
130
  │ ├── html-generator.ts # HTML report generator (based on frontend)
121
- │ └── index-generator.ts # conversation summaries and index
131
+ │ └── index-generator.ts # conversation summaries and index generation
122
132
  ├── web/ # Web timeline site (Vite + Vue 3)
123
133
  │ ├── src/ # frontend source
124
134
  │ ├── dist/ # build output
125
- │ └── server/ # Express backend (required by CLI to start)
135
+ │ └── server/ # Express backend (started by the CLI via require)
126
136
  ├── frontend/ # standalone HTML report frontend (bundle injected into HTML)
127
137
  ├── scripts/ # packaging scripts
128
- └── docs/ # docs and design notes
138
+ └── docs/ # documentation and design notes
129
139
  ```
130
140
 
131
141
  ## 🔧 Development
@@ -138,7 +148,7 @@ ccdebug/
138
148
  ### Local development
139
149
 
140
150
  ```bash
141
- # Clone
151
+ # Clone the repo
142
152
  git clone https://github.com/ThinkingBeing/ccdebug.git
143
153
  cd ccdebug
144
154
 
@@ -148,14 +158,14 @@ npm install
148
158
  # Build
149
159
  npm run build
150
160
 
151
- # Dev mode (watch core code + web frontend)
161
+ # Development mode (watch core code + frontend)
152
162
  npm run dev
153
163
 
154
- # Run CLI via tsx (for development/debugging)
164
+ # Run the CLI via tsx (for development debugging)
155
165
  npx tsx src/cli.ts --help
156
- npx tsx src/cli.ts --serve --port 3001 --project /path/to/your/cc_workdir
166
+ npx tsx src/cli.ts -l --port 3001 --project /path/to/your/cc_workdir
157
167
 
158
- # Package (artifacts will be placed under release/)
168
+ # Package after validation (artifacts will be under release/)
159
169
  npm run package
160
170
  ```
161
171
 
package/README.md CHANGED
@@ -1,23 +1,42 @@
1
1
  # CCDebug - Claude Code 调试工具
2
2
 
3
3
 
4
- CCDebug 是一个针对 Claude Code 的调试工具,用于记录并可视化 CC 运行轨迹,同时支持对单个 LLM 请求进行“修改-重放”,帮助你快速定位提示词/上下文/工具调用导致的偏差。本项目基于 [lemmy/claude-trace](https://github.com/badlogic/lemmy/tree/main/apps/claude-trace) 二次开发。
4
+ CCDebug 是一个针对 Claude Code 的调试工具,用于记录并可视化 CC 运行轨迹,同时支持对单个 LLM 请求进行“修改-重放”,帮助你快速定位提示词/上下文/工具调用导致的偏差。(本项目基于 [lemmy/claude-trace](https://github.com/badlogic/lemmy/tree/main/apps/claude-trace) 二次开发)
5
5
 
6
- 英文版:[README.en.md](./README.en.md)
6
+ [>>English README](./README.en.md)
7
7
 
8
8
  ## ✨ 主要功能
9
9
 
10
- ### 📊 时间线展示CC运行轨迹
11
- ![时间线展示CC运行轨迹](./docs/img/时间线.png)
12
- - **对话时间线**: 直观展示完整的对话流程和工具调用链
13
- - **按节点类型过滤**: 按不同类型的时间线节点过滤,如用户输入、LLM回复、工具调用等
14
- - **工具调用和结果整合展示**: 将工具调用和调用结果整合在一个节点展示,方便查看工具调用的输入参数和输出结果
15
- - **会话选择与子代理识别**: 支持主日志会话选择,子代理日志下拉框显示 agent 名称/描述
16
- - **项目切换**: Web 站点内可切换到 `~/.claude/projects` 下的其他项目,避免重复启动多个站点
10
+ ### **1、时间线展示轨迹**
11
+ - **按CC执行步骤显示**: 可以区分不同类型日志,用户输入、LLM回复、工具调用等
12
+ - **支持步骤详情**: 可以快速查看某一步的原始CC日志内容
13
+
14
+ ![时间线展示CC运行轨迹](./docs/img/1、日志以时间线形式展示.png)
15
+
16
+ ### **2、快速切换日志**
17
+ - **一键跳转SubAgent日志**: 一键跳转到子代理日志,方便查看子代理的运行轨迹
18
+ - **快速切换项目和会话**: 直接切换 `~/.claude/projects` 下的不同项目和会话,无需启动多次工具
19
+
20
+ ![快速切换项目和会话](./docs/img/2、快速切换项目和会话.gif)
21
+
22
+ ### **3、快速搜索定位**
23
+ - **全局搜索关键字**: 可以快速定位到包含指定关键字的日志(搜索当前会话下所有日志文件)
24
+ - **步骤概览过滤**: 步骤概览显示执行全貌,可按不同类型的时间线节点过滤
25
+ - **生成分享链接**: 可以生成当前会话的分享链接,方便多人协作分析
26
+
27
+ ![快速搜索定位](./docs/img/3、快速搜索定位.gif)
28
+
29
+ ### **4、快速分析耗时**
30
+ - **显示步骤开始时间**: 每个日志节点显示当前步骤的开始时间
31
+ - **显示工具调用耗时**: 对于工具调用、SubAgent执行的步骤,节点将显示调用耗时
32
+ - **统计步骤间耗时**: 用户可以标记2个步骤节点,共计自动计算并显示2个节点间耗时
33
+
34
+ ![快速分析耗时](./docs/img/4、快速分析耗时.gif)
35
+
36
+ ### **5、对CC步骤单点调试**
37
+ > 注意:调试功能仅支持NPM脚本形式安装的 Claude Code,不支持原生二进制版本。
17
38
 
18
- ### 🛠️ 对CC步骤单点调试
19
39
  ![对CC步骤单点调试](./docs/img/LLM请求调试.png)
20
- ![发送修改后的LLM请求](./docs/img/发送LLM请求.png)
21
40
  - **追踪LLM请求**: 详细记录CC对LLM的所有请求日志
22
41
  - **重新发送LLM请求**: 支持修改LLM请求数据,重新发送请求,方便反复验证LLM的响应是否符合预期
23
42
 
@@ -52,13 +71,13 @@ ccdebug --run-with -p "请按要求工作" --verbose
52
71
 
53
72
  ```bash
54
73
  # 启动 Web 服务器查看时间线(默认端口 3001,默认项目目录为当前目录)
55
- ccdebug --serve
74
+ ccdebug -l
56
75
 
57
76
  # 在自定义端口启动
58
- ccdebug --serve --port 3001
77
+ ccdebug -l --port 3001
59
78
 
60
79
  # 指定项目目录启动
61
- ccdebug --serve --project /path/to/your/cc_workdir
80
+ ccdebug -l --project /path/to/your/cc_workdir
62
81
  ```
63
82
 
64
83
  ### 日志输出目录
@@ -76,18 +95,13 @@ ccdebug --serve --project /path/to/your/cc_workdir
76
95
 
77
96
  | 选项 | 描述 |
78
97
  |------|------|
79
- | `--serve` | 启动 Web 时间线服务器 |
80
98
  | `--log, -l` | 启动 Web 时间线服务器(当 `--log` 不带参数时等同于 `--serve`;建议用 `-l` 避免与 `--log <name>` 混淆) |
81
99
  | `--port <number>` | 指定 Web 服务器端口(默认 3001) |
82
100
  | `--project <path>` | 指定项目目录路径 |
83
101
  | `--run-with <args>` | 将后续参数传递给 Claude 进程 |
84
102
  | `--include-all-requests` | 包含所有 fetch 请求,而不仅仅是对话 |
85
- | `--no-open` | 不在浏览器中自动打开生成的 HTML(当前仅对 `--generate-html` 生效) |
86
103
  | `--claude-path <path>` | 指定 Claude 二进制文件的自定义路径 |
87
- | `--log <name>` | 指定 API 跟踪日志基础名称(影响 `.claude-trace/tracelog/` 下文件名) |
88
- | `--generate-html <input.jsonl> [output.html]` | 从 JSONL 文件生成 HTML 报告 |
89
104
  | `--index` | 为 `.claude-trace/` 目录生成对话摘要和索引(会调用 Claude 产生额外 token 消耗) |
90
- | `--extract-token` | 提取 OAuth token 并退出 |
91
105
  | `--version, -v` | 显示版本信息 |
92
106
  | `--help, -h` | 显示帮助信息 |
93
107
 
@@ -149,7 +163,7 @@ npm run dev
149
163
 
150
164
  # 使用 tsx 直接运行 CLI(开发调试用)
151
165
  npx tsx src/cli.ts --help
152
- npx tsx src/cli.ts --serve --port 3001 --project /path/to/your/cc_workdir
166
+ npx tsx src/cli.ts -l --port 3001 --project /path/to/your/cc_workdir
153
167
 
154
168
  # 功能ok后打包,包会出现在release目录
155
169
  npm run package
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAyBA,eAAO,MAAM,MAAM;;;;;;CAMT,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA2BA,eAAO,MAAM,MAAM;;;;;;CAMT,CAAC"}
package/dist/cli.js CHANGED
@@ -38,7 +38,8 @@ exports.colors = void 0;
38
38
  const child_process_1 = require("child_process");
39
39
  const path = __importStar(require("path"));
40
40
  const fs = __importStar(require("fs"));
41
- const html_generator_1 = require("./html-generator");
41
+ const crypto = __importStar(require("crypto"));
42
+ const log_file_manager_1 = require("./log-file-manager");
42
43
  const os = __importStar(require("os"));
43
44
  /**
44
45
  * 获取工具版本号
@@ -320,12 +321,132 @@ function getLoaderPath() {
320
321
  }
321
322
  return loaderPath;
322
323
  }
323
- // Scenario 1: No args -> launch node with interceptor and absolute path to claude
324
- async function runClaudeWithInterception(claudeArgs = [], includeAllRequests = false, openInBrowser = false, customClaudePath, logBaseName, enableTrace = false) {
324
+ /**
325
+ * 拷贝 Claude Code 日志文件到 cclog 目录
326
+ * @param sessionId 会话ID
327
+ * @param ccLogDir cclog 目录路径
328
+ */
329
+ function copyCClogFile(sessionId, ccLogDir) {
330
+ // 检查是否启用了跟踪
331
+ if (!ccLogDir) {
332
+ return;
333
+ }
334
+ // 将当前会话对应的 cc 日志文件,拷贝到 .claude-trace/cclog 目录
335
+ try {
336
+ // 创建 LogFileManager 实例
337
+ const logFileManager = new log_file_manager_1.LogFileManager();
338
+ // 获取当前工作目录作为项目路径
339
+ const currentProjectPath = process.cwd();
340
+ // 通过 LogFileManager 解析源日志目录
341
+ const sourceLogDir = logFileManager.resolveLogDirectory(currentProjectPath);
342
+ // 构建源文件路径(假设源文件名为 sessionId.jsonl)
343
+ const sourceFile = path.join(sourceLogDir, `${sessionId}.jsonl`);
344
+ // 构建目标文件路径
345
+ const ccLogFile = path.join(ccLogDir, `${sessionId}.jsonl`);
346
+ // 检查源文件是否存在
347
+ if (!fs.existsSync(sourceFile)) {
348
+ console.log(`源CC日志文件不存在: ${sourceFile}`);
349
+ return;
350
+ }
351
+ // 确保目标 ccLogDir 目录存在(修复:之前未创建目录导致拷贝失败)
352
+ if (!fs.existsSync(ccLogDir)) {
353
+ fs.mkdirSync(ccLogDir, { recursive: true });
354
+ console.log(`已创建 cclog 目录: ${ccLogDir}`);
355
+ }
356
+ // 拷贝文件
357
+ fs.copyFileSync(sourceFile, ccLogFile);
358
+ console.log(`CC日志文件已从 ${sourceFile} 拷贝到 ${ccLogFile}`);
359
+ // 读取 sourceLogDir 目录下所有 agent_*.jsonl 文件,读取第一条记录的 sessionId,找到与 sessionId 变量值相同的文件,拷贝到 ccLogDir 目录
360
+ const files = fs.readdirSync(sourceLogDir).filter(file => file.startsWith('agent-') && file.endsWith('.jsonl'));
361
+ for (const file of files) {
362
+ const filePath = path.join(sourceLogDir, file);
363
+ const content = fs.readFileSync(filePath, 'utf-8');
364
+ const lines = content.split('\n').filter(line => line.trim());
365
+ if (lines.length > 0) {
366
+ try {
367
+ const firstRecord = JSON.parse(lines[0]);
368
+ const recordSessionId = firstRecord?.sessionId;
369
+ if (recordSessionId === sessionId) {
370
+ // 构建目标文件路径
371
+ const ccAgentLogFile = path.join(ccLogDir, file);
372
+ // 拷贝文件
373
+ fs.copyFileSync(filePath, ccAgentLogFile);
374
+ console.log(`SubAgent的CC日志文件已从 ${filePath} 拷贝到 ${ccAgentLogFile}`);
375
+ }
376
+ }
377
+ catch (parseError) {
378
+ // 静默处理解析错误,继续下一个文件
379
+ continue;
380
+ }
381
+ }
382
+ }
383
+ // 兼容 subagents 日志的另一种存放方式:sourceLogDir/{sessionId}/subagents/ 目录
384
+ const subagentsDir = path.join(sourceLogDir, sessionId, 'subagents');
385
+ if (fs.existsSync(subagentsDir)) {
386
+ try {
387
+ const subagentFiles = fs.readdirSync(subagentsDir).filter(file => file.startsWith('agent-') && file.endsWith('.jsonl'));
388
+ // 只有当存在需要拷贝的文件时,才创建目标目录
389
+ if (subagentFiles.length > 0) {
390
+ // 创建目标目录结构:ccLogDir/{sessionId}/subagents/
391
+ const targetSubagentsDir = path.join(ccLogDir, sessionId, 'subagents');
392
+ if (!fs.existsSync(targetSubagentsDir)) {
393
+ fs.mkdirSync(targetSubagentsDir, { recursive: true });
394
+ }
395
+ for (const file of subagentFiles) {
396
+ const sourceFilePath = path.join(subagentsDir, file);
397
+ const targetFilePath = path.join(targetSubagentsDir, file);
398
+ // 直接拷贝文件,因为已经在正确的 sessionId 目录下
399
+ fs.copyFileSync(sourceFilePath, targetFilePath);
400
+ console.log(`SubAgent的CC日志文件已从 ${sourceFilePath} 拷贝到 ${targetFilePath}`);
401
+ }
402
+ }
403
+ }
404
+ catch (error) {
405
+ console.log(`处理subagents目录时出错: ${error}`);
406
+ }
407
+ }
408
+ }
409
+ catch (error) {
410
+ console.log(`拷贝CC日志文件时出错: ${error}`);
411
+ }
412
+ }
413
+ /**
414
+ * 根据 sessionId 重命名跟踪日志文件
415
+ * @param sessionId 会话ID
416
+ * @param traceLogFile 跟踪日志文件路径
417
+ * @returns 新的日志文件路径
418
+ */
419
+ function renameTraceLogFileBySessionId(sessionId, traceLogFile) {
420
+ // 检查是否启用了跟踪
421
+ if (!traceLogFile) {
422
+ return null;
423
+ }
424
+ try {
425
+ const logDir = path.dirname(traceLogFile);
426
+ const newLogFile = path.join(logDir, `${sessionId}.jsonl`);
427
+ // 如果源文件不存在(如原生二进制模式下 interceptor 未运行,tracelog 未创建),直接跳过
428
+ if (!fs.existsSync(traceLogFile)) {
429
+ return null;
430
+ }
431
+ // 重命名文件
432
+ fs.renameSync(traceLogFile, newLogFile);
433
+ console.log(`Log file renamed from ${path.basename(traceLogFile)} to ${sessionId}.jsonl`);
434
+ return newLogFile;
435
+ }
436
+ catch (error) {
437
+ console.log(`Error renaming log file: ${error}`);
438
+ return traceLogFile;
439
+ }
440
+ }
441
+ // 启动claude code
442
+ async function runClaudeWithInterception(claudeArgs = [], includeAllRequests = false, openInBrowser = false, customClaudePath, logBaseName, enableTrace = true) {
325
443
  log("启动 Claude", "blue");
326
444
  if (claudeArgs.length > 0) {
327
445
  log(`Claude 参数: ${claudeArgs.join(" ")}`, "blue");
328
446
  }
447
+ // 生成 UUID 格式的 sessionId
448
+ const sessionId = crypto.randomUUID();
449
+ log(`生成 SessionId: ${sessionId}`, "blue");
329
450
  const claudePath = getClaudeAbsolutePath(customClaudePath);
330
451
  log(`使用 Claude 二进制文件: ${claudePath}`, "blue");
331
452
  let child;
@@ -338,7 +459,9 @@ async function runClaudeWithInterception(claudeArgs = [], includeAllRequests = f
338
459
  log("使用 Node.js 启动 Claude(未启用跟踪)", "blue");
339
460
  }
340
461
  const loaderPath = getLoaderPath();
341
- const spawnArgs = ["--require", loaderPath, claudePath, ...claudeArgs];
462
+ // 添加 --session-id 参数到 Claude 启动参数中
463
+ const claudeArgsWithSession = ["--session-id", sessionId, ...claudeArgs];
464
+ const spawnArgs = ["--require", loaderPath, claudePath, ...claudeArgsWithSession];
342
465
  child = (0, child_process_1.spawn)("node", spawnArgs, {
343
466
  env: {
344
467
  ...process.env,
@@ -362,8 +485,10 @@ async function runClaudeWithInterception(claudeArgs = [], includeAllRequests = f
362
485
  console.log("");
363
486
  // 给用户一点时间阅读提示信息
364
487
  await new Promise(resolve => setTimeout(resolve, 500));
488
+ // 添加 --session-id 参数到 Claude 启动参数中
489
+ const claudeArgsWithSession = ["--session-id", sessionId, ...claudeArgs];
365
490
  // 直接启动 Claude 二进制文件,不使用代理
366
- child = (0, child_process_1.spawn)(claudePath, claudeArgs, {
491
+ child = (0, child_process_1.spawn)(claudePath, claudeArgsWithSession, {
367
492
  env: {
368
493
  ...process.env,
369
494
  },
@@ -418,118 +543,29 @@ async function runClaudeWithInterception(claudeArgs = [], includeAllRequests = f
418
543
  log(`意外错误: ${err.message}`, "red");
419
544
  process.exit(1);
420
545
  }
421
- }
422
- // Scenario 2: --extract-token -> launch node with token interceptor and absolute path to claude
423
- async function extractToken(customClaudePath) {
424
- const claudePath = getClaudeAbsolutePath(customClaudePath);
425
- // Log to stderr so it doesn't interfere with token output
426
- console.error(`使用 Claude 二进制文件: ${claudePath}`);
427
- // Create .claude-trace directory if it doesn't exist
428
- const ccdebugDir = path.join(process.cwd(), ".claude-trace");
429
- if (!fs.existsSync(ccdebugDir)) {
430
- fs.mkdirSync(ccdebugDir, { recursive: true });
431
- }
432
- // Token file location
433
- const tokenFile = path.join(ccdebugDir, "token.txt");
434
- // Use the token extractor directly without copying
435
- const tokenExtractorPath = path.join(__dirname, "token-extractor.js");
436
- if (!fs.existsSync(tokenExtractorPath)) {
437
- log(`未找到令牌提取器: ${tokenExtractorPath}`, "red");
438
- process.exit(1);
439
- }
440
- const cleanup = () => {
441
- try {
442
- if (fs.existsSync(tokenFile))
443
- fs.unlinkSync(tokenFile);
444
- }
445
- catch (e) {
446
- // Ignore cleanup errors
447
- }
448
- };
449
- // Launch node with token interceptor and absolute path to claude
450
- const { ANTHROPIC_API_KEY, ...envWithoutApiKey } = process.env;
451
- const child = (0, child_process_1.spawn)("node", ["--require", tokenExtractorPath, claudePath, "-p", "hello"], {
452
- env: {
453
- ...envWithoutApiKey,
454
- NODE_TLS_REJECT_UNAUTHORIZED: "0",
455
- CLAUDE_TRACE_TOKEN_FILE: tokenFile,
456
- },
457
- stdio: "inherit", // Suppress all output from Claude
458
- cwd: process.cwd(),
459
- });
460
- // Set a timeout to avoid hanging
461
- const timeout = setTimeout(() => {
462
- child.kill();
463
- cleanup();
464
- console.error("超时: 30 秒内未找到令牌");
465
- process.exit(1);
466
- }, 30000);
467
- // Handle child process events
468
- child.on("error", (error) => {
469
- clearTimeout(timeout);
470
- cleanup();
471
- console.error(`启动 Claude 时出错: ${error.message}`);
472
- process.exit(1);
473
- });
474
- child.on("exit", () => {
475
- clearTimeout(timeout);
476
- try {
477
- if (fs.existsSync(tokenFile)) {
478
- const token = fs.readFileSync(tokenFile, "utf-8").trim();
479
- cleanup();
480
- if (token) {
481
- // Only output the token, nothing else
482
- console.log(token);
483
- process.exit(0);
484
- }
485
- }
486
- }
487
- catch (e) {
488
- // File doesn't exist or read error
489
- }
490
- cleanup();
491
- console.error("未找到授权令牌");
492
- process.exit(1);
493
- });
494
- // Check for token file periodically
495
- const checkToken = setInterval(() => {
496
- try {
497
- if (fs.existsSync(tokenFile)) {
498
- const token = fs.readFileSync(tokenFile, "utf-8").trim();
499
- if (token) {
500
- clearTimeout(timeout);
501
- clearInterval(checkToken);
502
- child.kill();
503
- cleanup();
504
- // Only output the token, nothing else
505
- console.log(token);
506
- process.exit(0);
507
- }
508
- }
509
- }
510
- catch (e) {
511
- // Ignore read errors, keep trying
512
- }
513
- }, 500);
514
- }
515
- // Scenario 3: --generate-html input.jsonl output.html
516
- async function generateHTMLFromCLI(inputFile, outputFile, includeAllRequests = false, openInBrowser = false) {
546
+ // Claude 执行完成后,处理 CC 日志文件(不管是否启用了跟踪)
517
547
  try {
518
- const htmlGenerator = new html_generator_1.HTMLGenerator();
519
- const finalOutputFile = await htmlGenerator.generateHTMLFromJSONL(inputFile, outputFile, includeAllRequests);
520
- if (openInBrowser) {
521
- (0, child_process_1.spawn)("open", [finalOutputFile], { detached: true, stdio: "ignore" }).unref();
522
- log(`正在浏览器中打开 ${finalOutputFile}`, "green");
523
- }
524
- process.exit(0);
548
+ console.log("\nClaude 执行完成,处理 CC 日志文件...");
549
+ // 构建日志文件路径
550
+ const traceHomeDir = ".claude-trace";
551
+ const traceLogDir = path.join(traceHomeDir, 'tracelog');
552
+ const ccLogDir = path.join(traceHomeDir, 'cclog');
553
+ // 生成日志文件名
554
+ const fileBaseName = logBaseName || `log-${new Date().toISOString().replace(/[:.]/g, "-").replace("T", "-").slice(0, -5)}`;
555
+ const traceLogFile = enableTrace ? path.join(traceLogDir, `${fileBaseName}.jsonl`) : null;
556
+ // 直接使用之前生成的 sessionId
557
+ console.log(`使用 SessionId: ${sessionId} 处理日志文件`);
558
+ // 将当前会话对应的 cc 日志文件,拷贝到 .claude-trace/cclog 目录
559
+ copyCClogFile(sessionId, ccLogDir);
560
+ // 根据 sessionId 重命名跟踪日志文件
561
+ renameTraceLogFileBySessionId(sessionId, traceLogFile);
525
562
  }
526
563
  catch (error) {
527
- const err = error;
528
- log(`错误: ${err.message}`, "red");
529
- process.exit(1);
564
+ // 静默处理错误,不影响主流程
565
+ console.log(`处理CC日志时出错: ${error}`);
530
566
  }
531
567
  }
532
- // Scenario 5: --serve, --log, -l
568
+ // 启动web工具
533
569
  async function startWebServer(port, projectDir) {
534
570
  try {
535
571
  // 使用 require 导入 web server 模块
@@ -561,20 +597,6 @@ async function startWebServer(port, projectDir) {
561
597
  process.exit(1);
562
598
  }
563
599
  }
564
- // Scenario 4: --index
565
- async function generateIndex() {
566
- try {
567
- const { IndexGenerator } = await Promise.resolve().then(() => __importStar(require("./index-generator")));
568
- const indexGenerator = new IndexGenerator();
569
- await indexGenerator.generateIndex();
570
- process.exit(0);
571
- }
572
- catch (error) {
573
- const err = error;
574
- log(`错误: ${err.message}`, "red");
575
- process.exit(1);
576
- }
577
- }
578
600
  // Main entry point
579
601
  async function main() {
580
602
  const args = process.argv.slice(2);
@@ -601,7 +623,7 @@ async function main() {
601
623
  process.exit(0);
602
624
  }
603
625
  // Check for trace flag
604
- const enableTrace = claudeTraceArgs.includes("--trace");
626
+ const enableTrace = !claudeTraceArgs.includes("--notrace");
605
627
  // Check for include all requests flag
606
628
  const includeAllRequests = claudeTraceArgs.includes("--include-all-requests");
607
629
  // Check for no-open flag (inverted logic - open by default)
@@ -633,37 +655,6 @@ async function main() {
633
655
  if (projectIndex !== -1 && claudeTraceArgs[projectIndex + 1]) {
634
656
  serveProjectDir = claudeTraceArgs[projectIndex + 1];
635
657
  }
636
- // Scenario 2: --extract-token
637
- if (claudeTraceArgs.includes("--extract-token")) {
638
- await extractToken(customClaudePath);
639
- return;
640
- }
641
- // Scenario 3: --generate-html input.jsonl output.html
642
- if (claudeTraceArgs.includes("--generate-html")) {
643
- const flagIndex = claudeTraceArgs.indexOf("--generate-html");
644
- const inputFile = claudeTraceArgs[flagIndex + 1];
645
- // Find is next argument that's not a flag as the output file
646
- let outputFile;
647
- for (let i = flagIndex + 2; i < claudeTraceArgs.length; i++) {
648
- const arg = claudeTraceArgs[i];
649
- if (!arg.startsWith("--")) {
650
- outputFile = arg;
651
- break;
652
- }
653
- }
654
- if (!inputFile) {
655
- log(`--generate-html 缺少输入文件`, "red");
656
- log(`用法: ccdebug --generate-html input.jsonl [output.html]`, "yellow");
657
- process.exit(1);
658
- }
659
- await generateHTMLFromCLI(inputFile, outputFile, includeAllRequests, openInBrowser);
660
- return;
661
- }
662
- // Scenario 4: --index
663
- if (claudeTraceArgs.includes("--index")) {
664
- await generateIndex();
665
- return;
666
- }
667
658
  // Scenario 5: --serve, --log, -l
668
659
  const hasServeFlag = claudeTraceArgs.includes("--serve");
669
660
  const hasLogFlag = claudeTraceArgs.includes("--log") || claudeTraceArgs.includes("-l");
@@ -31,9 +31,6 @@ export declare class ClaudeTrafficLogger {
31
31
  private writePairToLog;
32
32
  private generateHTML;
33
33
  cleanup(): void;
34
- private getSessionIdFromLog;
35
- private copyCClogFile;
36
- private renameTraceLogFileBySessionId;
37
34
  getStats(): {
38
35
  totalPairs: number;
39
36
  pendingRequests: number;
@@ -1 +1 @@
1
- {"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,iBAAiB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAC/C;AAED,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAAgB;gBAEzB,MAAM,GAAE,iBAAsB;IAmE1C,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,sBAAsB;YAgChB,aAAa;YAKb,gBAAgB;YAsBhB,iBAAiB;IAwBxB,aAAa,IAAI,IAAI;IAKrB,eAAe,IAAI,IAAI;IA+FvB,kBAAkB,IAAI,IAAI;IAmDjC,OAAO,CAAC,oBAAoB;IAuE5B,OAAO,CAAC,mBAAmB;YAab,2BAA2B;YAiB3B,cAAc;YAcd,YAAY;IAmBnB,OAAO,IAAI,IAAI;IAiDtB,OAAO,CAAC,mBAAmB;IA+C3B,OAAO,CAAC,aAAa;IAoFrB,OAAO,CAAC,6BAA6B;IAuB9B,QAAQ;;;;;;CAQf;AAQD,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,CA8BrF;AAED,wBAAgB,SAAS,IAAI,mBAAmB,GAAG,IAAI,CAEtD"}
1
+ {"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAC/C;AAED,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAAgB;gBAEzB,MAAM,GAAE,iBAAsB;IAmE1C,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,sBAAsB;YAgChB,aAAa;YAKb,gBAAgB;YAsBhB,iBAAiB;IAwBxB,aAAa,IAAI,IAAI;IAKrB,eAAe,IAAI,IAAI;IA+FvB,kBAAkB,IAAI,IAAI;IAmDjC,OAAO,CAAC,oBAAoB;IAuE5B,OAAO,CAAC,mBAAmB;YAab,2BAA2B;YAiB3B,cAAc;YAcd,YAAY;IAmBnB,OAAO,IAAI,IAAI;IAuCf,QAAQ;;;;;;CAQf;AAQD,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,CA8BrF;AAED,wBAAgB,SAAS,IAAI,mBAAmB,GAAG,IAAI,CAEtD"}
@@ -9,7 +9,6 @@ exports.getLogger = getLogger;
9
9
  const fs_1 = __importDefault(require("fs"));
10
10
  const path_1 = __importDefault(require("path"));
11
11
  const html_generator_1 = require("./html-generator");
12
- const log_file_manager_1 = require("./log-file-manager");
13
12
  class ClaudeTrafficLogger {
14
13
  constructor(config = {}) {
15
14
  this.pendingRequests = new Map();
@@ -433,14 +432,6 @@ class ClaudeTrafficLogger {
433
432
  }
434
433
  this.pendingRequests.clear();
435
434
  console.log(`Cleanup complete. Logged ${this.pairs.length} pairs`);
436
- //获取cc会话的sessionid
437
- let sessionId = this.getSessionIdFromLog();
438
- if (sessionId != '') {
439
- //将当前会话对应的cc日志文件,拷贝到.claude-trace/cclog目录
440
- this.copyCClogFile(sessionId);
441
- // Rename log file based on sessionid from first record
442
- this.renameTraceLogFileBySessionId(sessionId);
443
- }
444
435
  // Open browser if requested
445
436
  // const shouldOpenBrowser = process.env.CLAUDE_TRACE_OPEN_BROWSER === "true";
446
437
  // if (shouldOpenBrowser && fs.existsSync(this.htmlFile)) {
@@ -452,133 +443,6 @@ class ClaudeTrafficLogger {
452
443
  // }
453
444
  // }
454
445
  }
455
- getSessionIdFromLog() {
456
- // 检查是否启用了跟踪
457
- if (!this.traceLogFile) {
458
- return '';
459
- }
460
- // Check if log file exists
461
- if (!fs_1.default.existsSync(this.traceLogFile)) {
462
- console.log("获取sessionId错误:Log file does not exist");
463
- return '';
464
- }
465
- // Read the first line of the JSONL file
466
- const fileContent = fs_1.default.readFileSync(this.traceLogFile, 'utf-8');
467
- const lines = fileContent.split('\n').filter(line => line.trim());
468
- if (lines.length === 0) {
469
- console.log("获取sessionId错误:Log file is empty");
470
- return '';
471
- }
472
- // 循环读取日志,直到找到user_id为止
473
- let userId = null;
474
- for (const line of lines) {
475
- const record = JSON.parse(line);
476
- userId = record?.request?.body?.metadata?.user_id;
477
- if (userId) {
478
- break;
479
- }
480
- }
481
- if (!userId) {
482
- console.log("获取sessionId错误:No user_id found in any record");
483
- return '';
484
- }
485
- // Extract sessionid from user_id (format: xxxx_session_{sessionid})
486
- const sessionMatch = userId.match(/_session_([^_]+)$/);
487
- if (!sessionMatch || !sessionMatch[1]) {
488
- console.log(`获取sessionId错误:No sessionid found in user_id: ${userId}`);
489
- return '';
490
- }
491
- return sessionMatch[1];
492
- }
493
- copyCClogFile(sessionId) {
494
- // 检查是否启用了跟踪
495
- if (!this.ccLogDir) {
496
- return;
497
- }
498
- //将当前会话对应的cc日志文件,拷贝到.claude-trace/cclog目录
499
- try {
500
- // 创建LogFileManager实例
501
- const logFileManager = new log_file_manager_1.LogFileManager();
502
- // 获取当前工作目录作为项目路径
503
- const currentProjectPath = process.cwd();
504
- // 通过LogFileManager解析源日志目录
505
- const sourceLogDir = logFileManager.resolveLogDirectory(currentProjectPath);
506
- // 构建源文件路径(假设源文件名为sessionId.jsonl)
507
- const sourceFile = path_1.default.join(sourceLogDir, `${sessionId}.jsonl`);
508
- // 构建目标文件路径
509
- this.ccLogFile = path_1.default.join(this.ccLogDir, `${sessionId}.jsonl`);
510
- // 检查源文件是否存在
511
- if (!fs_1.default.existsSync(sourceFile)) {
512
- console.log(`源CC日志文件不存在: ${sourceFile}`);
513
- return;
514
- }
515
- // 拷贝文件
516
- fs_1.default.copyFileSync(sourceFile, this.ccLogFile);
517
- console.log(`CC日志文件已从 ${sourceFile} 拷贝到 ${this.ccLogFile}`);
518
- // 读取sourceLogDir目录下所有agent_*.jsonl文件,读取第一条记录的sessionId,找到与sessionId变量值相同的文件,拷贝到ccLogDir目录
519
- const files = fs_1.default.readdirSync(sourceLogDir).filter(file => file.startsWith('agent-') && file.endsWith('.jsonl'));
520
- for (const file of files) {
521
- const filePath = path_1.default.join(sourceLogDir, file);
522
- const content = fs_1.default.readFileSync(filePath, 'utf-8');
523
- const lines = content.split('\n').filter(line => line.trim());
524
- if (lines.length > 0) {
525
- try {
526
- const firstRecord = JSON.parse(lines[0]);
527
- const recordSessionId = firstRecord?.sessionId;
528
- if (recordSessionId === sessionId) {
529
- // 构建目标文件路径
530
- const ccAgentLogFile = path_1.default.join(this.ccLogDir, file);
531
- // 拷贝文件
532
- fs_1.default.copyFileSync(filePath, ccAgentLogFile);
533
- console.log(`SubAgent的CC日志文件已从 ${filePath} 拷贝到 ${ccAgentLogFile}`);
534
- }
535
- }
536
- catch (parseError) {
537
- // 静默处理解析错误,继续下一个文件
538
- continue;
539
- }
540
- }
541
- }
542
- // 兼容subagents日志的另一种存放方式:sourceLogDir/{sessionId}/subagents/目录
543
- const subagentsDir = path_1.default.join(sourceLogDir, sessionId, 'subagents');
544
- if (fs_1.default.existsSync(subagentsDir)) {
545
- try {
546
- const subagentFiles = fs_1.default.readdirSync(subagentsDir).filter(file => file.startsWith('agent-') && file.endsWith('.jsonl'));
547
- for (const file of subagentFiles) {
548
- const sourceFilePath = path_1.default.join(subagentsDir, file);
549
- const targetFilePath = path_1.default.join(this.ccLogDir, file);
550
- // 直接拷贝文件,因为已经在正确的sessionId目录下
551
- fs_1.default.copyFileSync(sourceFilePath, targetFilePath);
552
- console.log(`SubAgent的CC日志文件已从 ${sourceFilePath} 拷贝到 ${targetFilePath}`);
553
- }
554
- }
555
- catch (error) {
556
- console.log(`处理subagents目录时出错: ${error}`);
557
- }
558
- }
559
- }
560
- catch (error) {
561
- console.log(`拷贝CC日志文件时出错: ${error}`);
562
- }
563
- }
564
- renameTraceLogFileBySessionId(sessionId) {
565
- // 检查是否启用了跟踪
566
- if (!this.traceLogFile) {
567
- return;
568
- }
569
- try {
570
- const logDir = path_1.default.dirname(this.traceLogFile);
571
- const newLogFile = path_1.default.join(logDir, `${sessionId}.jsonl`);
572
- // Rename the file
573
- fs_1.default.renameSync(this.traceLogFile, newLogFile);
574
- console.log(`Log file renamed from ${path_1.default.basename(this.traceLogFile)} to ${sessionId}.jsonl`);
575
- // Update the logFile path for future reference
576
- this.traceLogFile = newLogFile;
577
- }
578
- catch (error) {
579
- console.log(`Error renaming log file: ${error}`);
580
- }
581
- }
582
446
  getStats() {
583
447
  return {
584
448
  totalPairs: this.pairs.length,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myskyline_ai/ccdebug",
3
- "version": "0.2.17",
3
+ "version": "0.2.18",
4
4
  "description": "跟踪记录CC请求,可针对特定请求反复调试验证,以更直观的时间线形式展示CC日志",
5
5
  "publishConfig": {
6
6
  "access": "public"