cc-claw 0.4.5 → 0.4.6
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/cli.js +248 -158
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -48,7 +48,7 @@ var VERSION;
|
|
|
48
48
|
var init_version = __esm({
|
|
49
49
|
"src/version.ts"() {
|
|
50
50
|
"use strict";
|
|
51
|
-
VERSION = true ? "0.4.
|
|
51
|
+
VERSION = true ? "0.4.6" : (() => {
|
|
52
52
|
try {
|
|
53
53
|
return JSON.parse(readFileSync(join2(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
54
54
|
} catch {
|
|
@@ -358,10 +358,10 @@ function claimTask(db3, taskId, agentId) {
|
|
|
358
358
|
).get(...blockedBy);
|
|
359
359
|
if (incomplete.count > 0) return false;
|
|
360
360
|
}
|
|
361
|
-
db3.prepare(
|
|
361
|
+
const result = db3.prepare(
|
|
362
362
|
"UPDATE agent_tasks SET assignee = ?, status = 'in_progress' WHERE id = ? AND status = 'pending'"
|
|
363
363
|
).run(agentId, taskId);
|
|
364
|
-
return
|
|
364
|
+
return result.changes > 0;
|
|
365
365
|
}
|
|
366
366
|
function sendInboxMessage(db3, opts) {
|
|
367
367
|
const result = db3.prepare(`
|
|
@@ -2490,6 +2490,7 @@ var init_store4 = __esm({
|
|
|
2490
2490
|
});
|
|
2491
2491
|
|
|
2492
2492
|
// src/env.ts
|
|
2493
|
+
import { homedir as homedir2 } from "os";
|
|
2493
2494
|
function stripProxyVars(env) {
|
|
2494
2495
|
for (const key of PROXY_KEYS) delete env[key];
|
|
2495
2496
|
}
|
|
@@ -2498,7 +2499,7 @@ function buildBaseEnv(extraOverrides) {
|
|
|
2498
2499
|
for (const [k, v] of Object.entries(process.env)) {
|
|
2499
2500
|
if (v !== void 0) env[k] = v;
|
|
2500
2501
|
}
|
|
2501
|
-
if (!env.HOME) env.HOME =
|
|
2502
|
+
if (!env.HOME) env.HOME = homedir2();
|
|
2502
2503
|
stripProxyVars(env);
|
|
2503
2504
|
if (extraOverrides) Object.assign(env, extraOverrides);
|
|
2504
2505
|
return env;
|
|
@@ -3208,8 +3209,9 @@ async function injectMemoryContext(userMessage) {
|
|
|
3208
3209
|
seen.add(mem.id);
|
|
3209
3210
|
combinedMemories.push(mem);
|
|
3210
3211
|
}
|
|
3212
|
+
if (combinedMemories.length >= FINAL_TOP_K_MEMORIES) break;
|
|
3211
3213
|
}
|
|
3212
|
-
combinedSessions = ftsSessions;
|
|
3214
|
+
combinedSessions = ftsSessions.slice(0, FINAL_TOP_K_SESSIONS);
|
|
3213
3215
|
}
|
|
3214
3216
|
if (combinedMemories.length === 0 && combinedSessions.length === 0) return null;
|
|
3215
3217
|
const lines = [];
|
|
@@ -4000,8 +4002,10 @@ function spawnAgentProcess(runner, opts, callbacks) {
|
|
|
4000
4002
|
const child = spawn2(runner.getExecutablePath(), args, {
|
|
4001
4003
|
env: buildSpawnEnv(runner, opts.isSubAgent),
|
|
4002
4004
|
cwd: opts.cwd,
|
|
4003
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4005
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4006
|
+
detached: true
|
|
4004
4007
|
});
|
|
4008
|
+
child.unref();
|
|
4005
4009
|
let resultText = "";
|
|
4006
4010
|
let usage2;
|
|
4007
4011
|
if (child.stdout) {
|
|
@@ -4024,7 +4028,14 @@ function spawnAgentProcess(runner, opts, callbacks) {
|
|
|
4024
4028
|
if (event.usage) usage2 = event.usage;
|
|
4025
4029
|
callbacks.onResult?.(resultText, usage2);
|
|
4026
4030
|
if (runner.shouldKillOnResult()) {
|
|
4027
|
-
|
|
4031
|
+
try {
|
|
4032
|
+
if (child.pid) process.kill(-child.pid, "SIGTERM");
|
|
4033
|
+
} catch {
|
|
4034
|
+
try {
|
|
4035
|
+
child.kill("SIGTERM");
|
|
4036
|
+
} catch {
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4028
4039
|
}
|
|
4029
4040
|
}
|
|
4030
4041
|
}
|
|
@@ -4104,7 +4115,7 @@ var init_cost = __esm({
|
|
|
4104
4115
|
// src/mcps/propagate.ts
|
|
4105
4116
|
import { execFile } from "child_process";
|
|
4106
4117
|
import { promisify } from "util";
|
|
4107
|
-
import { homedir as
|
|
4118
|
+
import { homedir as homedir3 } from "os";
|
|
4108
4119
|
async function discoverExistingMcps(runner) {
|
|
4109
4120
|
try {
|
|
4110
4121
|
const listCmd = runner.getMcpListCommand();
|
|
@@ -4113,7 +4124,7 @@ async function discoverExistingMcps(runner) {
|
|
|
4113
4124
|
const result = await execFileAsync(exe, args, {
|
|
4114
4125
|
encoding: "utf-8",
|
|
4115
4126
|
env: runner.getEnv(),
|
|
4116
|
-
cwd:
|
|
4127
|
+
cwd: homedir3(),
|
|
4117
4128
|
timeout: 3e4
|
|
4118
4129
|
});
|
|
4119
4130
|
const stdout = typeof result === "string" ? result : Array.isArray(result) ? result[0] : result?.stdout ?? null;
|
|
@@ -4628,6 +4639,26 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
4628
4639
|
clearTimeout(timeoutTimers.get(agentId));
|
|
4629
4640
|
timeoutTimers.delete(agentId);
|
|
4630
4641
|
activeProcesses.delete(agentId);
|
|
4642
|
+
const crashedAgent = getAgent(db3, agentId);
|
|
4643
|
+
if (crashedAgent) {
|
|
4644
|
+
const mcpsCrashed = crashedAgent.mcpsAdded ? JSON.parse(crashedAgent.mcpsAdded) : [];
|
|
4645
|
+
if (mcpsCrashed.length > 0) {
|
|
4646
|
+
const runner2 = getRunner(crashedAgent.runnerId);
|
|
4647
|
+
if (runner2) {
|
|
4648
|
+
const cleanupFn = () => cleanupMcps(runner2, mcpsCrashed, db3, `agent:${agentId}`);
|
|
4649
|
+
if (runner2.capabilities.mcpInjection === "add-remove") {
|
|
4650
|
+
withRunnerLock(runner2.id, cleanupFn).catch((err) => {
|
|
4651
|
+
warn(`[orchestrator] MCP cleanup failed for crashed agent ${agentId.slice(0, 8)}:`, err);
|
|
4652
|
+
});
|
|
4653
|
+
} else {
|
|
4654
|
+
cleanupFn().catch((err) => {
|
|
4655
|
+
warn(`[orchestrator] MCP cleanup failed for crashed agent ${agentId.slice(0, 8)}:`, err);
|
|
4656
|
+
});
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4660
|
+
deleteMcpConfigFile(`cc-claw-${agentId.slice(0, 8)}`);
|
|
4661
|
+
}
|
|
4631
4662
|
sendInboxMessage(db3, {
|
|
4632
4663
|
orchestrationId: agent.orchestrationId,
|
|
4633
4664
|
toAgentId: "main",
|
|
@@ -4789,9 +4820,23 @@ function cancelAgent(agentId, reason = "user_cancelled") {
|
|
|
4789
4820
|
if (!agent) return false;
|
|
4790
4821
|
const proc = activeProcesses.get(agentId);
|
|
4791
4822
|
if (proc) {
|
|
4792
|
-
|
|
4823
|
+
try {
|
|
4824
|
+
if (proc.pid) process.kill(-proc.pid, "SIGTERM");
|
|
4825
|
+
} catch {
|
|
4826
|
+
try {
|
|
4827
|
+
proc.kill("SIGTERM");
|
|
4828
|
+
} catch {
|
|
4829
|
+
}
|
|
4830
|
+
}
|
|
4793
4831
|
setTimeout(() => {
|
|
4794
|
-
|
|
4832
|
+
try {
|
|
4833
|
+
if (proc.pid) process.kill(-proc.pid, "SIGKILL");
|
|
4834
|
+
} catch {
|
|
4835
|
+
try {
|
|
4836
|
+
proc.kill("SIGKILL");
|
|
4837
|
+
} catch {
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4795
4840
|
}, 2e3);
|
|
4796
4841
|
}
|
|
4797
4842
|
updateAgentStatus(db3, agentId, "cancelled");
|
|
@@ -4836,7 +4881,14 @@ function cancelAllAgents(chatId, reason = "user_cancelled") {
|
|
|
4836
4881
|
}
|
|
4837
4882
|
function shutdownOrchestrator() {
|
|
4838
4883
|
for (const [agentId, proc] of activeProcesses) {
|
|
4839
|
-
|
|
4884
|
+
try {
|
|
4885
|
+
if (proc.pid) process.kill(-proc.pid, "SIGTERM");
|
|
4886
|
+
} catch {
|
|
4887
|
+
try {
|
|
4888
|
+
proc.kill("SIGTERM");
|
|
4889
|
+
} catch {
|
|
4890
|
+
}
|
|
4891
|
+
}
|
|
4840
4892
|
clearTimeout(timeoutTimers.get(agentId));
|
|
4841
4893
|
}
|
|
4842
4894
|
activeProcesses.clear();
|
|
@@ -5532,7 +5584,7 @@ function startDashboard() {
|
|
|
5532
5584
|
return jsonResponse(res, { error: "message and chatId required" }, 400);
|
|
5533
5585
|
}
|
|
5534
5586
|
const { askAgent: askAgent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
|
|
5535
|
-
const { getMode: getMode2, getCwd: getCwd2, getModel:
|
|
5587
|
+
const { getMode: getMode2, getCwd: getCwd2, getModel: getModel2, addUsage: addUsage2, getBackend: getBackend2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
5536
5588
|
const { getAdapterForChat: getAdapterForChat2 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
5537
5589
|
const chatId = body.chatId;
|
|
5538
5590
|
const PERM_LEVEL = { plan: 0, safe: 1, yolo: 2 };
|
|
@@ -5540,7 +5592,7 @@ function startDashboard() {
|
|
|
5540
5592
|
const requestedMode = body.mode ?? storedMode;
|
|
5541
5593
|
const mode = (PERM_LEVEL[requestedMode] ?? 2) <= (PERM_LEVEL[storedMode] ?? 2) ? requestedMode : storedMode;
|
|
5542
5594
|
const cwd = body.cwd ?? getCwd2(chatId);
|
|
5543
|
-
const model2 = body.model ??
|
|
5595
|
+
const model2 = body.model ?? getModel2(chatId) ?? (() => {
|
|
5544
5596
|
try {
|
|
5545
5597
|
return getAdapterForChat2(chatId).defaultModel;
|
|
5546
5598
|
} catch {
|
|
@@ -5696,8 +5748,8 @@ data: ${JSON.stringify(data)}
|
|
|
5696
5748
|
if (url.pathname === "/api/heartbeat/set" && req.method === "POST") {
|
|
5697
5749
|
try {
|
|
5698
5750
|
const body = JSON.parse(await readBody(req));
|
|
5699
|
-
const { setHeartbeatConfig:
|
|
5700
|
-
|
|
5751
|
+
const { setHeartbeatConfig: setHeartbeatConfig2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
5752
|
+
setHeartbeatConfig2(body.chatId, body);
|
|
5701
5753
|
return jsonResponse(res, { success: true });
|
|
5702
5754
|
} catch (err) {
|
|
5703
5755
|
return jsonResponse(res, { error: errorMessage(err) }, 400);
|
|
@@ -5998,14 +6050,21 @@ var init_server = __esm({
|
|
|
5998
6050
|
var agent_exports = {};
|
|
5999
6051
|
__export(agent_exports, {
|
|
6000
6052
|
askAgent: () => askAgent,
|
|
6001
|
-
isAgentActive: () => isAgentActive,
|
|
6002
6053
|
isChatBusy: () => isChatBusy,
|
|
6003
6054
|
stopAgent: () => stopAgent
|
|
6004
6055
|
});
|
|
6005
6056
|
import { spawn as spawn4 } from "child_process";
|
|
6006
6057
|
import { createInterface as createInterface3 } from "readline";
|
|
6007
|
-
|
|
6008
|
-
|
|
6058
|
+
function killProcessGroup(proc, signal = "SIGTERM") {
|
|
6059
|
+
try {
|
|
6060
|
+
if (proc.pid) process.kill(-proc.pid, signal);
|
|
6061
|
+
} catch {
|
|
6062
|
+
try {
|
|
6063
|
+
proc.kill(signal);
|
|
6064
|
+
} catch {
|
|
6065
|
+
}
|
|
6066
|
+
}
|
|
6067
|
+
}
|
|
6009
6068
|
function withChatLock(chatId, fn) {
|
|
6010
6069
|
const prev = chatLocks.get(chatId) ?? Promise.resolve();
|
|
6011
6070
|
const isBlocked = activeChats.has(chatId);
|
|
@@ -6026,14 +6085,13 @@ function stopAgent(chatId) {
|
|
|
6026
6085
|
if (!state) return false;
|
|
6027
6086
|
state.cancelled = true;
|
|
6028
6087
|
if (state.process) {
|
|
6029
|
-
state.process
|
|
6030
|
-
state.killTimer = setTimeout(() =>
|
|
6088
|
+
killProcessGroup(state.process, "SIGTERM");
|
|
6089
|
+
state.killTimer = setTimeout(() => {
|
|
6090
|
+
if (state.process) killProcessGroup(state.process, "SIGKILL");
|
|
6091
|
+
}, 2e3);
|
|
6031
6092
|
}
|
|
6032
6093
|
return true;
|
|
6033
6094
|
}
|
|
6034
|
-
function isAgentActive(chatId) {
|
|
6035
|
-
return activeChats.has(chatId);
|
|
6036
|
-
}
|
|
6037
6095
|
function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolAction, thinkingLevel, timeoutMs) {
|
|
6038
6096
|
const effectiveTimeout = timeoutMs ?? SPAWN_TIMEOUT_MS;
|
|
6039
6097
|
return new Promise((resolve, reject) => {
|
|
@@ -6044,21 +6102,18 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
6044
6102
|
const proc = spawn4(config2.executable, finalArgs, {
|
|
6045
6103
|
env,
|
|
6046
6104
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6105
|
+
detached: true,
|
|
6047
6106
|
...config2.cwd ? { cwd: config2.cwd } : {}
|
|
6048
6107
|
});
|
|
6108
|
+
proc.unref();
|
|
6049
6109
|
cancelState.process = proc;
|
|
6050
6110
|
let timedOut = false;
|
|
6051
6111
|
let sigkillTimer;
|
|
6052
6112
|
const spawnTimeout = setTimeout(() => {
|
|
6053
6113
|
timedOut = true;
|
|
6054
6114
|
warn(`[agent] Spawn timeout after ${effectiveTimeout / 1e3}s for ${adapter.id} \u2014 killing process`);
|
|
6055
|
-
proc
|
|
6056
|
-
sigkillTimer = setTimeout(() =>
|
|
6057
|
-
try {
|
|
6058
|
-
proc.kill("SIGKILL");
|
|
6059
|
-
} catch {
|
|
6060
|
-
}
|
|
6061
|
-
}, 3e3);
|
|
6115
|
+
killProcessGroup(proc, "SIGTERM");
|
|
6116
|
+
sigkillTimer = setTimeout(() => killProcessGroup(proc, "SIGKILL"), 3e3);
|
|
6062
6117
|
}, effectiveTimeout);
|
|
6063
6118
|
let resultText = "";
|
|
6064
6119
|
let accumulatedText = "";
|
|
@@ -6146,7 +6201,7 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
6146
6201
|
rl2.close();
|
|
6147
6202
|
} catch {
|
|
6148
6203
|
}
|
|
6149
|
-
proc
|
|
6204
|
+
killProcessGroup(proc, "SIGTERM");
|
|
6150
6205
|
}
|
|
6151
6206
|
break;
|
|
6152
6207
|
}
|
|
@@ -6288,7 +6343,7 @@ function injectMcpConfig(adapterId, args, mcpConfigPath) {
|
|
|
6288
6343
|
if (!flag) return args;
|
|
6289
6344
|
return [...args, ...flag, mcpConfigPath];
|
|
6290
6345
|
}
|
|
6291
|
-
var
|
|
6346
|
+
var activeChats, chatLocks, SPAWN_TIMEOUT_MS, MCP_CONFIG_FLAG;
|
|
6292
6347
|
var init_agent = __esm({
|
|
6293
6348
|
"src/agent.ts"() {
|
|
6294
6349
|
"use strict";
|
|
@@ -6301,8 +6356,6 @@ var init_agent = __esm({
|
|
|
6301
6356
|
init_summarize();
|
|
6302
6357
|
init_server();
|
|
6303
6358
|
init_mcp_config();
|
|
6304
|
-
__filename2 = fileURLToPath2(import.meta.url);
|
|
6305
|
-
__dirname2 = dirname2(__filename2);
|
|
6306
6359
|
activeChats = /* @__PURE__ */ new Map();
|
|
6307
6360
|
chatLocks = /* @__PURE__ */ new Map();
|
|
6308
6361
|
SPAWN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
@@ -6384,7 +6437,7 @@ ${responseText.slice(0, 500)}`);
|
|
|
6384
6437
|
if (!cleanText) return true;
|
|
6385
6438
|
if (channelName === "telegram") {
|
|
6386
6439
|
const parsed = parseTelegramTarget(targetChatId);
|
|
6387
|
-
await channel.sendText(parsed.chatId, cleanText);
|
|
6440
|
+
await channel.sendText(parsed.chatId, cleanText, void 0, parsed.threadId);
|
|
6388
6441
|
} else {
|
|
6389
6442
|
await channel.sendText(targetChatId, cleanText);
|
|
6390
6443
|
}
|
|
@@ -6410,7 +6463,8 @@ async function deliverWebhook(job, responseText) {
|
|
|
6410
6463
|
description: job.description,
|
|
6411
6464
|
text: responseText,
|
|
6412
6465
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6413
|
-
})
|
|
6466
|
+
}),
|
|
6467
|
+
signal: AbortSignal.timeout(3e4)
|
|
6414
6468
|
});
|
|
6415
6469
|
if (!resp.ok) {
|
|
6416
6470
|
error(`[delivery] Webhook POST to ${url} failed: ${resp.status} ${resp.statusText}`);
|
|
@@ -6815,6 +6869,9 @@ async function executeJob(job) {
|
|
|
6815
6869
|
}
|
|
6816
6870
|
} finally {
|
|
6817
6871
|
runningJobs.delete(job.id);
|
|
6872
|
+
if (job.sessionType === "isolated" && job.thinking && job.thinking !== "auto") {
|
|
6873
|
+
clearThinkingLevel(`cron:${job.id}:${runId}`);
|
|
6874
|
+
}
|
|
6818
6875
|
}
|
|
6819
6876
|
}
|
|
6820
6877
|
async function runWithRetry(job, model2, runId, t0) {
|
|
@@ -6911,7 +6968,7 @@ var init_cron = __esm({
|
|
|
6911
6968
|
});
|
|
6912
6969
|
|
|
6913
6970
|
// src/agents/runners/wrap-backend.ts
|
|
6914
|
-
import { join as
|
|
6971
|
+
import { join as join7 } from "path";
|
|
6915
6972
|
function buildMcpCommands(backendId) {
|
|
6916
6973
|
const exe = backendId;
|
|
6917
6974
|
return {
|
|
@@ -6972,7 +7029,8 @@ function wrapBackendAdapter(adapter) {
|
|
|
6972
7029
|
sessionId: opts.sessionId,
|
|
6973
7030
|
permMode: opts.permMode ?? "plan",
|
|
6974
7031
|
allowedTools: opts.allowedTools ?? [],
|
|
6975
|
-
cwd: opts.cwd
|
|
7032
|
+
cwd: opts.cwd,
|
|
7033
|
+
model: opts.model
|
|
6976
7034
|
});
|
|
6977
7035
|
return config2.args;
|
|
6978
7036
|
},
|
|
@@ -7001,7 +7059,7 @@ function wrapBackendAdapter(adapter) {
|
|
|
7001
7059
|
const configPath = writeMcpConfigFile(server);
|
|
7002
7060
|
return ["--mcp-config", configPath];
|
|
7003
7061
|
},
|
|
7004
|
-
getSkillPath: () =>
|
|
7062
|
+
getSkillPath: () => join7(SKILLS_PATH, `agent-${adapter.id}.md`)
|
|
7005
7063
|
};
|
|
7006
7064
|
}
|
|
7007
7065
|
var BACKEND_CAPABILITIES;
|
|
@@ -7044,7 +7102,7 @@ var init_wrap_backend = __esm({
|
|
|
7044
7102
|
|
|
7045
7103
|
// src/agents/runners/config-loader.ts
|
|
7046
7104
|
import { readFileSync as readFileSync6, readdirSync as readdirSync4, existsSync as existsSync9, mkdirSync as mkdirSync4, watchFile, unwatchFile } from "fs";
|
|
7047
|
-
import { join as
|
|
7105
|
+
import { join as join8 } from "path";
|
|
7048
7106
|
import { execFileSync } from "child_process";
|
|
7049
7107
|
function resolveExecutable(config2) {
|
|
7050
7108
|
if (existsSync9(config2.executable)) return config2.executable;
|
|
@@ -7180,7 +7238,7 @@ function configToRunner(config2) {
|
|
|
7180
7238
|
prepareMcpInjection() {
|
|
7181
7239
|
return [];
|
|
7182
7240
|
},
|
|
7183
|
-
getSkillPath: () =>
|
|
7241
|
+
getSkillPath: () => join8(SKILLS_PATH, `agent-${config2.id}.md`)
|
|
7184
7242
|
};
|
|
7185
7243
|
}
|
|
7186
7244
|
function loadRunnerConfig(filePath) {
|
|
@@ -7200,7 +7258,7 @@ function loadAllRunnerConfigs() {
|
|
|
7200
7258
|
const files = readdirSync4(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
7201
7259
|
const configs = [];
|
|
7202
7260
|
for (const file of files) {
|
|
7203
|
-
const config2 = loadRunnerConfig(
|
|
7261
|
+
const config2 = loadRunnerConfig(join8(RUNNERS_PATH, file));
|
|
7204
7262
|
if (config2) configs.push(config2);
|
|
7205
7263
|
}
|
|
7206
7264
|
return configs;
|
|
@@ -7230,7 +7288,7 @@ function watchRunnerConfigs(onChange) {
|
|
|
7230
7288
|
}
|
|
7231
7289
|
const files = readdirSync4(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
7232
7290
|
for (const file of files) {
|
|
7233
|
-
const fullPath =
|
|
7291
|
+
const fullPath = join8(RUNNERS_PATH, file);
|
|
7234
7292
|
if (watchedFiles.has(fullPath)) continue;
|
|
7235
7293
|
watchedFiles.add(fullPath);
|
|
7236
7294
|
watchFile(fullPath, { interval: 5e3 }, () => {
|
|
@@ -7599,11 +7657,12 @@ var init_telegram2 = __esm({
|
|
|
7599
7657
|
async sendTyping(chatId) {
|
|
7600
7658
|
await this.bot.api.sendChatAction(numericChatId(chatId), "typing");
|
|
7601
7659
|
}
|
|
7602
|
-
async sendText(chatId, text, parseMode) {
|
|
7660
|
+
async sendText(chatId, text, parseMode, threadId) {
|
|
7661
|
+
const threadOpts = threadId ? { message_thread_id: threadId } : {};
|
|
7603
7662
|
if (parseMode === "plain") {
|
|
7604
7663
|
const plainChunks = splitMessage(text);
|
|
7605
7664
|
for (const chunk of plainChunks) {
|
|
7606
|
-
await this.bot.api.sendMessage(numericChatId(chatId), chunk);
|
|
7665
|
+
await this.bot.api.sendMessage(numericChatId(chatId), chunk, { ...threadOpts });
|
|
7607
7666
|
}
|
|
7608
7667
|
return;
|
|
7609
7668
|
}
|
|
@@ -7612,12 +7671,14 @@ var init_telegram2 = __esm({
|
|
|
7612
7671
|
for (const chunk of chunks) {
|
|
7613
7672
|
try {
|
|
7614
7673
|
await this.bot.api.sendMessage(numericChatId(chatId), chunk, {
|
|
7615
|
-
parse_mode: "HTML"
|
|
7674
|
+
parse_mode: "HTML",
|
|
7675
|
+
...threadOpts
|
|
7616
7676
|
});
|
|
7617
7677
|
} catch {
|
|
7618
7678
|
await this.bot.api.sendMessage(
|
|
7619
7679
|
numericChatId(chatId),
|
|
7620
|
-
chunk.replace(/<[^>]+>/g, "")
|
|
7680
|
+
chunk.replace(/<[^>]+>/g, ""),
|
|
7681
|
+
{ ...threadOpts }
|
|
7621
7682
|
);
|
|
7622
7683
|
}
|
|
7623
7684
|
}
|
|
@@ -7642,7 +7703,9 @@ var init_telegram2 = __esm({
|
|
|
7642
7703
|
}
|
|
7643
7704
|
async sendTextReturningId(chatId, text, parseMode) {
|
|
7644
7705
|
try {
|
|
7645
|
-
const
|
|
7706
|
+
const formatted = parseMode === "html" ? text : parseMode === "plain" ? text : formatForTelegram(text);
|
|
7707
|
+
const opts = parseMode === "plain" ? {} : { parse_mode: "HTML" };
|
|
7708
|
+
const msg = await this.bot.api.sendMessage(numericChatId(chatId), formatted, opts);
|
|
7646
7709
|
return msg.message_id.toString();
|
|
7647
7710
|
} catch {
|
|
7648
7711
|
return void 0;
|
|
@@ -7816,13 +7879,13 @@ __export(discover_exports, {
|
|
|
7816
7879
|
});
|
|
7817
7880
|
import { readdir, readFile as readFile2 } from "fs/promises";
|
|
7818
7881
|
import { createHash } from "crypto";
|
|
7819
|
-
import { homedir as
|
|
7820
|
-
import { join as
|
|
7882
|
+
import { homedir as homedir4 } from "os";
|
|
7883
|
+
import { join as join9 } from "path";
|
|
7821
7884
|
async function discoverAllSkills() {
|
|
7822
7885
|
const rawSkills = [];
|
|
7823
7886
|
rawSkills.push(...await scanSkillDir(SKILLS_PATH, "cc-claw"));
|
|
7824
7887
|
for (const backendId of getAllBackendIds()) {
|
|
7825
|
-
const dirs = BACKEND_SKILL_DIRS[backendId] ?? [
|
|
7888
|
+
const dirs = BACKEND_SKILL_DIRS[backendId] ?? [join9(homedir4(), `.${backendId}`, "skills")];
|
|
7826
7889
|
for (const dir of dirs) {
|
|
7827
7890
|
rawSkills.push(...await scanSkillDir(dir, backendId));
|
|
7828
7891
|
}
|
|
@@ -7842,7 +7905,7 @@ async function scanSkillDir(skillsDir, source) {
|
|
|
7842
7905
|
let content;
|
|
7843
7906
|
let resolvedPath;
|
|
7844
7907
|
for (const candidate of SKILL_FILE_CANDIDATES) {
|
|
7845
|
-
const p =
|
|
7908
|
+
const p = join9(skillsDir, entry.name, candidate);
|
|
7846
7909
|
try {
|
|
7847
7910
|
content = await readFile2(p, "utf-8");
|
|
7848
7911
|
resolvedPath = p;
|
|
@@ -7945,11 +8008,11 @@ var init_discover = __esm({
|
|
|
7945
8008
|
init_backends();
|
|
7946
8009
|
SKILL_FILE_CANDIDATES = ["SKILL.md", "skill.md"];
|
|
7947
8010
|
BACKEND_SKILL_DIRS = {
|
|
7948
|
-
claude: [
|
|
7949
|
-
gemini: [
|
|
8011
|
+
claude: [join9(homedir4(), ".claude", "skills")],
|
|
8012
|
+
gemini: [join9(homedir4(), ".gemini", "skills")],
|
|
7950
8013
|
codex: [
|
|
7951
|
-
|
|
7952
|
-
|
|
8014
|
+
join9(homedir4(), ".agents", "skills"),
|
|
8015
|
+
join9(homedir4(), ".codex", "skills")
|
|
7953
8016
|
]
|
|
7954
8017
|
};
|
|
7955
8018
|
}
|
|
@@ -7962,7 +8025,7 @@ __export(install_exports, {
|
|
|
7962
8025
|
});
|
|
7963
8026
|
import { mkdir, readdir as readdir2, readFile as readFile3, cp } from "fs/promises";
|
|
7964
8027
|
import { existsSync as existsSync10 } from "fs";
|
|
7965
|
-
import { join as
|
|
8028
|
+
import { join as join10, basename } from "path";
|
|
7966
8029
|
import { execSync as execSync4 } from "child_process";
|
|
7967
8030
|
async function installSkillFromGitHub(urlOrShorthand) {
|
|
7968
8031
|
let repoUrl;
|
|
@@ -7973,23 +8036,23 @@ async function installSkillFromGitHub(urlOrShorthand) {
|
|
|
7973
8036
|
}
|
|
7974
8037
|
repoUrl = parsed.cloneUrl;
|
|
7975
8038
|
subPath = parsed.subPath;
|
|
7976
|
-
const tmpDir =
|
|
8039
|
+
const tmpDir = join10("/tmp", `cc-claw-skill-${Date.now()}`);
|
|
7977
8040
|
try {
|
|
7978
8041
|
log(`[skill-install] Cloning ${repoUrl} to ${tmpDir}`);
|
|
7979
8042
|
execSync4(`git clone --depth 1 ${repoUrl} ${tmpDir}`, {
|
|
7980
8043
|
stdio: "pipe",
|
|
7981
8044
|
timeout: 3e4
|
|
7982
8045
|
});
|
|
7983
|
-
if (!existsSync10(
|
|
8046
|
+
if (!existsSync10(join10(tmpDir, ".git"))) {
|
|
7984
8047
|
return { success: false, error: "Git clone failed: no .git directory produced" };
|
|
7985
8048
|
}
|
|
7986
|
-
const searchRoot = subPath ?
|
|
8049
|
+
const searchRoot = subPath ? join10(tmpDir, subPath) : tmpDir;
|
|
7987
8050
|
const skillDir = await findSkillDir(searchRoot);
|
|
7988
8051
|
if (!skillDir) {
|
|
7989
8052
|
return { success: false, error: "No SKILL.md found in the repository." };
|
|
7990
8053
|
}
|
|
7991
8054
|
const skillFolderName = basename(skillDir);
|
|
7992
|
-
const destDir =
|
|
8055
|
+
const destDir = join10(SKILLS_PATH, skillFolderName);
|
|
7993
8056
|
if (existsSync10(destDir)) {
|
|
7994
8057
|
log(`[skill-install] Overwriting existing skill at ${destDir}`);
|
|
7995
8058
|
}
|
|
@@ -7997,12 +8060,12 @@ async function installSkillFromGitHub(urlOrShorthand) {
|
|
|
7997
8060
|
await cp(skillDir, destDir, { recursive: true });
|
|
7998
8061
|
let skillName = skillFolderName;
|
|
7999
8062
|
try {
|
|
8000
|
-
const content = await readFile3(
|
|
8063
|
+
const content = await readFile3(join10(destDir, "SKILL.md"), "utf-8");
|
|
8001
8064
|
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
8002
8065
|
if (nameMatch) skillName = nameMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
8003
8066
|
} catch {
|
|
8004
8067
|
try {
|
|
8005
|
-
const content = await readFile3(
|
|
8068
|
+
const content = await readFile3(join10(destDir, "skill.md"), "utf-8");
|
|
8006
8069
|
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
8007
8070
|
if (nameMatch) skillName = nameMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
8008
8071
|
} catch {
|
|
@@ -8037,15 +8100,15 @@ function parseGitHubUrl(input) {
|
|
|
8037
8100
|
async function findSkillDir(root) {
|
|
8038
8101
|
const candidates = ["SKILL.md", "skill.md"];
|
|
8039
8102
|
for (const c of candidates) {
|
|
8040
|
-
if (existsSync10(
|
|
8103
|
+
if (existsSync10(join10(root, c))) return root;
|
|
8041
8104
|
}
|
|
8042
8105
|
try {
|
|
8043
8106
|
const entries = await readdir2(root, { withFileTypes: true });
|
|
8044
8107
|
for (const entry of entries) {
|
|
8045
8108
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
8046
8109
|
for (const c of candidates) {
|
|
8047
|
-
if (existsSync10(
|
|
8048
|
-
return
|
|
8110
|
+
if (existsSync10(join10(root, entry.name, c))) {
|
|
8111
|
+
return join10(root, entry.name);
|
|
8049
8112
|
}
|
|
8050
8113
|
}
|
|
8051
8114
|
}
|
|
@@ -8057,15 +8120,15 @@ async function findSkillDir(root) {
|
|
|
8057
8120
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
8058
8121
|
let subEntries;
|
|
8059
8122
|
try {
|
|
8060
|
-
subEntries = await readdir2(
|
|
8123
|
+
subEntries = await readdir2(join10(root, entry.name), { withFileTypes: true });
|
|
8061
8124
|
} catch {
|
|
8062
8125
|
continue;
|
|
8063
8126
|
}
|
|
8064
8127
|
for (const sub of subEntries) {
|
|
8065
8128
|
if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
|
|
8066
8129
|
for (const c of candidates) {
|
|
8067
|
-
if (existsSync10(
|
|
8068
|
-
return
|
|
8130
|
+
if (existsSync10(join10(root, entry.name, sub.name, c))) {
|
|
8131
|
+
return join10(root, entry.name, sub.name);
|
|
8069
8132
|
}
|
|
8070
8133
|
}
|
|
8071
8134
|
}
|
|
@@ -8084,7 +8147,7 @@ var init_install = __esm({
|
|
|
8084
8147
|
|
|
8085
8148
|
// src/bootstrap/profile.ts
|
|
8086
8149
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync11 } from "fs";
|
|
8087
|
-
import { join as
|
|
8150
|
+
import { join as join11 } from "path";
|
|
8088
8151
|
function hasActiveProfile(chatId) {
|
|
8089
8152
|
return activeProfiles.has(chatId);
|
|
8090
8153
|
}
|
|
@@ -8229,14 +8292,14 @@ var init_profile = __esm({
|
|
|
8229
8292
|
"use strict";
|
|
8230
8293
|
init_paths();
|
|
8231
8294
|
init_log();
|
|
8232
|
-
USER_PATH2 =
|
|
8295
|
+
USER_PATH2 = join11(WORKSPACE_PATH, "USER.md");
|
|
8233
8296
|
activeProfiles = /* @__PURE__ */ new Map();
|
|
8234
8297
|
}
|
|
8235
8298
|
});
|
|
8236
8299
|
|
|
8237
8300
|
// src/bootstrap/heartbeat.ts
|
|
8238
8301
|
import { readFileSync as readFileSync8, existsSync as existsSync12 } from "fs";
|
|
8239
|
-
import { join as
|
|
8302
|
+
import { join as join12 } from "path";
|
|
8240
8303
|
function initHeartbeat(channelReg) {
|
|
8241
8304
|
registry2 = channelReg;
|
|
8242
8305
|
}
|
|
@@ -8244,8 +8307,18 @@ function startHeartbeatForChat(chatId) {
|
|
|
8244
8307
|
stopHeartbeatForChat(chatId);
|
|
8245
8308
|
const config2 = getHeartbeatConfig(chatId);
|
|
8246
8309
|
if (!config2 || !config2.enabled) return;
|
|
8310
|
+
let running = false;
|
|
8247
8311
|
const timer = setInterval(async () => {
|
|
8248
|
-
|
|
8312
|
+
if (running) {
|
|
8313
|
+
log(`[heartbeat] Skipping tick for ${chatId}: previous heartbeat still running`);
|
|
8314
|
+
return;
|
|
8315
|
+
}
|
|
8316
|
+
running = true;
|
|
8317
|
+
try {
|
|
8318
|
+
await runHeartbeat(chatId, config2);
|
|
8319
|
+
} finally {
|
|
8320
|
+
running = false;
|
|
8321
|
+
}
|
|
8249
8322
|
}, config2.intervalMs);
|
|
8250
8323
|
activeTimers2.set(chatId, timer);
|
|
8251
8324
|
const nextBeat = new Date(Date.now() + config2.intervalMs).toISOString();
|
|
@@ -8412,7 +8485,7 @@ var init_heartbeat = __esm({
|
|
|
8412
8485
|
init_backends();
|
|
8413
8486
|
init_health2();
|
|
8414
8487
|
init_log();
|
|
8415
|
-
HEARTBEAT_MD_PATH =
|
|
8488
|
+
HEARTBEAT_MD_PATH = join12(WORKSPACE_PATH, "HEARTBEAT.md");
|
|
8416
8489
|
HEARTBEAT_OK = "HEARTBEAT_OK";
|
|
8417
8490
|
registry2 = null;
|
|
8418
8491
|
activeTimers2 = /* @__PURE__ */ new Map();
|
|
@@ -8458,8 +8531,9 @@ var init_format_time = __esm({
|
|
|
8458
8531
|
});
|
|
8459
8532
|
|
|
8460
8533
|
// src/media/image-gen.ts
|
|
8461
|
-
import {
|
|
8462
|
-
import {
|
|
8534
|
+
import { mkdirSync as mkdirSync5, existsSync as existsSync13 } from "fs";
|
|
8535
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
8536
|
+
import { join as join13 } from "path";
|
|
8463
8537
|
async function generateImage(prompt) {
|
|
8464
8538
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
8465
8539
|
if (!apiKey) {
|
|
@@ -8511,9 +8585,9 @@ async function generateImage(prompt) {
|
|
|
8511
8585
|
}
|
|
8512
8586
|
const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
|
|
8513
8587
|
const filename = `img_${Date.now()}.${ext}`;
|
|
8514
|
-
const filePath =
|
|
8588
|
+
const filePath = join13(IMAGE_OUTPUT_DIR, filename);
|
|
8515
8589
|
const buffer = Buffer.from(imageData, "base64");
|
|
8516
|
-
|
|
8590
|
+
await writeFile2(filePath, buffer);
|
|
8517
8591
|
log(`[image-gen] Saved ${buffer.length} bytes to ${filePath}`);
|
|
8518
8592
|
return { filePath, text: textResponse, mimeType };
|
|
8519
8593
|
}
|
|
@@ -8526,8 +8600,8 @@ var init_image_gen = __esm({
|
|
|
8526
8600
|
"use strict";
|
|
8527
8601
|
init_log();
|
|
8528
8602
|
IMAGE_MODEL = "gemini-3.1-flash-image-preview";
|
|
8529
|
-
IMAGE_OUTPUT_DIR =
|
|
8530
|
-
process.env.CC_CLAW_HOME ??
|
|
8603
|
+
IMAGE_OUTPUT_DIR = join13(
|
|
8604
|
+
process.env.CC_CLAW_HOME ?? join13(process.env.HOME ?? "/tmp", ".cc-claw"),
|
|
8531
8605
|
"data",
|
|
8532
8606
|
"images"
|
|
8533
8607
|
);
|
|
@@ -8675,8 +8749,8 @@ async function mp3ToOgg(mp3Buffer) {
|
|
|
8675
8749
|
const id = crypto.randomUUID();
|
|
8676
8750
|
const tmpMp3 = `/tmp/cc-claw-tts-${id}.mp3`;
|
|
8677
8751
|
const tmpOgg = `/tmp/cc-claw-tts-${id}.ogg`;
|
|
8678
|
-
const { writeFile:
|
|
8679
|
-
await
|
|
8752
|
+
const { writeFile: writeFile5 } = await import("fs/promises");
|
|
8753
|
+
await writeFile5(tmpMp3, mp3Buffer);
|
|
8680
8754
|
await execFileAsync2("ffmpeg", ["-y", "-i", tmpMp3, "-c:a", "libopus", "-b:a", "64k", tmpOgg]);
|
|
8681
8755
|
const oggBuffer = await readFile4(tmpOgg);
|
|
8682
8756
|
unlink(tmpMp3).catch((err) => {
|
|
@@ -8691,8 +8765,7 @@ async function macOsTts(text, voice2 = "Samantha") {
|
|
|
8691
8765
|
const id = crypto.randomUUID();
|
|
8692
8766
|
const tmpAiff = `/tmp/cc-claw-tts-${id}.aiff`;
|
|
8693
8767
|
const tmpOgg = `/tmp/cc-claw-tts-${id}.ogg`;
|
|
8694
|
-
|
|
8695
|
-
await execFileAsync2("say", ["-v", voice2, "-o", tmpAiff, sanitized]);
|
|
8768
|
+
await execFileAsync2("say", ["-v", voice2, "-o", tmpAiff, text]);
|
|
8696
8769
|
await execFileAsync2("ffmpeg", ["-y", "-i", tmpAiff, "-c:a", "libopus", "-b:a", "64k", tmpOgg]);
|
|
8697
8770
|
const oggBuffer = await readFile4(tmpOgg);
|
|
8698
8771
|
unlink(tmpAiff).catch((err) => {
|
|
@@ -9567,7 +9640,7 @@ var init_backend_cmd = __esm({
|
|
|
9567
9640
|
});
|
|
9568
9641
|
|
|
9569
9642
|
// src/router.ts
|
|
9570
|
-
import { readFile as readFile5, writeFile as
|
|
9643
|
+
import { readFile as readFile5, writeFile as writeFile3, unlink as unlink2 } from "fs/promises";
|
|
9571
9644
|
import { resolve as resolvePath } from "path";
|
|
9572
9645
|
function parseMcpListOutput(output2) {
|
|
9573
9646
|
const results = [];
|
|
@@ -10518,8 +10591,8 @@ Use /skills to see it.`, "plain");
|
|
|
10518
10591
|
if (!lim.max_input_tokens) continue;
|
|
10519
10592
|
const u = getBackendUsageInWindow(lim.backend, lim.window);
|
|
10520
10593
|
const pct = (u.input_tokens / lim.max_input_tokens * 100).toFixed(0);
|
|
10521
|
-
const
|
|
10522
|
-
lines.push(` ${lim.backend} (${lim.window}): ${pct}% of ${(lim.max_input_tokens / 1e3).toFixed(0)}K${
|
|
10594
|
+
const warn2 = u.input_tokens / lim.max_input_tokens >= lim.warn_pct;
|
|
10595
|
+
lines.push(` ${lim.backend} (${lim.window}): ${pct}% of ${(lim.max_input_tokens / 1e3).toFixed(0)}K${warn2 ? " \u26A0\uFE0F" : ""}`);
|
|
10523
10596
|
}
|
|
10524
10597
|
}
|
|
10525
10598
|
await channel.sendText(chatId, lines.join("\n"), "plain");
|
|
@@ -10719,8 +10792,8 @@ Use /skills to see it.`, "plain");
|
|
|
10719
10792
|
lines.push(` \u2705 <b>cc-claw</b> <i>Agent orchestrator (spawn, tasks, inbox)</i>`);
|
|
10720
10793
|
}
|
|
10721
10794
|
const { execFile: execFile5 } = await import("child_process");
|
|
10722
|
-
const { homedir:
|
|
10723
|
-
const discoveryCwd =
|
|
10795
|
+
const { homedir: homedir7 } = await import("os");
|
|
10796
|
+
const discoveryCwd = homedir7();
|
|
10724
10797
|
const runnerResults = await Promise.allSettled(
|
|
10725
10798
|
getAllRunners().map((runner) => {
|
|
10726
10799
|
const listCmd = runner.getMcpListCommand();
|
|
@@ -10912,8 +10985,10 @@ async function handleMedia(msg, channel) {
|
|
|
10912
10985
|
const videoMime = msg.metadata?.mimeType ?? msg.mimeType ?? "video/mp4";
|
|
10913
10986
|
const videoExt = videoMime.split("/")[1]?.replace("quicktime", "mov") || "mp4";
|
|
10914
10987
|
const tempVideoPath = `/tmp/cc-claw-video-${Date.now()}.${videoExt}`;
|
|
10915
|
-
await
|
|
10988
|
+
await writeFile3(tempVideoPath, videoBuffer);
|
|
10916
10989
|
let prompt2;
|
|
10990
|
+
const cleanupVideo = () => unlink2(tempVideoPath).catch(() => {
|
|
10991
|
+
});
|
|
10917
10992
|
if (wantsVideoAnalysis(caption)) {
|
|
10918
10993
|
const geminiPrompt = caption || "Analyze this video and describe what you see in detail.";
|
|
10919
10994
|
let analysis;
|
|
@@ -10952,6 +11027,7 @@ Acknowledge receipt. Do NOT analyze the video unless they ask you to.`;
|
|
|
10952
11027
|
const response2 = await askAgent(chatId, prompt2, { cwd: getCwd(chatId), model: vidModel, permMode: vMode, onToolAction: vidToolCb });
|
|
10953
11028
|
if (response2.usage) addUsage(chatId, response2.usage.input, response2.usage.output, response2.usage.cacheRead, vidModel);
|
|
10954
11029
|
await sendResponse(chatId, channel, response2.text, msg.messageId);
|
|
11030
|
+
cleanupVideo();
|
|
10955
11031
|
return;
|
|
10956
11032
|
}
|
|
10957
11033
|
const fileBuffer = await channel.downloadFile(fileName);
|
|
@@ -10962,7 +11038,7 @@ Acknowledge receipt. Do NOT analyze the video unless they ask you to.`;
|
|
|
10962
11038
|
if (msg.type === "photo" || isImageExt(ext)) {
|
|
10963
11039
|
const imgExt = msg.type === "photo" ? "jpg" : ext || "jpg";
|
|
10964
11040
|
tempFilePath = `/tmp/cc-claw-img-${Date.now()}.${imgExt}`;
|
|
10965
|
-
await
|
|
11041
|
+
await writeFile3(tempFilePath, fileBuffer);
|
|
10966
11042
|
prompt = caption ? `The user sent an image with caption: "${caption}"
|
|
10967
11043
|
|
|
10968
11044
|
The image has been saved to: ${tempFilePath}
|
|
@@ -11521,7 +11597,7 @@ ${PERM_MODES[chosen]}`,
|
|
|
11521
11597
|
const pending = getPendingEscalation(chatId);
|
|
11522
11598
|
if (pending) {
|
|
11523
11599
|
removePendingEscalation(chatId);
|
|
11524
|
-
await handleMessage({ text: pending, chatId, source: "telegram" }, channel);
|
|
11600
|
+
await handleMessage({ text: pending, chatId, source: "telegram", type: "text" }, channel);
|
|
11525
11601
|
}
|
|
11526
11602
|
} else if (data === "perm:deny") {
|
|
11527
11603
|
removePendingEscalation(chatId);
|
|
@@ -11954,7 +12030,7 @@ var init_router = __esm({
|
|
|
11954
12030
|
pendingFallbackMessages = /* @__PURE__ */ new Map();
|
|
11955
12031
|
CLI_INSTALL_HINTS = {
|
|
11956
12032
|
claude: "Install: npm install -g @anthropic-ai/claude-code",
|
|
11957
|
-
gemini: "Install: npm install -g @
|
|
12033
|
+
gemini: "Install: npm install -g @google/gemini-cli",
|
|
11958
12034
|
codex: "Install: npm install -g @openai/codex"
|
|
11959
12035
|
};
|
|
11960
12036
|
BLOCKED_PATH_PATTERNS2 = [
|
|
@@ -12047,17 +12123,17 @@ var init_router = __esm({
|
|
|
12047
12123
|
|
|
12048
12124
|
// src/skills/bootstrap.ts
|
|
12049
12125
|
import { existsSync as existsSync14 } from "fs";
|
|
12050
|
-
import { readdir as readdir3, readFile as readFile6, writeFile as
|
|
12051
|
-
import { join as
|
|
12052
|
-
import { fileURLToPath as
|
|
12126
|
+
import { readdir as readdir3, readFile as readFile6, writeFile as writeFile4, copyFile } from "fs/promises";
|
|
12127
|
+
import { join as join14, dirname as dirname2 } from "path";
|
|
12128
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12053
12129
|
async function copyAgentManifestSkills() {
|
|
12054
12130
|
if (!existsSync14(PKG_SKILLS)) return;
|
|
12055
12131
|
try {
|
|
12056
12132
|
const entries = await readdir3(PKG_SKILLS, { withFileTypes: true });
|
|
12057
12133
|
for (const entry of entries) {
|
|
12058
12134
|
if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
|
|
12059
|
-
const src =
|
|
12060
|
-
const dest =
|
|
12135
|
+
const src = join14(PKG_SKILLS, entry.name);
|
|
12136
|
+
const dest = join14(SKILLS_PATH, entry.name);
|
|
12061
12137
|
if (existsSync14(dest)) continue;
|
|
12062
12138
|
await copyFile(src, dest);
|
|
12063
12139
|
log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
|
|
@@ -12068,7 +12144,7 @@ async function copyAgentManifestSkills() {
|
|
|
12068
12144
|
}
|
|
12069
12145
|
async function bootstrapSkills() {
|
|
12070
12146
|
await copyAgentManifestSkills();
|
|
12071
|
-
const usmDir =
|
|
12147
|
+
const usmDir = join14(SKILLS_PATH, USM_DIR_NAME);
|
|
12072
12148
|
if (existsSync14(usmDir)) return;
|
|
12073
12149
|
try {
|
|
12074
12150
|
const entries = await readdir3(SKILLS_PATH);
|
|
@@ -12091,7 +12167,7 @@ async function bootstrapSkills() {
|
|
|
12091
12167
|
}
|
|
12092
12168
|
}
|
|
12093
12169
|
async function patchUsmForCcClaw(usmDir) {
|
|
12094
|
-
const skillPath =
|
|
12170
|
+
const skillPath = join14(usmDir, "SKILL.md");
|
|
12095
12171
|
if (!existsSync14(skillPath)) return;
|
|
12096
12172
|
try {
|
|
12097
12173
|
let content = await readFile6(skillPath, "utf-8");
|
|
@@ -12120,7 +12196,7 @@ async function patchUsmForCcClaw(usmDir) {
|
|
|
12120
12196
|
}
|
|
12121
12197
|
}
|
|
12122
12198
|
if (patched) {
|
|
12123
|
-
await
|
|
12199
|
+
await writeFile4(skillPath, content, "utf-8");
|
|
12124
12200
|
log("[skills] Patched USM SKILL.md with CC-Claw support");
|
|
12125
12201
|
}
|
|
12126
12202
|
} catch (err) {
|
|
@@ -12137,8 +12213,8 @@ var init_bootstrap = __esm({
|
|
|
12137
12213
|
USM_REPO = "jacob-bd/universal-skills-manager";
|
|
12138
12214
|
USM_DIR_NAME = "universal-skills-manager";
|
|
12139
12215
|
CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
|
|
12140
|
-
PKG_ROOT =
|
|
12141
|
-
PKG_SKILLS =
|
|
12216
|
+
PKG_ROOT = join14(dirname2(fileURLToPath2(import.meta.url)), "..", "..");
|
|
12217
|
+
PKG_SKILLS = join14(PKG_ROOT, "skills");
|
|
12142
12218
|
}
|
|
12143
12219
|
});
|
|
12144
12220
|
|
|
@@ -12352,9 +12428,9 @@ __export(ai_skill_exports, {
|
|
|
12352
12428
|
generateAiSkill: () => generateAiSkill,
|
|
12353
12429
|
installAiSkill: () => installAiSkill
|
|
12354
12430
|
});
|
|
12355
|
-
import { existsSync as existsSync15, writeFileSync as
|
|
12356
|
-
import { join as
|
|
12357
|
-
import { homedir as
|
|
12431
|
+
import { existsSync as existsSync15, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6 } from "fs";
|
|
12432
|
+
import { join as join15 } from "path";
|
|
12433
|
+
import { homedir as homedir5 } from "os";
|
|
12358
12434
|
function generateAiSkill() {
|
|
12359
12435
|
const version = VERSION;
|
|
12360
12436
|
let systemState = "";
|
|
@@ -12654,11 +12730,11 @@ function installAiSkill() {
|
|
|
12654
12730
|
const failed = [];
|
|
12655
12731
|
for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
|
|
12656
12732
|
for (const dir of dirs) {
|
|
12657
|
-
const skillDir =
|
|
12658
|
-
const skillPath =
|
|
12733
|
+
const skillDir = join15(dir, "cc-claw-cli");
|
|
12734
|
+
const skillPath = join15(skillDir, "SKILL.md");
|
|
12659
12735
|
try {
|
|
12660
12736
|
mkdirSync6(skillDir, { recursive: true });
|
|
12661
|
-
|
|
12737
|
+
writeFileSync5(skillPath, skill, "utf-8");
|
|
12662
12738
|
installed.push(skillPath);
|
|
12663
12739
|
} catch {
|
|
12664
12740
|
failed.push(skillPath);
|
|
@@ -12674,10 +12750,10 @@ var init_ai_skill = __esm({
|
|
|
12674
12750
|
init_paths();
|
|
12675
12751
|
init_version();
|
|
12676
12752
|
BACKEND_SKILL_DIRS2 = {
|
|
12677
|
-
"cc-claw": [
|
|
12678
|
-
claude: [
|
|
12679
|
-
gemini: [
|
|
12680
|
-
codex: [
|
|
12753
|
+
"cc-claw": [join15(homedir5(), ".cc-claw", "workspace", "skills")],
|
|
12754
|
+
claude: [join15(homedir5(), ".claude", "skills")],
|
|
12755
|
+
gemini: [join15(homedir5(), ".gemini", "skills")],
|
|
12756
|
+
codex: [join15(homedir5(), ".agents", "skills")]
|
|
12681
12757
|
};
|
|
12682
12758
|
}
|
|
12683
12759
|
});
|
|
@@ -12688,17 +12764,17 @@ __export(index_exports, {
|
|
|
12688
12764
|
main: () => main
|
|
12689
12765
|
});
|
|
12690
12766
|
import { mkdirSync as mkdirSync7, existsSync as existsSync16, renameSync, statSync as statSync2, readFileSync as readFileSync10 } from "fs";
|
|
12691
|
-
import { join as
|
|
12767
|
+
import { join as join16 } from "path";
|
|
12692
12768
|
import dotenv from "dotenv";
|
|
12693
12769
|
function migrateLayout() {
|
|
12694
12770
|
const moves = [
|
|
12695
|
-
[
|
|
12696
|
-
[
|
|
12697
|
-
[
|
|
12698
|
-
[
|
|
12699
|
-
[
|
|
12700
|
-
[
|
|
12701
|
-
[
|
|
12771
|
+
[join16(CC_CLAW_HOME, "cc-claw.db"), join16(DATA_PATH, "cc-claw.db")],
|
|
12772
|
+
[join16(CC_CLAW_HOME, "cc-claw.db-shm"), join16(DATA_PATH, "cc-claw.db-shm")],
|
|
12773
|
+
[join16(CC_CLAW_HOME, "cc-claw.db-wal"), join16(DATA_PATH, "cc-claw.db-wal")],
|
|
12774
|
+
[join16(CC_CLAW_HOME, "cc-claw.log"), join16(LOGS_PATH, "cc-claw.log")],
|
|
12775
|
+
[join16(CC_CLAW_HOME, "cc-claw.log.1"), join16(LOGS_PATH, "cc-claw.log.1")],
|
|
12776
|
+
[join16(CC_CLAW_HOME, "cc-claw.error.log"), join16(LOGS_PATH, "cc-claw.error.log")],
|
|
12777
|
+
[join16(CC_CLAW_HOME, "cc-claw.error.log.1"), join16(LOGS_PATH, "cc-claw.error.log.1")]
|
|
12702
12778
|
];
|
|
12703
12779
|
for (const [from, to] of moves) {
|
|
12704
12780
|
if (existsSync16(from) && !existsSync16(to)) {
|
|
@@ -12803,11 +12879,11 @@ async function main() {
|
|
|
12803
12879
|
bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
|
|
12804
12880
|
try {
|
|
12805
12881
|
const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
|
|
12806
|
-
const { writeFileSync:
|
|
12807
|
-
const { join:
|
|
12808
|
-
const skillDir =
|
|
12882
|
+
const { writeFileSync: writeFileSync8, mkdirSync: mkdirSync11 } = await import("fs");
|
|
12883
|
+
const { join: join19 } = await import("path");
|
|
12884
|
+
const skillDir = join19(SKILLS_PATH, "cc-claw-cli");
|
|
12809
12885
|
mkdirSync11(skillDir, { recursive: true });
|
|
12810
|
-
|
|
12886
|
+
writeFileSync8(join19(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
|
|
12811
12887
|
log("[cc-claw] AI skill updated");
|
|
12812
12888
|
} catch {
|
|
12813
12889
|
}
|
|
@@ -12833,7 +12909,13 @@ async function main() {
|
|
|
12833
12909
|
stopMonitor();
|
|
12834
12910
|
shutdownOrchestrator();
|
|
12835
12911
|
shutdownScheduler();
|
|
12836
|
-
await
|
|
12912
|
+
await Promise.race([
|
|
12913
|
+
summarizeAllPending(),
|
|
12914
|
+
new Promise((resolve) => setTimeout(() => {
|
|
12915
|
+
log("[cc-claw] Summarization timed out after 15s, skipping.");
|
|
12916
|
+
resolve();
|
|
12917
|
+
}, 15e3))
|
|
12918
|
+
]);
|
|
12837
12919
|
await channelRegistry.stopAll();
|
|
12838
12920
|
log("[cc-claw] Clean shutdown complete.");
|
|
12839
12921
|
} catch (err) {
|
|
@@ -12891,10 +12973,10 @@ __export(service_exports, {
|
|
|
12891
12973
|
serviceStatus: () => serviceStatus,
|
|
12892
12974
|
uninstallService: () => uninstallService
|
|
12893
12975
|
});
|
|
12894
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync8, writeFileSync as
|
|
12976
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, writeFileSync as writeFileSync6, unlinkSync as unlinkSync2 } from "fs";
|
|
12895
12977
|
import { execFileSync as execFileSync2, execSync as execSync5 } from "child_process";
|
|
12896
|
-
import { homedir as
|
|
12897
|
-
import { join as
|
|
12978
|
+
import { homedir as homedir6, platform } from "os";
|
|
12979
|
+
import { join as join17, dirname as dirname3 } from "path";
|
|
12898
12980
|
function resolveExecutable2(name) {
|
|
12899
12981
|
try {
|
|
12900
12982
|
return execFileSync2("which", [name], { encoding: "utf-8" }).trim();
|
|
@@ -12903,18 +12985,18 @@ function resolveExecutable2(name) {
|
|
|
12903
12985
|
}
|
|
12904
12986
|
}
|
|
12905
12987
|
function getPathDirs() {
|
|
12906
|
-
const nodeBin =
|
|
12907
|
-
const home =
|
|
12988
|
+
const nodeBin = dirname3(process.execPath);
|
|
12989
|
+
const home = homedir6();
|
|
12908
12990
|
const dirs = /* @__PURE__ */ new Set([
|
|
12909
12991
|
nodeBin,
|
|
12910
|
-
|
|
12992
|
+
join17(home, ".local", "bin"),
|
|
12911
12993
|
"/usr/local/bin",
|
|
12912
12994
|
"/usr/bin",
|
|
12913
12995
|
"/bin"
|
|
12914
12996
|
]);
|
|
12915
12997
|
try {
|
|
12916
12998
|
const prefix = execSync5("npm config get prefix", { encoding: "utf-8" }).trim();
|
|
12917
|
-
if (prefix) dirs.add(
|
|
12999
|
+
if (prefix) dirs.add(join17(prefix, "bin"));
|
|
12918
13000
|
} catch {
|
|
12919
13001
|
}
|
|
12920
13002
|
return [...dirs].join(":");
|
|
@@ -12922,7 +13004,7 @@ function getPathDirs() {
|
|
|
12922
13004
|
function generatePlist() {
|
|
12923
13005
|
const ccClawBin = resolveExecutable2("cc-claw");
|
|
12924
13006
|
const pathDirs = getPathDirs();
|
|
12925
|
-
const home =
|
|
13007
|
+
const home = homedir6();
|
|
12926
13008
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
12927
13009
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
12928
13010
|
<plist version="1.0">
|
|
@@ -12968,7 +13050,7 @@ function generatePlist() {
|
|
|
12968
13050
|
</plist>`;
|
|
12969
13051
|
}
|
|
12970
13052
|
function installMacOS() {
|
|
12971
|
-
const agentsDir =
|
|
13053
|
+
const agentsDir = dirname3(PLIST_PATH);
|
|
12972
13054
|
if (!existsSync17(agentsDir)) mkdirSync8(agentsDir, { recursive: true });
|
|
12973
13055
|
if (!existsSync17(LOGS_PATH)) mkdirSync8(LOGS_PATH, { recursive: true });
|
|
12974
13056
|
if (existsSync17(PLIST_PATH)) {
|
|
@@ -12977,7 +13059,7 @@ function installMacOS() {
|
|
|
12977
13059
|
} catch {
|
|
12978
13060
|
}
|
|
12979
13061
|
}
|
|
12980
|
-
|
|
13062
|
+
writeFileSync6(PLIST_PATH, generatePlist());
|
|
12981
13063
|
console.log(` Installed: ${PLIST_PATH}`);
|
|
12982
13064
|
execFileSync2("launchctl", ["load", PLIST_PATH]);
|
|
12983
13065
|
console.log(" Service loaded and starting.");
|
|
@@ -13027,7 +13109,7 @@ Restart=on-failure
|
|
|
13027
13109
|
RestartSec=10
|
|
13028
13110
|
WorkingDirectory=${CC_CLAW_HOME}
|
|
13029
13111
|
Environment=PATH=${pathDirs}
|
|
13030
|
-
Environment=HOME=${
|
|
13112
|
+
Environment=HOME=${homedir6()}
|
|
13031
13113
|
|
|
13032
13114
|
[Install]
|
|
13033
13115
|
WantedBy=default.target
|
|
@@ -13036,7 +13118,7 @@ WantedBy=default.target
|
|
|
13036
13118
|
function installLinux() {
|
|
13037
13119
|
if (!existsSync17(SYSTEMD_DIR)) mkdirSync8(SYSTEMD_DIR, { recursive: true });
|
|
13038
13120
|
if (!existsSync17(LOGS_PATH)) mkdirSync8(LOGS_PATH, { recursive: true });
|
|
13039
|
-
|
|
13121
|
+
writeFileSync6(UNIT_PATH, generateUnit());
|
|
13040
13122
|
console.log(` Installed: ${UNIT_PATH}`);
|
|
13041
13123
|
execFileSync2("systemctl", ["--user", "daemon-reload"]);
|
|
13042
13124
|
execFileSync2("systemctl", ["--user", "enable", "cc-claw"]);
|
|
@@ -13069,7 +13151,7 @@ function statusLinux() {
|
|
|
13069
13151
|
}
|
|
13070
13152
|
}
|
|
13071
13153
|
function installService() {
|
|
13072
|
-
if (!existsSync17(
|
|
13154
|
+
if (!existsSync17(join17(CC_CLAW_HOME, ".env"))) {
|
|
13073
13155
|
console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
|
|
13074
13156
|
console.error(" Run 'cc-claw setup' before installing the service.");
|
|
13075
13157
|
process.exitCode = 1;
|
|
@@ -13098,9 +13180,9 @@ var init_service = __esm({
|
|
|
13098
13180
|
"use strict";
|
|
13099
13181
|
init_paths();
|
|
13100
13182
|
PLIST_LABEL = "com.cc-claw";
|
|
13101
|
-
PLIST_PATH =
|
|
13102
|
-
SYSTEMD_DIR =
|
|
13103
|
-
UNIT_PATH =
|
|
13183
|
+
PLIST_PATH = join17(homedir6(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
13184
|
+
SYSTEMD_DIR = join17(homedir6(), ".config", "systemd", "user");
|
|
13185
|
+
UNIT_PATH = join17(SYSTEMD_DIR, "cc-claw.service");
|
|
13104
13186
|
}
|
|
13105
13187
|
});
|
|
13106
13188
|
|
|
@@ -13761,15 +13843,14 @@ async function logsCommand(opts) {
|
|
|
13761
13843
|
console.log(tailLines.join("\n"));
|
|
13762
13844
|
if (opts.follow) {
|
|
13763
13845
|
console.log(muted("\n Following... (Ctrl+C to stop)\n"));
|
|
13764
|
-
let
|
|
13846
|
+
let lastLength = content.length;
|
|
13765
13847
|
watchFile2(logFile, { interval: 500 }, () => {
|
|
13766
13848
|
try {
|
|
13767
13849
|
const newContent = readFileSync14(logFile, "utf-8");
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
const newPart = newContent.slice(content.length);
|
|
13850
|
+
if (newContent.length > lastLength) {
|
|
13851
|
+
const newPart = newContent.slice(lastLength);
|
|
13771
13852
|
process.stdout.write(newPart);
|
|
13772
|
-
|
|
13853
|
+
lastLength = newContent.length;
|
|
13773
13854
|
}
|
|
13774
13855
|
} catch {
|
|
13775
13856
|
}
|
|
@@ -14242,8 +14323,17 @@ async function cronEdit(globalOpts, id, opts) {
|
|
|
14242
14323
|
values.push(opts.at);
|
|
14243
14324
|
}
|
|
14244
14325
|
if (opts.every) {
|
|
14245
|
-
|
|
14246
|
-
|
|
14326
|
+
const m = opts.every.match(/^(\d+)\s*(m|min|h|hr|s|sec)$/i);
|
|
14327
|
+
if (m) {
|
|
14328
|
+
const num = parseInt(m[1], 10);
|
|
14329
|
+
const unit = m[2].toLowerCase();
|
|
14330
|
+
const ms = unit.startsWith("h") ? num * 36e5 : unit.startsWith("m") ? num * 6e4 : num * 1e3;
|
|
14331
|
+
updates.push("every_ms = ?, schedule_type = 'every'");
|
|
14332
|
+
values.push(ms);
|
|
14333
|
+
} else {
|
|
14334
|
+
updates.push("every_ms = ?, schedule_type = 'every'");
|
|
14335
|
+
values.push(parseInt(opts.every, 10) || 0);
|
|
14336
|
+
}
|
|
14247
14337
|
}
|
|
14248
14338
|
if (opts.backend) {
|
|
14249
14339
|
updates.push("backend = ?");
|
|
@@ -14495,7 +14585,7 @@ __export(db_exports, {
|
|
|
14495
14585
|
dbStats: () => dbStats
|
|
14496
14586
|
});
|
|
14497
14587
|
import { existsSync as existsSync27, statSync as statSync5, copyFileSync, mkdirSync as mkdirSync9 } from "fs";
|
|
14498
|
-
import { dirname as
|
|
14588
|
+
import { dirname as dirname4 } from "path";
|
|
14499
14589
|
async function dbStats(globalOpts) {
|
|
14500
14590
|
if (!existsSync27(DB_PATH)) {
|
|
14501
14591
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
@@ -14545,7 +14635,7 @@ async function dbBackup(globalOpts, destPath) {
|
|
|
14545
14635
|
}
|
|
14546
14636
|
const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
14547
14637
|
try {
|
|
14548
|
-
mkdirSync9(
|
|
14638
|
+
mkdirSync9(dirname4(dest), { recursive: true });
|
|
14549
14639
|
copyFileSync(DB_PATH, dest);
|
|
14550
14640
|
const walPath = DB_PATH + "-wal";
|
|
14551
14641
|
if (existsSync27(walPath)) copyFileSync(walPath, dest + "-wal");
|
|
@@ -15917,7 +16007,7 @@ var init_completion = __esm({
|
|
|
15917
16007
|
model: ["list", "get", "set"],
|
|
15918
16008
|
thinking: ["get", "set"],
|
|
15919
16009
|
summarizer: ["get", "set"],
|
|
15920
|
-
memory: ["list", "search", "
|
|
16010
|
+
memory: ["list", "search", "history"],
|
|
15921
16011
|
cron: ["list", "create", "edit", "cancel", "pause", "resume", "run", "runs", "health"],
|
|
15922
16012
|
schedule: ["list", "create", "edit", "cancel", "pause", "resume", "run", "runs", "health"],
|
|
15923
16013
|
agents: ["list", "spawn", "cancel", "cancel-all"],
|
|
@@ -15935,7 +16025,7 @@ var init_completion = __esm({
|
|
|
15935
16025
|
chats: ["list", "alias", "remove-alias"],
|
|
15936
16026
|
skills: ["list", "install"],
|
|
15937
16027
|
mcps: ["list"],
|
|
15938
|
-
db: ["stats", "path", "backup"
|
|
16028
|
+
db: ["stats", "path", "backup"],
|
|
15939
16029
|
chat: ["send", "stop"]
|
|
15940
16030
|
};
|
|
15941
16031
|
}
|
|
@@ -15943,10 +16033,10 @@ var init_completion = __esm({
|
|
|
15943
16033
|
|
|
15944
16034
|
// src/setup.ts
|
|
15945
16035
|
var setup_exports = {};
|
|
15946
|
-
import { existsSync as existsSync38, writeFileSync as
|
|
16036
|
+
import { existsSync as existsSync38, writeFileSync as writeFileSync7, readFileSync as readFileSync17, copyFileSync as copyFileSync2, mkdirSync as mkdirSync10, statSync as statSync6 } from "fs";
|
|
15947
16037
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
15948
16038
|
import { createInterface as createInterface5 } from "readline";
|
|
15949
|
-
import { join as
|
|
16039
|
+
import { join as join18 } from "path";
|
|
15950
16040
|
function divider2() {
|
|
15951
16041
|
console.log(dim("\u2500".repeat(55)));
|
|
15952
16042
|
}
|
|
@@ -16033,7 +16123,7 @@ async function setup() {
|
|
|
16033
16123
|
if (match) env[match[1].trim()] = match[2].trim();
|
|
16034
16124
|
}
|
|
16035
16125
|
}
|
|
16036
|
-
const cwdDb =
|
|
16126
|
+
const cwdDb = join18(process.cwd(), "cc-claw.db");
|
|
16037
16127
|
if (existsSync38(cwdDb) && !existsSync38(DB_PATH)) {
|
|
16038
16128
|
const { size } = statSync6(cwdDb);
|
|
16039
16129
|
console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
|
|
@@ -16247,7 +16337,7 @@ async function setup() {
|
|
|
16247
16337
|
envLines.push("", "# Video Analysis", `GEMINI_API_KEY=${env.GEMINI_API_KEY}`);
|
|
16248
16338
|
}
|
|
16249
16339
|
const envContent = envLines.join("\n") + "\n";
|
|
16250
|
-
|
|
16340
|
+
writeFileSync7(ENV_PATH, envContent, { mode: 384 });
|
|
16251
16341
|
console.log(green(` Config saved to ${ENV_PATH} (permissions: owner-only)`));
|
|
16252
16342
|
header(6, TOTAL_STEPS, "Run on Startup (Daemon)");
|
|
16253
16343
|
console.log(" CC-Claw can run automatically in the background, starting");
|
package/package.json
CHANGED