beecork 1.7.1 → 2.0.1
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/README.md +52 -111
- package/dist/index.js +1394 -581
- package/package.json +26 -54
- package/dist/capabilities/index.d.ts +0 -3
- package/dist/capabilities/index.js +0 -2
- package/dist/capabilities/manager.d.ts +0 -13
- package/dist/capabilities/manager.js +0 -115
- package/dist/capabilities/packs.d.ts +0 -2
- package/dist/capabilities/packs.js +0 -54
- package/dist/capabilities/types.d.ts +0 -21
- package/dist/capabilities/types.js +0 -1
- package/dist/channels/admin.d.ts +0 -10
- package/dist/channels/admin.js +0 -20
- package/dist/channels/command-handler.d.ts +0 -19
- package/dist/channels/command-handler.js +0 -235
- package/dist/channels/discord.d.ts +0 -17
- package/dist/channels/discord.js +0 -266
- package/dist/channels/index.d.ts +0 -7
- package/dist/channels/index.js +0 -6
- package/dist/channels/loader.d.ts +0 -7
- package/dist/channels/loader.js +0 -87
- package/dist/channels/pipeline.d.ts +0 -50
- package/dist/channels/pipeline.js +0 -92
- package/dist/channels/registry.d.ts +0 -36
- package/dist/channels/registry.js +0 -80
- package/dist/channels/send-helpers.d.ts +0 -19
- package/dist/channels/send-helpers.js +0 -21
- package/dist/channels/telegram.d.ts +0 -47
- package/dist/channels/telegram.js +0 -649
- package/dist/channels/types.d.ts +0 -41
- package/dist/channels/types.js +0 -1
- package/dist/channels/voice-state.d.ts +0 -29
- package/dist/channels/voice-state.js +0 -45
- package/dist/channels/webhook.d.ts +0 -16
- package/dist/channels/webhook.js +0 -222
- package/dist/channels/whatsapp.d.ts +0 -28
- package/dist/channels/whatsapp.js +0 -323
- package/dist/cli/capabilities.d.ts +0 -3
- package/dist/cli/capabilities.js +0 -72
- package/dist/cli/channel.d.ts +0 -3
- package/dist/cli/channel.js +0 -202
- package/dist/cli/commands.d.ts +0 -15
- package/dist/cli/commands.js +0 -279
- package/dist/cli/doctor.d.ts +0 -1
- package/dist/cli/doctor.js +0 -208
- package/dist/cli/handoff.d.ts +0 -8
- package/dist/cli/handoff.js +0 -33
- package/dist/cli/helpers.d.ts +0 -2
- package/dist/cli/helpers.js +0 -21
- package/dist/cli/mcp.d.ts +0 -3
- package/dist/cli/mcp.js +0 -47
- package/dist/cli/media.d.ts +0 -2
- package/dist/cli/media.js +0 -125
- package/dist/cli/setup.d.ts +0 -1
- package/dist/cli/setup.js +0 -239
- package/dist/cli/store.d.ts +0 -3
- package/dist/cli/store.js +0 -108
- package/dist/config.d.ts +0 -11
- package/dist/config.js +0 -115
- package/dist/cron/scheduler.d.ts +0 -22
- package/dist/cron/scheduler.js +0 -220
- package/dist/cron/store.d.ts +0 -12
- package/dist/cron/store.js +0 -83
- package/dist/daemon.d.ts +0 -1
- package/dist/daemon.js +0 -345
- package/dist/dashboard/html.d.ts +0 -1
- package/dist/dashboard/html.js +0 -849
- package/dist/dashboard/routes.d.ts +0 -17
- package/dist/dashboard/routes.js +0 -623
- package/dist/dashboard/server.d.ts +0 -1
- package/dist/dashboard/server.js +0 -104
- package/dist/db/connection.d.ts +0 -29
- package/dist/db/connection.js +0 -37
- package/dist/db/index.d.ts +0 -14
- package/dist/db/index.js +0 -127
- package/dist/db/migrations.d.ts +0 -2
- package/dist/db/migrations.js +0 -384
- package/dist/delegation/manager.d.ts +0 -18
- package/dist/delegation/manager.js +0 -89
- package/dist/index.d.ts +0 -2
- package/dist/knowledge/index.d.ts +0 -2
- package/dist/knowledge/index.js +0 -1
- package/dist/knowledge/manager.d.ts +0 -17
- package/dist/knowledge/manager.js +0 -160
- package/dist/knowledge/types.d.ts +0 -7
- package/dist/knowledge/types.js +0 -1
- package/dist/machines/forwarder.d.ts +0 -7
- package/dist/machines/forwarder.js +0 -35
- package/dist/machines/index.d.ts +0 -1
- package/dist/machines/index.js +0 -1
- package/dist/machines/registry.d.ts +0 -15
- package/dist/machines/registry.js +0 -46
- package/dist/mcp/handlers.d.ts +0 -37
- package/dist/mcp/handlers.js +0 -520
- package/dist/mcp/server.d.ts +0 -2
- package/dist/mcp/server.js +0 -86
- package/dist/mcp/tool-definitions.d.ts +0 -1225
- package/dist/mcp/tool-definitions.js +0 -412
- package/dist/mcp/validate.d.ts +0 -23
- package/dist/mcp/validate.js +0 -65
- package/dist/media/factory.d.ts +0 -6
- package/dist/media/factory.js +0 -36
- package/dist/media/generators/dall-e.d.ts +0 -10
- package/dist/media/generators/dall-e.js +0 -41
- package/dist/media/generators/elevenlabs-music.d.ts +0 -9
- package/dist/media/generators/elevenlabs-music.js +0 -34
- package/dist/media/generators/elevenlabs-sfx.d.ts +0 -9
- package/dist/media/generators/elevenlabs-sfx.js +0 -33
- package/dist/media/generators/kling.d.ts +0 -9
- package/dist/media/generators/kling.js +0 -47
- package/dist/media/generators/lyria.d.ts +0 -10
- package/dist/media/generators/lyria.js +0 -41
- package/dist/media/generators/nano-banana.d.ts +0 -10
- package/dist/media/generators/nano-banana.js +0 -45
- package/dist/media/generators/poll-util.d.ts +0 -12
- package/dist/media/generators/poll-util.js +0 -22
- package/dist/media/generators/recraft.d.ts +0 -9
- package/dist/media/generators/recraft.js +0 -52
- package/dist/media/generators/runway.d.ts +0 -9
- package/dist/media/generators/runway.js +0 -49
- package/dist/media/generators/stable-diffusion.d.ts +0 -9
- package/dist/media/generators/stable-diffusion.js +0 -35
- package/dist/media/generators/veo.d.ts +0 -9
- package/dist/media/generators/veo.js +0 -32
- package/dist/media/index.d.ts +0 -6
- package/dist/media/index.js +0 -8
- package/dist/media/loader.d.ts +0 -8
- package/dist/media/loader.js +0 -46
- package/dist/media/store.d.ts +0 -17
- package/dist/media/store.js +0 -69
- package/dist/media/types.d.ts +0 -43
- package/dist/media/types.js +0 -1
- package/dist/memory/extractor.d.ts +0 -5
- package/dist/memory/extractor.js +0 -157
- package/dist/notifications/index.d.ts +0 -4
- package/dist/notifications/index.js +0 -21
- package/dist/notifications/ntfy.d.ts +0 -9
- package/dist/notifications/ntfy.js +0 -25
- package/dist/notifications/pushover.d.ts +0 -9
- package/dist/notifications/pushover.js +0 -26
- package/dist/notifications/types.d.ts +0 -5
- package/dist/notifications/types.js +0 -1
- package/dist/notifications/webhook-provider.d.ts +0 -9
- package/dist/notifications/webhook-provider.js +0 -24
- package/dist/observability/analytics.d.ts +0 -30
- package/dist/observability/analytics.js +0 -118
- package/dist/pipe/anthropic-client.d.ts +0 -9
- package/dist/pipe/anthropic-client.js +0 -50
- package/dist/pipe/brain.d.ts +0 -16
- package/dist/pipe/brain.js +0 -89
- package/dist/pipe/memory-store.d.ts +0 -8
- package/dist/pipe/memory-store.js +0 -39
- package/dist/pipe/project-scanner.d.ts +0 -6
- package/dist/pipe/project-scanner.js +0 -26
- package/dist/pipe/types.d.ts +0 -34
- package/dist/pipe/types.js +0 -1
- package/dist/projects/index.d.ts +0 -4
- package/dist/projects/index.js +0 -2
- package/dist/projects/manager.d.ts +0 -13
- package/dist/projects/manager.js +0 -166
- package/dist/projects/router.d.ts +0 -17
- package/dist/projects/router.js +0 -246
- package/dist/projects/types.d.ts +0 -19
- package/dist/projects/types.js +0 -1
- package/dist/service/install.d.ts +0 -4
- package/dist/service/install.js +0 -146
- package/dist/service/templates.d.ts +0 -4
- package/dist/service/templates.js +0 -52
- package/dist/service/windows.d.ts +0 -8
- package/dist/service/windows.js +0 -59
- package/dist/session/budget-guard.d.ts +0 -20
- package/dist/session/budget-guard.js +0 -31
- package/dist/session/circuit-breaker.d.ts +0 -19
- package/dist/session/circuit-breaker.js +0 -91
- package/dist/session/context-compactor.d.ts +0 -32
- package/dist/session/context-compactor.js +0 -45
- package/dist/session/context-monitor.d.ts +0 -15
- package/dist/session/context-monitor.js +0 -44
- package/dist/session/handoff.d.ts +0 -21
- package/dist/session/handoff.js +0 -50
- package/dist/session/manager.d.ts +0 -60
- package/dist/session/manager.js +0 -416
- package/dist/session/memory-store.d.ts +0 -29
- package/dist/session/memory-store.js +0 -45
- package/dist/session/message-queue.d.ts +0 -28
- package/dist/session/message-queue.js +0 -52
- package/dist/session/pending-dispatcher.d.ts +0 -31
- package/dist/session/pending-dispatcher.js +0 -120
- package/dist/session/pending-store.d.ts +0 -60
- package/dist/session/pending-store.js +0 -118
- package/dist/session/stale-session.d.ts +0 -31
- package/dist/session/stale-session.js +0 -45
- package/dist/session/subprocess.d.ts +0 -32
- package/dist/session/subprocess.js +0 -230
- package/dist/session/tab-store.d.ts +0 -28
- package/dist/session/tab-store.js +0 -78
- package/dist/session/tool-classifier.d.ts +0 -4
- package/dist/session/tool-classifier.js +0 -56
- package/dist/tasks/scheduler.d.ts +0 -45
- package/dist/tasks/scheduler.js +0 -329
- package/dist/tasks/store.d.ts +0 -11
- package/dist/tasks/store.js +0 -103
- package/dist/timeline/index.d.ts +0 -3
- package/dist/timeline/index.js +0 -2
- package/dist/timeline/logger.d.ts +0 -8
- package/dist/timeline/logger.js +0 -11
- package/dist/timeline/query.d.ts +0 -11
- package/dist/timeline/query.js +0 -67
- package/dist/timeline/types.d.ts +0 -12
- package/dist/timeline/types.js +0 -1
- package/dist/types.d.ts +0 -225
- package/dist/types.js +0 -3
- package/dist/users/index.d.ts +0 -2
- package/dist/users/index.js +0 -1
- package/dist/users/service.d.ts +0 -17
- package/dist/users/service.js +0 -46
- package/dist/util/auto-heal.d.ts +0 -43
- package/dist/util/auto-heal.js +0 -107
- package/dist/util/install-info.d.ts +0 -37
- package/dist/util/install-info.js +0 -80
- package/dist/util/logger.d.ts +0 -18
- package/dist/util/logger.js +0 -118
- package/dist/util/paths.d.ts +0 -13
- package/dist/util/paths.js +0 -55
- package/dist/util/platform.d.ts +0 -2
- package/dist/util/platform.js +0 -11
- package/dist/util/progress.d.ts +0 -34
- package/dist/util/progress.js +0 -133
- package/dist/util/rate-limiter.d.ts +0 -14
- package/dist/util/rate-limiter.js +0 -50
- package/dist/util/retry.d.ts +0 -2
- package/dist/util/retry.js +0 -18
- package/dist/util/text.d.ts +0 -32
- package/dist/util/text.js +0 -101
- package/dist/version.d.ts +0 -1
- package/dist/version.js +0 -4
- package/dist/voice/index.d.ts +0 -17
- package/dist/voice/index.js +0 -42
- package/dist/voice/stt.d.ts +0 -16
- package/dist/voice/stt.js +0 -57
- package/dist/voice/tts.d.ts +0 -23
- package/dist/voice/tts.js +0 -84
- package/dist/watchers/evaluator.d.ts +0 -5
- package/dist/watchers/evaluator.js +0 -45
- package/dist/watchers/index.d.ts +0 -4
- package/dist/watchers/index.js +0 -3
- package/dist/watchers/scheduler.d.ts +0 -20
- package/dist/watchers/scheduler.js +0 -183
- package/dist/watchers/store.d.ts +0 -10
- package/dist/watchers/store.js +0 -56
- package/dist/watchers/types.d.ts +0 -15
- package/dist/watchers/types.js +0 -1
- package/scripts/postinstall.mjs +0 -50
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
-
import { logger } from '../util/logger.js';
|
|
5
|
-
import { getMcpConfigPath } from '../util/paths.js';
|
|
6
|
-
// Cache the MCP-config existence check. The file is created at setup time and
|
|
7
|
-
// stable for the daemon's lifetime; we don't need to stat() it per spawn.
|
|
8
|
-
let mcpConfigExistsCache = null;
|
|
9
|
-
function mcpConfigExists() {
|
|
10
|
-
if (mcpConfigExistsCache !== null)
|
|
11
|
-
return mcpConfigExistsCache;
|
|
12
|
-
mcpConfigExistsCache = fs.existsSync(getMcpConfigPath());
|
|
13
|
-
return mcpConfigExistsCache;
|
|
14
|
-
}
|
|
15
|
-
/** Test-only — reset the existsSync cache between test runs that toggle the mock. */
|
|
16
|
-
export function _resetMcpConfigExistsCacheForTests() {
|
|
17
|
-
mcpConfigExistsCache = null;
|
|
18
|
-
}
|
|
19
|
-
const BEECORK_SYSTEM_PROMPT = `You are running inside Beecork, an always-on infrastructure for Claude Code.
|
|
20
|
-
|
|
21
|
-
You have these special MCP tools available:
|
|
22
|
-
- beecork_remember: Store important facts for future sessions (preferences, server addresses, decisions, outcomes)
|
|
23
|
-
- beecork_recall: Search stored memories — ALWAYS call this at the start of complex tasks
|
|
24
|
-
- beecork_task_create: Schedule recurring tasks (types: "at" for one-time, "every" for interval like "30m", "cron" for expressions like "0 9 * * 1")
|
|
25
|
-
- beecork_task_list: List scheduled tasks
|
|
26
|
-
- beecork_task_delete: Remove a scheduled task
|
|
27
|
-
- beecork_tab_create: Create a new virtual tab for parallel work
|
|
28
|
-
- beecork_tab_list: List all tabs
|
|
29
|
-
- beecork_send_message: Send a message to another tab
|
|
30
|
-
- beecork_notify: Send the user a notification mid-task without stopping
|
|
31
|
-
- beecork_status: Check system status
|
|
32
|
-
|
|
33
|
-
Guidelines:
|
|
34
|
-
- You are running unattended. Be thorough and complete tasks fully.
|
|
35
|
-
- Always call beecork_recall at the start of any task to check relevant memories.
|
|
36
|
-
- Always call beecork_remember when you learn something important.
|
|
37
|
-
- When asked for recurring tasks, use beecork_task_create.
|
|
38
|
-
- Use beecork_notify for progress updates during long tasks.`;
|
|
39
|
-
export class ClaudeSubprocess {
|
|
40
|
-
tabName;
|
|
41
|
-
workingDir;
|
|
42
|
-
config;
|
|
43
|
-
tabSystemPrompt;
|
|
44
|
-
proc = null;
|
|
45
|
-
buffer = '';
|
|
46
|
-
killTimer = null;
|
|
47
|
-
runtimeTimer = null;
|
|
48
|
-
startupTimer = null;
|
|
49
|
-
/**
|
|
50
|
-
* Set when the startup watchdog kills a subprocess that never emitted a
|
|
51
|
-
* single event — distinguishes a transient network/connection stall from a
|
|
52
|
-
* normal exit or a real wall-clock overrun, so the manager can retry once.
|
|
53
|
-
*/
|
|
54
|
-
killReason = null;
|
|
55
|
-
sessionId;
|
|
56
|
-
constructor(tabName, workingDir, config, sessionId, tabSystemPrompt) {
|
|
57
|
-
this.tabName = tabName;
|
|
58
|
-
this.workingDir = workingDir;
|
|
59
|
-
this.config = config;
|
|
60
|
-
this.tabSystemPrompt = tabSystemPrompt;
|
|
61
|
-
this.sessionId = sessionId ?? uuidv4();
|
|
62
|
-
}
|
|
63
|
-
async send(prompt, callbacks, resume = false) {
|
|
64
|
-
if (this.proc) {
|
|
65
|
-
throw new Error(`Subprocess for tab "${this.tabName}" is already running`);
|
|
66
|
-
}
|
|
67
|
-
const args = this.buildArgs(prompt, resume);
|
|
68
|
-
logger.debug(`[${this.tabName}] Spawning: ${this.config.claudeCode.bin} ${args.join(' ')}`);
|
|
69
|
-
this.proc = spawn(this.config.claudeCode.bin, args, {
|
|
70
|
-
cwd: this.workingDir,
|
|
71
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
72
|
-
env: { ...process.env },
|
|
73
|
-
});
|
|
74
|
-
const pid = this.proc.pid;
|
|
75
|
-
logger.info(`[${this.tabName}] Claude subprocess started (PID: ${pid})`);
|
|
76
|
-
this.proc.stdout.on('data', (chunk) => {
|
|
77
|
-
this.buffer += chunk.toString();
|
|
78
|
-
const lines = this.buffer.split('\n');
|
|
79
|
-
this.buffer = lines.pop() || '';
|
|
80
|
-
for (const line of lines) {
|
|
81
|
-
if (!line.trim())
|
|
82
|
-
continue;
|
|
83
|
-
try {
|
|
84
|
-
const event = JSON.parse(line);
|
|
85
|
-
// First real event proves claude initialized and the socket is alive
|
|
86
|
-
// — the startup-stall window is over, so disarm the watchdog for good.
|
|
87
|
-
// It never re-arms, so legitimate multi-minute tool runs (which emit
|
|
88
|
-
// nothing on stdout until the tool returns) are never killed.
|
|
89
|
-
if (this.startupTimer) {
|
|
90
|
-
clearTimeout(this.startupTimer);
|
|
91
|
-
this.startupTimer = null;
|
|
92
|
-
}
|
|
93
|
-
callbacks.onEvent(event);
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
// Non-JSON line (verbose debug output), skip
|
|
97
|
-
logger.debug(`[${this.tabName}] non-json: ${line.slice(0, 200)}`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
this.proc.stderr.on('data', (chunk) => {
|
|
102
|
-
const text = chunk.toString().trim();
|
|
103
|
-
if (text) {
|
|
104
|
-
// claude prints auth failures, rate limits, license issues, and other
|
|
105
|
-
// operational errors to stderr. Surface at warn so they reach daemon.log
|
|
106
|
-
// at the default level — debugging "why did claude exit?" otherwise
|
|
107
|
-
// requires recompiling with a different log level.
|
|
108
|
-
logger.warn(`[${this.tabName}] claude stderr: ${text.slice(0, 500)}`);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
this.proc.on('error', (err) => {
|
|
112
|
-
this.proc = null;
|
|
113
|
-
if (this.runtimeTimer) {
|
|
114
|
-
clearTimeout(this.runtimeTimer);
|
|
115
|
-
this.runtimeTimer = null;
|
|
116
|
-
}
|
|
117
|
-
if (this.startupTimer) {
|
|
118
|
-
clearTimeout(this.startupTimer);
|
|
119
|
-
this.startupTimer = null;
|
|
120
|
-
}
|
|
121
|
-
callbacks.onError(err);
|
|
122
|
-
});
|
|
123
|
-
this.proc.on('exit', (code) => {
|
|
124
|
-
this.proc = null;
|
|
125
|
-
if (this.killTimer) {
|
|
126
|
-
clearTimeout(this.killTimer);
|
|
127
|
-
this.killTimer = null;
|
|
128
|
-
}
|
|
129
|
-
if (this.runtimeTimer) {
|
|
130
|
-
clearTimeout(this.runtimeTimer);
|
|
131
|
-
this.runtimeTimer = null;
|
|
132
|
-
}
|
|
133
|
-
if (this.startupTimer) {
|
|
134
|
-
clearTimeout(this.startupTimer);
|
|
135
|
-
this.startupTimer = null;
|
|
136
|
-
}
|
|
137
|
-
logger.info(`[${this.tabName}] Claude subprocess exited (code: ${code})`);
|
|
138
|
-
callbacks.onExit(code);
|
|
139
|
-
});
|
|
140
|
-
// Hard runtime cap so a wedged claude can't pin a tab forever.
|
|
141
|
-
// Default 30 minutes. Disable by setting maxRuntimeMs to 0.
|
|
142
|
-
const maxRuntimeMs = this.config.claudeCode.maxRuntimeMs ?? 30 * 60 * 1000;
|
|
143
|
-
if (maxRuntimeMs > 0) {
|
|
144
|
-
this.runtimeTimer = setTimeout(() => {
|
|
145
|
-
if (!this.proc)
|
|
146
|
-
return;
|
|
147
|
-
logger.warn(`[${this.tabName}] Subprocess exceeded maxRuntimeMs (${maxRuntimeMs}ms) — killing`);
|
|
148
|
-
callbacks.onError(new Error(`Subprocess timed out after ${Math.round(maxRuntimeMs / 1000)}s`));
|
|
149
|
-
this.kill();
|
|
150
|
-
}, maxRuntimeMs);
|
|
151
|
-
}
|
|
152
|
-
// Startup watchdog. A healthy claude emits its init event within seconds of
|
|
153
|
-
// spawn. Total silence this long means it wedged on a stalled network socket
|
|
154
|
-
// (DNS/connection blip with no client-side timeout) and would otherwise sit
|
|
155
|
-
// idle until the 30-min maxRuntime kill. Unlike maxRuntime, this routes
|
|
156
|
-
// through onExit (kill only, no onError) so the manager retries once. It is
|
|
157
|
-
// disarmed on the first event, so it can only fire before claude initializes
|
|
158
|
-
// — long-running tools, which emit nothing on stdout until they return, are
|
|
159
|
-
// never affected.
|
|
160
|
-
const silentTimeoutMs = this.config.claudeCode.silentTimeoutMs ?? 120_000;
|
|
161
|
-
if (silentTimeoutMs > 0) {
|
|
162
|
-
this.startupTimer = setTimeout(() => {
|
|
163
|
-
if (!this.proc)
|
|
164
|
-
return;
|
|
165
|
-
logger.warn(`[${this.tabName}] No output ${silentTimeoutMs}ms after spawn — killing as silent network stall`);
|
|
166
|
-
this.killReason = 'silent';
|
|
167
|
-
this.kill();
|
|
168
|
-
}, silentTimeoutMs);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
kill() {
|
|
172
|
-
if (!this.proc)
|
|
173
|
-
return;
|
|
174
|
-
logger.info(`[${this.tabName}] Killing subprocess (PID: ${this.proc.pid})`);
|
|
175
|
-
this.proc.kill('SIGTERM');
|
|
176
|
-
const proc = this.proc;
|
|
177
|
-
this.killTimer = setTimeout(() => {
|
|
178
|
-
try {
|
|
179
|
-
proc.kill('SIGKILL');
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
/* already dead */
|
|
183
|
-
}
|
|
184
|
-
}, 5000);
|
|
185
|
-
}
|
|
186
|
-
get isRunning() {
|
|
187
|
-
return this.proc !== null;
|
|
188
|
-
}
|
|
189
|
-
get pid() {
|
|
190
|
-
return this.proc?.pid ?? null;
|
|
191
|
-
}
|
|
192
|
-
buildArgs(prompt, resume) {
|
|
193
|
-
const args = [
|
|
194
|
-
'-p',
|
|
195
|
-
'--output-format',
|
|
196
|
-
'stream-json',
|
|
197
|
-
'--verbose',
|
|
198
|
-
...this.config.claudeCode.defaultFlags,
|
|
199
|
-
];
|
|
200
|
-
// Only add MCP config if the file exists. existsSync result is cached at
|
|
201
|
-
// module scope — the path is stable for the daemon's lifetime, so doing
|
|
202
|
-
// this once-per-process saves a syscall per claude spawn (every message,
|
|
203
|
-
// every task firing, every watcher trigger).
|
|
204
|
-
if (mcpConfigExists()) {
|
|
205
|
-
args.push('--mcp-config', getMcpConfigPath());
|
|
206
|
-
}
|
|
207
|
-
// Inject Beecork system context so Claude knows about available tools
|
|
208
|
-
if (!resume) {
|
|
209
|
-
let systemPrompt = BEECORK_SYSTEM_PROMPT;
|
|
210
|
-
if (this.tabSystemPrompt) {
|
|
211
|
-
systemPrompt += `\n\n[Tab-specific instructions for "${this.tabName}"]\n${this.tabSystemPrompt}`;
|
|
212
|
-
}
|
|
213
|
-
args.push('--system-prompt', systemPrompt);
|
|
214
|
-
}
|
|
215
|
-
if (resume) {
|
|
216
|
-
args.push('--resume', this.sessionId);
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
args.push('--session-id', this.sessionId);
|
|
220
|
-
}
|
|
221
|
-
if (this.config.claudeCode.computerUse) {
|
|
222
|
-
args.push('--computer-use');
|
|
223
|
-
}
|
|
224
|
-
if (this.config.claudeCode.maxBudgetUsd) {
|
|
225
|
-
args.push('--max-budget-usd', String(this.config.claudeCode.maxBudgetUsd));
|
|
226
|
-
}
|
|
227
|
-
args.push(prompt);
|
|
228
|
-
return args;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type Database from 'better-sqlite3';
|
|
2
|
-
import type { Tab, TabStatus } from '../types.js';
|
|
3
|
-
/**
|
|
4
|
-
* SQL helpers for the `tabs` table. Single place for any code that needs to
|
|
5
|
-
* read/write tab rows. TabManager owns subprocess lifecycle; TabStore owns
|
|
6
|
-
* the schema knowledge.
|
|
7
|
-
*
|
|
8
|
-
* All methods accept an optional `db` param so they're testable against an
|
|
9
|
-
* in-memory database. The no-arg form uses the singleton.
|
|
10
|
-
*/
|
|
11
|
-
export declare const TabStore: {
|
|
12
|
-
listAll(db?: Database.Database): Tab[];
|
|
13
|
-
findByName(name: string, db?: Database.Database): Tab | undefined;
|
|
14
|
-
getIdByName(name: string, db?: Database.Database): string | undefined;
|
|
15
|
-
countAll(db?: Database.Database): number;
|
|
16
|
-
countRunning(db?: Database.Database): number;
|
|
17
|
-
/** All tabs marked 'running' — used by daemon crash-recovery on startup. */
|
|
18
|
-
findRunning(db?: Database.Database): Tab[];
|
|
19
|
-
/** Most-recently-active tab — used by MCP to surface "current" context. */
|
|
20
|
-
mostRecent(db?: Database.Database): Tab | undefined;
|
|
21
|
-
setStatus(name: string, status: TabStatus, db?: Database.Database): void;
|
|
22
|
-
setIdleById(id: string, db?: Database.Database): void;
|
|
23
|
-
/** Used by MCP close-tab to nudge daemon recovery loop. */
|
|
24
|
-
markRunningAsStopped(name: string, db?: Database.Database): void;
|
|
25
|
-
setSystemPrompt(name: string, systemPrompt: string, db?: Database.Database): boolean;
|
|
26
|
-
/** Delete a tab and all of its messages atomically. Returns true if it existed. */
|
|
27
|
-
deleteWithMessages(name: string, db?: Database.Database): boolean;
|
|
28
|
-
};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { getDb } from '../db/index.js';
|
|
2
|
-
function rowToTab(row) {
|
|
3
|
-
return {
|
|
4
|
-
id: row.id,
|
|
5
|
-
name: row.name,
|
|
6
|
-
sessionId: row.session_id,
|
|
7
|
-
status: row.status,
|
|
8
|
-
workingDir: row.working_dir,
|
|
9
|
-
createdAt: row.created_at,
|
|
10
|
-
lastActivityAt: row.last_activity_at,
|
|
11
|
-
pid: row.pid,
|
|
12
|
-
systemPrompt: row.system_prompt,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* SQL helpers for the `tabs` table. Single place for any code that needs to
|
|
17
|
-
* read/write tab rows. TabManager owns subprocess lifecycle; TabStore owns
|
|
18
|
-
* the schema knowledge.
|
|
19
|
-
*
|
|
20
|
-
* All methods accept an optional `db` param so they're testable against an
|
|
21
|
-
* in-memory database. The no-arg form uses the singleton.
|
|
22
|
-
*/
|
|
23
|
-
export const TabStore = {
|
|
24
|
-
listAll(db = getDb()) {
|
|
25
|
-
return db.prepare('SELECT * FROM tabs ORDER BY last_activity_at DESC').all().map(rowToTab);
|
|
26
|
-
},
|
|
27
|
-
findByName(name, db = getDb()) {
|
|
28
|
-
const row = db.prepare('SELECT * FROM tabs WHERE name = ?').get(name);
|
|
29
|
-
return row ? rowToTab(row) : undefined;
|
|
30
|
-
},
|
|
31
|
-
getIdByName(name, db = getDb()) {
|
|
32
|
-
const row = db.prepare('SELECT id FROM tabs WHERE name = ?').get(name);
|
|
33
|
-
return row?.id;
|
|
34
|
-
},
|
|
35
|
-
countAll(db = getDb()) {
|
|
36
|
-
return db.prepare('SELECT COUNT(*) as c FROM tabs').get().c;
|
|
37
|
-
},
|
|
38
|
-
countRunning(db = getDb()) {
|
|
39
|
-
return db.prepare("SELECT COUNT(*) as c FROM tabs WHERE status = 'running'").get().c;
|
|
40
|
-
},
|
|
41
|
-
/** All tabs marked 'running' — used by daemon crash-recovery on startup. */
|
|
42
|
-
findRunning(db = getDb()) {
|
|
43
|
-
return db.prepare("SELECT * FROM tabs WHERE status = 'running'").all().map(rowToTab);
|
|
44
|
-
},
|
|
45
|
-
/** Most-recently-active tab — used by MCP to surface "current" context. */
|
|
46
|
-
mostRecent(db = getDb()) {
|
|
47
|
-
const row = db.prepare('SELECT * FROM tabs ORDER BY last_activity_at DESC LIMIT 1').get();
|
|
48
|
-
return row ? rowToTab(row) : undefined;
|
|
49
|
-
},
|
|
50
|
-
setStatus(name, status, db = getDb()) {
|
|
51
|
-
db.prepare('UPDATE tabs SET status = ?, last_activity_at = ?, pid = NULL WHERE name = ?').run(status, new Date().toISOString(), name);
|
|
52
|
-
},
|
|
53
|
-
setIdleById(id, db = getDb()) {
|
|
54
|
-
db.prepare("UPDATE tabs SET status = 'idle', pid = NULL WHERE id = ?").run(id);
|
|
55
|
-
},
|
|
56
|
-
/** Used by MCP close-tab to nudge daemon recovery loop. */
|
|
57
|
-
markRunningAsStopped(name, db = getDb()) {
|
|
58
|
-
db.prepare("UPDATE tabs SET status = 'stopped', pid = NULL WHERE name = ? AND status = 'running'").run(name);
|
|
59
|
-
},
|
|
60
|
-
setSystemPrompt(name, systemPrompt, db = getDb()) {
|
|
61
|
-
const result = db
|
|
62
|
-
.prepare('UPDATE tabs SET system_prompt = ? WHERE name = ?')
|
|
63
|
-
.run(systemPrompt, name);
|
|
64
|
-
return result.changes > 0;
|
|
65
|
-
},
|
|
66
|
-
/** Delete a tab and all of its messages atomically. Returns true if it existed. */
|
|
67
|
-
deleteWithMessages(name, db = getDb()) {
|
|
68
|
-
const id = this.getIdByName(name, db);
|
|
69
|
-
if (!id)
|
|
70
|
-
return false;
|
|
71
|
-
const tx = db.transaction(() => {
|
|
72
|
-
db.prepare('DELETE FROM messages WHERE tab_id = ?').run(id);
|
|
73
|
-
db.prepare('DELETE FROM tabs WHERE id = ?').run(id);
|
|
74
|
-
});
|
|
75
|
-
tx();
|
|
76
|
-
return true;
|
|
77
|
-
},
|
|
78
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
/** Reserved for future approval mode implementation. Not currently wired into the runtime. */
|
|
2
|
-
export type ToolRisk = 'safe' | 'dangerous';
|
|
3
|
-
/** Classify a tool call as safe or dangerous */
|
|
4
|
-
export declare function classifyTool(toolName: string, input: Record<string, unknown>): ToolRisk;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const SAFE_TOOLS = new Set([
|
|
2
|
-
'Read', 'Glob', 'Grep', 'LSP', 'WebFetch', 'WebSearch',
|
|
3
|
-
'ToolSearch', 'TaskGet', 'TaskList',
|
|
4
|
-
]);
|
|
5
|
-
const DANGEROUS_TOOLS = new Set([
|
|
6
|
-
'Write', 'Edit', 'NotebookEdit',
|
|
7
|
-
'TaskCreate', 'TaskUpdate', 'TaskStop',
|
|
8
|
-
]);
|
|
9
|
-
const SAFE_BASH_PATTERNS = [
|
|
10
|
-
/^(ls|cat|head|tail|wc|file|stat|which|type|echo|printf)\b/,
|
|
11
|
-
/^git\s+(status|log|diff|show|branch|tag|remote)\b/,
|
|
12
|
-
/^(pwd|whoami|hostname|date|uname|env|printenv)\b/,
|
|
13
|
-
/^(find|grep|rg|fd|ag)\b/,
|
|
14
|
-
/^(node|python|ruby|go)\s+--?(version|help)/,
|
|
15
|
-
/^npm\s+(list|ls|view|info|outdated|audit)\b/,
|
|
16
|
-
/^curl\s.*-X\s*GET\b/,
|
|
17
|
-
/^curl\s+(?!.*-X\s*(POST|PUT|DELETE|PATCH))(?!.*--data)(?!.*-d\s)/,
|
|
18
|
-
];
|
|
19
|
-
const DANGEROUS_BASH_PATTERNS = [
|
|
20
|
-
/^rm\b/,
|
|
21
|
-
/^(mv|cp)\b.*--?(force|f)\b/,
|
|
22
|
-
/^chmod\b/,
|
|
23
|
-
/^chown\b/,
|
|
24
|
-
/^git\s+(push|reset|rebase|merge|checkout\s+--)\b/,
|
|
25
|
-
/^(docker|kubectl|terraform|ansible)\b/,
|
|
26
|
-
/^(sudo|su)\b/,
|
|
27
|
-
/^npm\s+(publish|install|uninstall|link)\b/,
|
|
28
|
-
/^(kill|killall|pkill)\b/,
|
|
29
|
-
/^curl\s.*-X\s*(POST|PUT|DELETE|PATCH)\b/,
|
|
30
|
-
];
|
|
31
|
-
/** Classify a tool call as safe or dangerous */
|
|
32
|
-
export function classifyTool(toolName, input) {
|
|
33
|
-
if (SAFE_TOOLS.has(toolName))
|
|
34
|
-
return 'safe';
|
|
35
|
-
if (DANGEROUS_TOOLS.has(toolName))
|
|
36
|
-
return 'dangerous';
|
|
37
|
-
// Bash tool: inspect the command
|
|
38
|
-
if (toolName === 'Bash') {
|
|
39
|
-
const command = String(input.command || '').trim();
|
|
40
|
-
for (const pattern of SAFE_BASH_PATTERNS) {
|
|
41
|
-
if (pattern.test(command))
|
|
42
|
-
return 'safe';
|
|
43
|
-
}
|
|
44
|
-
for (const pattern of DANGEROUS_BASH_PATTERNS) {
|
|
45
|
-
if (pattern.test(command))
|
|
46
|
-
return 'dangerous';
|
|
47
|
-
}
|
|
48
|
-
// Default: unknown bash commands are dangerous
|
|
49
|
-
return 'dangerous';
|
|
50
|
-
}
|
|
51
|
-
// MCP tools from external servers: default to dangerous
|
|
52
|
-
if (toolName.startsWith('mcp__'))
|
|
53
|
-
return 'dangerous';
|
|
54
|
-
// Unknown tools: default to dangerous
|
|
55
|
-
return 'dangerous';
|
|
56
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { exec } from 'node:child_process';
|
|
2
|
-
import type { TabManager, NotifyCallback } from '../session/manager.js';
|
|
3
|
-
export declare const execAsync: typeof exec.__promisify__;
|
|
4
|
-
export declare class TaskScheduler {
|
|
5
|
-
private tabManager;
|
|
6
|
-
private onNotify;
|
|
7
|
-
private nextRunAt;
|
|
8
|
-
private running;
|
|
9
|
-
private failureCounts;
|
|
10
|
-
private stopping;
|
|
11
|
-
private store;
|
|
12
|
-
constructor(tabManager: TabManager, onNotify: NotifyCallback | null);
|
|
13
|
-
/** Load all tasks from store and schedule them */
|
|
14
|
-
loadAndSchedule(): void;
|
|
15
|
-
/** Check for the reload signal file and reload if present */
|
|
16
|
-
checkForReload(): void;
|
|
17
|
-
/**
|
|
18
|
-
* Fire any tasks whose nextRunAt has elapsed. Called every ~5s by the daemon
|
|
19
|
-
* poll loop. This is the macOS-sleep-resilient replacement for setTimeout-driven
|
|
20
|
-
* cron heartbeats — after a wake, the next tick catches all overdue tasks.
|
|
21
|
-
*/
|
|
22
|
-
tick(): void;
|
|
23
|
-
/** Stop the scheduler. In-flight fireJob promises are detached and resolve naturally. */
|
|
24
|
-
stopAll(): void;
|
|
25
|
-
/** Compute next run time in ms epoch, given a "from" anchor. Returns null if invalid. */
|
|
26
|
-
private computeNextRun;
|
|
27
|
-
private fireJob;
|
|
28
|
-
/**
|
|
29
|
-
* Track consecutive failures per task. After MAX_CONSECUTIVE_FAILURES the
|
|
30
|
-
* task is auto-disabled in the DB and a single "auto-disabled" notification
|
|
31
|
-
* is sent. Counter resets on the next successful fire.
|
|
32
|
-
*/
|
|
33
|
-
private recordFailure;
|
|
34
|
-
private handleSystemEvent;
|
|
35
|
-
}
|
|
36
|
-
/** Convert human interval (30m, 2h, 1d, 1h30m, 2w) to milliseconds */
|
|
37
|
-
export declare function intervalToMs(interval: string): number | null;
|
|
38
|
-
/** Convert human interval (30m, 2h, 1d, 1h30m, 2w) to cron expression */
|
|
39
|
-
export declare function intervalToCron(interval: string): string | null;
|
|
40
|
-
/**
|
|
41
|
-
* Validate a schedule string for a given scheduleType. Returns an error string
|
|
42
|
-
* on invalid input or null when valid. Used by MCP + dashboard before insert
|
|
43
|
-
* so misconfigured tasks fail loud instead of silently never firing.
|
|
44
|
-
*/
|
|
45
|
-
export declare function validateSchedule(scheduleType: string, schedule: string): string | null;
|