cc-viewer 1.6.317 → 1.6.319
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/dist/assets/App-CGjNy_0v.js +2 -0
- package/dist/assets/{MdxEditorPanel-DUuntF_N.js → MdxEditorPanel-D1QgbU1C.js} +1 -1
- package/dist/assets/Mobile-CfjrWbCr.js +1 -0
- package/dist/assets/{index-GjHuuuMx.js → index-nk1eaFci.js} +2 -2
- package/dist/assets/seqResourceLoaders-Y-0LM2t9.js +2 -0
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/server/lib/interceptor-core.js +7 -0
- package/server/lib/kv-cache-analyzer.js +9 -0
- package/server/lib/stats-worker.js +62 -3
- package/dist/assets/App-D-fXJm25.js +0 -2
- package/dist/assets/Mobile-axZHQmGd.js +0 -1
- package/dist/assets/seqResourceLoaders-BkngOp0i.js +0 -2
package/dist/index.html
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// 整体显示大小已弃用 CSS zoom:Electron 改用 webFrame.setZoomFactor(首屏抢占见
|
|
22
22
|
// electron/tab-content-preload.js),纯浏览器交由用户用浏览器自带快捷键缩放,故此处不再设 zoom。
|
|
23
23
|
</script>
|
|
24
|
-
<script type="module" crossorigin src="/assets/index-
|
|
24
|
+
<script type="module" crossorigin src="/assets/index-nk1eaFci.js"></script>
|
|
25
25
|
<link rel="modulepreload" crossorigin href="/assets/vendor-antd-UnftwvMU.js">
|
|
26
26
|
<link rel="modulepreload" crossorigin href="/assets/vendor-codemirror-BAehR6rN.js">
|
|
27
27
|
<link rel="modulepreload" crossorigin href="/assets/vendor-mdxeditor-Cq-CSRE5.js">
|
package/package.json
CHANGED
|
@@ -4,6 +4,11 @@ import { join } from 'node:path';
|
|
|
4
4
|
|
|
5
5
|
const SUBAGENT_SYSTEM_RE = /(?:command execution|file search|planning) specialist|general-purpose agent|security monitor|performing a web search/i;
|
|
6
6
|
|
|
7
|
+
// cc_version 2.1.181+:CLI 在 billing header 显式标注子代理(cc_is_subagent=true);真·主代理省略此字段(从不为 =false)。
|
|
8
|
+
// 这类子代理继承完整 "You are Claude Code" prompt + Edit/Bash/Agent 工具,会误中轻量 MainAgent 启发式,故须显式排除。
|
|
9
|
+
// 结尾 \b 锚定:仅匹配 `=true`(其后为 `;` / 空白 / 串尾),避免 `=truex` 之类误匹配。
|
|
10
|
+
const SUBAGENT_BILLING_RE = /cc_is_subagent=true\b/;
|
|
11
|
+
|
|
7
12
|
export function getSystemText(body) {
|
|
8
13
|
const system = body?.system;
|
|
9
14
|
if (typeof system === 'string') return system;
|
|
@@ -17,6 +22,8 @@ export function isMainAgentRequest(body) {
|
|
|
17
22
|
if (!body?.system || !Array.isArray(body?.tools)) return false;
|
|
18
23
|
|
|
19
24
|
const sysText = getSystemText(body);
|
|
25
|
+
// cc_is_subagent=true ⇒ 子代理,绝非 MainAgent(cc_version 2.1.181+)。从源头让新日志的 mainAgent 字段为 false。
|
|
26
|
+
if (SUBAGENT_BILLING_RE.test(sysText)) return false;
|
|
20
27
|
if (!sysText.includes('You are Claude Code')) return false;
|
|
21
28
|
if (SUBAGENT_SYSTEM_RE.test(sysText)) return false;
|
|
22
29
|
|
|
@@ -7,6 +7,10 @@ import { formatToolAsXml } from './tools-xml-formatter.js';
|
|
|
7
7
|
export { formatToolAsXml };
|
|
8
8
|
|
|
9
9
|
const SUBAGENT_SYSTEM_RE = /command execution specialist|file search specialist|planning specialist|general-purpose agent|security monitor|performing a web search/i;
|
|
10
|
+
// cc_version 2.1.181+: billing header marks subagents (cc_is_subagent=true); genuine main omits it (never =false).
|
|
11
|
+
// Such subagents inherit the full "You are Claude Code" prompt + Edit/Bash/Agent tools and would otherwise hit the
|
|
12
|
+
// lightweight heuristic below. \b anchor avoids matching =truex. KEEP IN SYNC with src/utils/contentFilter.js + interceptor-core.js.
|
|
13
|
+
const SUBAGENT_BILLING_RE = /cc_is_subagent=true\b/;
|
|
10
14
|
const TEAMMATE_SYSTEM_RE = /running as an agent in a team|Agent Teammate Communication/i;
|
|
11
15
|
|
|
12
16
|
function getSystemText(body) {
|
|
@@ -29,6 +33,11 @@ export function isMainAgentEntry(entry) {
|
|
|
29
33
|
const sysText = getSystemText(entry.body || {});
|
|
30
34
|
if (TEAMMATE_SYSTEM_RE.test(sysText)) return false;
|
|
31
35
|
|
|
36
|
+
// cc_is_subagent=true ⇒ subagent (cc 2.1.181+), never MainAgent. Before the mainAgent-flag short-circuit
|
|
37
|
+
// so already-logged entries (flag baked true) are corrected too, and so new entries (flag now false) don't
|
|
38
|
+
// fall through to the lightweight heuristic below and get mis-classified.
|
|
39
|
+
if (SUBAGENT_BILLING_RE.test(sysText)) return false;
|
|
40
|
+
|
|
32
41
|
if (entry.mainAgent === true) {
|
|
33
42
|
if (SUBAGENT_SYSTEM_RE.test(sysText)) return false;
|
|
34
43
|
return true;
|
|
@@ -7,8 +7,21 @@ import { resolveJsonlPath } from './jsonl-archive.js';
|
|
|
7
7
|
// 统计 schema 版本号,新增统计字段时递增,强制旧缓存失效重新解析
|
|
8
8
|
const STATS_VERSION = 8;
|
|
9
9
|
|
|
10
|
+
// 跨会话 / teammate 协议通知 type 白名单(须与 src/utils/contentFilter.js 的 INTER_SESSION_NOTIFICATION_TYPES
|
|
11
|
+
// 一致;新增 type 时两处都要加)。单一数组派生 Set(brace 扫描用)+ 正则(isSystemText 用),避免本文件内漂移。
|
|
12
|
+
// test/stats-worker-notification-filter.test.js 有 frontend↔server 同步守卫断言。
|
|
13
|
+
export const INTER_SESSION_TYPES = [
|
|
14
|
+
'idle_notification', 'shutdown_request', 'shutdown_response', 'shutdown_approved',
|
|
15
|
+
'teammate_terminated', 'plan_approval_request', 'plan_approval_response',
|
|
16
|
+
];
|
|
17
|
+
const INTER_SESSION_TYPES_SET = new Set(INTER_SESSION_TYPES);
|
|
18
|
+
const INTER_SESSION_TYPES_RE = new RegExp(`"type"\\s*:\\s*"(?:${INTER_SESSION_TYPES.join('|')})"`);
|
|
19
|
+
|
|
10
20
|
/**
|
|
11
|
-
*
|
|
21
|
+
* 判断文本是否为系统注入文本。
|
|
22
|
+
* 注意:这是服务端「子集」实现,只覆盖 project-stats 预览过滤所需规则,并非 contentFilter 的完整副本——
|
|
23
|
+
* 完整分类(synthetic prompt、二次回收等)见 src/utils/contentFilter.js:isSystemText。前端(dist)与后端(server)
|
|
24
|
+
* 分属两个 bundle、无法直接共享同一模块,故此处仅同步「会泄漏进预览」的关键规则:系统标签 + 跨会话队友通知。
|
|
12
25
|
*/
|
|
13
26
|
function isSystemText(text) {
|
|
14
27
|
if (!text) return true;
|
|
@@ -16,18 +29,61 @@ function isSystemText(text) {
|
|
|
16
29
|
if (!trimmed) return true;
|
|
17
30
|
// 包含 plan 内容的文本块不应被过滤(即使开头有系统标签)
|
|
18
31
|
if (/Implement the following plan:/i.test(trimmed)) return false;
|
|
19
|
-
if (/^<[a-zA-Z_][\w-]*[\s>]/i.test(trimmed)) return true;
|
|
32
|
+
if (/^<[a-zA-Z_][\w-]*[\s>]/i.test(trimmed)) return true; // 含 <teammate-message> 包裹形态
|
|
20
33
|
if (/^\[SUGGESTION MODE:/i.test(trimmed)) return true;
|
|
21
34
|
if (/^Your response was cut off because it exceeded the output token limit/i.test(trimmed)) return true;
|
|
22
35
|
if (/^Base directory for this skill:/i.test(trimmed)) return true;
|
|
36
|
+
// 未包裹的跨会话队友通知:前缀行 / 新版 caveat / 裸协议 JSON —— 防泄漏进 stats 预览当成用户 prompt
|
|
37
|
+
if (/^Another Claude session sent a message:/i.test(trimmed)) return true;
|
|
38
|
+
if (/^This came from another Claude session\b/i.test(trimmed)) return true;
|
|
39
|
+
if (trimmed.startsWith('{') && INTER_SESSION_TYPES_RE.test(trimmed)) return true;
|
|
23
40
|
return false;
|
|
24
41
|
}
|
|
25
42
|
|
|
43
|
+
// 单次扫描剔除顶层协议通知 JSON(brace 配对,正确处理嵌套;跳过字符串字面量内的花括号 / 转义)。
|
|
44
|
+
// 与 src/utils/contentFilter.js 的 scanTopLevelJsonObjects + extractProtocolNotifications 同语义——
|
|
45
|
+
// 旧的 `\{[^{}]*...[^{}]*\}` 正则无法跨嵌套花括号,含嵌套字段的协议体(如 plan_approval_*)会漏剥。
|
|
46
|
+
function stripProtocolJson(s) {
|
|
47
|
+
if (typeof s !== 'string' || s.indexOf('{') === -1) return s;
|
|
48
|
+
let out = '', cursor = 0, depth = 0, start = -1, inStr = false, esc = false;
|
|
49
|
+
for (let i = 0; i < s.length; i++) {
|
|
50
|
+
const ch = s[i];
|
|
51
|
+
if (inStr) {
|
|
52
|
+
if (esc) esc = false;
|
|
53
|
+
else if (ch === '\\') esc = true;
|
|
54
|
+
else if (ch === '"') inStr = false;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (ch === '"') inStr = true;
|
|
58
|
+
else if (ch === '{') { if (depth === 0) start = i; depth++; }
|
|
59
|
+
else if (ch === '}' && depth > 0) {
|
|
60
|
+
depth--;
|
|
61
|
+
if (depth === 0 && start >= 0) {
|
|
62
|
+
let j; try { j = JSON.parse(s.slice(start, i + 1)); } catch { j = null; }
|
|
63
|
+
if (j && typeof j.type === 'string' && INTER_SESSION_TYPES_SET.has(j.type)) {
|
|
64
|
+
out += s.slice(cursor, start);
|
|
65
|
+
cursor = i + 1;
|
|
66
|
+
}
|
|
67
|
+
start = -1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
out += s.slice(cursor);
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
|
|
26
75
|
/**
|
|
27
76
|
* 剥离系统注入标签,保留标签外的用户文本(仅用于 string 类型 content 的混合内容场景)
|
|
28
77
|
*/
|
|
29
78
|
function stripSystemTags(text) {
|
|
30
|
-
|
|
79
|
+
let out = text
|
|
80
|
+
.replace(/<(system-reminder|local-command-caveat|project-reminder|important-instruction-reminders|file-modified-reminder|todo-reminder|user-prompt-submit-hook|local-command-stdout|command-name|task-notification|environment_details|context|teammate-message)\b[^>]*>[\s\S]*?<\/\1>/gi, '')
|
|
81
|
+
// 未包裹跨会话队友通知的 chrome:前缀行 + 两版 caveat + 裸协议 JSON(含嵌套),剥掉后回收用户混入正文
|
|
82
|
+
.replace(/^Another Claude session sent a message:\s*/i, '')
|
|
83
|
+
.replace(/(^|\n)This came from another Claude session[\s\S]*?(?=\n\n|$)/i, '')
|
|
84
|
+
.replace(/(^|\n)IMPORTANT: This is NOT from your user[\s\S]*?(?=\n\n|$)/i, '');
|
|
85
|
+
out = stripProtocolJson(out);
|
|
86
|
+
return out.trim();
|
|
31
87
|
}
|
|
32
88
|
|
|
33
89
|
/**
|
|
@@ -355,6 +411,9 @@ function scanAllProjects(logDir) {
|
|
|
355
411
|
}
|
|
356
412
|
}
|
|
357
413
|
|
|
414
|
+
// 供单元测试引用的内部纯函数(worker 入口逻辑走 parentPort,不受 export 影响)
|
|
415
|
+
export { isSystemText, extractUserTexts };
|
|
416
|
+
|
|
358
417
|
// Worker 消息处理
|
|
359
418
|
parentPort?.on('message', (msg) => {
|
|
360
419
|
switch (msg.type) {
|