@lifeaitools/clauth 1.5.39 → 1.5.40
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 +252 -1
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -3119,7 +3119,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3119
3119
|
const isMcpPath = MCP_PATHS.includes(reqPath);
|
|
3120
3120
|
function toolsForPath(p) {
|
|
3121
3121
|
if (p === "/gws") return MCP_TOOLS.filter(t => t.name.startsWith("gws_"));
|
|
3122
|
-
if (p === "/clauth") return MCP_TOOLS.filter(t => t.name.startsWith("clauth_") || t.name === "monkey_dispatch");
|
|
3122
|
+
if (p === "/clauth") return MCP_TOOLS.filter(t => t.name.startsWith("clauth_") || t.name === "monkey_dispatch" || t.name.startsWith("terminal_"));
|
|
3123
3123
|
if (p === "/fs") return MCP_TOOLS.filter(t => t.name.startsWith("fs_"));
|
|
3124
3124
|
return MCP_TOOLS; // /mcp — all tools
|
|
3125
3125
|
}
|
|
@@ -3494,6 +3494,83 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3494
3494
|
return;
|
|
3495
3495
|
}
|
|
3496
3496
|
|
|
3497
|
+
// POST /terminal/start — start a named terminal session
|
|
3498
|
+
if (method === "POST" && reqPath === "/terminal/start") {
|
|
3499
|
+
let body = "";
|
|
3500
|
+
req.on("data", d => body += d);
|
|
3501
|
+
req.on("end", () => {
|
|
3502
|
+
try {
|
|
3503
|
+
const { name, knowledge_tier, context_md } = JSON.parse(body);
|
|
3504
|
+
if (!name) {
|
|
3505
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3506
|
+
return res.end(JSON.stringify({ error: "name required" }));
|
|
3507
|
+
}
|
|
3508
|
+
const tier = knowledge_tier || 'db_only';
|
|
3509
|
+
const result = startTerminalSession(name, tier, context_md || null);
|
|
3510
|
+
const status = result.error ? 503 : 200;
|
|
3511
|
+
res.writeHead(status, { "Content-Type": "application/json", ...CORS });
|
|
3512
|
+
res.end(JSON.stringify(result));
|
|
3513
|
+
} catch {
|
|
3514
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3515
|
+
res.end(JSON.stringify({ error: "invalid JSON" }));
|
|
3516
|
+
}
|
|
3517
|
+
});
|
|
3518
|
+
return;
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
// POST /terminal/send — send a message to a running terminal session
|
|
3522
|
+
if (method === "POST" && reqPath === "/terminal/send") {
|
|
3523
|
+
let body = "";
|
|
3524
|
+
req.on("data", d => body += d);
|
|
3525
|
+
req.on("end", () => {
|
|
3526
|
+
try {
|
|
3527
|
+
const { session_id, message } = JSON.parse(body);
|
|
3528
|
+
if (!session_id || !message) {
|
|
3529
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3530
|
+
return res.end(JSON.stringify({ error: "session_id and message required" }));
|
|
3531
|
+
}
|
|
3532
|
+
const result = sendTerminalMessage(session_id, message);
|
|
3533
|
+
const status = result.error === 'session_busy' ? 409 : result.error ? 404 : 200;
|
|
3534
|
+
res.writeHead(status, { "Content-Type": "application/json", ...CORS });
|
|
3535
|
+
res.end(JSON.stringify(result));
|
|
3536
|
+
} catch {
|
|
3537
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3538
|
+
res.end(JSON.stringify({ error: "invalid JSON" }));
|
|
3539
|
+
}
|
|
3540
|
+
});
|
|
3541
|
+
return;
|
|
3542
|
+
}
|
|
3543
|
+
|
|
3544
|
+
// GET /terminal/list — list all active terminal sessions
|
|
3545
|
+
if (method === "GET" && reqPath === "/terminal/list") {
|
|
3546
|
+
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
3547
|
+
res.end(JSON.stringify(listTerminalSessions()));
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
3550
|
+
|
|
3551
|
+
// POST /terminal/stop — stop a terminal session
|
|
3552
|
+
if (method === "POST" && reqPath === "/terminal/stop") {
|
|
3553
|
+
let body = "";
|
|
3554
|
+
req.on("data", d => body += d);
|
|
3555
|
+
req.on("end", () => {
|
|
3556
|
+
try {
|
|
3557
|
+
const { session_id } = JSON.parse(body);
|
|
3558
|
+
if (!session_id) {
|
|
3559
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3560
|
+
return res.end(JSON.stringify({ error: "session_id required" }));
|
|
3561
|
+
}
|
|
3562
|
+
const result = stopTerminalSession(session_id);
|
|
3563
|
+
const status = result.error ? 404 : 200;
|
|
3564
|
+
res.writeHead(status, { "Content-Type": "application/json", ...CORS });
|
|
3565
|
+
res.end(JSON.stringify(result));
|
|
3566
|
+
} catch {
|
|
3567
|
+
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3568
|
+
res.end(JSON.stringify({ error: "invalid JSON" }));
|
|
3569
|
+
}
|
|
3570
|
+
});
|
|
3571
|
+
return;
|
|
3572
|
+
}
|
|
3573
|
+
|
|
3497
3574
|
// GET|POST /shutdown (for daemon stop — programmatic, keeps boot.key)
|
|
3498
3575
|
// Accept POST as well — older scripts and curl default to POST
|
|
3499
3576
|
if ((method === "GET" || method === "POST") && reqPath === "/shutdown") {
|
|
@@ -4866,6 +4943,106 @@ function spawnClaudeTask(prompt, jobId) {
|
|
|
4866
4943
|
return { status: 'spawned', pid: proc.pid, jobId, activeWorkers: activeCliWorkers };
|
|
4867
4944
|
}
|
|
4868
4945
|
|
|
4946
|
+
// ── Terminal session manager ─────────────────────────────────────
|
|
4947
|
+
// Rolling-context approach: each session stores a context string.
|
|
4948
|
+
// /terminal/send spawns a fresh claude -p with [context + message],
|
|
4949
|
+
// captures stdout, stores result back in session context.
|
|
4950
|
+
const terminalSessions = new Map(); // session_id → SessionState
|
|
4951
|
+
|
|
4952
|
+
function generateSessionId() {
|
|
4953
|
+
return crypto.randomUUID();
|
|
4954
|
+
}
|
|
4955
|
+
|
|
4956
|
+
function startTerminalSession(name, knowledge_tier, context_md) {
|
|
4957
|
+
const binary = findClaudeBinary();
|
|
4958
|
+
if (!binary) {
|
|
4959
|
+
return { error: 'binary_not_found', message: 'claude CLI not found in PATH or AppData/npm' };
|
|
4960
|
+
}
|
|
4961
|
+
const session_id = generateSessionId();
|
|
4962
|
+
const preamble = context_md
|
|
4963
|
+
? `${context_md}\n\n---\n`
|
|
4964
|
+
: '';
|
|
4965
|
+
const initialContext = `${preamble}Session: ${name} | Tier: ${knowledge_tier}\nReady. Await instructions.`;
|
|
4966
|
+
const session = {
|
|
4967
|
+
session_id,
|
|
4968
|
+
name,
|
|
4969
|
+
knowledge_tier,
|
|
4970
|
+
status: 'ready',
|
|
4971
|
+
started_at: new Date().toISOString(),
|
|
4972
|
+
context: initialContext,
|
|
4973
|
+
activeProc: null,
|
|
4974
|
+
};
|
|
4975
|
+
terminalSessions.set(session_id, session);
|
|
4976
|
+
console.log(`[terminal] started session ${session_id} name=${name}`);
|
|
4977
|
+
return { session_id, status: 'ready' };
|
|
4978
|
+
}
|
|
4979
|
+
|
|
4980
|
+
function sendTerminalMessage(session_id, message) {
|
|
4981
|
+
const session = terminalSessions.get(session_id);
|
|
4982
|
+
if (!session) return { error: 'not_found', message: `Session ${session_id} not found` };
|
|
4983
|
+
if (session.status === 'stopped') return { error: 'stopped', message: 'Session is stopped' };
|
|
4984
|
+
if (session.status === 'busy') return { error: 'session_busy', message: 'Session is busy — try again shortly' };
|
|
4985
|
+
|
|
4986
|
+
const binary = findClaudeBinary();
|
|
4987
|
+
if (!binary) return { error: 'binary_not_found', message: 'claude CLI not found in PATH or AppData/npm' };
|
|
4988
|
+
|
|
4989
|
+
session.status = 'busy';
|
|
4990
|
+
const fullPrompt = `${session.context}\n\n---\nUser: ${message}`;
|
|
4991
|
+
|
|
4992
|
+
const proc = spawnProc(binary, ['-p', fullPrompt, '--dangerously-skip-permissions'], {
|
|
4993
|
+
cwd: 'C:/Dev/regen-root',
|
|
4994
|
+
env: process.env,
|
|
4995
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
4996
|
+
shell: true,
|
|
4997
|
+
});
|
|
4998
|
+
session.activeProc = proc;
|
|
4999
|
+
|
|
5000
|
+
let stdout = '';
|
|
5001
|
+
let stderr = '';
|
|
5002
|
+
proc.stdout.on('data', d => { stdout += d; });
|
|
5003
|
+
proc.stderr.on('data', d => { stderr += d; });
|
|
5004
|
+
proc.on('close', (code) => {
|
|
5005
|
+
if (terminalSessions.has(session_id)) {
|
|
5006
|
+
const s = terminalSessions.get(session_id);
|
|
5007
|
+
const response = stdout.trim() || stderr.trim() || '(no output)';
|
|
5008
|
+
// Append turn to rolling context (cap at ~8000 chars to avoid overflow)
|
|
5009
|
+
const turn = `\n\nUser: ${message}\nAssistant: ${response}`;
|
|
5010
|
+
const combined = s.context + turn;
|
|
5011
|
+
s.context = combined.length > 8000 ? combined.slice(combined.length - 8000) : combined;
|
|
5012
|
+
s.status = 'ready';
|
|
5013
|
+
s.activeProc = null;
|
|
5014
|
+
console.log(`[terminal] session ${session_id} turn complete code=${code}`);
|
|
5015
|
+
}
|
|
5016
|
+
});
|
|
5017
|
+
|
|
5018
|
+
return { queued: true, session_id };
|
|
5019
|
+
}
|
|
5020
|
+
|
|
5021
|
+
function listTerminalSessions() {
|
|
5022
|
+
const sessions = [];
|
|
5023
|
+
for (const [, s] of terminalSessions) {
|
|
5024
|
+
sessions.push({
|
|
5025
|
+
session_id: s.session_id,
|
|
5026
|
+
name: s.name,
|
|
5027
|
+
status: s.status,
|
|
5028
|
+
knowledge_tier: s.knowledge_tier,
|
|
5029
|
+
started_at: s.started_at,
|
|
5030
|
+
});
|
|
5031
|
+
}
|
|
5032
|
+
return sessions;
|
|
5033
|
+
}
|
|
5034
|
+
|
|
5035
|
+
function stopTerminalSession(session_id) {
|
|
5036
|
+
const session = terminalSessions.get(session_id);
|
|
5037
|
+
if (!session) return { error: 'not_found', message: `Session ${session_id} not found` };
|
|
5038
|
+
if (session.activeProc) {
|
|
5039
|
+
try { session.activeProc.kill(); } catch {}
|
|
5040
|
+
}
|
|
5041
|
+
terminalSessions.delete(session_id);
|
|
5042
|
+
console.log(`[terminal] stopped session ${session_id}`);
|
|
5043
|
+
return { stopped: true, session_id };
|
|
5044
|
+
}
|
|
5045
|
+
|
|
4869
5046
|
const ENV_MAP = {
|
|
4870
5047
|
"github": "GITHUB_TOKEN",
|
|
4871
5048
|
"supabase-anon": "NEXT_PUBLIC_SUPABASE_ANON_KEY",
|
|
@@ -5046,6 +5223,52 @@ const MCP_TOOLS = [
|
|
|
5046
5223
|
},
|
|
5047
5224
|
},
|
|
5048
5225
|
|
|
5226
|
+
// ── Terminal session manager ───────────────────────────────────────────
|
|
5227
|
+
{
|
|
5228
|
+
name: "terminal_start",
|
|
5229
|
+
description: "Start a named persistent Claude session. Sessions maintain rolling context across sends. Returns session_id for subsequent sends.",
|
|
5230
|
+
inputSchema: {
|
|
5231
|
+
type: "object",
|
|
5232
|
+
properties: {
|
|
5233
|
+
name: { type: "string", description: "Human-readable session name (e.g. 'knowledgedude-prt')" },
|
|
5234
|
+
knowledge_tier: { type: "string", enum: ["db_only", "corpus", "project"], description: "Knowledge tier for the session. 'corpus' injects context_md as preamble." },
|
|
5235
|
+
context_md: { type: "string", description: "Optional markdown preamble injected as session context (used for 'corpus' tier)" },
|
|
5236
|
+
},
|
|
5237
|
+
required: ["name"],
|
|
5238
|
+
additionalProperties: false,
|
|
5239
|
+
},
|
|
5240
|
+
},
|
|
5241
|
+
{
|
|
5242
|
+
name: "terminal_send",
|
|
5243
|
+
description: "Send a message to a running terminal session. Spawns a Claude worker with rolling context + message. Returns immediately — session processes async.",
|
|
5244
|
+
inputSchema: {
|
|
5245
|
+
type: "object",
|
|
5246
|
+
properties: {
|
|
5247
|
+
session_id: { type: "string", description: "Session ID returned by terminal_start" },
|
|
5248
|
+
message: { type: "string", description: "Message to send to the session" },
|
|
5249
|
+
},
|
|
5250
|
+
required: ["session_id", "message"],
|
|
5251
|
+
additionalProperties: false,
|
|
5252
|
+
},
|
|
5253
|
+
},
|
|
5254
|
+
{
|
|
5255
|
+
name: "terminal_list",
|
|
5256
|
+
description: "List all active terminal sessions with their status (ready/busy/stopped), knowledge tier, and start time.",
|
|
5257
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
5258
|
+
},
|
|
5259
|
+
{
|
|
5260
|
+
name: "terminal_stop",
|
|
5261
|
+
description: "Stop a terminal session and remove it from memory. Kills any active process.",
|
|
5262
|
+
inputSchema: {
|
|
5263
|
+
type: "object",
|
|
5264
|
+
properties: {
|
|
5265
|
+
session_id: { type: "string", description: "Session ID to stop" },
|
|
5266
|
+
},
|
|
5267
|
+
required: ["session_id"],
|
|
5268
|
+
additionalProperties: false,
|
|
5269
|
+
},
|
|
5270
|
+
},
|
|
5271
|
+
|
|
5049
5272
|
// ── Google Workspace (gws CLI) ──────────────────────────────────────────
|
|
5050
5273
|
{
|
|
5051
5274
|
name: "gws_run",
|
|
@@ -5762,6 +5985,34 @@ async function handleMcpTool(vault, name, args) {
|
|
|
5762
5985
|
return mcpResult(JSON.stringify(result));
|
|
5763
5986
|
}
|
|
5764
5987
|
|
|
5988
|
+
case "terminal_start": {
|
|
5989
|
+
const { name, knowledge_tier, context_md } = args;
|
|
5990
|
+
if (!name) return mcpError("name required");
|
|
5991
|
+
const result = startTerminalSession(name, knowledge_tier || 'db_only', context_md || null);
|
|
5992
|
+
if (result.error) return mcpError(`${result.error}: ${result.message}`);
|
|
5993
|
+
return mcpResult(JSON.stringify(result));
|
|
5994
|
+
}
|
|
5995
|
+
|
|
5996
|
+
case "terminal_send": {
|
|
5997
|
+
const { session_id, message } = args;
|
|
5998
|
+
if (!session_id || !message) return mcpError("session_id and message required");
|
|
5999
|
+
const result = sendTerminalMessage(session_id, message);
|
|
6000
|
+
if (result.error) return mcpError(`${result.error}: ${result.message}`);
|
|
6001
|
+
return mcpResult(JSON.stringify(result));
|
|
6002
|
+
}
|
|
6003
|
+
|
|
6004
|
+
case "terminal_list": {
|
|
6005
|
+
return mcpResult(JSON.stringify(listTerminalSessions()));
|
|
6006
|
+
}
|
|
6007
|
+
|
|
6008
|
+
case "terminal_stop": {
|
|
6009
|
+
const { session_id } = args;
|
|
6010
|
+
if (!session_id) return mcpError("session_id required");
|
|
6011
|
+
const result = stopTerminalSession(session_id);
|
|
6012
|
+
if (result.error) return mcpError(`${result.error}: ${result.message}`);
|
|
6013
|
+
return mcpResult(JSON.stringify(result));
|
|
6014
|
+
}
|
|
6015
|
+
|
|
5765
6016
|
default:
|
|
5766
6017
|
return mcpError(`Unknown tool: ${name}`);
|
|
5767
6018
|
}
|