@lifeaitools/clauth 1.5.43 → 1.5.45
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/commands/serve.js +214 -53
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -3382,6 +3382,81 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3382
3382
|
});
|
|
3383
3383
|
}
|
|
3384
3384
|
|
|
3385
|
+
// GET /debug/sessions — live view of all terminal/chitchat sessions
|
|
3386
|
+
if (method === "GET" && reqPath === "/debug/sessions") {
|
|
3387
|
+
const now = Date.now();
|
|
3388
|
+
const sessions = [];
|
|
3389
|
+
for (const [, s] of terminalSessions) {
|
|
3390
|
+
const startedMs = new Date(s.started_at).getTime();
|
|
3391
|
+
sessions.push({
|
|
3392
|
+
session_id: s.session_id,
|
|
3393
|
+
name: s.name,
|
|
3394
|
+
type: s.is_chitchat ? "chitchat" : "terminal",
|
|
3395
|
+
status: s.status,
|
|
3396
|
+
turn: s.turn || 0,
|
|
3397
|
+
cwd: s.cwd || null,
|
|
3398
|
+
knowledge_tier: s.knowledge_tier,
|
|
3399
|
+
started_at: s.started_at,
|
|
3400
|
+
age_seconds: Math.round((now - startedMs) / 1000),
|
|
3401
|
+
last_response_at: s.lastResponseAt || null,
|
|
3402
|
+
last_response_preview: s.lastResponse
|
|
3403
|
+
? s.lastResponse.slice(0, 300) + (s.lastResponse.length > 300 ? "…" : "")
|
|
3404
|
+
: null,
|
|
3405
|
+
context_chars: s.context ? s.context.length : 0,
|
|
3406
|
+
active_pid: s.activeProc ? s.activeProc.pid : null,
|
|
3407
|
+
});
|
|
3408
|
+
}
|
|
3409
|
+
const html = `<!DOCTYPE html>
|
|
3410
|
+
<html>
|
|
3411
|
+
<head>
|
|
3412
|
+
<meta charset="utf-8">
|
|
3413
|
+
<meta http-equiv="refresh" content="3">
|
|
3414
|
+
<title>clauth sessions</title>
|
|
3415
|
+
<style>
|
|
3416
|
+
body { font-family: monospace; background: #0d1117; color: #c9d1d9; padding: 20px; }
|
|
3417
|
+
h1 { color: #58a6ff; font-size: 16px; margin-bottom: 4px; }
|
|
3418
|
+
.meta { color: #6e7681; font-size: 12px; margin-bottom: 20px; }
|
|
3419
|
+
.empty { color: #6e7681; }
|
|
3420
|
+
.session { border: 1px solid #30363d; border-radius: 6px; padding: 16px; margin-bottom: 16px; }
|
|
3421
|
+
.session.busy { border-color: #f0883e; }
|
|
3422
|
+
.session.ready { border-color: #3fb950; }
|
|
3423
|
+
.session.stopped { border-color: #6e7681; opacity: 0.6; }
|
|
3424
|
+
.label { color: #6e7681; font-size: 11px; text-transform: uppercase; }
|
|
3425
|
+
.value { color: #e6edf3; font-size: 13px; margin-bottom: 8px; }
|
|
3426
|
+
.badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: bold; }
|
|
3427
|
+
.badge.chitchat { background: #1f4068; color: #58a6ff; }
|
|
3428
|
+
.badge.terminal { background: #2d1f3d; color: #bc8cff; }
|
|
3429
|
+
.badge.busy { background: #3d2400; color: #f0883e; }
|
|
3430
|
+
.badge.ready { background: #0f2a0f; color: #3fb950; }
|
|
3431
|
+
.preview { background: #161b22; border-radius: 4px; padding: 10px; font-size: 12px; color: #8b949e; white-space: pre-wrap; word-break: break-word; max-height: 120px; overflow: auto; }
|
|
3432
|
+
</style>
|
|
3433
|
+
</head>
|
|
3434
|
+
<body>
|
|
3435
|
+
<h1>clauth · live sessions</h1>
|
|
3436
|
+
<div class="meta">v${VERSION} · ${sessions.length} session${sessions.length !== 1 ? "s" : ""} · auto-refresh 3s · ${new Date().toISOString()}</div>
|
|
3437
|
+
${sessions.length === 0
|
|
3438
|
+
? '<div class="empty">No active sessions.</div>'
|
|
3439
|
+
: sessions.map(s => `
|
|
3440
|
+
<div class="session ${s.status}">
|
|
3441
|
+
<span class="badge ${s.type}">${s.type}</span>
|
|
3442
|
+
<span class="badge ${s.status}" style="margin-left:6px">${s.status}${s.status === "busy" ? " ⟳" : ""}</span>
|
|
3443
|
+
<div style="margin-top:10px">
|
|
3444
|
+
<div class="label">name</div><div class="value">${s.name}</div>
|
|
3445
|
+
<div class="label">session_id</div><div class="value" style="color:#6e7681;font-size:11px">${s.session_id}</div>
|
|
3446
|
+
<div class="label">turn / age / context</div>
|
|
3447
|
+
<div class="value">turn ${s.turn} · ${s.age_seconds}s old · ${s.context_chars} chars context${s.active_pid ? ` · pid ${s.active_pid}` : ""}</div>
|
|
3448
|
+
<div class="label">cwd</div><div class="value" style="color:#6e7681">${s.cwd || "(not set)"}</div>
|
|
3449
|
+
${s.last_response_preview ? `
|
|
3450
|
+
<div class="label">last response ${s.last_response_at ? "· " + s.last_response_at : ""}</div>
|
|
3451
|
+
<div class="preview">${s.last_response_preview.replace(/</g, "<").replace(/>/g, ">")}</div>` : ""}
|
|
3452
|
+
</div>
|
|
3453
|
+
</div>`).join("")}
|
|
3454
|
+
</body>
|
|
3455
|
+
</html>`;
|
|
3456
|
+
res.writeHead(200, { "Content-Type": "text/html", ...CORS });
|
|
3457
|
+
return res.end(html);
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3385
3460
|
// GET /builds — CI build status (no auth required, same as /ping)
|
|
3386
3461
|
if (method === "GET" && reqPath === "/builds") {
|
|
3387
3462
|
return ok(res, buildStatus);
|
|
@@ -5074,11 +5149,16 @@ function stopTerminalSession(session_id) {
|
|
|
5074
5149
|
return { stopped: true, session_id };
|
|
5075
5150
|
}
|
|
5076
5151
|
|
|
5077
|
-
// ── Chitchat helpers
|
|
5078
|
-
//
|
|
5079
|
-
//
|
|
5080
|
-
//
|
|
5081
|
-
//
|
|
5152
|
+
// ── Chitchat helpers — file-relay transport ───────────────────────────────
|
|
5153
|
+
// claude.ai sends messages by writing to inbox files. A running /rdc:collab
|
|
5154
|
+
// CLI session watches inbox, acts, writes responses to outbox. clauth reads
|
|
5155
|
+
// outbox and returns them to claude.ai via chitchat_recv. Dave can watch the
|
|
5156
|
+
// terminal, interject, and see exactly what Claude Code is doing.
|
|
5157
|
+
//
|
|
5158
|
+
// Session dirs: <root>/.rdc/relay/sessions/<session_id>/inbox/ + outbox/
|
|
5159
|
+
//
|
|
5160
|
+
// cwd is resolved from the vault's first fileserver mount at call time.
|
|
5161
|
+
// Falls back to C:/Dev/regen-root if vault is locked or no mount configured.
|
|
5082
5162
|
|
|
5083
5163
|
const CHITCHAT_FALLBACK_CWD = 'C:/Dev/regen-root';
|
|
5084
5164
|
|
|
@@ -5090,34 +5170,52 @@ async function resolveChitchatRoot(vault) {
|
|
|
5090
5170
|
return CHITCHAT_FALLBACK_CWD;
|
|
5091
5171
|
}
|
|
5092
5172
|
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
try {
|
|
5096
|
-
return fs.readFileSync(bootstrapPath, 'utf-8');
|
|
5097
|
-
} catch {
|
|
5098
|
-
return `# agent-bootstrap.md not found at ${bootstrapPath} — proceeding without corpus context\n`;
|
|
5099
|
-
}
|
|
5173
|
+
function chitchatSessionDir(rootPath, session_id) {
|
|
5174
|
+
return path.join(rootPath, '.rdc', 'relay', 'sessions', session_id);
|
|
5100
5175
|
}
|
|
5101
5176
|
|
|
5102
5177
|
async function startChitchatSession(name, vault) {
|
|
5103
5178
|
const rootPath = await resolveChitchatRoot(vault);
|
|
5104
|
-
const corpus = await readBootstrapContext(rootPath);
|
|
5105
5179
|
const session_id = generateSessionId();
|
|
5106
|
-
const
|
|
5180
|
+
const sessionDir = chitchatSessionDir(rootPath, session_id);
|
|
5181
|
+
|
|
5182
|
+
// Create inbox + outbox dirs
|
|
5183
|
+
fs.mkdirSync(path.join(sessionDir, 'inbox'), { recursive: true });
|
|
5184
|
+
fs.mkdirSync(path.join(sessionDir, 'outbox'), { recursive: true });
|
|
5185
|
+
|
|
5186
|
+
// Write session metadata
|
|
5187
|
+
fs.writeFileSync(path.join(sessionDir, 'status.json'), JSON.stringify({
|
|
5188
|
+
session_id,
|
|
5189
|
+
name,
|
|
5190
|
+
status: 'waiting',
|
|
5191
|
+
started_at: new Date().toISOString(),
|
|
5192
|
+
cwd: rootPath,
|
|
5193
|
+
}, null, 2));
|
|
5194
|
+
|
|
5107
5195
|
const session = {
|
|
5108
5196
|
session_id,
|
|
5109
5197
|
name,
|
|
5110
|
-
|
|
5111
|
-
status: 'ready',
|
|
5198
|
+
status: 'waiting', // waiting = CLI not yet connected
|
|
5112
5199
|
started_at: new Date().toISOString(),
|
|
5113
|
-
context: preamble,
|
|
5114
|
-
activeProc: null,
|
|
5115
5200
|
is_chitchat: true,
|
|
5116
5201
|
cwd: rootPath,
|
|
5202
|
+
sessionDir,
|
|
5203
|
+
turn: 0,
|
|
5204
|
+
lastResponse: undefined,
|
|
5205
|
+
lastResponseAt: undefined,
|
|
5117
5206
|
};
|
|
5118
5207
|
terminalSessions.set(session_id, session);
|
|
5119
|
-
console.log(`[chitchat] started session ${session_id} name=${name}
|
|
5120
|
-
|
|
5208
|
+
console.log(`[chitchat] started session ${session_id} name=${name} dir=${sessionDir}`);
|
|
5209
|
+
|
|
5210
|
+
return {
|
|
5211
|
+
session_id,
|
|
5212
|
+
status: 'waiting',
|
|
5213
|
+
name,
|
|
5214
|
+
cwd: rootPath,
|
|
5215
|
+
next_step: `Open a terminal and run: /rdc:collab --session ${session_id}`,
|
|
5216
|
+
inbox: path.join(sessionDir, 'inbox'),
|
|
5217
|
+
outbox: path.join(sessionDir, 'outbox'),
|
|
5218
|
+
};
|
|
5121
5219
|
}
|
|
5122
5220
|
|
|
5123
5221
|
function sendChitchatMessage(session_id, message) {
|
|
@@ -5125,43 +5223,80 @@ function sendChitchatMessage(session_id, message) {
|
|
|
5125
5223
|
if (!session) return { error: 'not_found', message: `Chitchat session ${session_id} not found` };
|
|
5126
5224
|
if (!session.is_chitchat) return { error: 'wrong_type', message: 'Use terminal_send for non-chitchat sessions' };
|
|
5127
5225
|
if (session.status === 'stopped') return { error: 'stopped', message: 'Session is stopped' };
|
|
5128
|
-
if (session.status === 'busy') return { error: 'session_busy', message: 'Session is busy — try again shortly' };
|
|
5129
5226
|
|
|
5130
|
-
const
|
|
5131
|
-
|
|
5227
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
5228
|
+
session.turn = (session.turn || 0) + 1;
|
|
5229
|
+
const filename = `${ts}-turn${session.turn}.md`;
|
|
5230
|
+
const inboxPath = path.join(session.sessionDir, 'inbox', filename);
|
|
5231
|
+
|
|
5232
|
+
const content = [
|
|
5233
|
+
'---',
|
|
5234
|
+
`from: claude-ai`,
|
|
5235
|
+
`to: claude-code`,
|
|
5236
|
+
`session_id: ${session_id}`,
|
|
5237
|
+
`turn: ${session.turn}`,
|
|
5238
|
+
`sent_at: ${new Date().toISOString()}`,
|
|
5239
|
+
`status: pending`,
|
|
5240
|
+
'---',
|
|
5241
|
+
'',
|
|
5242
|
+
message,
|
|
5243
|
+
].join('\n');
|
|
5244
|
+
|
|
5245
|
+
try {
|
|
5246
|
+
fs.writeFileSync(inboxPath, content, 'utf-8');
|
|
5247
|
+
} catch (err) {
|
|
5248
|
+
return { error: 'write_failed', message: `Could not write to inbox: ${err.message}` };
|
|
5249
|
+
}
|
|
5132
5250
|
|
|
5133
5251
|
session.status = 'busy';
|
|
5134
|
-
|
|
5252
|
+
console.log(`[chitchat] session ${session_id} turn=${session.turn} message written to inbox`);
|
|
5253
|
+
return { queued: true, session_id, turn: session.turn, inbox_file: filename };
|
|
5254
|
+
}
|
|
5135
5255
|
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
5140
|
-
shell: true,
|
|
5141
|
-
});
|
|
5142
|
-
session.activeProc = proc;
|
|
5256
|
+
function recvChitchatResponse(session_id) {
|
|
5257
|
+
const session = terminalSessions.get(session_id);
|
|
5258
|
+
if (!session) return { error: 'not_found', message: `Chitchat session ${session_id} not found` };
|
|
5143
5259
|
|
|
5144
|
-
|
|
5145
|
-
let
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
const turn = `\n\nFrom claude.ai: ${message}\nClaude Code: ${response}`;
|
|
5153
|
-
const combined = s.context + turn;
|
|
5154
|
-
s.context = combined.length > 8000 ? combined.slice(combined.length - 8000) : combined;
|
|
5155
|
-
s.lastResponse = response;
|
|
5156
|
-
s.lastResponseAt = new Date().toISOString();
|
|
5157
|
-
s.turn = (s.turn || 0) + 1;
|
|
5158
|
-
s.status = 'ready';
|
|
5159
|
-
s.activeProc = null;
|
|
5160
|
-
console.log(`[chitchat] session ${session_id} turn=${s.turn} complete code=${code}`);
|
|
5161
|
-
}
|
|
5162
|
-
});
|
|
5260
|
+
const outboxDir = path.join(session.sessionDir, 'outbox');
|
|
5261
|
+
let files;
|
|
5262
|
+
try {
|
|
5263
|
+
files = fs.readdirSync(outboxDir).filter(f => f.endsWith('.md')).sort();
|
|
5264
|
+
} catch {
|
|
5265
|
+
return { session_id, status: session.status, turn: session.turn || 0, response: null,
|
|
5266
|
+
message: 'Outbox not readable — is /rdc:collab running?' };
|
|
5267
|
+
}
|
|
5163
5268
|
|
|
5164
|
-
|
|
5269
|
+
if (files.length === 0) {
|
|
5270
|
+
return { session_id, status: 'busy', turn: session.turn || 0, response: null,
|
|
5271
|
+
message: session.status === 'waiting'
|
|
5272
|
+
? 'Waiting for /rdc:collab to connect — open your terminal and run it'
|
|
5273
|
+
: 'Claude Code is working — poll again in a few seconds' };
|
|
5274
|
+
}
|
|
5275
|
+
|
|
5276
|
+
// Read the latest response file
|
|
5277
|
+
const latest = files[files.length - 1];
|
|
5278
|
+
const responsePath = path.join(outboxDir, latest);
|
|
5279
|
+
let raw;
|
|
5280
|
+
try {
|
|
5281
|
+
raw = fs.readFileSync(responsePath, 'utf-8');
|
|
5282
|
+
} catch (err) {
|
|
5283
|
+
return { error: 'read_failed', message: `Could not read outbox: ${err.message}` };
|
|
5284
|
+
}
|
|
5285
|
+
|
|
5286
|
+
// Strip frontmatter, return body
|
|
5287
|
+
const body = raw.replace(/^---[\s\S]*?---\n?/, '').trim();
|
|
5288
|
+
const respondedAt = new Date().toISOString();
|
|
5289
|
+
|
|
5290
|
+
// Archive the file so next recv doesn't return it again
|
|
5291
|
+
const archivePath = responsePath + '.processed';
|
|
5292
|
+
try { fs.renameSync(responsePath, archivePath); } catch {}
|
|
5293
|
+
|
|
5294
|
+
session.status = 'ready';
|
|
5295
|
+
session.lastResponse = body;
|
|
5296
|
+
session.lastResponseAt = respondedAt;
|
|
5297
|
+
console.log(`[chitchat] session ${session_id} response received from outbox file=${latest}`);
|
|
5298
|
+
|
|
5299
|
+
return { session_id, status: 'ready', turn: session.turn || 0, response: body, responded_at: respondedAt };
|
|
5165
5300
|
}
|
|
5166
5301
|
|
|
5167
5302
|
function listChitchatSessions() {
|
|
@@ -5181,6 +5316,32 @@ function listChitchatSessions() {
|
|
|
5181
5316
|
return sessions;
|
|
5182
5317
|
}
|
|
5183
5318
|
|
|
5319
|
+
function stopChitchatSession(session_id) {
|
|
5320
|
+
const session = terminalSessions.get(session_id);
|
|
5321
|
+
if (!session) return { error: 'not_found', message: `Session ${session_id} not found` };
|
|
5322
|
+
|
|
5323
|
+
// Write a stop signal to inbox so the running /rdc:collab loop knows to exit
|
|
5324
|
+
try {
|
|
5325
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
5326
|
+
const stopFile = path.join(session.sessionDir, 'inbox', `${ts}-stop.md`);
|
|
5327
|
+
fs.writeFileSync(stopFile, [
|
|
5328
|
+
'---',
|
|
5329
|
+
'from: claude-ai',
|
|
5330
|
+
'to: claude-code',
|
|
5331
|
+
`session_id: ${session_id}`,
|
|
5332
|
+
'type: stop',
|
|
5333
|
+
`sent_at: ${new Date().toISOString()}`,
|
|
5334
|
+
'---',
|
|
5335
|
+
'',
|
|
5336
|
+
'Session ended by claude.ai. Write final summary and exit.',
|
|
5337
|
+
].join('\n'));
|
|
5338
|
+
} catch {}
|
|
5339
|
+
|
|
5340
|
+
terminalSessions.delete(session_id);
|
|
5341
|
+
console.log(`[chitchat] stopped session ${session_id}`);
|
|
5342
|
+
return { stopped: true, session_id };
|
|
5343
|
+
}
|
|
5344
|
+
|
|
5184
5345
|
const ENV_MAP = {
|
|
5185
5346
|
"github": "GITHUB_TOKEN",
|
|
5186
5347
|
"supabase-anon": "NEXT_PUBLIC_SUPABASE_ANON_KEY",
|
|
@@ -6248,7 +6409,7 @@ async function handleMcpTool(vault, name, args) {
|
|
|
6248
6409
|
case "chitchat_recv": {
|
|
6249
6410
|
const { session_id } = args;
|
|
6250
6411
|
if (!session_id) return mcpError("session_id required");
|
|
6251
|
-
const result =
|
|
6412
|
+
const result = recvChitchatResponse(session_id);
|
|
6252
6413
|
if (result.error) return mcpError(`${result.error}: ${result.message}`);
|
|
6253
6414
|
return mcpResult(JSON.stringify(result));
|
|
6254
6415
|
}
|
|
@@ -6260,7 +6421,7 @@ async function handleMcpTool(vault, name, args) {
|
|
|
6260
6421
|
case "chitchat_stop": {
|
|
6261
6422
|
const { session_id } = args;
|
|
6262
6423
|
if (!session_id) return mcpError("session_id required");
|
|
6263
|
-
const result =
|
|
6424
|
+
const result = stopChitchatSession(session_id);
|
|
6264
6425
|
if (result.error) return mcpError(`${result.error}: ${result.message}`);
|
|
6265
6426
|
return mcpResult(JSON.stringify(result));
|
|
6266
6427
|
}
|