@clawchatsai/connector 0.0.39 → 0.0.41

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/server.js +78 -11
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @clawchatsai/connector
2
2
 
3
- OpenClaw plugin for [ShellChat](https://clawchats.ai) — connects your local gateway to the ShellChat web app via WebRTC P2P.
3
+ OpenClaw plugin for [ClawChats](https://clawchats.ai) — connects your local gateway to the ClawChats web app via WebRTC P2P.
4
4
 
5
5
  ## Install
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawchatsai/connector",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "type": "module",
5
5
  "description": "ClawChats OpenClaw plugin — P2P tunnel + local API bridge",
6
6
  "main": "dist/index.js",
package/server.js CHANGED
@@ -10,12 +10,50 @@ import { pipeline } from 'node:stream/promises';
10
10
  import { execSync } from 'node:child_process';
11
11
  import os from 'node:os';
12
12
  import { fileURLToPath } from 'node:url';
13
- import Database from 'better-sqlite3';
13
+ import { createRequire } from 'node:module';
14
14
  import { WebSocket as WS, WebSocketServer } from 'ws';
15
15
 
16
16
  const __filename = fileURLToPath(import.meta.url);
17
17
  const __dirname = path.dirname(__filename);
18
18
 
19
+ // ─── Native Module Bootstrap (better-sqlite3) ───────────────────────────────
20
+ // better-sqlite3 is a native (.node) binary compiled for a specific Node.js
21
+ // ABI. If the installed binary doesn't match the running Node version, we
22
+ // auto-rebuild in-place before proceeding. Falls back to a clear error message
23
+ // if the user is missing build tools.
24
+ const _require = createRequire(import.meta.url);
25
+ let Database;
26
+ {
27
+ const _nativeErr = (e) =>
28
+ e.message && (
29
+ e.message.includes('did not self-register') ||
30
+ e.message.includes('NODE_MODULE_VERSION') ||
31
+ e.message.includes('was compiled against a different Node.js version')
32
+ );
33
+ try {
34
+ Database = _require('better-sqlite3');
35
+ } catch (e) {
36
+ if (_nativeErr(e)) {
37
+ console.error('[ClawChats] better-sqlite3 binary is incompatible with your Node.js version. Attempting auto-rebuild...');
38
+ try {
39
+ execSync('npm rebuild better-sqlite3', { cwd: __dirname, stdio: 'inherit' });
40
+ Database = _require('better-sqlite3');
41
+ console.log('[ClawChats] Auto-rebuild succeeded — continuing startup.');
42
+ } catch (rebuildErr) {
43
+ console.error('[ClawChats] Auto-rebuild failed. Build tools may be missing.');
44
+ console.error('[ClawChats] To fix, run the following, then restart the gateway:');
45
+ console.error(`[ClawChats] cd ${__dirname} && npm rebuild better-sqlite3`);
46
+ console.error('[ClawChats] If that fails, install build tools first:');
47
+ console.error('[ClawChats] Linux: sudo apt install build-essential python3');
48
+ console.error('[ClawChats] macOS: xcode-select --install');
49
+ process.exit(1);
50
+ }
51
+ } else {
52
+ throw e;
53
+ }
54
+ }
55
+ }
56
+
19
57
  // ─── Device Identity (ed25519 signing for OpenClaw ≥2.15 scope preservation) ─
20
58
 
21
59
  const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
@@ -1518,6 +1556,35 @@ async function handleWorkspaceFileWrite(req, res, query) {
1518
1556
  send(res, 200, { ok: true });
1519
1557
  }
1520
1558
 
1559
+ function handleWorkspaceFileDelete(req, res, query) {
1560
+ const filePath = query.path;
1561
+ if (!filePath) return sendError(res, 400, 'Missing path parameter');
1562
+
1563
+ const resolved = path.resolve(filePath.replace(/^~/, HOME));
1564
+
1565
+ // Security: only allow paths under home directory
1566
+ if (!resolved.startsWith(HOME)) {
1567
+ return sendError(res, 403, 'Access denied');
1568
+ }
1569
+
1570
+ if (!fs.existsSync(resolved)) {
1571
+ return sendError(res, 404, 'Path not found');
1572
+ }
1573
+
1574
+ try {
1575
+ const stat = fs.statSync(resolved);
1576
+ if (stat.isDirectory()) {
1577
+ fs.rmSync(resolved, { recursive: true, force: true });
1578
+ send(res, 200, { ok: true, type: 'dir' });
1579
+ } else {
1580
+ fs.unlinkSync(resolved);
1581
+ send(res, 200, { ok: true, type: 'file' });
1582
+ }
1583
+ } catch (err) {
1584
+ sendError(res, 500, 'Delete failed: ' + err.message);
1585
+ }
1586
+ }
1587
+
1521
1588
  async function handleWorkspaceUpload(req, res, query) {
1522
1589
  const targetDir = query.path;
1523
1590
  if (!targetDir) return sendError(res, 400, 'Missing path parameter');
@@ -2250,6 +2317,9 @@ async function handleRequest(req, res) {
2250
2317
  if (method === 'PUT' && urlPath === '/api/workspace/file') {
2251
2318
  return await handleWorkspaceFileWrite(req, res, query);
2252
2319
  }
2320
+ if (method === 'DELETE' && urlPath === '/api/workspace/file') {
2321
+ return handleWorkspaceFileDelete(req, res, query);
2322
+ }
2253
2323
  if (method === 'POST' && urlPath === '/api/workspace/upload') {
2254
2324
  return await handleWorkspaceUpload(req, res, query);
2255
2325
  }
@@ -2663,11 +2733,9 @@ class GatewayClient {
2663
2733
  // Auto-generate AI title upgrade after first assistant response
2664
2734
  // Heuristic was already set on user message save; this fires the AI upgrade
2665
2735
  const currentTitle = db.prepare('SELECT title FROM threads WHERE id = ?').get(parsed.threadId)?.title;
2666
- if (currentTitle && currentTitle !== 'New chat') {
2667
- const msgCount = db.prepare('SELECT COUNT(*) as c FROM messages WHERE thread_id = ?').get(parsed.threadId).c;
2668
- if (msgCount >= 2) {
2669
- this.generateThreadTitle(db, parsed.threadId, parsed.workspace, true);
2670
- }
2736
+ const msgCount = db.prepare('SELECT COUNT(*) as c FROM messages WHERE thread_id = ?').get(parsed.threadId).c;
2737
+ if (msgCount === 2 || currentTitle === 'New chat') {
2738
+ this.generateThreadTitle(db, parsed.threadId, parsed.workspace, true);
2671
2739
  }
2672
2740
  } catch (e) {
2673
2741
  console.error(`Failed to save assistant message:`, e.message);
@@ -3987,11 +4055,9 @@ export function createApp(config = {}) {
3987
4055
 
3988
4056
  // Auto-generate AI title upgrade after first assistant response
3989
4057
  const currentTitle = db.prepare('SELECT title FROM threads WHERE id = ?').get(parsed.threadId)?.title;
3990
- if (currentTitle && currentTitle !== 'New chat') {
3991
- const msgCount = db.prepare('SELECT COUNT(*) as c FROM messages WHERE thread_id = ?').get(parsed.threadId).c;
3992
- if (msgCount >= 2) {
3993
- this.generateThreadTitle(db, parsed.threadId, parsed.workspace, true);
3994
- }
4058
+ const msgCount = db.prepare('SELECT COUNT(*) as c FROM messages WHERE thread_id = ?').get(parsed.threadId).c;
4059
+ if (msgCount === 2 || currentTitle === 'New chat') {
4060
+ this.generateThreadTitle(db, parsed.threadId, parsed.workspace, true);
3995
4061
  }
3996
4062
  } catch (e) { console.error(`Failed to save assistant message:`, e.message); }
3997
4063
  }
@@ -4370,6 +4436,7 @@ export function createApp(config = {}) {
4370
4436
  if (method === 'GET' && urlPath === '/api/workspace') return handleWorkspaceList(req, res, query);
4371
4437
  if (method === 'GET' && urlPath === '/api/workspace/file') return handleWorkspaceFileRead(req, res, query);
4372
4438
  if (method === 'PUT' && urlPath === '/api/workspace/file') return await handleWorkspaceFileWrite(req, res, query);
4439
+ if (method === 'DELETE' && urlPath === '/api/workspace/file') return handleWorkspaceFileDelete(req, res, query);
4373
4440
  if (method === 'POST' && urlPath === '/api/workspace/upload') return await handleWorkspaceUpload(req, res, query);
4374
4441
  if (method === 'GET' && urlPath === '/api/memory/status') return await _handleMemoryStatus(req, res);
4375
4442
  if (method === 'GET' && urlPath === '/api/memory/list') return await _handleMemoryList(req, res, query);