@clawchatsai/connector 0.0.42 → 0.0.44
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/package.json +1 -1
- package/server.js +36 -20
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -334,14 +334,14 @@ function getActiveDb() {
|
|
|
334
334
|
return getDb(getWorkspaces().active);
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
|
|
338
|
-
function getGlobalDb() {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
337
|
+
const _globalDbCache = new Map(); // keyed by resolved dbPath
|
|
338
|
+
function getGlobalDb(dataDir = DATA_DIR) {
|
|
339
|
+
const dbPath = path.join(dataDir, 'global.db');
|
|
340
|
+
if (_globalDbCache.has(dbPath)) return _globalDbCache.get(dbPath);
|
|
341
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
342
|
+
const db = new Database(dbPath);
|
|
343
|
+
db.pragma('journal_mode = WAL');
|
|
344
|
+
db.exec(`
|
|
345
345
|
CREATE TABLE IF NOT EXISTS custom_emojis (
|
|
346
346
|
name TEXT NOT NULL,
|
|
347
347
|
pack TEXT NOT NULL DEFAULT 'slackmojis',
|
|
@@ -351,7 +351,8 @@ function getGlobalDb() {
|
|
|
351
351
|
PRIMARY KEY (name, pack)
|
|
352
352
|
)
|
|
353
353
|
`);
|
|
354
|
-
|
|
354
|
+
_globalDbCache.set(dbPath, db);
|
|
355
|
+
return db;
|
|
355
356
|
}
|
|
356
357
|
|
|
357
358
|
function closeDb(workspaceName) {
|
|
@@ -363,11 +364,10 @@ function closeDb(workspaceName) {
|
|
|
363
364
|
}
|
|
364
365
|
|
|
365
366
|
function closeAllDbs() {
|
|
366
|
-
for (const [
|
|
367
|
-
db.close();
|
|
368
|
-
}
|
|
367
|
+
for (const [, db] of dbCache) db.close();
|
|
369
368
|
dbCache.clear();
|
|
370
|
-
|
|
369
|
+
for (const [, db] of _globalDbCache) db.close();
|
|
370
|
+
_globalDbCache.clear();
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
function _createFtsTables(db) {
|
|
@@ -1437,7 +1437,10 @@ function handleServeFile(req, res, query) {
|
|
|
1437
1437
|
if (!filePath) return sendError(res, 400, 'Missing path parameter');
|
|
1438
1438
|
|
|
1439
1439
|
// Resolve to prevent traversal attacks
|
|
1440
|
-
|
|
1440
|
+
// Relative paths (./filename) resolve against the workspace directory
|
|
1441
|
+
const resolved = (filePath.startsWith('./') || filePath.startsWith('../'))
|
|
1442
|
+
? path.resolve(MEMORY_CONFIG.workspaceDir, filePath)
|
|
1443
|
+
: path.resolve(filePath);
|
|
1441
1444
|
|
|
1442
1445
|
// Security: only serve files from allowed directories
|
|
1443
1446
|
const allowed = ALLOWED_FILE_DIRS.some(dir => resolved.startsWith(dir + '/') || resolved === dir);
|
|
@@ -4417,7 +4420,7 @@ export function createApp(config = {}) {
|
|
|
4417
4420
|
// Custom emoji listing (no auth)
|
|
4418
4421
|
if (method === 'GET' && urlPath === '/api/emoji') {
|
|
4419
4422
|
try {
|
|
4420
|
-
const db = getGlobalDb();
|
|
4423
|
+
const db = getGlobalDb(_DATA_DIR);
|
|
4421
4424
|
const rows = db.prepare('SELECT name, pack, url, mime_type FROM custom_emojis ORDER BY created_at DESC').all();
|
|
4422
4425
|
res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'public, max-age=300' });
|
|
4423
4426
|
return res.end(JSON.stringify(rows));
|
|
@@ -4461,7 +4464,7 @@ export function createApp(config = {}) {
|
|
|
4461
4464
|
if (urlLower.endsWith('.gif')) mimeType = 'image/gif';
|
|
4462
4465
|
else if (urlLower.endsWith('.webp')) mimeType = 'image/webp';
|
|
4463
4466
|
else if (urlLower.endsWith('.jpg') || urlLower.endsWith('.jpeg')) mimeType = 'image/jpeg';
|
|
4464
|
-
const db = getGlobalDb();
|
|
4467
|
+
const db = getGlobalDb(_DATA_DIR);
|
|
4465
4468
|
db.prepare('INSERT OR REPLACE INTO custom_emojis (name, pack, url, mime_type) VALUES (?, ?, ?, ?)').run(safeName, targetPack, url, mimeType);
|
|
4466
4469
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4467
4470
|
return res.end(JSON.stringify({ name: safeName, pack: targetPack, url, mime_type: mimeType }));
|
|
@@ -4473,7 +4476,7 @@ export function createApp(config = {}) {
|
|
|
4473
4476
|
try {
|
|
4474
4477
|
const { name, pack } = await parseBody(req);
|
|
4475
4478
|
if (!name || !pack) { res.writeHead(400, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ error: 'Missing name or pack' })); }
|
|
4476
|
-
const db = getGlobalDb();
|
|
4479
|
+
const db = getGlobalDb(_DATA_DIR);
|
|
4477
4480
|
db.prepare('DELETE FROM custom_emojis WHERE name = ? AND pack = ?').run(name, pack);
|
|
4478
4481
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4479
4482
|
return res.end(JSON.stringify({ ok: true }));
|
|
@@ -4544,6 +4547,9 @@ export function createApp(config = {}) {
|
|
|
4544
4547
|
}
|
|
4545
4548
|
|
|
4546
4549
|
// ── Browser WebSocket setup (shared logic for standalone and plugin) ────────
|
|
4550
|
+
// Track which sessions have already received the ClawChats file hint (once per session)
|
|
4551
|
+
const _clawchatsHintedSessions = new Set();
|
|
4552
|
+
|
|
4547
4553
|
function _setupBrowserWs(wssInstance) {
|
|
4548
4554
|
wssInstance.on('connection', (ws) => {
|
|
4549
4555
|
console.log('Browser client connected');
|
|
@@ -4554,6 +4560,7 @@ export function createApp(config = {}) {
|
|
|
4554
4560
|
ws.on('message', (data) => {
|
|
4555
4561
|
const msgStr = data.toString();
|
|
4556
4562
|
_debugLogger.logFrame('BR→SRV', msgStr);
|
|
4563
|
+
let forwardStr = msgStr;
|
|
4557
4564
|
try {
|
|
4558
4565
|
const msg = JSON.parse(msgStr);
|
|
4559
4566
|
if (msg.type === 'req' && msg.method === 'connect') {
|
|
@@ -4573,8 +4580,17 @@ export function createApp(config = {}) {
|
|
|
4573
4580
|
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; }
|
|
4574
4581
|
if (msg.action === 'debug-dump') { const { sessionId, files } = _debugLogger.saveDump(msg); ws.send(JSON.stringify({ type: 'clawchats', event: 'debug-saved', sessionId, files })); return; }
|
|
4575
4582
|
}
|
|
4576
|
-
|
|
4577
|
-
|
|
4583
|
+
// Inject ClawChats file hint once per session (first message only, ~15 tokens)
|
|
4584
|
+
if (msg.type === 'req' && msg.method === 'chat.send' && typeof msg.params?.message === 'string') {
|
|
4585
|
+
const sk = msg.params.sessionKey;
|
|
4586
|
+
if (sk && !_clawchatsHintedSessions.has(sk)) {
|
|
4587
|
+
_clawchatsHintedSessions.add(sk);
|
|
4588
|
+
msg.params.message += '\n[ClawChats context: MEDIA: tags are stripped by the gateway and will NOT display. To show images/files inline, use markdown syntax:  for workspace files or  for any path. Always use this instead of MEDIA:]';
|
|
4589
|
+
forwardStr = JSON.stringify(msg);
|
|
4590
|
+
}
|
|
4591
|
+
}
|
|
4592
|
+
} catch { /* Not JSON or not a ClawChats message, forward as-is */ }
|
|
4593
|
+
_gatewayClient.sendToGateway(forwardStr);
|
|
4578
4594
|
});
|
|
4579
4595
|
|
|
4580
4596
|
ws.on('close', () => { console.log('Browser client disconnected'); _debugLogger.handleClientDisconnect(ws); _gatewayClient.removeBrowserClient(ws); });
|
|
@@ -4630,7 +4646,7 @@ if (isDirectRun) {
|
|
|
4630
4646
|
app.gatewayClient.connect();
|
|
4631
4647
|
|
|
4632
4648
|
// Initialize global DB (custom emojis, etc.)
|
|
4633
|
-
getGlobalDb();
|
|
4649
|
+
getGlobalDb(_DATA_DIR);
|
|
4634
4650
|
});
|
|
4635
4651
|
|
|
4636
4652
|
// Graceful shutdown
|