cc-viewer 0.1.5 → 0.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/lib/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Claude Code Viewer</title>
7
7
 
8
- <script type="module" crossorigin src="/assets/index-W-UhJiNi.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-BX8W4MxH.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-C7-c9XfU.css">
10
10
  </head>
11
11
  <body>
package/lib/server.js CHANGED
@@ -1,8 +1,13 @@
1
1
  import { createServer, request as httpRequest } from 'node:http';
2
- import { readFileSync, existsSync, watchFile, unwatchFile, statSync, writeFileSync, unlinkSync } from 'node:fs';
2
+ import { readFileSync, existsSync, watchFile, unwatchFile, statSync, writeFileSync, unlinkSync, readdirSync, openSync, closeSync } from 'node:fs';
3
3
  import { fileURLToPath } from 'node:url';
4
- import { dirname, join, extname } from 'node:path';
4
+ import { dirname, join, extname, basename } from 'node:path';
5
+ import { homedir } from 'node:os';
5
6
  import { LOG_FILE } from '../interceptor.js';
7
+ import { t } from '../i18n.js';
8
+
9
+ const LOG_DIR = join(homedir(), '.claude', 'cc-viewer');
10
+ const SHOW_ALL_FILE = '/tmp/cc-viewer-show-all';
6
11
 
7
12
  const __filename = fileURLToPath(import.meta.url);
8
13
  const __dirname = dirname(__filename);
@@ -10,6 +15,34 @@ const START_PORT = 7008;
10
15
  const MAX_PORT = 7099;
11
16
  const HOST = '127.0.0.1';
12
17
  const PORT_FILE = '/tmp/cc-viewer-port';
18
+ const LOCK_FILE = '/tmp/cc-viewer-lock';
19
+
20
+ function acquireLock() {
21
+ try {
22
+ // wx flag: exclusive create, fails if file already exists
23
+ const fd = openSync(LOCK_FILE, 'wx');
24
+ writeFileSync(fd, String(process.pid));
25
+ closeSync(fd);
26
+ return true;
27
+ } catch {
28
+ // 检查锁文件是否过期(超过 10 秒视为过期)
29
+ try {
30
+ const stat = statSync(LOCK_FILE);
31
+ if (Date.now() - stat.mtimeMs > 10000) {
32
+ unlinkSync(LOCK_FILE);
33
+ const fd = openSync(LOCK_FILE, 'wx');
34
+ writeFileSync(fd, String(process.pid));
35
+ closeSync(fd);
36
+ return true;
37
+ }
38
+ } catch {}
39
+ return false;
40
+ }
41
+ }
42
+
43
+ function releaseLock() {
44
+ try { unlinkSync(LOCK_FILE); } catch {}
45
+ }
13
46
 
14
47
  function checkPortAlive(port) {
15
48
  return new Promise((resolve) => {
@@ -138,6 +171,93 @@ function handleRequest(req, res) {
138
171
  return;
139
172
  }
140
173
 
174
+ // 查询是否显示全部请求(包括心跳)
175
+ if (url === '/api/show-all' && method === 'GET') {
176
+ const showAll = existsSync(SHOW_ALL_FILE);
177
+ res.writeHead(200, { 'Content-Type': 'application/json' });
178
+ res.end(JSON.stringify({ showAll }));
179
+ return;
180
+ }
181
+
182
+ // 列出本地日志文件(按项目分组)
183
+ if (url === '/api/local-logs' && method === 'GET') {
184
+ try {
185
+ const files = existsSync(LOG_DIR)
186
+ ? readdirSync(LOG_DIR).filter(f => f.endsWith('.jsonl')).sort().reverse()
187
+ : [];
188
+ // 按项目名分组: {projectName: [{file, timestamp, size}]}
189
+ const grouped = {};
190
+ for (const f of files) {
191
+ const match = f.match(/^(.+?)_(\d{8}_\d{6})\.jsonl$/);
192
+ if (!match) continue;
193
+ const project = match[1];
194
+ const ts = match[2]; // 20260217_224218
195
+ const filePath = join(LOG_DIR, f);
196
+ const size = statSync(filePath).size;
197
+ if (!grouped[project]) grouped[project] = [];
198
+ grouped[project].push({ file: f, timestamp: ts, size });
199
+ }
200
+ res.writeHead(200, { 'Content-Type': 'application/json' });
201
+ res.end(JSON.stringify(grouped));
202
+ } catch (err) {
203
+ res.writeHead(500, { 'Content-Type': 'application/json' });
204
+ res.end(JSON.stringify({ error: err.message }));
205
+ }
206
+ return;
207
+ }
208
+
209
+ // 读取指定本地日志文件
210
+ if (url.startsWith('/api/local-log?') && method === 'GET') {
211
+ const params = new URLSearchParams(url.split('?')[1]);
212
+ const file = params.get('file');
213
+ if (!file || file.includes('..') || file.includes('/')) {
214
+ res.writeHead(400, { 'Content-Type': 'application/json' });
215
+ res.end(JSON.stringify({ error: 'Invalid file name' }));
216
+ return;
217
+ }
218
+ const filePath = join(LOG_DIR, file);
219
+ try {
220
+ if (!existsSync(filePath)) {
221
+ res.writeHead(404, { 'Content-Type': 'application/json' });
222
+ res.end(JSON.stringify({ error: 'File not found' }));
223
+ return;
224
+ }
225
+ const content = readFileSync(filePath, 'utf-8');
226
+ const entries = content.split('\n---\n').filter(line => line.trim()).map(entry => {
227
+ try { return JSON.parse(entry); } catch { return null; }
228
+ }).filter(Boolean);
229
+ res.writeHead(200, { 'Content-Type': 'application/json' });
230
+ res.end(JSON.stringify(entries));
231
+ } catch (err) {
232
+ res.writeHead(500, { 'Content-Type': 'application/json' });
233
+ res.end(JSON.stringify({ error: err.message }));
234
+ }
235
+ return;
236
+ }
237
+
238
+ // 下载当前日志文件
239
+ if (url === '/api/download-log' && method === 'GET') {
240
+ try {
241
+ if (!existsSync(LOG_FILE)) {
242
+ res.writeHead(404, { 'Content-Type': 'application/json' });
243
+ res.end(JSON.stringify({ error: 'Log file not found' }));
244
+ return;
245
+ }
246
+ const content = readFileSync(LOG_FILE);
247
+ const fileName = basename(LOG_FILE);
248
+ res.writeHead(200, {
249
+ 'Content-Type': 'application/octet-stream',
250
+ 'Content-Disposition': `attachment; filename="${fileName}"`,
251
+ 'Content-Length': content.length,
252
+ });
253
+ res.end(content);
254
+ } catch (err) {
255
+ res.writeHead(500, { 'Content-Type': 'application/json' });
256
+ res.end(JSON.stringify({ error: err.message }));
257
+ }
258
+ return;
259
+ }
260
+
141
261
  // 静态文件服务
142
262
  if (method === 'GET') {
143
263
  let filePath = url === '/' ? '/index.html' : url;
@@ -177,55 +297,84 @@ function handleRequest(req, res) {
177
297
  }
178
298
 
179
299
  export async function startViewer() {
180
- // 检查是否已有 cc-viewer 实例在运行
181
- if (existsSync(PORT_FILE)) {
182
- try {
183
- const existingPort = parseInt(readFileSync(PORT_FILE, 'utf-8').trim(), 10);
184
- if (existingPort >= START_PORT && existingPort <= MAX_PORT) {
185
- const alive = await checkPortAlive(existingPort);
186
- if (alive) {
187
- actualPort = existingPort;
188
- console.log(`\n🔍 CC Viewer 已在运行: http://${HOST}:${existingPort}\n`);
189
- return null;
300
+ // 尝试获取文件锁,防止多个进程同时启动服务器
301
+ if (!acquireLock()) {
302
+ // 另一个进程正在启动,等待它完成后复用
303
+ await new Promise(resolve => setTimeout(resolve, 2000));
304
+ if (existsSync(PORT_FILE)) {
305
+ try {
306
+ const existingPort = parseInt(readFileSync(PORT_FILE, 'utf-8').trim(), 10);
307
+ if (existingPort >= START_PORT && existingPort <= MAX_PORT) {
308
+ const alive = await checkPortAlive(existingPort);
309
+ if (alive) {
310
+ actualPort = existingPort;
311
+ return null;
312
+ }
190
313
  }
191
- }
192
- } catch {
193
- // PORT_FILE 读取失败,继续正常启动
314
+ } catch {}
194
315
  }
195
- // 旧实例已不存在,清理 PORT_FILE
196
- try { unlinkSync(PORT_FILE); } catch {}
316
+ // 等待后仍无法复用,静默退出
317
+ return null;
197
318
  }
198
319
 
199
- return new Promise((resolve, reject) => {
200
- function tryListen(port) {
201
- if (port > MAX_PORT) {
202
- console.log(`⚠️ 端口 ${START_PORT}-${MAX_PORT} 均被占用,请求监控服务未启动`);
203
- resolve(null);
204
- return;
320
+ try {
321
+ // 检查是否已有 cc-viewer 实例在运行
322
+ if (existsSync(PORT_FILE)) {
323
+ try {
324
+ const existingPort = parseInt(readFileSync(PORT_FILE, 'utf-8').trim(), 10);
325
+ if (existingPort >= START_PORT && existingPort <= MAX_PORT) {
326
+ const alive = await checkPortAlive(existingPort);
327
+ if (alive) {
328
+ actualPort = existingPort;
329
+ releaseLock();
330
+ console.log(t('server.reuse', { host: HOST, port: existingPort }));
331
+ return null;
332
+ }
333
+ }
334
+ } catch {
335
+ // PORT_FILE 读取失败,继续正常启动
205
336
  }
337
+ // 旧实例已不存在,清理 PORT_FILE
338
+ try { unlinkSync(PORT_FILE); } catch {}
339
+ }
206
340
 
207
- const currentServer = createServer(handleRequest);
341
+ return new Promise((resolve, reject) => {
342
+ function tryListen(port) {
343
+ if (port > MAX_PORT) {
344
+ console.log(t('server.portsBusy', { start: START_PORT, end: MAX_PORT }));
345
+ releaseLock();
346
+ resolve(null);
347
+ return;
348
+ }
208
349
 
209
- currentServer.listen(port, HOST, () => {
210
- server = currentServer;
211
- actualPort = port;
212
- try { writeFileSync(PORT_FILE, String(port)); } catch {}
213
- console.log(`\n🔍 Claude 请求监控服务已启动: http://${HOST}:${port}\n`);
214
- startWatching();
215
- resolve(server);
216
- });
350
+ const currentServer = createServer(handleRequest);
217
351
 
218
- currentServer.on('error', (err) => {
219
- if (err.code === 'EADDRINUSE') {
220
- tryListen(port + 1);
221
- } else {
222
- reject(err);
223
- }
224
- });
225
- }
352
+ currentServer.listen(port, HOST, () => {
353
+ server = currentServer;
354
+ actualPort = port;
355
+ try { writeFileSync(PORT_FILE, String(port)); } catch {}
356
+ releaseLock();
357
+ console.log(t('server.started', { host: HOST, port }));
358
+ startWatching();
359
+ resolve(server);
360
+ });
226
361
 
227
- tryListen(START_PORT);
228
- });
362
+ currentServer.on('error', (err) => {
363
+ if (err.code === 'EADDRINUSE') {
364
+ tryListen(port + 1);
365
+ } else {
366
+ releaseLock();
367
+ reject(err);
368
+ }
369
+ });
370
+ }
371
+
372
+ tryListen(START_PORT);
373
+ });
374
+ } catch (err) {
375
+ releaseLock();
376
+ throw err;
377
+ }
229
378
  }
230
379
 
231
380
  export function stopViewer() {
@@ -0,0 +1,62 @@
1
+ {
2
+ "cli.inject.success": "✅ CC Viewer تم الحقن بنجاح",
3
+ "cli.inject.exists": "✅ CC Viewer محقون بالفعل، لا حاجة لأي إجراء",
4
+ "cli.inject.fail": "❌ فشل الحقن: {error}",
5
+ "cli.inject.notFound": "❌ لم يتم العثور على Claude Code cli.js: {path}",
6
+ "cli.inject.notFoundHint": " يرجى التأكد من تثبيت @anthropic-ai/claude-code",
7
+ "cli.hook.installed": "✅ تم كتابة hook إعادة الحقن التلقائي في {path}",
8
+ "cli.hook.exists": "✅ hook إعادة الحقن التلقائي موجود بالفعل في {path}",
9
+ "cli.hook.fail": "⚠️ فشل كتابة shell hook: {error}",
10
+ "cli.usage.hint": "\nقم بتشغيل claude مباشرة. سيتم إعادة الحقن تلقائياً بعد تحديثات Claude Code",
11
+ "cli.usage.uninstallHint": "لإلغاء التثبيت، قم بتشغيل: ccv --uninstall",
12
+ "cli.uninstall.cliCleaned": "✅ تم تنظيف حقن cli.js",
13
+ "cli.uninstall.cliNotFound": "⚠️ لم يتم العثور على Claude Code cli.js، تم التخطي",
14
+ "cli.uninstall.cliFail": "❌ فشل تنظيف حقن cli.js",
15
+ "cli.uninstall.hookRemoved": "✅ تم إزالة shell hook من {path}",
16
+ "cli.uninstall.hookClean": "✅ لا حاجة للتنظيف في {path}",
17
+ "cli.uninstall.hookFail": "❌ فشل تنظيف shell hook: {error}",
18
+ "cli.uninstall.done": "\n🗑️ تم إلغاء تثبيت CC Viewer بالكامل",
19
+
20
+ "server.started": "\n🔍 تم تشغيل CC Viewer: http://{host}:{port}\n",
21
+ "server.reuse": "\n🔍 CC Viewer يعمل بالفعل: http://{host}:{port}\n",
22
+ "server.portsBusy": "⚠️ المنافذ {start}-{end} كلها مشغولة، لم يتم تشغيل خدمة المراقبة",
23
+
24
+ "ui.requestList": "الطلبات",
25
+ "ui.totalRequests": "الإجمالي: {count}",
26
+ "ui.waitingRequests": "في انتظار الطلبات...",
27
+ "ui.importLocalLogs": "استيراد السجلات المحلية",
28
+ "ui.saveLog": "حفظ السجل الحالي",
29
+ "ui.exportPrompts": "تصدير Prompt المستخدم",
30
+ "ui.tokenStats": "إحصائيات Token",
31
+ "ui.liveMonitoring": "مباشر",
32
+ "ui.historyLog": "السجل: {file}",
33
+ "ui.chatMode": "وضع المحادثة",
34
+ "ui.rawMode": "العودة للوضع الخام",
35
+ "ui.cacheExpired": "منتهي الصلاحية",
36
+ "ui.cacheCountdown": "ينتهي cache{type} لـ MainAgent خلال: ",
37
+ "ui.minuteSecond": "{m}د{s}ث",
38
+ "ui.second": "{s}ث",
39
+ "ui.hitRate": "معدل الإصابة",
40
+ "ui.userPrompt": "Prompt المستخدم",
41
+ "ui.noPrompt": "لا توجد Prompt للمستخدم بعد",
42
+ "ui.unknownTime": "وقت غير معروف",
43
+ "ui.userSelection": "👤 اختيار المستخدم",
44
+ "ui.noAnswer": "لا إجابة",
45
+ "ui.systemContext": "سياق النظام #{index}",
46
+ "ui.logCount": "{count} سجلات",
47
+ "ui.noLogs": "لا توجد ملفات سجلات",
48
+
49
+ "ui.toolReturn": "نتيجة الأداة",
50
+ "ui.toolReturnNamed": "نتيجة {name}",
51
+ "ui.lastResponse": "Last Response",
52
+
53
+ "ui.copySuccess": "تم النسخ",
54
+ "ui.noHeaders": "لا يوجد Headers",
55
+ "ui.noBody": "لا يوجد Body",
56
+ "ui.streamingResponse": "⚡ استجابة متدفقة — استخدم هذا الطلب بث SSE، لا يمكن التقاط محتوى الاستجابة بالكامل.",
57
+ "ui.responseNotCaptured": "لم يتم التقاط بيانات الاستجابة",
58
+
59
+ "ui.expand": "▶ توسيع",
60
+ "ui.collapse": "▼ طي",
61
+ "ui.noChat": "لا توجد بيانات محادثة MainAgent"
62
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "cli.inject.success": "✅ CC Viewer indsprøjtet korrekt",
3
+ "cli.inject.exists": "✅ CC Viewer allerede indsprøjtet, ingen handling nødvendig",
4
+ "cli.inject.fail": "❌ Indsprøjtning mislykkedes: {error}",
5
+ "cli.inject.notFound": "❌ Claude Code cli.js ikke fundet: {path}",
6
+ "cli.inject.notFoundHint": " Sørg for at @anthropic-ai/claude-code er installeret",
7
+ "cli.hook.installed": "✅ Auto-reinject hook skrevet til {path}",
8
+ "cli.hook.exists": "✅ Auto-reinject hook findes allerede i {path}",
9
+ "cli.hook.fail": "⚠️ Kunne ikke skrive shell hook: {error}",
10
+ "cli.usage.hint": "\nKør claude direkte. Det vil automatisk genindsprøjte efter Claude Code opdateringer",
11
+ "cli.usage.uninstallHint": "For at afinstallere, kør: ccv --uninstall",
12
+ "cli.uninstall.cliCleaned": "✅ cli.js indsprøjtning renset",
13
+ "cli.uninstall.cliNotFound": "⚠️ Claude Code cli.js ikke fundet, sprunget over",
14
+ "cli.uninstall.cliFail": "❌ Kunne ikke rense cli.js indsprøjtning",
15
+ "cli.uninstall.hookRemoved": "✅ Shell hook fjernet fra {path}",
16
+ "cli.uninstall.hookClean": "✅ Ingen oprydning nødvendig i {path}",
17
+ "cli.uninstall.hookFail": "❌ Kunne ikke rense shell hook: {error}",
18
+ "cli.uninstall.done": "\n🗑️ CC Viewer fuldstændigt afinstalleret",
19
+
20
+ "server.started": "\n🔍 CC Viewer startet: http://{host}:{port}\n",
21
+ "server.reuse": "\n🔍 CC Viewer kører allerede: http://{host}:{port}\n",
22
+ "server.portsBusy": "⚠️ Porte {start}-{end} er alle i brug, overvågningstjeneste ikke startet",
23
+
24
+ "ui.requestList": "Forespørgsler",
25
+ "ui.totalRequests": "Total: {count}",
26
+ "ui.waitingRequests": "Venter på forespørgsler...",
27
+ "ui.importLocalLogs": "Importér lokale logs",
28
+ "ui.saveLog": "Gem nuværende log",
29
+ "ui.exportPrompts": "Eksportér bruger-prompts",
30
+ "ui.tokenStats": "Token-statistik",
31
+ "ui.liveMonitoring": "Live",
32
+ "ui.historyLog": "Historik: {file}",
33
+ "ui.chatMode": "Chat-tilstand",
34
+ "ui.rawMode": "Tilbage til rå tilstand",
35
+ "ui.cacheExpired": "Udløbet",
36
+ "ui.cacheCountdown": "MainAgent cache{type} udløber om: ",
37
+ "ui.minuteSecond": "{m}m{s}s",
38
+ "ui.second": "{s}s",
39
+ "ui.hitRate": "Hitrate",
40
+ "ui.userPrompt": "Bruger-Prompt",
41
+ "ui.noPrompt": "Ingen bruger-prompts endnu",
42
+ "ui.unknownTime": "Ukendt tid",
43
+ "ui.userSelection": "👤 Brugervalg",
44
+ "ui.noAnswer": "Intet svar",
45
+ "ui.systemContext": "Systemkontekst #{index}",
46
+ "ui.logCount": "{count} logs",
47
+ "ui.noLogs": "Ingen logfiler",
48
+
49
+ "ui.toolReturn": "Værktøjsresultat",
50
+ "ui.toolReturnNamed": "{name}-resultat",
51
+ "ui.lastResponse": "Last Response",
52
+
53
+ "ui.copySuccess": "Kopieret",
54
+ "ui.noHeaders": "Ingen Headers",
55
+ "ui.noBody": "Ingen Body",
56
+ "ui.streamingResponse": "⚡ Streaming-svar — Denne forespørgsel brugte SSE-streaming, svarindholdet kunne ikke fuldt indfanges.",
57
+ "ui.responseNotCaptured": "Svardata ikke indfanget",
58
+
59
+ "ui.expand": "▶ Udvid",
60
+ "ui.collapse": "▼ Fold sammen",
61
+ "ui.noChat": "Ingen MainAgent samtaledata"
62
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "cli.inject.success": "✅ CC Viewer erfolgreich injiziert",
3
+ "cli.inject.exists": "✅ CC Viewer bereits injiziert, keine Aktion nötig",
4
+ "cli.inject.fail": "❌ Injektion fehlgeschlagen: {error}",
5
+ "cli.inject.notFound": "❌ Claude Code cli.js nicht gefunden: {path}",
6
+ "cli.inject.notFoundHint": " Bitte stellen Sie sicher, dass @anthropic-ai/claude-code installiert ist",
7
+ "cli.hook.installed": "✅ Auto-Reinject-Hook in {path} geschrieben",
8
+ "cli.hook.exists": "✅ Auto-Reinject-Hook existiert bereits in {path}",
9
+ "cli.hook.fail": "⚠️ Shell-Hook konnte nicht geschrieben werden: {error}",
10
+ "cli.usage.hint": "\nFühren Sie claude direkt aus. Nach Claude Code Updates wird automatisch neu injiziert",
11
+ "cli.usage.uninstallHint": "Zum Deinstallieren: ccv --uninstall",
12
+ "cli.uninstall.cliCleaned": "✅ cli.js-Injektion bereinigt",
13
+ "cli.uninstall.cliNotFound": "⚠️ Claude Code cli.js nicht gefunden, übersprungen",
14
+ "cli.uninstall.cliFail": "❌ cli.js-Injektion konnte nicht bereinigt werden",
15
+ "cli.uninstall.hookRemoved": "✅ Shell-Hook aus {path} entfernt",
16
+ "cli.uninstall.hookClean": "✅ Keine Bereinigung in {path} nötig",
17
+ "cli.uninstall.hookFail": "❌ Shell-Hook-Bereinigung fehlgeschlagen: {error}",
18
+ "cli.uninstall.done": "\n🗑️ CC Viewer vollständig deinstalliert",
19
+
20
+ "server.started": "\n🔍 CC Viewer gestartet: http://{host}:{port}\n",
21
+ "server.reuse": "\n🔍 CC Viewer läuft bereits: http://{host}:{port}\n",
22
+ "server.portsBusy": "⚠️ Ports {start}-{end} sind alle belegt, Überwachungsdienst nicht gestartet",
23
+
24
+ "ui.requestList": "Anfragen",
25
+ "ui.totalRequests": "Gesamt: {count}",
26
+ "ui.waitingRequests": "Warte auf Anfragen...",
27
+ "ui.importLocalLogs": "Lokale Logs importieren",
28
+ "ui.saveLog": "Aktuelles Log speichern",
29
+ "ui.exportPrompts": "Benutzer-Prompts exportieren",
30
+ "ui.tokenStats": "Token-Statistik",
31
+ "ui.liveMonitoring": "Live",
32
+ "ui.historyLog": "Verlauf: {file}",
33
+ "ui.chatMode": "Chat-Modus",
34
+ "ui.rawMode": "Zurück zum Rohmodus",
35
+ "ui.cacheExpired": "Abgelaufen",
36
+ "ui.cacheCountdown": "MainAgent Cache{type} läuft ab in: ",
37
+ "ui.minuteSecond": "{m}m{s}s",
38
+ "ui.second": "{s}s",
39
+ "ui.hitRate": "Trefferquote",
40
+ "ui.userPrompt": "Benutzer-Prompt",
41
+ "ui.noPrompt": "Noch keine Benutzer-Prompts",
42
+ "ui.unknownTime": "Unbekannte Zeit",
43
+ "ui.userSelection": "👤 Benutzerauswahl",
44
+ "ui.noAnswer": "Keine Antwort",
45
+ "ui.systemContext": "Systemkontext #{index}",
46
+ "ui.logCount": "{count} Logs",
47
+ "ui.noLogs": "Keine Log-Dateien",
48
+
49
+ "ui.toolReturn": "Tool-Ergebnis",
50
+ "ui.toolReturnNamed": "{name}-Ergebnis",
51
+ "ui.lastResponse": "Last Response",
52
+
53
+ "ui.copySuccess": "Kopiert",
54
+ "ui.noHeaders": "Keine Headers",
55
+ "ui.noBody": "Kein Body",
56
+ "ui.streamingResponse": "⚡ Streaming-Antwort — Diese Anfrage nutzte SSE-Streaming, der Antwortinhalt konnte nicht vollständig erfasst werden.",
57
+ "ui.responseNotCaptured": "Antwortdaten nicht erfasst",
58
+
59
+ "ui.expand": "▶ Aufklappen",
60
+ "ui.collapse": "▼ Zuklappen",
61
+ "ui.noChat": "Keine MainAgent-Gesprächsdaten"
62
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "cli.inject.success": "✅ CC Viewer injected successfully",
3
+ "cli.inject.exists": "✅ CC Viewer already injected, no action needed",
4
+ "cli.inject.fail": "❌ Injection failed: {error}",
5
+ "cli.inject.notFound": "❌ Claude Code cli.js not found: {path}",
6
+ "cli.inject.notFoundHint": " Please make sure @anthropic-ai/claude-code is installed",
7
+ "cli.hook.installed": "✅ Auto-reinject hook written to {path}",
8
+ "cli.hook.exists": "✅ Auto-reinject hook already exists in {path}",
9
+ "cli.hook.fail": "⚠️ Failed to write shell hook: {error}",
10
+ "cli.usage.hint": "\nJust run claude directly. It will auto-reinject after Claude Code updates",
11
+ "cli.usage.uninstallHint": "To uninstall, run: ccv --uninstall",
12
+ "cli.uninstall.cliCleaned": "✅ cli.js injection cleaned",
13
+ "cli.uninstall.cliNotFound": "⚠️ Claude Code cli.js not found, skipped",
14
+ "cli.uninstall.cliFail": "❌ Failed to clean cli.js injection",
15
+ "cli.uninstall.hookRemoved": "✅ Shell hook removed from {path}",
16
+ "cli.uninstall.hookClean": "✅ No cleanup needed in {path}",
17
+ "cli.uninstall.hookFail": "❌ Failed to clean shell hook: {error}",
18
+ "cli.uninstall.done": "\n🗑️ CC Viewer fully uninstalled",
19
+
20
+ "server.started": "\n🔍 CC Viewer started: http://{host}:{port}\n",
21
+ "server.reuse": "\n🔍 CC Viewer already running: http://{host}:{port}\n",
22
+ "server.portsBusy": "⚠️ Ports {start}-{end} are all in use, monitoring service not started",
23
+
24
+ "ui.requestList": "Requests",
25
+ "ui.totalRequests": "Total: {count}",
26
+ "ui.waitingRequests": "Waiting for requests...",
27
+ "ui.importLocalLogs": "Import local logs",
28
+ "ui.saveLog": "Save current log",
29
+ "ui.exportPrompts": "Export user prompts",
30
+ "ui.tokenStats": "Token Stats",
31
+ "ui.liveMonitoring": "Live",
32
+ "ui.historyLog": "History: {file}",
33
+ "ui.chatMode": "Chat mode",
34
+ "ui.rawMode": "Back to Raw",
35
+ "ui.cacheExpired": "Expired",
36
+ "ui.cacheCountdown": "MainAgent cache{type} expires in: ",
37
+ "ui.minuteSecond": "{m}m{s}s",
38
+ "ui.second": "{s}s",
39
+ "ui.hitRate": "Hit rate",
40
+ "ui.userPrompt": "User Prompt",
41
+ "ui.noPrompt": "No user prompts yet",
42
+ "ui.unknownTime": "Unknown time",
43
+ "ui.userSelection": "👤 User selection",
44
+ "ui.noAnswer": "No answer",
45
+ "ui.systemContext": "System context #{index}",
46
+ "ui.logCount": "{count} logs",
47
+ "ui.noLogs": "No log files",
48
+
49
+ "ui.toolReturn": "Tool result",
50
+ "ui.toolReturnNamed": "{name} result",
51
+ "ui.lastResponse": "Last Response",
52
+
53
+ "ui.copySuccess": "Copied",
54
+ "ui.noHeaders": "No Headers",
55
+ "ui.noBody": "No Body",
56
+ "ui.streamingResponse": "⚡ Streaming response — This request used SSE streaming, response content cannot be fully captured.",
57
+ "ui.responseNotCaptured": "Response not captured",
58
+
59
+ "ui.expand": "▶ Expand",
60
+ "ui.collapse": "▼ Collapse",
61
+ "ui.noChat": "No MainAgent conversation data"
62
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "cli.inject.success": "✅ CC Viewer inyectado correctamente",
3
+ "cli.inject.exists": "✅ CC Viewer ya inyectado, no se requiere acción",
4
+ "cli.inject.fail": "❌ Inyección fallida: {error}",
5
+ "cli.inject.notFound": "❌ Claude Code cli.js no encontrado: {path}",
6
+ "cli.inject.notFoundHint": " Asegúrese de que @anthropic-ai/claude-code esté instalado",
7
+ "cli.hook.installed": "✅ Hook de reinyección automática escrito en {path}",
8
+ "cli.hook.exists": "✅ Hook de reinyección automática ya existe en {path}",
9
+ "cli.hook.fail": "⚠️ Error al escribir el shell hook: {error}",
10
+ "cli.usage.hint": "\nEjecute claude directamente. Se reinyectará automáticamente tras actualizaciones de Claude Code",
11
+ "cli.usage.uninstallHint": "Para desinstalar, ejecute: ccv --uninstall",
12
+ "cli.uninstall.cliCleaned": "✅ Inyección de cli.js limpiada",
13
+ "cli.uninstall.cliNotFound": "⚠️ Claude Code cli.js no encontrado, omitido",
14
+ "cli.uninstall.cliFail": "❌ Error al limpiar la inyección de cli.js",
15
+ "cli.uninstall.hookRemoved": "✅ Shell hook eliminado de {path}",
16
+ "cli.uninstall.hookClean": "✅ No se necesita limpieza en {path}",
17
+ "cli.uninstall.hookFail": "❌ Error al limpiar el shell hook: {error}",
18
+ "cli.uninstall.done": "\n🗑️ CC Viewer desinstalado completamente",
19
+
20
+ "server.started": "\n🔍 CC Viewer iniciado: http://{host}:{port}\n",
21
+ "server.reuse": "\n🔍 CC Viewer ya en ejecución: http://{host}:{port}\n",
22
+ "server.portsBusy": "⚠️ Puertos {start}-{end} están todos en uso, servicio de monitoreo no iniciado",
23
+
24
+ "ui.requestList": "Solicitudes",
25
+ "ui.totalRequests": "Total: {count}",
26
+ "ui.waitingRequests": "Esperando solicitudes...",
27
+ "ui.importLocalLogs": "Importar logs locales",
28
+ "ui.saveLog": "Guardar log actual",
29
+ "ui.exportPrompts": "Exportar prompts de usuario",
30
+ "ui.tokenStats": "Estadísticas de Token",
31
+ "ui.liveMonitoring": "En vivo",
32
+ "ui.historyLog": "Historial: {file}",
33
+ "ui.chatMode": "Modo chat",
34
+ "ui.rawMode": "Volver al modo raw",
35
+ "ui.cacheExpired": "Expirado",
36
+ "ui.cacheCountdown": "Cache{type} de MainAgent expira en: ",
37
+ "ui.minuteSecond": "{m}m{s}s",
38
+ "ui.second": "{s}s",
39
+ "ui.hitRate": "Tasa de aciertos",
40
+ "ui.userPrompt": "Prompt de usuario",
41
+ "ui.noPrompt": "Sin prompts de usuario aún",
42
+ "ui.unknownTime": "Hora desconocida",
43
+ "ui.userSelection": "👤 Selección del usuario",
44
+ "ui.noAnswer": "Sin respuesta",
45
+ "ui.systemContext": "Contexto del sistema #{index}",
46
+ "ui.logCount": "{count} logs",
47
+ "ui.noLogs": "Sin archivos de log",
48
+
49
+ "ui.toolReturn": "Resultado de herramienta",
50
+ "ui.toolReturnNamed": "Resultado de {name}",
51
+ "ui.lastResponse": "Last Response",
52
+
53
+ "ui.copySuccess": "Copiado",
54
+ "ui.noHeaders": "Sin Headers",
55
+ "ui.noBody": "Sin Body",
56
+ "ui.streamingResponse": "⚡ Respuesta en streaming — Esta solicitud usó streaming SSE, el contenido de la respuesta no se pudo capturar completamente.",
57
+ "ui.responseNotCaptured": "Datos de respuesta no capturados",
58
+
59
+ "ui.expand": "▶ Expandir",
60
+ "ui.collapse": "▼ Contraer",
61
+ "ui.noChat": "Sin datos de conversación de MainAgent"
62
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "cli.inject.success": "✅ CC Viewer injecté avec succès",
3
+ "cli.inject.exists": "✅ CC Viewer déjà injecté, aucune action nécessaire",
4
+ "cli.inject.fail": "❌ Échec de l'injection : {error}",
5
+ "cli.inject.notFound": "❌ Claude Code cli.js introuvable : {path}",
6
+ "cli.inject.notFoundHint": " Veuillez vérifier que @anthropic-ai/claude-code est installé",
7
+ "cli.hook.installed": "✅ Hook de réinjection automatique écrit dans {path}",
8
+ "cli.hook.exists": "✅ Hook de réinjection automatique déjà présent dans {path}",
9
+ "cli.hook.fail": "⚠️ Échec de l'écriture du shell hook : {error}",
10
+ "cli.usage.hint": "\nExécutez claude directement. La réinjection se fera automatiquement après les mises à jour de Claude Code",
11
+ "cli.usage.uninstallHint": "Pour désinstaller, exécutez : ccv --uninstall",
12
+ "cli.uninstall.cliCleaned": "✅ Injection cli.js nettoyée",
13
+ "cli.uninstall.cliNotFound": "⚠️ Claude Code cli.js introuvable, ignoré",
14
+ "cli.uninstall.cliFail": "❌ Échec du nettoyage de l'injection cli.js",
15
+ "cli.uninstall.hookRemoved": "✅ Shell hook supprimé de {path}",
16
+ "cli.uninstall.hookClean": "✅ Aucun nettoyage nécessaire dans {path}",
17
+ "cli.uninstall.hookFail": "❌ Échec du nettoyage du shell hook : {error}",
18
+ "cli.uninstall.done": "\n🗑️ CC Viewer entièrement désinstallé",
19
+
20
+ "server.started": "\n🔍 CC Viewer démarré : http://{host}:{port}\n",
21
+ "server.reuse": "\n🔍 CC Viewer déjà en cours d'exécution : http://{host}:{port}\n",
22
+ "server.portsBusy": "⚠️ Ports {start}-{end} tous occupés, service de surveillance non démarré",
23
+
24
+ "ui.requestList": "Requêtes",
25
+ "ui.totalRequests": "Total : {count}",
26
+ "ui.waitingRequests": "En attente de requêtes...",
27
+ "ui.importLocalLogs": "Importer les logs locaux",
28
+ "ui.saveLog": "Enregistrer le log actuel",
29
+ "ui.exportPrompts": "Exporter les prompts utilisateur",
30
+ "ui.tokenStats": "Statistiques Token",
31
+ "ui.liveMonitoring": "En direct",
32
+ "ui.historyLog": "Historique : {file}",
33
+ "ui.chatMode": "Mode conversation",
34
+ "ui.rawMode": "Retour au mode brut",
35
+ "ui.cacheExpired": "Expiré",
36
+ "ui.cacheCountdown": "Cache{type} MainAgent expire dans : ",
37
+ "ui.minuteSecond": "{m}m{s}s",
38
+ "ui.second": "{s}s",
39
+ "ui.hitRate": "Taux de succès",
40
+ "ui.userPrompt": "Prompt utilisateur",
41
+ "ui.noPrompt": "Aucun prompt utilisateur",
42
+ "ui.unknownTime": "Heure inconnue",
43
+ "ui.userSelection": "👤 Sélection utilisateur",
44
+ "ui.noAnswer": "Pas de réponse",
45
+ "ui.systemContext": "Contexte système #{index}",
46
+ "ui.logCount": "{count} logs",
47
+ "ui.noLogs": "Aucun fichier de log",
48
+
49
+ "ui.toolReturn": "Résultat d'outil",
50
+ "ui.toolReturnNamed": "Résultat de {name}",
51
+ "ui.lastResponse": "Last Response",
52
+
53
+ "ui.copySuccess": "Copié",
54
+ "ui.noHeaders": "Pas de Headers",
55
+ "ui.noBody": "Pas de Body",
56
+ "ui.streamingResponse": "⚡ Réponse en streaming — Cette requête a utilisé le streaming SSE, le contenu de la réponse n'a pas pu être entièrement capturé.",
57
+ "ui.responseNotCaptured": "Données de réponse non capturées",
58
+
59
+ "ui.expand": "▶ Déplier",
60
+ "ui.collapse": "▼ Replier",
61
+ "ui.noChat": "Aucune donnée de conversation MainAgent"
62
+ }