sensorium-mcp 2.16.178 → 2.16.180
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/dist/claude-keeper.d.ts +7 -25
- package/dist/claude-keeper.d.ts.map +1 -1
- package/dist/claude-keeper.js +94 -210
- package/dist/claude-keeper.js.map +1 -1
- package/dist/dashboard/routes/threads.js +1 -1
- package/dist/dashboard/routes/threads.js.map +1 -1
- package/dist/dashboard/spa.html +9 -9
- package/dist/data/memory/schema.d.ts.map +1 -1
- package/dist/data/memory/schema.js +43 -1
- package/dist/data/memory/schema.js.map +1 -1
- package/dist/tools/shared-agent-utils.d.ts +8 -0
- package/dist/tools/shared-agent-utils.d.ts.map +1 -0
- package/dist/tools/shared-agent-utils.js +24 -0
- package/dist/tools/shared-agent-utils.js.map +1 -0
- package/dist/tools/thread-lifecycle.d.ts.map +1 -1
- package/dist/tools/thread-lifecycle.js +5 -21
- package/dist/tools/thread-lifecycle.js.map +1 -1
- package/dist/watcher-service.d.ts.map +1 -1
- package/dist/watcher-service.js +18 -90
- package/dist/watcher-service.js.map +1 -1
- package/package.json +1 -1
package/dist/claude-keeper.d.ts
CHANGED
|
@@ -1,40 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Thread keeper — monitors keep-alive threads and restarts them
|
|
3
|
+
* via the start_thread MCP tool when they stop running.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Process exit → schedule restart with exponential backoff
|
|
7
|
-
* - HTTP liveness check → force-restart if agent stops polling
|
|
5
|
+
* No direct process spawning — delegates to start_thread which handles
|
|
6
|
+
* all lifecycle concerns (PID tracking, registry updates, MCP config).
|
|
8
7
|
*/
|
|
9
|
-
interface KeeperConfig {
|
|
10
|
-
/** Telegram thread ID of the always-on session. */
|
|
8
|
+
export interface KeeperConfig {
|
|
11
9
|
threadId: number;
|
|
12
|
-
/** Human-readable session name passed to start_session. */
|
|
13
10
|
sessionName: string;
|
|
14
|
-
|
|
15
|
-
client?: "claude" | "copilot";
|
|
16
|
-
/** Path to the `claude` binary (default: "claude"). */
|
|
17
|
-
claudeCmd: string;
|
|
18
|
-
/** Path to the `copilot` binary (default: "copilot"). */
|
|
19
|
-
copilotCmd?: string;
|
|
20
|
-
/** Model flag passed to Copilot CLI (default: "claude-opus-4.6"). */
|
|
21
|
-
copilotModel?: string;
|
|
22
|
-
/** Path where the keeper writes its Claude MCP config JSON. */
|
|
23
|
-
mcpConfigPath: string;
|
|
24
|
-
/** Port of the sensorium MCP HTTP server. */
|
|
11
|
+
client: string;
|
|
25
12
|
mcpHttpPort: number;
|
|
26
|
-
/** Bearer token for MCP HTTP auth, or null if unauthenticated. */
|
|
27
13
|
mcpHttpSecret: string | null;
|
|
28
|
-
|
|
29
|
-
dataDir: string;
|
|
30
|
-
/** Max consecutive fast crashes before entering cooldown. Default: 5. */
|
|
14
|
+
workingDirectory?: string;
|
|
31
15
|
maxRetries?: number;
|
|
32
|
-
/** Cooldown duration in ms after max retries exceeded. Default: 300000. */
|
|
33
16
|
cooldownMs?: number;
|
|
34
17
|
}
|
|
35
18
|
export interface KeeperHandle {
|
|
36
19
|
stop(): Promise<void>;
|
|
37
20
|
}
|
|
38
21
|
export declare function startClaudeKeeper(config: KeeperConfig): Promise<KeeperHandle>;
|
|
39
|
-
export {};
|
|
40
22
|
//# sourceMappingURL=claude-keeper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-keeper.d.ts","sourceRoot":"","sources":["../src/claude-keeper.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"claude-keeper.d.ts","sourceRoot":"","sources":["../src/claude-keeper.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAqFD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA0DnF"}
|
package/dist/claude-keeper.js
CHANGED
|
@@ -1,266 +1,150 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Thread keeper — monitors keep-alive threads and restarts them
|
|
3
|
+
* via the start_thread MCP tool when they stop running.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Process exit → schedule restart with exponential backoff
|
|
7
|
-
* - HTTP liveness check → force-restart if agent stops polling
|
|
5
|
+
* No direct process spawning — delegates to start_thread which handles
|
|
6
|
+
* all lifecycle concerns (PID tracking, registry updates, MCP config).
|
|
8
7
|
*/
|
|
9
|
-
import { spawn } from "node:child_process";
|
|
10
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
|
-
import { join } from "node:path";
|
|
12
8
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
13
|
-
const DEFAULT_COPILOT_MODEL = "claude-opus-4.6";
|
|
14
|
-
const COPILOT_MCP_CONFIG_FILENAME = "mcp-config.json";
|
|
15
|
-
const COPILOT_INSTRUCTIONS_FILENAME = "copilot-instructions.md";
|
|
16
|
-
const COPILOT_SYSTEM_PROMPT = "You are a remote copilot agent. " +
|
|
17
|
-
"Use the sensorium MCP tools to handle tasks from your operator via Telegram.";
|
|
18
9
|
const BASE_BACKOFF_MS = 5_000;
|
|
19
10
|
const MAX_BACKOFF_MS = 5 * 60_000;
|
|
20
|
-
const
|
|
21
|
-
/** Minimum uptime before a restart is considered "healthy" and retry count resets. */
|
|
22
|
-
const HEALTHY_UPTIME_MS = 60_000;
|
|
11
|
+
const HEALTH_CHECK_INTERVAL_MS = 2 * 60_000;
|
|
23
12
|
const DEFAULT_MAX_RETRIES = 5;
|
|
24
13
|
const DEFAULT_COOLDOWN_MS = 300_000;
|
|
25
|
-
const WARM_CONTEXT_LINE_LIMIT = 50;
|
|
26
|
-
const WARM_CONTEXT_TEXT_LIMIT = 200;
|
|
27
14
|
const MCP_READY_POLL_INTERVAL_MS = 3_000;
|
|
28
15
|
const MCP_READY_TIMEOUT_MS = 120_000;
|
|
29
|
-
// WAIT_TIMEOUT_MINUTES can be up to 120 min — allow full cycle + buffer before flagging dead
|
|
30
|
-
const rawWaitTimeout = parseInt(process.env.WAIT_TIMEOUT_MINUTES ?? "120", 10);
|
|
31
|
-
const LIVENESS_THRESHOLD_MS = (Math.max(1, rawWaitTimeout) + 10) * 60_000;
|
|
32
16
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
33
17
|
function keeperLog(level, msg) {
|
|
34
|
-
const ts = new Date().toISOString()
|
|
18
|
+
const ts = new Date().toISOString();
|
|
35
19
|
console.log(`[${ts}] [KEEPER/${level}] ${msg}`);
|
|
36
20
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const serverConfig = {
|
|
40
|
-
type: "http",
|
|
41
|
-
url: `http://127.0.0.1:${port}/mcp`,
|
|
42
|
-
};
|
|
21
|
+
function authHeaders(secret) {
|
|
22
|
+
const h = { "Content-Type": "application/json" };
|
|
43
23
|
if (secret)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
writeFileSync(path, JSON.stringify(config, null, 2), "utf-8");
|
|
47
|
-
}
|
|
48
|
-
/** Write Copilot CLI home directory files: MCP config + system prompt. */
|
|
49
|
-
function writeCopilotHomeFiles(copilotHome, port, secret) {
|
|
50
|
-
mkdirSync(copilotHome, { recursive: true });
|
|
51
|
-
writeMcpConfig(join(copilotHome, COPILOT_MCP_CONFIG_FILENAME), port, secret);
|
|
52
|
-
writeFileSync(join(copilotHome, COPILOT_INSTRUCTIONS_FILENAME), COPILOT_SYSTEM_PROMPT, "utf-8");
|
|
53
|
-
}
|
|
54
|
-
/** Read-only peek at the last N messages from a thread's JSONL broker file for warm context. */
|
|
55
|
-
function readWarmContext(dataDir, threadId) {
|
|
56
|
-
const file = join(dataDir, "threads", `${threadId}.jsonl`);
|
|
57
|
-
if (!existsSync(file))
|
|
58
|
-
return "";
|
|
59
|
-
try {
|
|
60
|
-
const lines = readFileSync(file, "utf-8").split("\n").filter((l) => l.trim());
|
|
61
|
-
const recent = lines.slice(-WARM_CONTEXT_LINE_LIMIT);
|
|
62
|
-
const texts = [];
|
|
63
|
-
for (const line of recent) {
|
|
64
|
-
try {
|
|
65
|
-
const m = JSON.parse(line);
|
|
66
|
-
const text = m.message?.text ?? m.message?.caption;
|
|
67
|
-
if (text)
|
|
68
|
-
texts.push(text.slice(0, WARM_CONTEXT_TEXT_LIMIT));
|
|
69
|
-
}
|
|
70
|
-
catch { /* skip corrupt lines */ }
|
|
71
|
-
}
|
|
72
|
-
if (!texts.length)
|
|
73
|
-
return "";
|
|
74
|
-
return (`[Warm context: last ${texts.length} messages from thread ${threadId}]\n` +
|
|
75
|
-
texts.map((t) => `- ${t}`).join("\n") +
|
|
76
|
-
"\n\n");
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return "";
|
|
80
|
-
}
|
|
24
|
+
h["Authorization"] = `Bearer ${secret}`;
|
|
25
|
+
return h;
|
|
81
26
|
}
|
|
82
|
-
/** Poll the MCP HTTP server until it responds or timeout elapses. */
|
|
83
27
|
async function waitForMcpReady(port, secret) {
|
|
84
|
-
const url = `http://127.0.0.1:${port}/api/status`;
|
|
85
|
-
const headers = {};
|
|
86
|
-
if (secret)
|
|
87
|
-
headers["Authorization"] = `Bearer ${secret}`;
|
|
88
28
|
const deadline = Date.now() + MCP_READY_TIMEOUT_MS;
|
|
89
29
|
while (Date.now() < deadline) {
|
|
90
30
|
try {
|
|
91
|
-
const res = await fetch(
|
|
92
|
-
|
|
93
|
-
|
|
31
|
+
const res = await fetch(`http://127.0.0.1:${port}/api/threads/roots`, {
|
|
32
|
+
headers: authHeaders(secret),
|
|
33
|
+
signal: AbortSignal.timeout(5_000),
|
|
34
|
+
});
|
|
35
|
+
if (res.ok)
|
|
36
|
+
return true;
|
|
94
37
|
}
|
|
95
|
-
catch { /* not ready
|
|
96
|
-
await new Promise(
|
|
38
|
+
catch { /* server not ready */ }
|
|
39
|
+
await new Promise(r => setTimeout(r, MCP_READY_POLL_INTERVAL_MS));
|
|
97
40
|
}
|
|
98
41
|
return false;
|
|
99
42
|
}
|
|
100
|
-
|
|
101
|
-
async function checkHttpLiveness(port, secret) {
|
|
102
|
-
const url = `http://127.0.0.1:${port}/api/sessions`;
|
|
103
|
-
const headers = {};
|
|
104
|
-
if (secret)
|
|
105
|
-
headers["Authorization"] = `Bearer ${secret}`;
|
|
43
|
+
async function isThreadRunning(port, secret, threadId) {
|
|
106
44
|
try {
|
|
107
|
-
const res = await fetch(
|
|
45
|
+
const res = await fetch(`http://127.0.0.1:${port}/api/threads/${threadId}`, {
|
|
46
|
+
headers: authHeaders(secret),
|
|
47
|
+
signal: AbortSignal.timeout(5_000),
|
|
48
|
+
});
|
|
108
49
|
if (!res.ok)
|
|
109
50
|
return false;
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
return
|
|
51
|
+
const data = await res.json();
|
|
52
|
+
const status = data.thread?.status;
|
|
53
|
+
return status === "running" || status === "active";
|
|
113
54
|
}
|
|
114
55
|
catch {
|
|
115
56
|
return false;
|
|
116
57
|
}
|
|
117
58
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
59
|
+
async function callStartThread(config) {
|
|
60
|
+
const { mcpHttpPort: port, mcpHttpSecret: secret, threadId, sessionName, client, workingDirectory } = config;
|
|
61
|
+
const body = JSON.stringify({
|
|
62
|
+
jsonrpc: "2.0",
|
|
63
|
+
method: "tools/call",
|
|
64
|
+
params: {
|
|
65
|
+
name: "start_thread",
|
|
66
|
+
arguments: {
|
|
67
|
+
name: sessionName,
|
|
68
|
+
targetThreadId: threadId,
|
|
69
|
+
agentType: client,
|
|
70
|
+
workingDirectory: workingDirectory ?? process.cwd(),
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
id: `keeper-${threadId}-${Date.now()}`,
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
const res = await fetch(`http://127.0.0.1:${port}/mcp`, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: authHeaders(secret),
|
|
79
|
+
body,
|
|
80
|
+
signal: AbortSignal.timeout(30_000),
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
keeperLog("WARN", `start_thread HTTP ${res.status}: ${res.statusText}`);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const result = await res.json();
|
|
87
|
+
const text = result.result?.content?.[0]?.text ?? "";
|
|
88
|
+
keeperLog("INFO", `start_thread response: ${text.slice(0, 200)}`);
|
|
89
|
+
return !text.toLowerCase().includes("error");
|
|
127
90
|
}
|
|
128
|
-
|
|
129
|
-
|
|
91
|
+
catch (err) {
|
|
92
|
+
keeperLog("ERROR", `start_thread call failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
93
|
+
return false;
|
|
130
94
|
}
|
|
95
|
+
}
|
|
96
|
+
// ─── Core keeper ──────────────────────────────────────────────────────────────
|
|
97
|
+
export async function startClaudeKeeper(config) {
|
|
98
|
+
const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
99
|
+
const cooldownMs = config.cooldownMs ?? DEFAULT_COOLDOWN_MS;
|
|
100
|
+
keeperLog("INFO", `Starting keeper for thread ${config.threadId} ('${config.sessionName}') [client=${config.client}]`);
|
|
101
|
+
let stopped = false;
|
|
102
|
+
let retryCount = 0;
|
|
103
|
+
let timer = null;
|
|
131
104
|
keeperLog("INFO", "Waiting for MCP server to be ready...");
|
|
132
105
|
const ready = await waitForMcpReady(config.mcpHttpPort, config.mcpHttpSecret);
|
|
133
106
|
if (!ready)
|
|
134
|
-
keeperLog("WARN", "MCP server did not respond in time —
|
|
107
|
+
keeperLog("WARN", "MCP server did not respond in time — attempting start_thread anyway.");
|
|
135
108
|
else
|
|
136
109
|
keeperLog("INFO", "MCP server ready.");
|
|
137
|
-
|
|
138
|
-
let backoffMs = BASE_BACKOFF_MS;
|
|
139
|
-
let stopped = false;
|
|
140
|
-
let retryCount = 0;
|
|
141
|
-
let livenessTimer = null;
|
|
142
|
-
let restartTimer = null;
|
|
143
|
-
const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
144
|
-
const cooldownMs = config.cooldownMs ?? DEFAULT_COOLDOWN_MS;
|
|
145
|
-
function scheduleRestart() {
|
|
110
|
+
async function checkAndStart() {
|
|
146
111
|
if (stopped)
|
|
147
112
|
return;
|
|
148
|
-
|
|
113
|
+
const running = await isThreadRunning(config.mcpHttpPort, config.mcpHttpSecret, config.threadId);
|
|
114
|
+
if (running) {
|
|
115
|
+
scheduleCheck();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (retryCount >= maxRetries) {
|
|
149
119
|
keeperLog("WARN", `Max retries (${maxRetries}) exceeded — cooling down for ${Math.round(cooldownMs / 1000)}s`);
|
|
150
120
|
retryCount = 0;
|
|
151
|
-
|
|
152
|
-
restartTimer = setTimeout(() => { restartTimer = null; spawnAgent(); }, cooldownMs);
|
|
121
|
+
timer = setTimeout(() => void checkAndStart(), cooldownMs);
|
|
153
122
|
return;
|
|
154
123
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (stopped)
|
|
162
|
-
return;
|
|
163
|
-
const warmContext = readWarmContext(config.dataDir, config.threadId);
|
|
164
|
-
const prompt = `${warmContext}Start remote session with sensorium. Thread name = '${config.sessionName}'`;
|
|
165
|
-
// Pass prompt via args array with shell: false to prevent cmd.exe interpreting
|
|
166
|
-
// shell metacharacters (> | & ^) in warm context message text.
|
|
167
|
-
// On Windows, claude/copilot are .cmd shims — they need shell: true, so we
|
|
168
|
-
// sanitize the prompt instead by replacing shell-unsafe chars.
|
|
169
|
-
const safePrompt = process.platform === "win32"
|
|
170
|
-
? prompt.replace(/[>|&^<"]/g, " ")
|
|
171
|
-
: prompt;
|
|
172
|
-
const useShell = process.platform === "win32";
|
|
173
|
-
let cmd;
|
|
174
|
-
let args;
|
|
175
|
-
let spawnEnv;
|
|
176
|
-
if (client === "claude") {
|
|
177
|
-
cmd = config.claudeCmd;
|
|
178
|
-
args = ["--mcp-config", config.mcpConfigPath, "-p", safePrompt];
|
|
179
|
-
spawnEnv = undefined;
|
|
124
|
+
retryCount++;
|
|
125
|
+
keeperLog("INFO", `Thread ${config.threadId} not running — calling start_thread (attempt ${retryCount}/${maxRetries})`);
|
|
126
|
+
const ok = await callStartThread(config);
|
|
127
|
+
if (ok) {
|
|
128
|
+
retryCount = 0;
|
|
129
|
+
scheduleCheck();
|
|
180
130
|
}
|
|
181
131
|
else {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
keeperLog("INFO", `Spawning ${cmd} [${client}] with ${warmContext ? "warm context" : "cold start"}`);
|
|
187
|
-
try {
|
|
188
|
-
const spawned = spawn(cmd, args, {
|
|
189
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
190
|
-
windowsHide: true,
|
|
191
|
-
shell: useShell,
|
|
192
|
-
env: spawnEnv,
|
|
193
|
-
});
|
|
194
|
-
child = spawned;
|
|
195
|
-
const spawnedAt = Date.now();
|
|
196
|
-
spawned.stdout?.on("data", (chunk) => {
|
|
197
|
-
const text = chunk.toString().trimEnd();
|
|
198
|
-
if (text)
|
|
199
|
-
keeperLog("INFO", `[${client}] ${text}`);
|
|
200
|
-
});
|
|
201
|
-
spawned.stderr?.on("data", (chunk) => {
|
|
202
|
-
const text = chunk.toString().trimEnd();
|
|
203
|
-
if (text)
|
|
204
|
-
keeperLog("WARN", `[${client}:err] ${text}`);
|
|
205
|
-
});
|
|
206
|
-
spawned.on("error", (err) => {
|
|
207
|
-
keeperLog("ERROR", `Spawn error: ${err.message}`);
|
|
208
|
-
});
|
|
209
|
-
spawned.on("exit", (code, signal) => {
|
|
210
|
-
if (child === spawned)
|
|
211
|
-
child = null;
|
|
212
|
-
if (stopped)
|
|
213
|
-
return;
|
|
214
|
-
const ranLongEnough = Date.now() - spawnedAt >= HEALTHY_UPTIME_MS;
|
|
215
|
-
if (ranLongEnough) {
|
|
216
|
-
// Healthy run — reset backoff and retry counter.
|
|
217
|
-
backoffMs = BASE_BACKOFF_MS;
|
|
218
|
-
retryCount = 0;
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
retryCount++;
|
|
222
|
-
}
|
|
223
|
-
keeperLog("WARN", `${client} exited (code=${code ?? "?"}, signal=${signal ?? "none"})`);
|
|
224
|
-
scheduleRestart();
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
catch (err) {
|
|
228
|
-
keeperLog("ERROR", `Failed to spawn ${client}: ${err}`);
|
|
229
|
-
scheduleRestart();
|
|
132
|
+
const delay = Math.min(BASE_BACKOFF_MS * 2 ** retryCount, MAX_BACKOFF_MS);
|
|
133
|
+
keeperLog("INFO", `Scheduling retry in ${delay}ms`);
|
|
134
|
+
timer = setTimeout(() => void checkAndStart(), delay);
|
|
230
135
|
}
|
|
231
136
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (stopped || child === null)
|
|
137
|
+
function scheduleCheck() {
|
|
138
|
+
if (stopped)
|
|
235
139
|
return;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
child.kill();
|
|
240
|
-
// exit handler will schedule the restart
|
|
241
|
-
}
|
|
242
|
-
}, LIVENESS_CHECK_INTERVAL_MS);
|
|
243
|
-
spawnAgent();
|
|
140
|
+
timer = setTimeout(() => void checkAndStart(), HEALTH_CHECK_INTERVAL_MS);
|
|
141
|
+
}
|
|
142
|
+
void checkAndStart();
|
|
244
143
|
return {
|
|
245
144
|
async stop() {
|
|
246
|
-
if (stopped)
|
|
247
|
-
return;
|
|
248
145
|
stopped = true;
|
|
249
|
-
if (
|
|
250
|
-
|
|
251
|
-
livenessTimer = null;
|
|
252
|
-
}
|
|
253
|
-
if (restartTimer !== null) {
|
|
254
|
-
clearTimeout(restartTimer);
|
|
255
|
-
restartTimer = null;
|
|
256
|
-
}
|
|
257
|
-
if (child !== null) {
|
|
258
|
-
keeperLog("INFO", "Stopping Claude agent...");
|
|
259
|
-
child.kill();
|
|
260
|
-
await new Promise((r) => setTimeout(r, 2_000));
|
|
261
|
-
child = null;
|
|
262
|
-
}
|
|
263
|
-
keeperLog("INFO", "Keeper stopped.");
|
|
146
|
+
if (timer)
|
|
147
|
+
clearTimeout(timer);
|
|
264
148
|
},
|
|
265
149
|
};
|
|
266
150
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-keeper.js","sourceRoot":"","sources":["../src/claude-keeper.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"claude-keeper.js","sourceRoot":"","sources":["../src/claude-keeper.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { setKeepAliveEnabled, setKeepAliveThreadId, setKeepAliveClient, setKeepA
|
|
|
7
7
|
import { readBody, safeParseJSON } from "./types.js";
|
|
8
8
|
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
9
9
|
const VALID_STATUSES = ["active", "archived", "expired", "exited"];
|
|
10
|
-
const VALID_CLIENTS = ["claude", "copilot", "codex"];
|
|
10
|
+
const VALID_CLIENTS = ["claude", "copilot", "codex", "openai_codex", "copilot_claude", "copilot_codex", "cursor"];
|
|
11
11
|
function isKeeperClient(client) {
|
|
12
12
|
return client === "claude" || client === "copilot";
|
|
13
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"threads.js","sourceRoot":"","sources":["../../../src/dashboard/routes/threads.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACH,cAAc,EACd,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,YAAY,GAEf,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EACH,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,qBAAqB,GAExB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAqC,MAAM,YAAY,CAAC;AAExF,+EAA+E;AAE/E,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAU,CAAC;AAC5E,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"threads.js","sourceRoot":"","sources":["../../../src/dashboard/routes/threads.ts"],"names":[],"mappings":"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"}
|