@lifeaitools/clauth 1.5.47 → 1.5.49

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 (2) hide show
  1. package/cli/commands/serve.js +114 -12
  2. package/package.json +1 -1
@@ -3382,6 +3382,90 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3382
3382
  });
3383
3383
  }
3384
3384
 
3385
+ // GET /chitchat/<session_id>/stream — SSE push stream for Claude Code (inbox events)
3386
+ // Claude Code connects once; daemon pushes an event on every chitchat_send call
3387
+ const inboxStreamMatch = reqPath.match(/^\/chitchat\/([^/]+)\/stream$/);
3388
+ if (method === "GET" && inboxStreamMatch) {
3389
+ const session_id = inboxStreamMatch[1];
3390
+ const session = terminalSessions.get(session_id);
3391
+ if (!session || !session.is_chitchat) {
3392
+ res.writeHead(404, { "Content-Type": "application/json", ...CORS });
3393
+ return res.end(JSON.stringify({ error: "session not found" }));
3394
+ }
3395
+
3396
+ res.writeHead(200, {
3397
+ "Content-Type": "text/event-stream",
3398
+ "Cache-Control": "no-cache",
3399
+ "Connection": "keep-alive",
3400
+ ...CORS,
3401
+ });
3402
+
3403
+ // Send any already-queued inbox messages immediately
3404
+ if (session.inbox.length) {
3405
+ for (const entry of session.inbox) {
3406
+ res.write(`event: message\ndata: ${JSON.stringify(entry)}\n\n`);
3407
+ }
3408
+ session.inbox = [];
3409
+ }
3410
+
3411
+ session.inboxStreams.push(res);
3412
+ console.log(`[ClaudeAItoCLI] session ${session_id} inbox stream connected (${session.inboxStreams.length} total)`);
3413
+
3414
+ const keepalive = setInterval(() => {
3415
+ try { res.write(": keepalive\n\n"); } catch {}
3416
+ }, 15_000);
3417
+
3418
+ req.on("close", () => {
3419
+ clearInterval(keepalive);
3420
+ session.inboxStreams = session.inboxStreams.filter(r => r !== res);
3421
+ console.log(`[ClaudeAItoCLI] session ${session_id} inbox stream disconnected`);
3422
+ });
3423
+
3424
+ return;
3425
+ }
3426
+
3427
+ // GET /chitchat/<session_id>/watch — SSE push stream for claude.ai (outbox events)
3428
+ // claude.ai connects once; daemon pushes an event on every chitchat_reply call
3429
+ const outboxStreamMatch = reqPath.match(/^\/chitchat\/([^/]+)\/watch$/);
3430
+ if (method === "GET" && outboxStreamMatch) {
3431
+ const session_id = outboxStreamMatch[1];
3432
+ const session = terminalSessions.get(session_id);
3433
+ if (!session || !session.is_chitchat) {
3434
+ res.writeHead(404, { "Content-Type": "application/json", ...CORS });
3435
+ return res.end(JSON.stringify({ error: "session not found" }));
3436
+ }
3437
+
3438
+ res.writeHead(200, {
3439
+ "Content-Type": "text/event-stream",
3440
+ "Cache-Control": "no-cache",
3441
+ "Connection": "keep-alive",
3442
+ ...CORS,
3443
+ });
3444
+
3445
+ // Send any already-queued outbox messages immediately
3446
+ if (session.outbox.length) {
3447
+ for (const entry of session.outbox) {
3448
+ res.write(`event: message\ndata: ${JSON.stringify(entry)}\n\n`);
3449
+ }
3450
+ session.outbox = [];
3451
+ }
3452
+
3453
+ session.outboxStreams.push(res);
3454
+ console.log(`[ClaudeAItoCLI] session ${session_id} outbox stream connected (${session.outboxStreams.length} total)`);
3455
+
3456
+ const keepalive = setInterval(() => {
3457
+ try { res.write(": keepalive\n\n"); } catch {}
3458
+ }, 15_000);
3459
+
3460
+ req.on("close", () => {
3461
+ clearInterval(keepalive);
3462
+ session.outboxStreams = session.outboxStreams.filter(r => r !== res);
3463
+ console.log(`[ClaudeAItoCLI] session ${session_id} outbox stream disconnected`);
3464
+ });
3465
+
3466
+ return;
3467
+ }
3468
+
3385
3469
  // GET /debug/sessions — live view of all terminal/chitchat sessions
3386
3470
  if (method === "GET" && reqPath === "/debug/sessions") {
3387
3471
  const now = Date.now();
@@ -5174,8 +5258,10 @@ async function startChitchatSession(name) {
5174
5258
  started_at: new Date().toISOString(),
5175
5259
  is_chitchat: true,
5176
5260
  turn: 0,
5177
- inbox: [], // claude.ai → Claude Code
5178
- outbox: [], // Claude Code → claude.ai
5261
+ inbox: [], // claude.ai → Claude Code
5262
+ outbox: [], // Claude Code → claude.ai
5263
+ inboxStreams: [], // SSE listeners waiting on inbox (Claude Code side)
5264
+ outboxStreams: [], // SSE listeners waiting on outbox (claude.ai side)
5179
5265
  };
5180
5266
  terminalSessions.set(session_id, session);
5181
5267
 
@@ -5183,8 +5269,8 @@ async function startChitchatSession(name) {
5183
5269
  const binary = findClaudeBinary();
5184
5270
  if (binary) {
5185
5271
  try {
5186
- const cmd = `start cmd /k "cd /d ${CHITCHAT_CWD} && ${binary} /rdc:collab --session ${session_id}"`;
5187
- require('child_process').exec(cmd, { shell: true });
5272
+ const child = spawnProc('wt.exe', ['new-tab', '--title', 'rdc:collab', 'cmd', '/k', `cd /d ${CHITCHAT_CWD} && ${binary} /rdc:collab --session ${session_id}`], { detached: true, stdio: 'ignore', shell: false });
5273
+ child.unref();
5188
5274
  console.log(`[ClaudeAItoCLI] spawned terminal for session ${session_id}`);
5189
5275
  } catch (err) {
5190
5276
  console.warn(`[ClaudeAItoCLI] could not spawn terminal: ${err.message}`);
@@ -5204,7 +5290,7 @@ async function startChitchatSession(name) {
5204
5290
  return { session_id, status: 'ready', name };
5205
5291
  }
5206
5292
 
5207
- // claude.ai → inbox (Claude Code reads via chitchat_poll)
5293
+ // claude.ai → inbox — also pushes SSE event to any connected Claude Code stream listeners
5208
5294
  function sendChitchatMessage(session_id, message) {
5209
5295
  const session = terminalSessions.get(session_id);
5210
5296
  if (!session) return { error: 'not_found', message: `Session ${session_id} not found` };
@@ -5213,12 +5299,20 @@ function sendChitchatMessage(session_id, message) {
5213
5299
 
5214
5300
  session.turn = (session.turn || 0) + 1;
5215
5301
  const turn = session.turn;
5216
- session.inbox.push({ turn, message, sent_at: new Date().toISOString() });
5217
- console.log(`[ClaudeAItoCLI] session ${session_id} turn=${turn} message queued`);
5302
+ const entry = { turn, message, sent_at: new Date().toISOString() };
5303
+ session.inbox.push(entry);
5304
+
5305
+ // Notify any connected Claude Code SSE listeners immediately
5306
+ const event = `event: message\ndata: ${JSON.stringify(entry)}\n\n`;
5307
+ session.inboxStreams = session.inboxStreams.filter(res => {
5308
+ try { res.write(event); return true; } catch { return false; }
5309
+ });
5310
+
5311
+ console.log(`[ClaudeAItoCLI] session ${session_id} turn=${turn} queued (${session.inboxStreams.length} stream(s) notified)`);
5218
5312
  return { queued: true, session_id, turn };
5219
5313
  }
5220
5314
 
5221
- // claude.ai ← outbox (drains all pending replies in one call)
5315
+ // claude.ai ← outbox drains all pending replies in one call
5222
5316
  function recvChitchatResponse(session_id) {
5223
5317
  const session = terminalSessions.get(session_id);
5224
5318
  if (!session) return { error: 'not_found', message: `Session ${session_id} not found` };
@@ -5230,7 +5324,7 @@ function recvChitchatResponse(session_id) {
5230
5324
  return { session_id, status: 'ready', count: messages.length, messages };
5231
5325
  }
5232
5326
 
5233
- // Claude Code reads all pending messages from claude.ai in one call
5327
+ // Claude Code reads all pending inbox messages in one call (fallback when not using SSE stream)
5234
5328
  function pollChitchatMessage(session_id) {
5235
5329
  const session = terminalSessions.get(session_id);
5236
5330
  if (!session) return { error: 'not_found', message: `Session ${session_id} not found` };
@@ -5242,14 +5336,22 @@ function pollChitchatMessage(session_id) {
5242
5336
  return { session_id, status: 'ready', count: messages.length, messages };
5243
5337
  }
5244
5338
 
5245
- // Claude Code sends response back to claude.ai
5339
+ // Claude Code outbox also pushes SSE event to any connected claude.ai stream listeners
5246
5340
  function replyChitchatMessage(session_id, message) {
5247
5341
  const session = terminalSessions.get(session_id);
5248
5342
  if (!session) return { error: 'not_found', message: `Session ${session_id} not found` };
5249
5343
  if (!session.is_chitchat) return { error: 'wrong_type', message: 'Not a ClaudeAItoCLI session' };
5250
5344
 
5251
- session.outbox.push({ turn: session.turn, message, sent_at: new Date().toISOString() });
5252
- console.log(`[ClaudeAItoCLI] session ${session_id} reply queued turn=${session.turn}`);
5345
+ const entry = { turn: session.turn, message, sent_at: new Date().toISOString() };
5346
+ session.outbox.push(entry);
5347
+
5348
+ // Notify any connected claude.ai SSE listeners immediately
5349
+ const event = `event: message\ndata: ${JSON.stringify(entry)}\n\n`;
5350
+ session.outboxStreams = session.outboxStreams.filter(res => {
5351
+ try { res.write(event); return true; } catch { return false; }
5352
+ });
5353
+
5354
+ console.log(`[ClaudeAItoCLI] session ${session_id} reply queued turn=${session.turn} (${session.outboxStreams.length} stream(s) notified)`);
5253
5355
  return { queued: true, session_id, turn: session.turn };
5254
5356
  }
5255
5357
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/clauth",
3
- "version": "1.5.47",
3
+ "version": "1.5.49",
4
4
  "description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
5
5
  "type": "module",
6
6
  "bin": {