cc-team-viewer 1.5.4 → 1.5.5

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/cli.js CHANGED
@@ -247,6 +247,18 @@ async function runProxyCommand(args) {
247
247
  cmdArgs.unshift(settingsJson);
248
248
  cmdArgs.unshift('--settings');
249
249
 
250
+ // 打印 viewer 访问地址(服务器由 interceptor 自动启动)
251
+ // 等待 viewer 服务器就绪后打印
252
+ const { getPort } = await import('../server/server.js');
253
+ await new Promise(resolve => {
254
+ const check = () => { getPort() ? resolve() : setTimeout(check, 200); };
255
+ setTimeout(check, 300);
256
+ });
257
+ const viewerPort = getPort();
258
+ if (viewerPort) {
259
+ console.error(`\n[cctv] 监控面板: http://127.0.0.1:${viewerPort}\n`);
260
+ }
261
+
250
262
  const child = spawn(cmd, cmdArgs, { stdio: 'inherit', env });
251
263
 
252
264
  child.on('exit', (code) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-team-viewer",
3
- "version": "1.5.4",
3
+ "version": "1.5.5",
4
4
  "description": "Claude Code Logger visualization management tool",
5
5
  "license": "MIT",
6
6
  "main": "server/server.js",
@@ -10,6 +10,8 @@ import { dirname, join, basename } from 'node:path';
10
10
  import { LOG_DIR } from '../cli/findcc.js';
11
11
  import { initLogger, logInfo, logWarn, logError, logDebug } from '../lib/logger.js';
12
12
 
13
+ const MOBILE_DEBUG = process.env.CCV_MOBILE_DEBUG === '1';
14
+ const mobileLog = MOBILE_DEBUG ? (...args) => logDebug('[MOBILE-DEBUG]', ...args) : () => {};
13
15
 
14
16
  const __filename = fileURLToPath(import.meta.url);
15
17
  const __dirname = dirname(__filename);
@@ -605,15 +607,15 @@ export function setOnLogWrittenCallback(callback) {
605
607
  * @param {Object|Array} newEntries - 新增的日志条目(单个对象或数组)
606
608
  */
607
609
  function triggerLogWrittenCallback(newEntries) {
608
- console.log('[MOBILE-DEBUG] triggerLogWrittenCallback called, hasCallback:', !!_onLogWrittenCallback);
610
+ mobileLog('triggerLogWrittenCallback called, hasCallback:', !!_onLogWrittenCallback);
609
611
  if (_onLogWrittenCallback) {
610
612
  try {
611
613
  // 统一转为数组格式
612
614
  const entries = Array.isArray(newEntries) ? newEntries : (newEntries ? [newEntries] : []);
613
- console.log('[MOBILE-DEBUG] calling callback with', entries.length, 'entries');
615
+ mobileLog('calling callback with', entries.length, 'entries');
614
616
  _onLogWrittenCallback(entries);
615
617
  } catch (err) {
616
- console.error('[MOBILE-DEBUG] callback error:', err.message);
618
+ mobileLog('callback error:', err.message);
617
619
  }
618
620
  }
619
621
  }
@@ -668,6 +670,24 @@ export function setupInterceptor() {
668
670
  stdio: 'ignore',
669
671
  env: { ...process.env, CCV_DETACHED: '1' }
670
672
  }).unref();
673
+
674
+ // 等待 viewer 服务器就绪后打印访问地址
675
+ const waitAndPrint = async () => {
676
+ for (let i = 0; i < 30; i++) {
677
+ await new Promise(r => setTimeout(r, 500));
678
+ for (let p = 7008; p <= 7020; p++) {
679
+ const ok = await new Promise(res => {
680
+ const c = connect(p, '127.0.0.1', () => { c.end(); res(true); });
681
+ c.on('error', () => res(false));
682
+ });
683
+ if (ok) {
684
+ process.stderr.write(`\n[cctv] 监控面板: http://127.0.0.1:${p}\n`);
685
+ return;
686
+ }
687
+ }
688
+ }
689
+ };
690
+ waitAndPrint().catch(() => {});
671
691
  };
672
692
 
673
693
  tryStartProxy().catch(() => {});
@@ -18,6 +18,9 @@ import { readLogFile } from './sse.js';
18
18
  import { buildSessionsFromEntries, assignMessageTimestamps } from '../src/utils/sessionBuilder.js';
19
19
  import { classifyUserContent } from '../src/utils/contentFilter.js';
20
20
 
21
+ const MOBILE_DEBUG = process.env.CCV_MOBILE_DEBUG === '1';
22
+ const mobileLog = MOBILE_DEBUG ? (...args) => console.log('[MOBILE-DEBUG]', ...args) : () => {};
23
+
21
24
  let actualPort = 0;
22
25
  let accessToken = '';
23
26
  let mobileWss = null;
@@ -173,10 +176,10 @@ function simplifyMessage(message, index) {
173
176
 
174
177
  function buildLatestChatSnapshot() {
175
178
  const entries = readLogFile();
176
- console.log('[MOBILE-DEBUG] buildLatestChatSnapshot: entries count:', entries?.length || 0);
179
+ mobileLog('buildLatestChatSnapshot: entries count:', entries?.length || 0);
177
180
 
178
181
  if (!Array.isArray(entries) || entries.length === 0) {
179
- console.log('[MOBILE-DEBUG] buildLatestChatSnapshot: no entries, returning empty snapshot');
182
+ mobileLog('buildLatestChatSnapshot: no entries, returning empty snapshot');
180
183
  return {
181
184
  type: 'chat_snapshot',
182
185
  connectionSessionId: connectionState.connectionSessionId || '',
@@ -190,26 +193,26 @@ function buildLatestChatSnapshot() {
190
193
 
191
194
  assignMessageTimestamps(entries);
192
195
  const sessions = buildSessionsFromEntries(entries);
193
- console.log('[MOBILE-DEBUG] buildLatestChatSnapshot: sessions count:', sessions?.length || 0);
196
+ mobileLog('buildLatestChatSnapshot: sessions count:', sessions?.length || 0);
194
197
 
195
198
  // DEBUG: 检查第一条 entry 的 mainAgent 标记
196
199
  if (entries.length > 0 && sessions.length === 0) {
197
200
  const first = entries[0];
198
- console.log('[MOBILE-DEBUG] DEBUG: first entry has mainAgent:', first?.mainAgent, 'url:', first?.url, 'timestamp:', first?.timestamp);
201
+ mobileLog('DEBUG: first entry has mainAgent:', first?.mainAgent, 'url:', first?.url, 'timestamp:', first?.timestamp);
199
202
  // 检查 body.messages
200
203
  const hasMessages = Array.isArray(first?.body?.messages);
201
- console.log('[MOBILE-DEBUG] DEBUG: first entry has body.messages:', hasMessages, 'count:', first?.body?.messages?.length);
204
+ mobileLog('DEBUG: first entry has body.messages:', hasMessages, 'count:', first?.body?.messages?.length);
202
205
  // 检查 system
203
206
  const hasSystem = !!first?.body?.system;
204
- console.log('[MOBILE-DEBUG] DEBUG: first entry has body.system:', hasSystem);
207
+ mobileLog('DEBUG: first entry has body.system:', hasSystem);
205
208
  const sysText = Array.isArray(first?.body?.system)
206
209
  ? first.body.system.map(s => s?.text || '').join('')
207
210
  : (first?.body?.system || '');
208
- console.log('[MOBILE-DEBUG] DEBUG: system contains "Claude Code":', sysText.includes('Claude Code'));
211
+ mobileLog('DEBUG: system contains "Claude Code":', sysText.includes('Claude Code'));
209
212
  }
210
213
 
211
214
  const latestSession = sessions[sessions.length - 1];
212
- console.log('[MOBILE-DEBUG] buildLatestChatSnapshot: latestSession messages:', latestSession?.messages?.length || 0);
215
+ mobileLog('buildLatestChatSnapshot: latestSession messages:', latestSession?.messages?.length || 0);
213
216
 
214
217
  const messages = Array.isArray(latestSession?.messages)
215
218
  ? latestSession.messages
@@ -217,7 +220,7 @@ function buildLatestChatSnapshot() {
217
220
  .filter(msg => msg.text || msg.role !== 'user')
218
221
  : [];
219
222
 
220
- console.log('[MOBILE-DEBUG] buildLatestChatSnapshot: final messages after filter:', messages.length);
223
+ mobileLog('buildLatestChatSnapshot: final messages after filter:', messages.length);
221
224
 
222
225
  const latestReply = normalizeTextContent(latestSession?.response?.body?.content);
223
226
 
@@ -281,7 +284,7 @@ function sendHubMessage(message) {
281
284
  }
282
285
 
283
286
  function broadcastLocal(message) {
284
- console.log('[MOBILE-DEBUG] broadcastLocal: clients count:', mobileClients.size);
287
+ mobileLog('broadcastLocal: clients count:', mobileClients.size);
285
288
  const payload = typeof message === 'string' ? message : JSON.stringify(message);
286
289
  for (const client of mobileClients) {
287
290
  if (client.readyState === WebSocket.OPEN) {
@@ -293,7 +296,7 @@ function broadcastLocal(message) {
293
296
  }
294
297
 
295
298
  function broadcast(message, { includeHub = true } = {}) {
296
- console.log('[MOBILE-DEBUG] broadcast called');
299
+ mobileLog('broadcast called');
297
300
  broadcastLocal(message);
298
301
  if (includeHub) {
299
302
  sendHubMessage(message);
@@ -319,26 +322,26 @@ function broadcastState({ includeHub = true } = {}) {
319
322
  }
320
323
 
321
324
  function maybeBroadcastChatSnapshot({ includeHub = true } = {}) {
322
- console.log('[MOBILE-DEBUG] maybeBroadcastChatSnapshot called, active:', connectionState.active);
325
+ mobileLog('maybeBroadcastChatSnapshot called, active:', connectionState.active);
323
326
  if (!connectionState.active) {
324
- console.log('[MOBILE-DEBUG] skipped: connection not active');
327
+ mobileLog('skipped: connection not active');
325
328
  return;
326
329
  }
327
330
  const snapshot = buildLatestChatSnapshot();
328
- console.log('[MOBILE-DEBUG] snapshot built, messages:', snapshot?.messages?.length, 'cached:', cachedMessages.length);
331
+ mobileLog('snapshot built, messages:', snapshot?.messages?.length, 'cached:', cachedMessages.length);
329
332
  // 去重时排除时间戳字段,只比较消息内容
330
333
  const { updatedAt, ...contentOnly } = snapshot;
331
334
  const nextJson = JSON.stringify(contentOnly);
332
335
 
333
336
  // DEBUG: 输出 JSON 长度变化,帮助诊断问题
334
- console.log('[MOBILE-DEBUG] json len:', nextJson.length, 'vs last:', lastChatSnapshotJson.length, 'equal:', nextJson === lastChatSnapshotJson);
337
+ mobileLog('json len:', nextJson.length, 'vs last:', lastChatSnapshotJson.length, 'equal:', nextJson === lastChatSnapshotJson);
335
338
 
336
339
  if (nextJson === lastChatSnapshotJson) {
337
- console.log('[MOBILE-DEBUG] skipped: snapshot unchanged (dedup)');
340
+ mobileLog('skipped: snapshot unchanged (dedup)');
338
341
  return;
339
342
  }
340
343
  lastChatSnapshotJson = nextJson;
341
- console.log('[MOBILE-DEBUG] broadcasting snapshot to', mobileClients.size, 'clients');
344
+ mobileLog('broadcasting snapshot to', mobileClients.size, 'clients');
342
345
  // 更新缓存
343
346
  cachedMessages = snapshot.messages;
344
347
  cachedLatestReply = snapshot.latestReply;
@@ -501,7 +504,7 @@ async function handlePromptAnswer(answer, sessionId) {
501
504
  }
502
505
 
503
506
  function handlePtyData(data) {
504
- console.log('[MOBILE-DEBUG] handlePtyData called, data length:', data?.length, 'active:', connectionState.active, 'mode:', connectionState.mode);
507
+ mobileLog('handlePtyData called, data length:', data?.length, 'active:', connectionState.active, 'mode:', connectionState.mode);
505
508
  const clean = stripAnsi(data);
506
509
  if (!clean) return;
507
510
  ptyBuffer += clean;
@@ -520,7 +523,7 @@ function handlePtyData(data) {
520
523
  timestamp: new Date().toISOString(),
521
524
  });
522
525
  } else {
523
- console.log('[MOBILE-DEBUG] terminal_output NOT sent: hubSocket=', hubSocket ? hubSocket.readyState : 'null', 'hubConnected=', connectionState.hubConnected);
526
+ mobileLog('terminal_output NOT sent: hubSocket=', hubSocket ? hubSocket.readyState : 'null', 'hubConnected=', connectionState.hubConnected);
524
527
  }
525
528
  }
526
529
  }
@@ -743,7 +746,7 @@ export function initMobileBridge({ server, port, token, projectName }) {
743
746
  ptyExitUnsubscribe = onPtyExit(handlePtyExit);
744
747
 
745
748
  mobileWss.on('connection', (ws) => {
746
- console.log('[MOBILE-DEBUG] mobile client connected');
749
+ mobileLog('mobile client connected');
747
750
  mobileClients.add(ws);
748
751
  refreshConnectedClients();
749
752
  sendJson(ws, buildConnectionStateMessage());
@@ -978,7 +981,7 @@ export function stopMobileConnection() {
978
981
  }
979
982
 
980
983
  export function notifyMobileLogEntries(newEntries) {
981
- console.log('[MOBILE-DEBUG] notifyMobileLogEntries called, entries:', newEntries?.length, 'active:', connectionState.active);
984
+ mobileLog('notifyMobileLogEntries called, entries:', newEntries?.length, 'active:', connectionState.active);
982
985
  // 直接走完整日志重建路径
983
986
  // 实时性来自 interceptor 的直接回调(跳过 fs.watchFile 轮询延迟)
984
987
  // 可靠性来自完整日志重建(避免增量逻辑的各种边界问题)
package/server/sse.js CHANGED
@@ -446,7 +446,7 @@ export function watchLogDirectory() {
446
446
 
447
447
  if (entries.length > 0) {
448
448
  // 通知移动端,传递新增条目以支持增量构建
449
- console.log('[MOBILE-DEBUG] sse.js handleFileChange triggered, calling notifyMobileLogEntries');
449
+ debugLog('sse.js handleFileChange triggered, calling notifyMobileLogEntries');
450
450
  notifyMobileLogEntries(entries);
451
451
  // 根据日志文件路径查找对应的 team
452
452
  let team = getTeamByLogFile(filePath);