cc-viewer 1.2.2 → 1.2.3
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/cli.js +45 -4
- package/interceptor.js +8 -4
- package/package.json +1 -1
- package/server.js +2 -2
package/cli.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
4
|
-
import { resolve } from 'node:path';
|
|
4
|
+
import { resolve, join } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
6
7
|
import { homedir } from 'node:os';
|
|
7
8
|
import { t } from './i18n.js';
|
|
8
9
|
|
|
@@ -17,7 +18,41 @@ const INJECT_BLOCK = `${INJECT_START}\n${INJECT_IMPORT}\n${INJECT_END}`;
|
|
|
17
18
|
const SHELL_HOOK_START = '# >>> CC-Viewer Auto-Inject >>>';
|
|
18
19
|
const SHELL_HOOK_END = '# <<< CC-Viewer Auto-Inject <<<';
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
// Claude Code cli.js 包名候选列表,按优先级排列
|
|
22
|
+
const CLAUDE_CODE_PACKAGES = [
|
|
23
|
+
'@anthropic-ai/claude-code',
|
|
24
|
+
'@ali/claude-code',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
function getGlobalNodeModulesDir() {
|
|
28
|
+
try {
|
|
29
|
+
return execSync('npm root -g', { encoding: 'utf-8' }).trim();
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolveClaudeCodeCliPath() {
|
|
36
|
+
// 候选基础目录:__dirname 的上级(适用于常规 npm 安装)+ 全局 node_modules(适用于符号链接安装)
|
|
37
|
+
const baseDirs = [resolve(__dirname, '..')];
|
|
38
|
+
const globalRoot = getGlobalNodeModulesDir();
|
|
39
|
+
if (globalRoot && globalRoot !== resolve(__dirname, '..')) {
|
|
40
|
+
baseDirs.push(globalRoot);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const baseDir of baseDirs) {
|
|
44
|
+
for (const packageName of CLAUDE_CODE_PACKAGES) {
|
|
45
|
+
const candidate = join(baseDir, packageName, 'cli.js');
|
|
46
|
+
if (existsSync(candidate)) {
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 兜底:返回全局目录下的默认路径,便于错误提示
|
|
52
|
+
return join(globalRoot || resolve(__dirname, '..'), CLAUDE_CODE_PACKAGES[0], 'cli.js');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cliPath = resolveClaudeCodeCliPath();
|
|
21
56
|
|
|
22
57
|
function getShellConfigPath() {
|
|
23
58
|
const shell = process.env.SHELL || '';
|
|
@@ -33,8 +68,14 @@ function getShellConfigPath() {
|
|
|
33
68
|
function buildShellHook() {
|
|
34
69
|
return `${SHELL_HOOK_START}
|
|
35
70
|
claude() {
|
|
36
|
-
local cli_js="
|
|
37
|
-
|
|
71
|
+
local cli_js=""
|
|
72
|
+
for candidate in "$HOME/.npm-global/lib/node_modules/@anthropic-ai/claude-code/cli.js" "$HOME/.npm-global/lib/node_modules/@ali/claude-code/cli.js"; do
|
|
73
|
+
if [ -f "$candidate" ]; then
|
|
74
|
+
cli_js="$candidate"
|
|
75
|
+
break
|
|
76
|
+
fi
|
|
77
|
+
done
|
|
78
|
+
if [ -n "$cli_js" ] && ! grep -q "CC Viewer" "$cli_js" 2>/dev/null; then
|
|
38
79
|
ccv 2>/dev/null
|
|
39
80
|
fi
|
|
40
81
|
command claude "$@"
|
package/interceptor.js
CHANGED
|
@@ -514,19 +514,23 @@ export function setupInterceptor() {
|
|
|
514
514
|
.map(block => {
|
|
515
515
|
// SSE 块可能包含多行: event: xxx\ndata: {...}
|
|
516
516
|
const lines = block.split('\n');
|
|
517
|
-
const dataLine = lines.find(l => l.startsWith('data:
|
|
517
|
+
const dataLine = lines.find(l => l.startsWith('data:'));
|
|
518
518
|
if (dataLine) {
|
|
519
|
+
// 处理 "data:" 或 "data: " 两种格式
|
|
520
|
+
const jsonStr = dataLine.startsWith('data: ')
|
|
521
|
+
? dataLine.substring(6)
|
|
522
|
+
: dataLine.substring(5);
|
|
519
523
|
try {
|
|
520
|
-
return JSON.parse(
|
|
524
|
+
return JSON.parse(jsonStr);
|
|
521
525
|
} catch {
|
|
522
|
-
return
|
|
526
|
+
return jsonStr;
|
|
523
527
|
}
|
|
524
528
|
}
|
|
525
529
|
return null;
|
|
526
530
|
})
|
|
527
531
|
.filter(Boolean);
|
|
528
532
|
|
|
529
|
-
// 组装完整的 message
|
|
533
|
+
// 组装完整的 message 对象(GLM 使用标准格式,但 data: 后无空格)
|
|
530
534
|
const assembledMessage = assembleStreamMessage(events);
|
|
531
535
|
|
|
532
536
|
// 直接使用组装后的 message 对象作为 response.body
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -598,7 +598,7 @@ export async function startViewer() {
|
|
|
598
598
|
return new Promise((resolve, reject) => {
|
|
599
599
|
function tryListen(port) {
|
|
600
600
|
if (port > MAX_PORT) {
|
|
601
|
-
console.
|
|
601
|
+
console.error(t('server.portsBusy', { start: START_PORT, end: MAX_PORT }));
|
|
602
602
|
resolve(null);
|
|
603
603
|
return;
|
|
604
604
|
}
|
|
@@ -609,7 +609,7 @@ export async function startViewer() {
|
|
|
609
609
|
server = currentServer;
|
|
610
610
|
actualPort = port;
|
|
611
611
|
const url = `http://${HOST}:${port}`;
|
|
612
|
-
console.
|
|
612
|
+
console.error(t('server.started', { host: HOST, port }));
|
|
613
613
|
// v2.0.69 之前的版本会清空控制台,自动打开浏览器确保用户能看到界面
|
|
614
614
|
try {
|
|
615
615
|
const ccPkgPath = join(__dirname, '..', '@anthropic-ai', 'claude-code', 'package.json');
|