@clawchatsai/connector 0.0.13 → 0.0.15

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/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * @shellchat/tunnel — OpenClaw plugin entry point
2
+ * @clawchatsai/connector — OpenClaw plugin entry point
3
3
  *
4
- * Registers ShellChat as a gateway plugin, providing:
4
+ * Registers ClawChats as a gateway plugin, providing:
5
5
  * - Local HTTP API bridge via createApp()
6
6
  * - WebRTC DataChannel for browser connections
7
7
  * - Signaling client for NAT traversal
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * @shellchat/tunnel — OpenClaw plugin entry point
2
+ * @clawchatsai/connector — OpenClaw plugin entry point
3
3
  *
4
- * Registers ShellChat as a gateway plugin, providing:
4
+ * Registers ClawChats as a gateway plugin, providing:
5
5
  * - Local HTTP API bridge via createApp()
6
6
  * - WebRTC DataChannel for browser connections
7
7
  * - Signaling client for NAT traversal
@@ -24,6 +24,8 @@ export const PLUGIN_VERSION = '0.0.13';
24
24
  const MAX_DC_MESSAGE_SIZE = 256 * 1024;
25
25
  /** Active DataChannel connections: connectionId → send function */
26
26
  const connectedClients = new Map();
27
+ /** Reassembly buffers for chunked gateway-msg from browser (large payloads like image attachments). */
28
+ const gatewayMsgChunkBuffers = new Map();
27
29
  let app = null;
28
30
  let signaling = null;
29
31
  let webrtcPeer = null;
@@ -32,7 +34,7 @@ let _stopRequested = false;
32
34
  // ---------------------------------------------------------------------------
33
35
  // Config helpers
34
36
  // ---------------------------------------------------------------------------
35
- const CONFIG_DIR = path.join(process.env.HOME || '/root', '.openclaw', 'shellchats');
37
+ const CONFIG_DIR = path.join(process.env.HOME || '/root', '.openclaw', 'clawchats');
36
38
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
37
39
  const RUNTIME_FILE = path.join(CONFIG_DIR, 'runtime.json');
38
40
  function loadConfig() {
@@ -73,11 +75,11 @@ async function ensureNativeModules(ctx) {
73
75
  ctx.logger.error('Try running manually: cd ~/.openclaw/extensions/connector && npm rebuild better-sqlite3');
74
76
  }
75
77
  }
76
- async function startShellChat(ctx, api) {
78
+ async function startClawChats(ctx, api) {
77
79
  _stopRequested = false;
78
80
  let config = loadConfig();
79
81
  if (!config) {
80
- ctx.logger.info('ShellChats not configured. Waiting for setup...');
82
+ ctx.logger.info('ClawChats not configured. Waiting for setup...');
81
83
  fs.mkdirSync(CONFIG_DIR, { recursive: true });
82
84
  while (!config && !_stopRequested) {
83
85
  await new Promise(r => setTimeout(r, 2000));
@@ -85,7 +87,7 @@ async function startShellChat(ctx, api) {
85
87
  }
86
88
  if (_stopRequested || !config)
87
89
  return;
88
- ctx.logger.info('Setup detected — connecting to ShellChats...');
90
+ ctx.logger.info('Setup detected — connecting to ClawChats...');
89
91
  }
90
92
  // 1. Check for updates
91
93
  const update = await checkForUpdates();
@@ -95,7 +97,7 @@ async function startShellChat(ctx, api) {
95
97
  try {
96
98
  await performUpdate();
97
99
  ctx.logger.info(`Updated to ${update.latest}. Requesting graceful restart...`);
98
- api.runtime.requestRestart?.('shellchats update');
100
+ api.runtime.requestRestart?.('clawchats update');
99
101
  return; // will restart with new version
100
102
  }
101
103
  catch (e) {
@@ -108,14 +110,14 @@ async function startShellChat(ctx, api) {
108
110
  const gwAuth = gwCfg?.['gateway']?.['auth'];
109
111
  const gatewayToken = gwAuth?.['token'] || config.gatewayToken || '';
110
112
  if (!gatewayToken) {
111
- ctx.logger.error('No gateway token available. Re-run: openclaw shellchats setup <token>');
113
+ ctx.logger.error('No gateway token available. Re-run: openclaw clawchats setup <token>');
112
114
  return;
113
115
  }
114
116
  // 3. Ensure native modules are built (OpenClaw installs with --ignore-scripts)
115
117
  await ensureNativeModules(ctx);
116
118
  // 4. Import server.js and create app instance with plugin paths
117
- const dataDir = path.join(ctx.stateDir, 'shellchats', 'data');
118
- const uploadsDir = path.join(ctx.stateDir, 'shellchats', 'uploads');
119
+ const dataDir = path.join(ctx.stateDir, 'clawchats', 'data');
120
+ const uploadsDir = path.join(ctx.stateDir, 'clawchats', 'uploads');
119
121
  // Dynamic import of server.js (plain JS, no type declarations)
120
122
  // @ts-expect-error — server.js is plain JS with no .d.ts
121
123
  const serverModule = await import('../server.js');
@@ -228,11 +230,11 @@ async function startShellChat(ctx, api) {
228
230
  }, null, 2), { mode: 0o600 });
229
231
  ctx.logger.info(`Health endpoint on 127.0.0.1:${addr.port}`);
230
232
  });
231
- ctx.logger.info('ShellChat service started');
233
+ ctx.logger.info('ClawChats service started');
232
234
  }
233
- async function stopShellChat(ctx) {
235
+ async function stopClawChats(ctx) {
234
236
  _stopRequested = true;
235
- ctx.logger.info('ShellChat service stopping...');
237
+ ctx.logger.info('ClawChats service stopping...');
236
238
  // 0. Tear down health endpoint
237
239
  if (healthServer) {
238
240
  healthServer.close();
@@ -259,7 +261,7 @@ async function stopShellChat(ctx) {
259
261
  // 4. Close SQLite databases
260
262
  app?.shutdown();
261
263
  app = null;
262
- ctx.logger.info('ShellChat service stopped');
264
+ ctx.logger.info('ClawChats service stopped');
263
265
  }
264
266
  // ---------------------------------------------------------------------------
265
267
  // DataChannel message handler (spec section 6.4)
@@ -286,6 +288,43 @@ function setupDataChannelHandler(dc, connectionId, ctx) {
286
288
  app.gatewayClient.sendToGateway(msg['payload']);
287
289
  }
288
290
  break;
291
+ case 'gateway-msg-chunk': {
292
+ // Reassemble chunked gateway messages from the browser.
293
+ // Large payloads (e.g. image attachments as base64) exceed the
294
+ // DataChannel's safe single-message limit (~64 KiB) and are split
295
+ // by the browser's transport.js into indexed chunks.
296
+ const chunkId = msg['id'];
297
+ const index = msg['index'];
298
+ const total = msg['total'];
299
+ const chunkData = msg['data'];
300
+ if (!chunkId || typeof index !== 'number' || typeof total !== 'number' || !chunkData) {
301
+ dc.send(JSON.stringify({ type: 'error', message: 'malformed gateway-msg-chunk' }));
302
+ break;
303
+ }
304
+ if (!gatewayMsgChunkBuffers.has(chunkId)) {
305
+ gatewayMsgChunkBuffers.set(chunkId, {
306
+ chunks: new Array(total),
307
+ received: 0,
308
+ total,
309
+ createdAt: Date.now(),
310
+ });
311
+ // Expire stale buffers after 30s to prevent memory leaks
312
+ setTimeout(() => gatewayMsgChunkBuffers.delete(chunkId), 30_000);
313
+ }
314
+ const buf = gatewayMsgChunkBuffers.get(chunkId);
315
+ if (!buf.chunks[index]) {
316
+ buf.chunks[index] = chunkData;
317
+ buf.received++;
318
+ }
319
+ if (buf.received === buf.total) {
320
+ gatewayMsgChunkBuffers.delete(chunkId);
321
+ const fullPayload = buf.chunks.join('');
322
+ if (app?.gatewayClient) {
323
+ app.gatewayClient.sendToGateway(fullPayload);
324
+ }
325
+ }
326
+ break;
327
+ }
289
328
  default:
290
329
  dc.send(JSON.stringify({ type: 'error', message: 'unknown message type' }));
291
330
  }
@@ -386,7 +425,7 @@ function broadcastToClients(msg) {
386
425
  // ---------------------------------------------------------------------------
387
426
  function formatStatus() {
388
427
  const lines = [];
389
- lines.push(`ShellChat Plugin v${PLUGIN_VERSION}`);
428
+ lines.push(`ClawChats Plugin v${PLUGIN_VERSION}`);
390
429
  lines.push(`Gateway: ${app?.gatewayClient?.connected ? 'connected' : 'disconnected'}`);
391
430
  lines.push(`Signaling: ${signaling?.isConnected ? 'connected' : 'disconnected'}`);
392
431
  lines.push(`Clients: ${connectedClients.size}`);
@@ -410,7 +449,7 @@ async function handleSetup(token) {
410
449
  console.error('Setup token has expired. Generate a new one from clawchats.ai.');
411
450
  return;
412
451
  }
413
- console.log('Setting up ShellChats...');
452
+ console.log('Setting up ClawChats...');
414
453
  console.log(` Server: ${tokenData.serverUrl}`);
415
454
  // Generate API key for signaling server auth
416
455
  const { randomBytes } = await import('node:crypto');
@@ -467,7 +506,7 @@ async function handleSetup(token) {
467
506
  const uploadsDir = path.join(CONFIG_DIR, 'uploads');
468
507
  fs.mkdirSync(dataDir, { recursive: true });
469
508
  fs.mkdirSync(uploadsDir, { recursive: true });
470
- console.log(' ShellChats is ready!');
509
+ console.log(' ClawChats is ready!');
471
510
  console.log(' Open clawchats.ai in your browser to start chatting.');
472
511
  ws.close();
473
512
  resolve();
@@ -497,7 +536,7 @@ async function handleStatus() {
497
536
  runtime = JSON.parse(fs.readFileSync(RUNTIME_FILE, 'utf8'));
498
537
  }
499
538
  catch {
500
- console.log('ShellChats: offline (service not running)');
539
+ console.log('ClawChats: offline (service not running)');
501
540
  return;
502
541
  }
503
542
  // Verify PID is alive
@@ -505,7 +544,7 @@ async function handleStatus() {
505
544
  process.kill(runtime.pid, 0);
506
545
  }
507
546
  catch {
508
- console.log('ShellChats: offline (stale runtime file)');
547
+ console.log('ClawChats: offline (stale runtime file)');
509
548
  try {
510
549
  fs.unlinkSync(RUNTIME_FILE);
511
550
  }
@@ -524,20 +563,20 @@ async function handleStatus() {
524
563
  req.setTimeout(3000, () => { req.destroy(); reject(new Error('timeout')); });
525
564
  });
526
565
  const status = JSON.parse(body);
527
- console.log(`ShellChats Plugin v${status.version}`);
566
+ console.log(`ClawChats Plugin v${status.version}`);
528
567
  console.log(`Uptime: ${Math.floor(status.uptime)}s`);
529
568
  console.log(`Gateway: ${status.gateway.connected ? 'connected' : 'disconnected'}`);
530
569
  console.log(`Signaling: ${status.signaling.connected ? 'connected' : 'disconnected'}`);
531
570
  console.log(`Clients: ${status.clients.active}`);
532
571
  }
533
572
  catch {
534
- console.log('ShellChats: offline (could not reach service)');
573
+ console.log('ClawChats: offline (could not reach service)');
535
574
  }
536
575
  }
537
576
  async function handleReset() {
538
577
  try {
539
578
  fs.rmSync(CONFIG_DIR, { recursive: true, force: true });
540
- console.log('ShellChats data removed. Plugin disconnected.');
579
+ console.log('ClawChats data removed. Plugin disconnected.');
541
580
  }
542
581
  catch (e) {
543
582
  console.error(`Reset failed: ${e.message}`);
@@ -554,7 +593,7 @@ async function handleImport(sourcePath) {
554
593
  console.error(`Source must be a directory: ${resolvedSource}`);
555
594
  return;
556
595
  }
557
- // Destination: ~/.openclaw/shellchats/data/
596
+ // Destination: ~/.openclaw/clawchats/data/
558
597
  const destDataDir = path.join(CONFIG_DIR, 'data');
559
598
  fs.mkdirSync(destDataDir, { recursive: true });
560
599
  // Import .db files
@@ -586,7 +625,7 @@ async function handleImport(sourcePath) {
586
625
  }
587
626
  }
588
627
  // Also try to migrate config.json from the parent directory
589
- // e.g. if source is ~/.openclaw/shellchat/data/, config is at ~/.openclaw/shellchat/config.json
628
+ // e.g. if source is ~/.openclaw/clawchats/data/, config is at ~/.openclaw/clawchats/config.json
590
629
  const parentConfigPath = path.join(path.dirname(resolvedSource), 'config.json');
591
630
  if (fs.existsSync(parentConfigPath)) {
592
631
  try {
@@ -605,26 +644,26 @@ async function handleImport(sourcePath) {
605
644
  // ---------------------------------------------------------------------------
606
645
  const plugin = {
607
646
  id: PLUGIN_ID,
608
- name: 'ShellChats',
609
- description: 'Connects your gateway to ShellChats via WebRTC P2P',
647
+ name: 'ClawChats',
648
+ description: 'Connects your gateway to ClawChats via WebRTC P2P',
610
649
  register(api) {
611
650
  // Background service: signaling + gateway bridge + future WebRTC
612
651
  api.registerService({
613
652
  id: 'connector-service',
614
- start: (ctx) => startShellChat(ctx, api),
615
- stop: (ctx) => stopShellChat(ctx),
653
+ start: (ctx) => startClawChats(ctx, api),
654
+ stop: (ctx) => stopClawChats(ctx),
616
655
  });
617
656
  // CLI commands
618
657
  api.registerCli((ctx) => {
619
- const cmd = ctx.program.command('shellchats');
658
+ const cmd = ctx.program.command('clawchats');
620
659
  cmd.command('setup <token>')
621
- .description('Set up ShellChats with a setup token')
660
+ .description('Set up ClawChats with a setup token')
622
661
  .action((token) => handleSetup(String(token)));
623
662
  cmd.command('status')
624
- .description('Show ShellChats connection status')
663
+ .description('Show ClawChats connection status')
625
664
  .action(() => handleStatus());
626
665
  cmd.command('reset')
627
- .description('Disconnect and remove all ShellChats data')
666
+ .description('Disconnect and remove all ClawChats data')
628
667
  .action(() => handleReset());
629
668
  cmd.command('import <path>')
630
669
  .description('Import databases and config from a folder (e.g. migrate from old data directory)')
@@ -632,8 +671,8 @@ const plugin = {
632
671
  });
633
672
  // Slash command for status from any channel
634
673
  api.registerCommand({
635
- name: 'shellchats',
636
- description: 'Show ShellChats tunnel status',
674
+ name: 'clawchats',
675
+ description: 'Show ClawChats tunnel status',
637
676
  handler: () => ({ text: formatStatus() }),
638
677
  });
639
678
  },
package/dist/migrate.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Schema migration runner for the ShellChat plugin SQLite database.
2
+ * Schema migration runner for the ClawChats plugin SQLite database.
3
3
  *
4
4
  * - Tracks schema version in a `_schema_version` table
5
5
  * - Runs migrations sequentially from current version to target
package/dist/migrate.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Schema migration runner for the ShellChat plugin SQLite database.
2
+ * Schema migration runner for the ClawChats plugin SQLite database.
3
3
  *
4
4
  * - Tracks schema version in a `_schema_version` table
5
5
  * - Runs migrations sequentially from current version to target
package/dist/shim.js CHANGED
@@ -46,7 +46,7 @@ class FakeReq extends Readable {
46
46
  }
47
47
  else if (parsed && parsed['_multipart']) {
48
48
  // Multipart form data: { _multipart: true, fields: { key: string | { filename, contentType, data } } }
49
- const boundary = '----ShellChatBoundary' + Date.now();
49
+ const boundary = '----ClawChatsBoundary' + Date.now();
50
50
  this.headers['content-type'] = `multipart/form-data; boundary=${boundary}`;
51
51
  const fields = parsed['fields'] || {};
52
52
  const parts = [];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * SignalingClient — persistent WSS connection to the ShellChat signaling server.
2
+ * SignalingClient — persistent WSS connection to the ClawChats signaling server.
3
3
  *
4
4
  * Responsibilities:
5
5
  * - Authenticate with the signaling server on connect (gateway-auth)
@@ -1,5 +1,5 @@
1
1
  /**
2
- * SignalingClient — persistent WSS connection to the ShellChat signaling server.
2
+ * SignalingClient — persistent WSS connection to the ClawChats signaling server.
3
3
  *
4
4
  * Responsibilities:
5
5
  * - Authenticate with the signaling server on connect (gateway-auth)
@@ -109,7 +109,7 @@ export declare class WebRTCPeerManager extends EventEmitter {
109
109
  handleIceCandidate(connectionId: string, candidate: unknown): void;
110
110
  /**
111
111
  * Close all active peer connections and DataChannels.
112
- * Called during plugin shutdown (stopShellChat).
112
+ * Called during plugin shutdown (stopClawChats).
113
113
  */
114
114
  closeAll(): void;
115
115
  /**
@@ -194,7 +194,7 @@ export class WebRTCPeerManager extends EventEmitter {
194
194
  }
195
195
  /**
196
196
  * Close all active peer connections and DataChannels.
197
- * Called during plugin shutdown (stopShellChat).
197
+ * Called during plugin shutdown (stopClawChats).
198
198
  */
199
199
  closeAll() {
200
200
  console.log(`[WebRTCPeerManager] Closing all connections (${this.peerConnections.size} peers, ${this.activeChannels.size} channels)`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "connector",
3
- "name": "ShellChats",
4
- "description": "Connects your OpenClaw gateway to ShellChats via WebRTC P2P",
3
+ "name": "ClawChats",
4
+ "description": "Connects your OpenClaw gateway to ClawChats via WebRTC P2P",
5
5
  "kind": "integration",
6
6
  "configSchema": {
7
7
  "type": "object",
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@clawchatsai/connector",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "type": "module",
5
- "description": "ShellChat OpenClaw plugin — P2P tunnel + local API bridge",
5
+ "description": "ClawChats OpenClaw plugin — P2P tunnel + local API bridge",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "files": [
package/server.js CHANGED
@@ -1,4 +1,4 @@
1
- // ShellChat Backend Server
1
+ // ClawChats Backend Server
2
2
  // Single-file Node.js HTTP server with SQLite storage
3
3
  // See specs/backend-session-architecture.md for full spec
4
4
 
@@ -64,7 +64,7 @@ function _buildDeviceAuth(identity, { clientId, clientMode, role, scopes, token,
64
64
 
65
65
  // ─── Configuration ──────────────────────────────────────────────────────────
66
66
 
67
- const PORT = parseInt(process.env.SHELLCHAT_PORT || '3001', 10);
67
+ const PORT = parseInt(process.env.CLAWCHATS_PORT || process.env.SHELLCHAT_PORT || '3001', 10);
68
68
  const DATA_DIR = path.join(__dirname, 'data');
69
69
  const UPLOADS_DIR = path.join(__dirname, 'uploads');
70
70
  const WORKSPACES_FILE = path.join(DATA_DIR, 'workspaces.json');
@@ -174,9 +174,9 @@ function parseConfigField(field) {
174
174
  }
175
175
 
176
176
  // Load auth token from config.js or env var
177
- let AUTH_TOKEN = process.env.SHELLCHAT_AUTH_TOKEN || parseConfigField('authToken') || '';
177
+ let AUTH_TOKEN = process.env.CLAWCHATS_AUTH_TOKEN || process.env.SHELLCHAT_AUTH_TOKEN || parseConfigField('authToken') || '';
178
178
  if (!AUTH_TOKEN) {
179
- console.error('WARNING: No auth token configured. Set SHELLCHAT_AUTH_TOKEN or create config.js');
179
+ console.error('WARNING: No auth token configured. Set CLAWCHATS_AUTH_TOKEN or create config.js');
180
180
  }
181
181
 
182
182
  // Load gateway WebSocket URL
@@ -883,7 +883,7 @@ async function handleMarkMessagesRead(req, res, params) {
883
883
  // Broadcast unread-update to ALL browser clients (so other tabs/devices sync)
884
884
  const workspace = getWorkspaces().active;
885
885
  gatewayClient.broadcastToBrowsers(JSON.stringify({
886
- type: 'shellchat',
886
+ type: 'clawchats',
887
887
  event: 'unread-update',
888
888
  workspace,
889
889
  threadId,
@@ -2369,7 +2369,7 @@ class GatewayClient {
2369
2369
 
2370
2370
  saveAssistantMessage(sessionKey, message, seq) {
2371
2371
  const parsed = parseSessionKey(sessionKey);
2372
- if (!parsed) return; // Non-ShellChat session key, silently ignore
2372
+ if (!parsed) return; // Non-ClawChats session key, silently ignore
2373
2373
 
2374
2374
  // Guard: verify workspace still exists
2375
2375
  const ws = getWorkspaces();
@@ -2424,7 +2424,7 @@ class GatewayClient {
2424
2424
 
2425
2425
  // Broadcast message-saved for active thread reload
2426
2426
  this.broadcastToBrowsers(JSON.stringify({
2427
- type: 'shellchat',
2427
+ type: 'clawchats',
2428
2428
  event: 'message-saved',
2429
2429
  threadId: parsed.threadId,
2430
2430
  workspace: parsed.workspace,
@@ -2438,7 +2438,7 @@ class GatewayClient {
2438
2438
  // Always broadcast unread-update — browser sends read receipts to clear
2439
2439
  const workspaceUnreadTotal = db.prepare('SELECT COALESCE(SUM(unread_count), 0) as total FROM threads').get().total;
2440
2440
  this.broadcastToBrowsers(JSON.stringify({
2441
- type: 'shellchat',
2441
+ type: 'clawchats',
2442
2442
  event: 'unread-update',
2443
2443
  workspace: parsed.workspace,
2444
2444
  threadId: parsed.threadId,
@@ -2616,7 +2616,7 @@ class GatewayClient {
2616
2616
  if (!parsed) return;
2617
2617
 
2618
2618
  this.broadcastToBrowsers(JSON.stringify({
2619
- type: 'shellchat',
2619
+ type: 'clawchats',
2620
2620
  event: 'agent-activity',
2621
2621
  workspace: parsed.workspace,
2622
2622
  threadId: parsed.threadId,
@@ -2761,7 +2761,7 @@ class GatewayClient {
2761
2761
 
2762
2762
  // Notify browsers to re-render this message with activity data
2763
2763
  this.broadcastToBrowsers(JSON.stringify({
2764
- type: 'shellchat',
2764
+ type: 'clawchats',
2765
2765
  event: 'activity-saved',
2766
2766
  workspace: parsed.workspace,
2767
2767
  threadId: parsed.threadId,
@@ -2844,7 +2844,7 @@ class GatewayClient {
2844
2844
 
2845
2845
  broadcastGatewayStatus(connected) {
2846
2846
  const msg = JSON.stringify({
2847
- type: 'shellchat',
2847
+ type: 'clawchats',
2848
2848
  event: 'gateway-status',
2849
2849
  connected
2850
2850
  });
@@ -2873,7 +2873,7 @@ class GatewayClient {
2873
2873
  // Send current gateway status
2874
2874
  if (ws.readyState === WS.OPEN) {
2875
2875
  ws.send(JSON.stringify({
2876
- type: 'shellchat',
2876
+ type: 'clawchats',
2877
2877
  event: 'gateway-status',
2878
2878
  connected: this.connected
2879
2879
  }));
@@ -2887,7 +2887,7 @@ class GatewayClient {
2887
2887
  }
2888
2888
  if (streams.length > 0) {
2889
2889
  ws.send(JSON.stringify({
2890
- type: 'shellchat',
2890
+ type: 'clawchats',
2891
2891
  event: 'stream-sync',
2892
2892
  streams
2893
2893
  }));
@@ -2924,7 +2924,7 @@ class GatewayClient {
2924
2924
  // Broadcast unread-update clear to ALL browser clients
2925
2925
  const workspaceUnreadTotal = db.prepare('SELECT COALESCE(SUM(unread_count), 0) as total FROM threads').get().total;
2926
2926
  this.broadcastToBrowsers(JSON.stringify({
2927
- type: 'shellchat',
2927
+ type: 'clawchats',
2928
2928
  event: 'unread-update',
2929
2929
  workspace,
2930
2930
  threadId,
@@ -2952,7 +2952,7 @@ function syncThreadUnreadCount(db, threadId) {
2952
2952
  function parseSessionKey(sessionKey) {
2953
2953
  if (!sessionKey) return null;
2954
2954
  const match = sessionKey.match(/^agent:main:([^:]+):chat:([^:]+)$/);
2955
- if (!match) return null; // Non-ShellChat keys — silently ignore
2955
+ if (!match) return null; // Non-ClawChats keys — silently ignore
2956
2956
  return { workspace: match[1], threadId: match[2] };
2957
2957
  }
2958
2958
 
@@ -2973,7 +2973,7 @@ const gatewayClient = new GatewayClient();
2973
2973
 
2974
2974
  // ─── createApp Factory ───────────────────────────────────────────────────────
2975
2975
  // Returns an isolated instance of the app state + handlers.
2976
- // Used by the plugin (signaling/index.js) to embed ShellChat logic without
2976
+ // Used by the plugin (signaling/index.js) to embed ClawChats logic without
2977
2977
  // spinning up a standalone HTTP server.
2978
2978
 
2979
2979
  export function createApp(config = {}) {
@@ -2986,7 +2986,7 @@ export function createApp(config = {}) {
2986
2986
 
2987
2987
  let _AUTH_TOKEN = config.authToken !== undefined
2988
2988
  ? config.authToken
2989
- : (process.env.SHELLCHAT_AUTH_TOKEN || parseConfigField('authToken') || '');
2989
+ : (process.env.CLAWCHATS_AUTH_TOKEN || process.env.SHELLCHAT_AUTH_TOKEN || parseConfigField('authToken') || '');
2990
2990
 
2991
2991
  // Separate token for gateway WS auth (falls back to _AUTH_TOKEN for direct mode)
2992
2992
  const _GATEWAY_TOKEN = config.gatewayToken !== undefined
@@ -3232,7 +3232,7 @@ export function createApp(config = {}) {
3232
3232
  const remaining = syncThreadUnreadCount(db, threadId);
3233
3233
  const workspace = _getWorkspaces().active;
3234
3234
  _gatewayClient.broadcastToBrowsers(JSON.stringify({
3235
- type: 'shellchat', event: 'unread-update', workspace, threadId,
3235
+ type: 'clawchats', event: 'unread-update', workspace, threadId,
3236
3236
  action: 'read', messageIds, unreadCount: remaining, timestamp: Date.now()
3237
3237
  }));
3238
3238
  send(res, 200, { unread_count: remaining });
@@ -3679,9 +3679,9 @@ export function createApp(config = {}) {
3679
3679
  const threadInfo = db.prepare('SELECT title FROM threads WHERE id = ?').get(parsed.threadId);
3680
3680
  const unreadCount = db.prepare('SELECT COUNT(*) as c FROM unread_messages WHERE thread_id = ?').get(parsed.threadId).c;
3681
3681
  const preview = content.length > 120 ? content.substring(0, 120) + '...' : content;
3682
- this.broadcastToBrowsers(JSON.stringify({ type: 'shellchat', event: 'message-saved', threadId: parsed.threadId, workspace: parsed.workspace, messageId, timestamp: now, title: threadInfo?.title || 'Chat', preview, unreadCount }));
3682
+ this.broadcastToBrowsers(JSON.stringify({ type: 'clawchats', event: 'message-saved', threadId: parsed.threadId, workspace: parsed.workspace, messageId, timestamp: now, title: threadInfo?.title || 'Chat', preview, unreadCount }));
3683
3683
  const workspaceUnreadTotal = db.prepare('SELECT COALESCE(SUM(unread_count), 0) as total FROM threads').get().total;
3684
- this.broadcastToBrowsers(JSON.stringify({ type: 'shellchat', event: 'unread-update', workspace: parsed.workspace, threadId: parsed.threadId, messageId, action: 'new', unreadCount, workspaceUnreadTotal, title: threadInfo?.title || 'Chat', preview, timestamp: now }));
3684
+ this.broadcastToBrowsers(JSON.stringify({ type: 'clawchats', event: 'unread-update', workspace: parsed.workspace, threadId: parsed.threadId, messageId, action: 'new', unreadCount, workspaceUnreadTotal, title: threadInfo?.title || 'Chat', preview, timestamp: now }));
3685
3685
  console.log(`Saved assistant message to ${parsed.workspace}/${parsed.threadId} (seq: ${seq})`);
3686
3686
  } catch (e) { console.error(`Failed to save assistant message:`, e.message); }
3687
3687
  }
@@ -3759,7 +3759,7 @@ export function createApp(config = {}) {
3759
3759
  broadcastActivityUpdate(runId, log) {
3760
3760
  const parsed = log.sessionKey ? parseSessionKey(log.sessionKey) : null;
3761
3761
  if (!parsed) return;
3762
- this.broadcastToBrowsers(JSON.stringify({ type: 'shellchat', event: 'agent-activity', workspace: parsed.workspace, threadId: parsed.threadId, runId, steps: log.steps, summary: this.generateActivitySummary(log.steps) }));
3762
+ this.broadcastToBrowsers(JSON.stringify({ type: 'clawchats', event: 'agent-activity', workspace: parsed.workspace, threadId: parsed.threadId, runId, steps: log.steps, summary: this.generateActivitySummary(log.steps) }));
3763
3763
  }
3764
3764
 
3765
3765
  finalizeActivityLog(runId, log) {
@@ -3824,7 +3824,7 @@ export function createApp(config = {}) {
3824
3824
  metadata.activitySummary = this.generateActivitySummary(log.steps);
3825
3825
  db.prepare('UPDATE messages SET metadata = ? WHERE id = ?').run(JSON.stringify(metadata), msg.id);
3826
3826
  console.log(`[ActivityLog] Saved ${toolSteps.length} tool steps for message ${msg.id}`);
3827
- this.broadcastToBrowsers(JSON.stringify({ type: 'shellchat', event: 'activity-saved', workspace: parsed.workspace, threadId: parsed.threadId, messageId: msg.id }));
3827
+ this.broadcastToBrowsers(JSON.stringify({ type: 'clawchats', event: 'activity-saved', workspace: parsed.workspace, threadId: parsed.threadId, messageId: msg.id }));
3828
3828
  }
3829
3829
  }
3830
3830
  } catch (e) { console.error('Failed to save activity log:', e.message); }
@@ -3864,7 +3864,7 @@ export function createApp(config = {}) {
3864
3864
  }
3865
3865
 
3866
3866
  broadcastGatewayStatus(connected) {
3867
- this.broadcastToBrowsers(JSON.stringify({ type: 'shellchat', event: 'gateway-status', connected }));
3867
+ this.broadcastToBrowsers(JSON.stringify({ type: 'clawchats', event: 'gateway-status', connected }));
3868
3868
  }
3869
3869
 
3870
3870
  sendToGateway(data) {
@@ -3883,12 +3883,12 @@ export function createApp(config = {}) {
3883
3883
  addBrowserClient(ws) {
3884
3884
  this.browserClients.set(ws, { activeWorkspace: null, activeThreadId: null });
3885
3885
  if (ws.readyState === WS.OPEN) {
3886
- ws.send(JSON.stringify({ type: 'shellchat', event: 'gateway-status', connected: this.connected }));
3886
+ ws.send(JSON.stringify({ type: 'clawchats', event: 'gateway-status', connected: this.connected }));
3887
3887
  const streams = [];
3888
3888
  for (const [sessionKey, state] of this.streamState.entries()) {
3889
3889
  if (state.state === 'streaming') streams.push({ sessionKey, threadId: state.threadId, buffer: state.buffer });
3890
3890
  }
3891
- if (streams.length > 0) ws.send(JSON.stringify({ type: 'shellchat', event: 'stream-sync', streams }));
3891
+ if (streams.length > 0) ws.send(JSON.stringify({ type: 'clawchats', event: 'stream-sync', streams }));
3892
3892
  }
3893
3893
  }
3894
3894
 
@@ -3908,7 +3908,7 @@ export function createApp(config = {}) {
3908
3908
  if (deleted.changes > 0) {
3909
3909
  syncThreadUnreadCount(db, threadId);
3910
3910
  const workspaceUnreadTotal = db.prepare('SELECT COALESCE(SUM(unread_count), 0) as total FROM threads').get().total;
3911
- this.broadcastToBrowsers(JSON.stringify({ type: 'shellchat', event: 'unread-update', workspace, threadId, action: 'clear', unreadCount: 0, workspaceUnreadTotal, timestamp: Date.now() }));
3911
+ this.broadcastToBrowsers(JSON.stringify({ type: 'clawchats', event: 'unread-update', workspace, threadId, action: 'clear', unreadCount: 0, workspaceUnreadTotal, timestamp: Date.now() }));
3912
3912
  }
3913
3913
  } catch (e) { console.error('Failed to auto-clear unreads on active-thread:', e.message); }
3914
3914
  }
@@ -4024,7 +4024,7 @@ export function createApp(config = {}) {
4024
4024
  const token = msg.params?.auth?.token;
4025
4025
  if (token === _AUTH_TOKEN || !_AUTH_TOKEN) {
4026
4026
  console.log('Browser client authenticated');
4027
- ws.send(JSON.stringify({ type: 'res', id: msg.id, ok: true, payload: { type: 'hello-ok', protocol: 3, server: { version: '0.1.0', host: 'shellchat-backend' } } }));
4027
+ ws.send(JSON.stringify({ type: 'res', id: msg.id, ok: true, payload: { type: 'hello-ok', protocol: 3, server: { version: '0.1.0', host: 'clawchats-backend' } } }));
4028
4028
  } else {
4029
4029
  console.log('Browser client auth failed');
4030
4030
  ws.send(JSON.stringify({ type: 'res', id: msg.id, ok: false, error: { code: 'AUTH_FAILED', message: 'Invalid auth token' } }));
@@ -4032,12 +4032,12 @@ export function createApp(config = {}) {
4032
4032
  }
4033
4033
  return;
4034
4034
  }
4035
- if (msg.type === 'shellchat') {
4035
+ if (msg.type === 'clawchats' || msg.type === 'shellchat') { // backward compat: accept legacy 'shellchat' type
4036
4036
  if (msg.action === 'active-thread') { _gatewayClient.setActiveThread(ws, msg.workspace, msg.threadId); console.log(`Browser client set active thread: ${msg.workspace}/${msg.threadId}`); return; }
4037
- if (msg.action === 'debug-start') { const result = _debugLogger.start(msg.ts, ws); if (result.error === 'already-active') ws.send(JSON.stringify({ type: 'shellchat', event: 'debug-error', error: 'Recording already active in another tab', sessionId: result.sessionId })); else ws.send(JSON.stringify({ type: 'shellchat', event: 'debug-started', sessionId: result.sessionId })); return; }
4038
- if (msg.action === 'debug-dump') { const { sessionId, files } = _debugLogger.saveDump(msg); ws.send(JSON.stringify({ type: 'shellchat', event: 'debug-saved', sessionId, files })); return; }
4037
+ if (msg.action === 'debug-start') { const result = _debugLogger.start(msg.ts, ws); if (result.error === 'already-active') ws.send(JSON.stringify({ type: 'clawchats', event: 'debug-error', error: 'Recording already active in another tab', sessionId: result.sessionId })); else ws.send(JSON.stringify({ type: 'clawchats', event: 'debug-started', sessionId: result.sessionId })); return; }
4038
+ if (msg.action === 'debug-dump') { const { sessionId, files } = _debugLogger.saveDump(msg); ws.send(JSON.stringify({ type: 'clawchats', event: 'debug-saved', sessionId, files })); return; }
4039
4039
  }
4040
- } catch { /* Not JSON or not a ShellChat message, forward to gateway */ }
4040
+ } catch { /* Not JSON or not a ClawChats message, forward to gateway */ }
4041
4041
  _gatewayClient.sendToGateway(msgStr);
4042
4042
  });
4043
4043
 
@@ -4086,7 +4086,7 @@ if (isDirectRun) {
4086
4086
  });
4087
4087
 
4088
4088
  server.listen(PORT, () => {
4089
- console.log(`ShellChat backend listening on port ${PORT}`);
4089
+ console.log(`ClawChats backend listening on port ${PORT}`);
4090
4090
  console.log(`Active workspace: ${app.getWorkspaces().active}`);
4091
4091
  console.log(`Data dir: ${app.dataDir}`);
4092
4092