@lifeaitools/clauth 1.5.67 → 1.5.68
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 +227 -3
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -862,6 +862,11 @@ function dashboardHtml(port, whitelist, isStaged = false) {
|
|
|
862
862
|
<span class="mcp-val" id="mcp-url">—</span>
|
|
863
863
|
<button class="mcp-copy" onclick="copyMcp('mcp-url')">copy</button>
|
|
864
864
|
</div>
|
|
865
|
+
<div class="mcp-row">
|
|
866
|
+
<span class="mcp-label">GWS</span>
|
|
867
|
+
<span class="mcp-val" id="mcp-gws-url">—</span>
|
|
868
|
+
<button class="mcp-copy" onclick="copyMcp('mcp-gws-url')">copy</button>
|
|
869
|
+
</div>
|
|
865
870
|
<div class="mcp-row">
|
|
866
871
|
<span class="mcp-label">Client ID</span>
|
|
867
872
|
<span class="mcp-val" id="mcp-client-id">—</span>
|
|
@@ -1954,10 +1959,12 @@ async function toggleMcpSetup() {
|
|
|
1954
1959
|
try {
|
|
1955
1960
|
const m = await fetch(BASE + "/mcp-setup").then(r => r.json());
|
|
1956
1961
|
document.getElementById("mcp-url").textContent = m.url || "(tunnel not running)";
|
|
1962
|
+
document.getElementById("mcp-gws-url").textContent = m.gwsUrl || "(tunnel not running)";
|
|
1957
1963
|
document.getElementById("mcp-client-id").textContent = m.clientId || "—";
|
|
1958
1964
|
document.getElementById("mcp-client-secret").textContent = m.clientSecret || "—";
|
|
1959
1965
|
} catch {
|
|
1960
1966
|
document.getElementById("mcp-url").textContent = "(error fetching)";
|
|
1967
|
+
document.getElementById("mcp-gws-url").textContent = "(error fetching)";
|
|
1961
1968
|
}
|
|
1962
1969
|
}
|
|
1963
1970
|
}
|
|
@@ -2335,17 +2342,23 @@ async function wizRunCreateTunnel() {
|
|
|
2335
2342
|
async function wizShowMcpSetup(hostname) {
|
|
2336
2343
|
wizStep = "mcp_setup";
|
|
2337
2344
|
const clauthUrl = \`https://\${hostname}/clauth\`;
|
|
2345
|
+
const gwsUrl = \`https://\${hostname}/gws\`;
|
|
2338
2346
|
|
|
2339
2347
|
const mcpData = await apiFetch("/mcp-setup");
|
|
2340
2348
|
|
|
2341
2349
|
renderWizBody(\`
|
|
2342
|
-
<div class="wiz-desc">Add
|
|
2350
|
+
<div class="wiz-desc">Add two MCP connectors in claude.ai — one for Clauth, one for GWS:</div>
|
|
2343
2351
|
<div style="display:flex;flex-direction:column;gap:8px;margin-top:10px">
|
|
2344
2352
|
<div class="mcp-row">
|
|
2345
2353
|
<span class="mcp-label">Clauth URL</span>
|
|
2346
2354
|
<span class="mcp-val" id="wiz-mcp-url">\${clauthUrl}</span>
|
|
2347
2355
|
<button class="mcp-copy" onclick="wizCopy('wiz-mcp-url',this)">copy</button>
|
|
2348
2356
|
</div>
|
|
2357
|
+
<div class="mcp-row">
|
|
2358
|
+
<span class="mcp-label">GWS URL</span>
|
|
2359
|
+
<span class="mcp-val" id="wiz-mcp-gws">\${gwsUrl}</span>
|
|
2360
|
+
<button class="mcp-copy" onclick="wizCopy('wiz-mcp-gws',this)">copy</button>
|
|
2361
|
+
</div>
|
|
2349
2362
|
<div class="mcp-row">
|
|
2350
2363
|
<span class="mcp-label">Client ID</span>
|
|
2351
2364
|
<span class="mcp-val" id="wiz-mcp-cid">\${mcpData?.clientId || '(unlock required)'}</span>
|
|
@@ -2940,7 +2953,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
2940
2953
|
if (reqPath.startsWith("/.well-known/oauth-protected-resource")) {
|
|
2941
2954
|
const base = oauthBase();
|
|
2942
2955
|
const suffix = reqPath.replace("/.well-known/oauth-protected-resource", "").replace(/^\//, "");
|
|
2943
|
-
const resourcePath = suffix && ["/clauth", "/mcp", "/sse"].includes("/" + suffix) ? "/" + suffix : "/sse";
|
|
2956
|
+
const resourcePath = suffix && ["/gws", "/clauth", "/mcp", "/fs", "/sse"].includes("/" + suffix) ? "/" + suffix : "/sse";
|
|
2944
2957
|
res.writeHead(200, { "Content-Type": "application/json", "Cache-Control": "no-store", ...CORS });
|
|
2945
2958
|
return res.end(JSON.stringify({
|
|
2946
2959
|
resource: `${base}${resourcePath}`,
|
|
@@ -3120,14 +3133,20 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3120
3133
|
}
|
|
3121
3134
|
|
|
3122
3135
|
// ── MCP path helpers ──
|
|
3123
|
-
const MCP_PATHS = ["/mcp", "/clauth"];
|
|
3136
|
+
const MCP_PATHS = ["/mcp", "/gws", "/clauth", "/fs", "/chitchat"];
|
|
3124
3137
|
const isMcpPath = MCP_PATHS.includes(reqPath);
|
|
3125
3138
|
function toolsForPath(p) {
|
|
3139
|
+
if (p === "/gws") return MCP_TOOLS.filter(t => t.name.startsWith("gws_"));
|
|
3126
3140
|
if (p === "/clauth") return MCP_TOOLS.filter(t => t.name.startsWith("clauth_") || t.name === "monkey_dispatch" || t.name.startsWith("terminal_") || t.name.startsWith("channel_"));
|
|
3141
|
+
if (p === "/fs") return MCP_TOOLS.filter(t => t.name.startsWith("fs_"));
|
|
3142
|
+
if (p === "/chitchat") return MCP_TOOLS.filter(t => t.name.startsWith("chitchat_"));
|
|
3127
3143
|
return MCP_TOOLS; // /mcp — all tools
|
|
3128
3144
|
}
|
|
3129
3145
|
function serverNameForPath(p) {
|
|
3146
|
+
if (p === "/gws") return "gws";
|
|
3130
3147
|
if (p === "/clauth") return "clauth";
|
|
3148
|
+
if (p === "/fs") return "fs";
|
|
3149
|
+
if (p === "/chitchat") return "chitchat";
|
|
3131
3150
|
return "clauth";
|
|
3132
3151
|
}
|
|
3133
3152
|
|
|
@@ -3392,6 +3411,90 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3392
3411
|
});
|
|
3393
3412
|
}
|
|
3394
3413
|
|
|
3414
|
+
// GET /chitchat/<session_id>/stream — SSE push stream for Claude Code (inbox events)
|
|
3415
|
+
// Claude Code connects once; daemon pushes an event on every chitchat_send call
|
|
3416
|
+
const inboxStreamMatch = reqPath.match(/^\/chitchat\/([^/]+)\/stream$/);
|
|
3417
|
+
if (method === "GET" && inboxStreamMatch) {
|
|
3418
|
+
const session_id = inboxStreamMatch[1];
|
|
3419
|
+
const session = terminalSessions.get(session_id);
|
|
3420
|
+
if (!session || !session.is_chitchat) {
|
|
3421
|
+
res.writeHead(404, { "Content-Type": "application/json", ...CORS });
|
|
3422
|
+
return res.end(JSON.stringify({ error: "session not found" }));
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
res.writeHead(200, {
|
|
3426
|
+
"Content-Type": "text/event-stream",
|
|
3427
|
+
"Cache-Control": "no-cache",
|
|
3428
|
+
"Connection": "keep-alive",
|
|
3429
|
+
...CORS,
|
|
3430
|
+
});
|
|
3431
|
+
|
|
3432
|
+
// Send any already-queued inbox messages immediately
|
|
3433
|
+
if (session.inbox.length) {
|
|
3434
|
+
for (const entry of session.inbox) {
|
|
3435
|
+
res.write(`event: message\ndata: ${JSON.stringify(entry)}\n\n`);
|
|
3436
|
+
}
|
|
3437
|
+
session.inbox = [];
|
|
3438
|
+
}
|
|
3439
|
+
|
|
3440
|
+
session.inboxStreams.push(res);
|
|
3441
|
+
console.log(`[ClaudeAItoCLI] session ${session_id} inbox stream connected (${session.inboxStreams.length} total)`);
|
|
3442
|
+
|
|
3443
|
+
const keepalive = setInterval(() => {
|
|
3444
|
+
try { res.write(": keepalive\n\n"); } catch {}
|
|
3445
|
+
}, 15_000);
|
|
3446
|
+
|
|
3447
|
+
req.on("close", () => {
|
|
3448
|
+
clearInterval(keepalive);
|
|
3449
|
+
session.inboxStreams = session.inboxStreams.filter(r => r !== res);
|
|
3450
|
+
console.log(`[ClaudeAItoCLI] session ${session_id} inbox stream disconnected`);
|
|
3451
|
+
});
|
|
3452
|
+
|
|
3453
|
+
return;
|
|
3454
|
+
}
|
|
3455
|
+
|
|
3456
|
+
// GET /chitchat/<session_id>/watch — SSE push stream for claude.ai (outbox events)
|
|
3457
|
+
// claude.ai connects once; daemon pushes an event on every chitchat_reply call
|
|
3458
|
+
const outboxStreamMatch = reqPath.match(/^\/chitchat\/([^/]+)\/watch$/);
|
|
3459
|
+
if (method === "GET" && outboxStreamMatch) {
|
|
3460
|
+
const session_id = outboxStreamMatch[1];
|
|
3461
|
+
const session = terminalSessions.get(session_id);
|
|
3462
|
+
if (!session || !session.is_chitchat) {
|
|
3463
|
+
res.writeHead(404, { "Content-Type": "application/json", ...CORS });
|
|
3464
|
+
return res.end(JSON.stringify({ error: "session not found" }));
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3467
|
+
res.writeHead(200, {
|
|
3468
|
+
"Content-Type": "text/event-stream",
|
|
3469
|
+
"Cache-Control": "no-cache",
|
|
3470
|
+
"Connection": "keep-alive",
|
|
3471
|
+
...CORS,
|
|
3472
|
+
});
|
|
3473
|
+
|
|
3474
|
+
// Send any already-queued outbox messages immediately
|
|
3475
|
+
if (session.outbox.length) {
|
|
3476
|
+
for (const entry of session.outbox) {
|
|
3477
|
+
res.write(`event: message\ndata: ${JSON.stringify(entry)}\n\n`);
|
|
3478
|
+
}
|
|
3479
|
+
session.outbox = [];
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
session.outboxStreams.push(res);
|
|
3483
|
+
console.log(`[ClaudeAItoCLI] session ${session_id} outbox stream connected (${session.outboxStreams.length} total)`);
|
|
3484
|
+
|
|
3485
|
+
const keepalive = setInterval(() => {
|
|
3486
|
+
try { res.write(": keepalive\n\n"); } catch {}
|
|
3487
|
+
}, 15_000);
|
|
3488
|
+
|
|
3489
|
+
req.on("close", () => {
|
|
3490
|
+
clearInterval(keepalive);
|
|
3491
|
+
session.outboxStreams = session.outboxStreams.filter(r => r !== res);
|
|
3492
|
+
console.log(`[ClaudeAItoCLI] session ${session_id} outbox stream disconnected`);
|
|
3493
|
+
});
|
|
3494
|
+
|
|
3495
|
+
return;
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3395
3498
|
// GET /debug/sessions — live view of all terminal/chitchat sessions
|
|
3396
3499
|
if (method === "GET" && reqPath === "/debug/sessions") {
|
|
3397
3500
|
const now = Date.now();
|
|
@@ -3486,6 +3589,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3486
3589
|
const base = tunnelUrl && tunnelUrl.startsWith("http") ? tunnelUrl : null;
|
|
3487
3590
|
return ok(res, {
|
|
3488
3591
|
url: base ? `${base}/clauth` : null,
|
|
3592
|
+
gwsUrl: base ? `${base}/gws` : null,
|
|
3489
3593
|
note: "OAuth 2.1 public client — Claude registers dynamically, no client_secret needed",
|
|
3490
3594
|
});
|
|
3491
3595
|
}
|
|
@@ -3581,6 +3685,114 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3581
3685
|
return;
|
|
3582
3686
|
}
|
|
3583
3687
|
|
|
3688
|
+
// GET /chitchat/:id — session status (used by clauth chitchat CLI to verify session exists)
|
|
3689
|
+
const chitchatStatusMatch = reqPath.match(/^\/chitchat\/([^/]+)$/);
|
|
3690
|
+
if (method === "GET" && chitchatStatusMatch) {
|
|
3691
|
+
const sid = chitchatStatusMatch[1];
|
|
3692
|
+
const s = terminalSessions.get(sid);
|
|
3693
|
+
if (!s || !s.is_chitchat) {
|
|
3694
|
+
res.writeHead(404, { "Content-Type": "application/json", ...CORS });
|
|
3695
|
+
return res.end(JSON.stringify({ error: "not_found" }));
|
|
3696
|
+
}
|
|
3697
|
+
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
3698
|
+
return res.end(JSON.stringify({ session_id: sid, status: s.status, name: s.name, turn: s.turn }));
|
|
3699
|
+
}
|
|
3700
|
+
|
|
3701
|
+
// POST /chitchat/start — start a chitchat collab session (local REST, same as MCP chitchat_start)
|
|
3702
|
+
if (method === "POST" && reqPath === "/chitchat/start") {
|
|
3703
|
+
let body = "";
|
|
3704
|
+
req.on("data", d => body += d);
|
|
3705
|
+
req.on("end", async () => {
|
|
3706
|
+
try {
|
|
3707
|
+
const { name } = JSON.parse(body || "{}");
|
|
3708
|
+
const result = await startChitchatSession(name || "collab");
|
|
3709
|
+
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
3710
|
+
res.end(JSON.stringify(result));
|
|
3711
|
+
} catch (e) {
|
|
3712
|
+
res.writeHead(500, { "Content-Type": "application/json", ...CORS });
|
|
3713
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
3714
|
+
}
|
|
3715
|
+
});
|
|
3716
|
+
return;
|
|
3717
|
+
}
|
|
3718
|
+
|
|
3719
|
+
// POST /terminal/start — start a named terminal session
|
|
3720
|
+
if (method === "POST" && reqPath === "/terminal/start") {
|
|
3721
|
+
let body = "";
|
|
3722
|
+
req.on("data", d => body += d);
|
|
3723
|
+
req.on("end", () => {
|
|
3724
|
+
try {
|
|
3725
|
+
const { name, knowledge_tier, context_md } = JSON.parse(body);
|
|
3726
|
+
if (!name) {
|
|
3727
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3728
|
+
return res.end(JSON.stringify({ error: "name required" }));
|
|
3729
|
+
}
|
|
3730
|
+
const tier = knowledge_tier || 'db_only';
|
|
3731
|
+
const result = startTerminalSession(name, tier, context_md || null);
|
|
3732
|
+
const status = result.error ? 503 : 200;
|
|
3733
|
+
res.writeHead(status, { "Content-Type": "application/json", ...CORS });
|
|
3734
|
+
res.end(JSON.stringify(result));
|
|
3735
|
+
} catch {
|
|
3736
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3737
|
+
res.end(JSON.stringify({ error: "invalid JSON" }));
|
|
3738
|
+
}
|
|
3739
|
+
});
|
|
3740
|
+
return;
|
|
3741
|
+
}
|
|
3742
|
+
|
|
3743
|
+
// POST /terminal/send — send a message to a running terminal session
|
|
3744
|
+
if (method === "POST" && reqPath === "/terminal/send") {
|
|
3745
|
+
let body = "";
|
|
3746
|
+
req.on("data", d => body += d);
|
|
3747
|
+
req.on("end", () => {
|
|
3748
|
+
try {
|
|
3749
|
+
const { session_id, message } = JSON.parse(body);
|
|
3750
|
+
if (!session_id || !message) {
|
|
3751
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3752
|
+
return res.end(JSON.stringify({ error: "session_id and message required" }));
|
|
3753
|
+
}
|
|
3754
|
+
const result = sendTerminalMessage(session_id, message);
|
|
3755
|
+
const status = result.error === 'session_busy' ? 409 : result.error ? 404 : 200;
|
|
3756
|
+
res.writeHead(status, { "Content-Type": "application/json", ...CORS });
|
|
3757
|
+
res.end(JSON.stringify(result));
|
|
3758
|
+
} catch {
|
|
3759
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3760
|
+
res.end(JSON.stringify({ error: "invalid JSON" }));
|
|
3761
|
+
}
|
|
3762
|
+
});
|
|
3763
|
+
return;
|
|
3764
|
+
}
|
|
3765
|
+
|
|
3766
|
+
// GET /terminal/list — list all active terminal sessions
|
|
3767
|
+
if (method === "GET" && reqPath === "/terminal/list") {
|
|
3768
|
+
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
3769
|
+
res.end(JSON.stringify(listTerminalSessions()));
|
|
3770
|
+
return;
|
|
3771
|
+
}
|
|
3772
|
+
|
|
3773
|
+
// POST /terminal/stop — stop a terminal session
|
|
3774
|
+
if (method === "POST" && reqPath === "/terminal/stop") {
|
|
3775
|
+
let body = "";
|
|
3776
|
+
req.on("data", d => body += d);
|
|
3777
|
+
req.on("end", () => {
|
|
3778
|
+
try {
|
|
3779
|
+
const { session_id } = JSON.parse(body);
|
|
3780
|
+
if (!session_id) {
|
|
3781
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3782
|
+
return res.end(JSON.stringify({ error: "session_id required" }));
|
|
3783
|
+
}
|
|
3784
|
+
const result = stopTerminalSession(session_id);
|
|
3785
|
+
const status = result.error ? 404 : 200;
|
|
3786
|
+
res.writeHead(status, { "Content-Type": "application/json", ...CORS });
|
|
3787
|
+
res.end(JSON.stringify(result));
|
|
3788
|
+
} catch {
|
|
3789
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3790
|
+
res.end(JSON.stringify({ error: "invalid JSON" }));
|
|
3791
|
+
}
|
|
3792
|
+
});
|
|
3793
|
+
return;
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3584
3796
|
// POST /channel — receive Coolify/GitHub webhook events
|
|
3585
3797
|
if (method === "POST" && reqPath === "/channel") {
|
|
3586
3798
|
let body = "";
|
|
@@ -5318,6 +5530,18 @@ function stopTerminalSession(session_id) {
|
|
|
5318
5530
|
// Pure in-memory. No files. No CLI spawning on send/recv.
|
|
5319
5531
|
|
|
5320
5532
|
const CHITCHAT_CWD = 'C:/Dev/regen-root';
|
|
5533
|
+
const CHITCHAT_FALLBACK_CWD = CHITCHAT_CWD;
|
|
5534
|
+
|
|
5535
|
+
// Resolve the working directory for Claude CLI tasks.
|
|
5536
|
+
// Uses the first fileserver mount from vault (if unlocked and configured),
|
|
5537
|
+
// falling back to CHITCHAT_CWD so the daemon always has a usable cwd.
|
|
5538
|
+
async function resolveChitchatRoot(vault) {
|
|
5539
|
+
try {
|
|
5540
|
+
const { mounts } = await getFileserverMounts(vault);
|
|
5541
|
+
if (mounts && mounts.length > 0 && mounts[0].path) return mounts[0].path;
|
|
5542
|
+
} catch {}
|
|
5543
|
+
return CHITCHAT_CWD;
|
|
5544
|
+
}
|
|
5321
5545
|
|
|
5322
5546
|
async function startChitchatSession(name) {
|
|
5323
5547
|
const session_id = generateSessionId();
|