cc-viewer 0.1.2 → 0.1.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.
@@ -0,0 +1 @@
1
+ body{margin:0;background-color:#0d0d0d}*{scrollbar-width:thin;scrollbar-color:#3a3a3a #0d0d0d}*::-webkit-scrollbar{width:6px;height:6px}*::-webkit-scrollbar-track{background:#0d0d0d}*::-webkit-scrollbar-thumb{background:#3a3a3a;border-radius:3px}*::-webkit-scrollbar-thumb:hover{background:#555}.diff-view{background:#1a1a2e;border:1px solid #2a2a3e;border-radius:8px;padding:8px 12px}.diff-line-del{background:#ef444426;color:#fca5a5;padding:0 4px}.diff-line-add{background:#22c55e26;color:#86efac;padding:0 4px}.code-highlight{color:#e6edf3}.hl-keyword{color:#ff7b72}.hl-string{color:#a5d6ff}.hl-comment{color:#8b949e;font-style:italic}.hl-number{color:#79c0ff}.hl-linenum{color:#484f58;-webkit-user-select:none;user-select:none}._GzYRV{line-height:1.2;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}._3eOF8{margin-right:5px;font-weight:700}._3eOF8+._3eOF8{margin-left:-5px}._1MFti{cursor:pointer}._f10Tu{font-size:1.2em;margin-right:5px;-webkit-user-select:none;-moz-user-select:none;user-select:none}._1UmXx:after{content:"▸"}._1LId0:after{content:"▾"}._1pNG9{margin-right:5px}._1pNG9:after{content:"...";font-size:.8em}._2IvMF{background:#eee}._2bkNM{margin:0;padding:0 10px}._1BXBN{margin:0;padding:0}._1MGIk{font-weight:600;margin-right:5px;color:#000}._3uHL6{color:#000}._2T6PJ,._1Gho6{color:#df113a}._vGjyY{color:#2a3f3c}._1bQdo{color:#0b75f5}._3zQKs{color:#469038}._1xvuR{color:#43413d}._oLqym,._2AXVT,._2KJWg{color:#000}._11RoI{background:#002b36}._17H2C,._3QHg2,._3fDAz{color:#fdf6e3}._2bSDX{font-weight:bolder;margin-right:5px;color:#fdf6e3}._gsbQL{color:#fdf6e3}._LaAZe,._GTKgm{color:#81b5ac}._Chy1W{color:#cb4b16}._2bveF{color:#d33682}._2vRm-{color:#ae81ff}._1prJR{color:#268bd2}
package/lib/index.html CHANGED
@@ -4,9 +4,9 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Claude Code Viewer</title>
7
- <style>body {margin: 0}</style>
8
- <script type="module" crossorigin src="/assets/index-Cz06a4Sw.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-B9Z7D9kT.css">
7
+
8
+ <script type="module" crossorigin src="/assets/index-BMPce72-.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-C7-c9XfU.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
package/lib/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createServer } from 'node:http';
2
- import { readFileSync, existsSync, watchFile, unwatchFile, statSync, writeFileSync } from 'node:fs';
1
+ import { createServer, request as httpRequest } from 'node:http';
2
+ import { readFileSync, existsSync, watchFile, unwatchFile, statSync, writeFileSync, unlinkSync } from 'node:fs';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { dirname, join, extname } from 'node:path';
5
5
  import { LOG_FILE } from '../interceptor.js';
@@ -11,6 +11,18 @@ const MAX_PORT = 7099;
11
11
  const HOST = '127.0.0.1';
12
12
  const PORT_FILE = '/tmp/cc-viewer-port';
13
13
 
14
+ function checkPortAlive(port) {
15
+ return new Promise((resolve) => {
16
+ const req = httpRequest({ host: HOST, port, path: '/api/requests', method: 'GET', timeout: 1000 }, (res) => {
17
+ res.resume();
18
+ resolve(true);
19
+ });
20
+ req.on('error', () => resolve(false));
21
+ req.on('timeout', () => { req.destroy(); resolve(false); });
22
+ req.end();
23
+ });
24
+ }
25
+
14
26
  let clients = [];
15
27
  let server;
16
28
  let actualPort = START_PORT;
@@ -164,7 +176,26 @@ function handleRequest(req, res) {
164
176
  res.end('Not Found');
165
177
  }
166
178
 
167
- export function startViewer() {
179
+ 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;
190
+ }
191
+ }
192
+ } catch {
193
+ // PORT_FILE 读取失败,继续正常启动
194
+ }
195
+ // 旧实例已不存在,清理 PORT_FILE
196
+ try { unlinkSync(PORT_FILE); } catch {}
197
+ }
198
+
168
199
  return new Promise((resolve, reject) => {
169
200
  function tryListen(port) {
170
201
  if (port > MAX_PORT) {
@@ -186,7 +217,6 @@ export function startViewer() {
186
217
 
187
218
  currentServer.on('error', (err) => {
188
219
  if (err.code === 'EADDRINUSE') {
189
- console.log(`⚠️ 端口 ${port} 已被占用,尝试 ${port + 1}...`);
190
220
  tryListen(port + 1);
191
221
  } else {
192
222
  reject(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-viewer",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Claude Code Logger visualization management tool",
5
5
  "license": "MIT",
6
6
  "main": "lib/server.js",
@@ -1 +0,0 @@
1
- ._GzYRV{line-height:1.2;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}._3eOF8{margin-right:5px;font-weight:700}._3eOF8+._3eOF8{margin-left:-5px}._1MFti{cursor:pointer}._f10Tu{font-size:1.2em;margin-right:5px;-webkit-user-select:none;-moz-user-select:none;user-select:none}._1UmXx:after{content:"▸"}._1LId0:after{content:"▾"}._1pNG9{margin-right:5px}._1pNG9:after{content:"...";font-size:.8em}._2IvMF{background:#eee}._2bkNM{margin:0;padding:0 10px}._1BXBN{margin:0;padding:0}._1MGIk{font-weight:600;margin-right:5px;color:#000}._3uHL6{color:#000}._2T6PJ,._1Gho6{color:#df113a}._vGjyY{color:#2a3f3c}._1bQdo{color:#0b75f5}._3zQKs{color:#469038}._1xvuR{color:#43413d}._oLqym,._2AXVT,._2KJWg{color:#000}._11RoI{background:#002b36}._17H2C,._3QHg2,._3fDAz{color:#fdf6e3}._2bSDX{font-weight:bolder;margin-right:5px;color:#fdf6e3}._gsbQL{color:#fdf6e3}._LaAZe,._GTKgm{color:#81b5ac}._Chy1W{color:#cb4b16}._2bveF{color:#d33682}._2vRm-{color:#ae81ff}._1prJR{color:#268bd2}