cc-claw 0.17.1 → 0.18.0
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/agents/mcp-server.js +1 -1
- package/dist/cli.js +2179 -405
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ var VERSION;
|
|
|
33
33
|
var init_version = __esm({
|
|
34
34
|
"src/version.ts"() {
|
|
35
35
|
"use strict";
|
|
36
|
-
VERSION = true ? "0.
|
|
36
|
+
VERSION = true ? "0.18.0" : (() => {
|
|
37
37
|
try {
|
|
38
38
|
return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
39
39
|
} catch {
|
|
@@ -60,13 +60,21 @@ __export(paths_exports, {
|
|
|
60
60
|
SKILLS_PATH: () => SKILLS_PATH,
|
|
61
61
|
WORKSPACE_PATH: () => WORKSPACE_PATH
|
|
62
62
|
});
|
|
63
|
-
import { homedir } from "os";
|
|
63
|
+
import { homedir, userInfo } from "os";
|
|
64
64
|
import { join as join2 } from "path";
|
|
65
|
+
function resolveRealHome() {
|
|
66
|
+
try {
|
|
67
|
+
const info = userInfo();
|
|
68
|
+
if (info.homedir) return info.homedir;
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
return homedir();
|
|
72
|
+
}
|
|
65
73
|
var CC_CLAW_HOME, ENV_PATH, DATA_PATH, DB_PATH, LOGS_PATH, LOG_PATH, ERROR_LOG_PATH, IDENTITY_PATH, WORKSPACE_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH, MEDIA_PATH;
|
|
66
74
|
var init_paths = __esm({
|
|
67
75
|
"src/paths.ts"() {
|
|
68
76
|
"use strict";
|
|
69
|
-
CC_CLAW_HOME = process.env.CC_CLAW_HOME ?? join2(
|
|
77
|
+
CC_CLAW_HOME = process.env.CC_CLAW_HOME ?? join2(resolveRealHome(), ".cc-claw");
|
|
70
78
|
ENV_PATH = join2(CC_CLAW_HOME, ".env");
|
|
71
79
|
DATA_PATH = join2(CC_CLAW_HOME, "data");
|
|
72
80
|
DB_PATH = process.env.DB_PATH ?? join2(DATA_PATH, "cc-claw.db");
|
|
@@ -1735,6 +1743,12 @@ function initSchema(db3) {
|
|
|
1735
1743
|
mode TEXT NOT NULL DEFAULT 'approved'
|
|
1736
1744
|
);
|
|
1737
1745
|
`);
|
|
1746
|
+
db3.exec(`
|
|
1747
|
+
CREATE TABLE IF NOT EXISTS chat_show_thinking_ui (
|
|
1748
|
+
chat_id TEXT PRIMARY KEY,
|
|
1749
|
+
value INTEGER NOT NULL DEFAULT 0
|
|
1750
|
+
);
|
|
1751
|
+
`);
|
|
1738
1752
|
db3.exec(`
|
|
1739
1753
|
CREATE TABLE IF NOT EXISTS backend_credentials (
|
|
1740
1754
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -2419,6 +2433,52 @@ var init_sessions = __esm({
|
|
|
2419
2433
|
});
|
|
2420
2434
|
|
|
2421
2435
|
// src/memory/chat-settings.ts
|
|
2436
|
+
var chat_settings_exports = {};
|
|
2437
|
+
__export(chat_settings_exports, {
|
|
2438
|
+
ALL_TOOLS: () => ALL_TOOLS,
|
|
2439
|
+
clearAgentMode: () => clearAgentMode,
|
|
2440
|
+
clearCwd: () => clearCwd,
|
|
2441
|
+
clearExecMode: () => clearExecMode,
|
|
2442
|
+
clearModel: () => clearModel,
|
|
2443
|
+
clearSummarizer: () => clearSummarizer,
|
|
2444
|
+
clearThinkingLevel: () => clearThinkingLevel,
|
|
2445
|
+
deleteBookmark: () => deleteBookmark,
|
|
2446
|
+
determineEscalationTarget: () => determineEscalationTarget,
|
|
2447
|
+
findBookmarksByPrefix: () => findBookmarksByPrefix,
|
|
2448
|
+
getAgentMode: () => getAgentMode,
|
|
2449
|
+
getAllBookmarks: () => getAllBookmarks,
|
|
2450
|
+
getBackend: () => getBackend,
|
|
2451
|
+
getBookmark: () => getBookmark,
|
|
2452
|
+
getCwd: () => getCwd,
|
|
2453
|
+
getEnabledTools: () => getEnabledTools,
|
|
2454
|
+
getExecMode: () => getExecMode,
|
|
2455
|
+
getMode: () => getMode,
|
|
2456
|
+
getModel: () => getModel,
|
|
2457
|
+
getPendingEscalation: () => getPendingEscalation,
|
|
2458
|
+
getRecentBookmarks: () => getRecentBookmarks,
|
|
2459
|
+
getShowThinkingUi: () => getShowThinkingUi,
|
|
2460
|
+
getSummarizer: () => getSummarizer,
|
|
2461
|
+
getThinkingLevel: () => getThinkingLevel,
|
|
2462
|
+
getToolsMap: () => getToolsMap,
|
|
2463
|
+
getVerboseLevel: () => getVerboseLevel,
|
|
2464
|
+
removePendingEscalation: () => removePendingEscalation,
|
|
2465
|
+
resetTools: () => resetTools,
|
|
2466
|
+
setAgentMode: () => setAgentMode,
|
|
2467
|
+
setBackend: () => setBackend,
|
|
2468
|
+
setCwd: () => setCwd,
|
|
2469
|
+
setExecMode: () => setExecMode,
|
|
2470
|
+
setMode: () => setMode,
|
|
2471
|
+
setModel: () => setModel,
|
|
2472
|
+
setShowThinkingUi: () => setShowThinkingUi,
|
|
2473
|
+
setSummarizer: () => setSummarizer,
|
|
2474
|
+
setThinkingLevel: () => setThinkingLevel,
|
|
2475
|
+
setVerboseLevel: () => setVerboseLevel,
|
|
2476
|
+
storePendingEscalation: () => storePendingEscalation,
|
|
2477
|
+
toggleShowThinkingUi: () => toggleShowThinkingUi,
|
|
2478
|
+
toggleTool: () => toggleTool,
|
|
2479
|
+
touchBookmark: () => touchBookmark,
|
|
2480
|
+
upsertBookmark: () => upsertBookmark
|
|
2481
|
+
});
|
|
2422
2482
|
function getCwd(chatId) {
|
|
2423
2483
|
const row = getDb().prepare(
|
|
2424
2484
|
"SELECT cwd FROM chat_cwd WHERE chat_id = ?"
|
|
@@ -2517,6 +2577,25 @@ function setVerboseLevel(chatId, level) {
|
|
|
2517
2577
|
ON CONFLICT(chat_id) DO UPDATE SET level = ?
|
|
2518
2578
|
`).run(chatId, level, level);
|
|
2519
2579
|
}
|
|
2580
|
+
function getShowThinkingUi(chatId) {
|
|
2581
|
+
const row = getDb().prepare(
|
|
2582
|
+
"SELECT value FROM chat_show_thinking_ui WHERE chat_id = ?"
|
|
2583
|
+
).get(chatId);
|
|
2584
|
+
return (row?.value ?? 0) === 1;
|
|
2585
|
+
}
|
|
2586
|
+
function setShowThinkingUi(chatId, enabled) {
|
|
2587
|
+
getDb().prepare(`
|
|
2588
|
+
INSERT INTO chat_show_thinking_ui (chat_id, value)
|
|
2589
|
+
VALUES (?, ?)
|
|
2590
|
+
ON CONFLICT(chat_id) DO UPDATE SET value = ?
|
|
2591
|
+
`).run(chatId, enabled ? 1 : 0, enabled ? 1 : 0);
|
|
2592
|
+
}
|
|
2593
|
+
function toggleShowThinkingUi(chatId) {
|
|
2594
|
+
const current = getShowThinkingUi(chatId);
|
|
2595
|
+
const next = !current;
|
|
2596
|
+
setShowThinkingUi(chatId, next);
|
|
2597
|
+
return next;
|
|
2598
|
+
}
|
|
2520
2599
|
function getMode(chatId) {
|
|
2521
2600
|
const row = getDb().prepare(
|
|
2522
2601
|
"SELECT mode FROM chat_mode WHERE chat_id = ?"
|
|
@@ -3532,6 +3611,7 @@ __export(store_exports5, {
|
|
|
3532
3611
|
getSessionStartedAt: () => getSessionStartedAt,
|
|
3533
3612
|
getSessionSummaries: () => getSessionSummaries,
|
|
3534
3613
|
getSessionSummariesWithoutEmbeddings: () => getSessionSummariesWithoutEmbeddings,
|
|
3614
|
+
getShowThinkingUi: () => getShowThinkingUi,
|
|
3535
3615
|
getSummarizer: () => getSummarizer,
|
|
3536
3616
|
getThinkingLevel: () => getThinkingLevel,
|
|
3537
3617
|
getToolsMap: () => getToolsMap,
|
|
@@ -3591,11 +3671,13 @@ __export(store_exports5, {
|
|
|
3591
3671
|
setResponseStyle: () => setResponseStyle,
|
|
3592
3672
|
setSessionId: () => setSessionId,
|
|
3593
3673
|
setSessionStartedAt: () => setSessionStartedAt,
|
|
3674
|
+
setShowThinkingUi: () => setShowThinkingUi,
|
|
3594
3675
|
setSummarizer: () => setSummarizer,
|
|
3595
3676
|
setThinkingLevel: () => setThinkingLevel,
|
|
3596
3677
|
setVerboseLevel: () => setVerboseLevel,
|
|
3597
3678
|
storePendingEscalation: () => storePendingEscalation,
|
|
3598
3679
|
toFts5Query: () => toFts5Query,
|
|
3680
|
+
toggleShowThinkingUi: () => toggleShowThinkingUi,
|
|
3599
3681
|
toggleTool: () => toggleTool,
|
|
3600
3682
|
touchBookmark: () => touchBookmark,
|
|
3601
3683
|
updateHeartbeatTimestamps: () => updateHeartbeatTimestamps,
|
|
@@ -3914,10 +3996,16 @@ var init_claude = __esm({
|
|
|
3914
3996
|
});
|
|
3915
3997
|
}
|
|
3916
3998
|
const content = message?.content ?? [];
|
|
3917
|
-
|
|
3999
|
+
let hasTextContent = false;
|
|
4000
|
+
let textContent = "";
|
|
3918
4001
|
for (const block of content) {
|
|
3919
4002
|
if (block.type === "text" && block.text) {
|
|
3920
|
-
|
|
4003
|
+
textContent += block.text;
|
|
4004
|
+
hasTextContent = true;
|
|
4005
|
+
} else if (block.type === "thinking" && block.thinking) {
|
|
4006
|
+
events.push({ type: "thinking", text: block.thinking });
|
|
4007
|
+
} else if (block.type === "redacted_thinking") {
|
|
4008
|
+
events.push({ type: "thinking", text: "[Redacted Thinking]" });
|
|
3921
4009
|
} else if (block.type === "tool_use") {
|
|
3922
4010
|
events.push({
|
|
3923
4011
|
type: "tool_start",
|
|
@@ -3927,8 +4015,16 @@ var init_claude = __esm({
|
|
|
3927
4015
|
});
|
|
3928
4016
|
}
|
|
3929
4017
|
}
|
|
3930
|
-
if (
|
|
3931
|
-
const
|
|
4018
|
+
if (hasTextContent) {
|
|
4019
|
+
const matches = [...textContent.matchAll(/<thinking>([\s\S]*?)<\/thinking>/gi)];
|
|
4020
|
+
for (const match of matches) {
|
|
4021
|
+
events.push({ type: "thinking", text: match[1].trim() });
|
|
4022
|
+
}
|
|
4023
|
+
const matchesThink = [...textContent.matchAll(/<think>([\s\S]*?)<\/think>/gi)];
|
|
4024
|
+
for (const match of matchesThink) {
|
|
4025
|
+
events.push({ type: "thinking", text: match[1].trim() });
|
|
4026
|
+
}
|
|
4027
|
+
const cleaned = stripThinkingContent(textContent);
|
|
3932
4028
|
if (cleaned) events.push({ type: "text", text: cleaned });
|
|
3933
4029
|
}
|
|
3934
4030
|
} else if (line.type === "user") {
|
|
@@ -4282,8 +4378,18 @@ var init_gemini = __esm({
|
|
|
4282
4378
|
events.push({ type: "init", sessionId: line.session_id });
|
|
4283
4379
|
} else if (line.type === "message" && line.role === "assistant") {
|
|
4284
4380
|
if (line.thought === true) {
|
|
4381
|
+
events.push({ type: "thinking", text: String(line.content ?? "") });
|
|
4285
4382
|
} else if (line.content) {
|
|
4286
|
-
|
|
4383
|
+
let contentStr = line.content;
|
|
4384
|
+
const matches = [...contentStr.matchAll(/<thinking>([\s\S]*?)<\/thinking>/gi)];
|
|
4385
|
+
for (const match of matches) {
|
|
4386
|
+
events.push({ type: "thinking", text: match[1].trim() });
|
|
4387
|
+
}
|
|
4388
|
+
const matchesThink = [...contentStr.matchAll(/<think>([\s\S]*?)<\/think>/gi)];
|
|
4389
|
+
for (const match of matchesThink) {
|
|
4390
|
+
events.push({ type: "thinking", text: match[1].trim() });
|
|
4391
|
+
}
|
|
4392
|
+
const cleaned = stripThinkingContent(contentStr);
|
|
4287
4393
|
if (cleaned) {
|
|
4288
4394
|
events.push({ type: "text", text: cleaned });
|
|
4289
4395
|
}
|
|
@@ -4490,26 +4596,74 @@ var init_codex = __esm({
|
|
|
4490
4596
|
events.push({ type: "init", sessionId: line.thread_id });
|
|
4491
4597
|
} else if (line.type === "item.completed") {
|
|
4492
4598
|
const item = line.item;
|
|
4493
|
-
if (item
|
|
4599
|
+
if (!item) return events;
|
|
4600
|
+
if (item.type === "agent_message" && item.text) {
|
|
4494
4601
|
const cleaned = stripThinkingContent(item.text);
|
|
4495
4602
|
if (cleaned) events.push({ type: "text", text: cleaned });
|
|
4496
|
-
} else if (item
|
|
4603
|
+
} else if (item.type === "command_execution") {
|
|
4497
4604
|
events.push({
|
|
4498
4605
|
type: "tool_end",
|
|
4499
4606
|
toolName: "Shell",
|
|
4500
4607
|
toolId: item.id,
|
|
4501
4608
|
toolOutput: item.aggregated_output ?? ""
|
|
4502
4609
|
});
|
|
4610
|
+
} else if (item.type === "web_search") {
|
|
4611
|
+
const action = item.action;
|
|
4612
|
+
const query = action?.query || item.query || "";
|
|
4613
|
+
events.push({
|
|
4614
|
+
type: "tool_end",
|
|
4615
|
+
toolName: "Web Search",
|
|
4616
|
+
toolId: item.id,
|
|
4617
|
+
toolOutput: query ? `Searched: ${query}` : "Search completed"
|
|
4618
|
+
});
|
|
4619
|
+
} else if (item.type === "file_search") {
|
|
4620
|
+
events.push({
|
|
4621
|
+
type: "tool_end",
|
|
4622
|
+
toolName: "File Search",
|
|
4623
|
+
toolId: item.id,
|
|
4624
|
+
toolOutput: item.query ?? ""
|
|
4625
|
+
});
|
|
4626
|
+
} else if (item.type === "mcp_tool_call") {
|
|
4627
|
+
events.push({
|
|
4628
|
+
type: "tool_end",
|
|
4629
|
+
toolName: item.name ?? "MCP Tool",
|
|
4630
|
+
toolId: item.id,
|
|
4631
|
+
toolOutput: typeof item.output === "string" ? item.output : ""
|
|
4632
|
+
});
|
|
4503
4633
|
}
|
|
4504
4634
|
} else if (line.type === "item.started") {
|
|
4505
4635
|
const item = line.item;
|
|
4506
|
-
if (item
|
|
4636
|
+
if (!item) return events;
|
|
4637
|
+
if (item.type === "command_execution") {
|
|
4507
4638
|
events.push({
|
|
4508
4639
|
type: "tool_start",
|
|
4509
4640
|
toolName: "Shell",
|
|
4510
4641
|
toolId: item.id,
|
|
4511
4642
|
toolInput: { command: item.command ?? "" }
|
|
4512
4643
|
});
|
|
4644
|
+
} else if (item.type === "web_search") {
|
|
4645
|
+
const action = item.action;
|
|
4646
|
+
const query = action?.query || item.query || "";
|
|
4647
|
+
events.push({
|
|
4648
|
+
type: "tool_start",
|
|
4649
|
+
toolName: "Web Search",
|
|
4650
|
+
toolId: item.id,
|
|
4651
|
+
toolInput: { query: query || "Searching\u2026" }
|
|
4652
|
+
});
|
|
4653
|
+
} else if (item.type === "file_search") {
|
|
4654
|
+
events.push({
|
|
4655
|
+
type: "tool_start",
|
|
4656
|
+
toolName: "File Search",
|
|
4657
|
+
toolId: item.id,
|
|
4658
|
+
toolInput: { query: item.query ?? "" }
|
|
4659
|
+
});
|
|
4660
|
+
} else if (item.type === "mcp_tool_call") {
|
|
4661
|
+
events.push({
|
|
4662
|
+
type: "tool_start",
|
|
4663
|
+
toolName: item.name ?? "MCP Tool",
|
|
4664
|
+
toolId: item.id,
|
|
4665
|
+
toolInput: item.arguments ?? {}
|
|
4666
|
+
});
|
|
4513
4667
|
}
|
|
4514
4668
|
} else if (line.type === "turn.completed") {
|
|
4515
4669
|
const u = line.usage;
|
|
@@ -5292,6 +5446,11 @@ If the user asks *how* to do something with CC-Claw, use this expertise to sugge
|
|
|
5292
5446
|
});
|
|
5293
5447
|
|
|
5294
5448
|
// src/bootstrap/init.ts
|
|
5449
|
+
var init_exports = {};
|
|
5450
|
+
__export(init_exports, {
|
|
5451
|
+
bootstrapWorkspaceFiles: () => bootstrapWorkspaceFiles,
|
|
5452
|
+
syncNativeCliFiles: () => syncNativeCliFiles
|
|
5453
|
+
});
|
|
5295
5454
|
import {
|
|
5296
5455
|
existsSync as existsSync8,
|
|
5297
5456
|
writeFileSync,
|
|
@@ -8677,15 +8836,37 @@ var init_scheduler = __esm({
|
|
|
8677
8836
|
validateAgentIdentity(req, body);
|
|
8678
8837
|
const { updateJob: updateJob2, getJobById: getJobById3 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
8679
8838
|
const { stopJobTimer: stopJobTimer2, startSingleJob: startSingleJob2 } = await Promise.resolve().then(() => (init_cron(), cron_exports));
|
|
8680
|
-
const
|
|
8681
|
-
if (
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8839
|
+
const existing = getJobById3(body.jobId);
|
|
8840
|
+
if (!existing) {
|
|
8841
|
+
return jsonResponse(res, { success: false, error: `Job #${body.jobId} not found.` }, 404);
|
|
8842
|
+
}
|
|
8843
|
+
const updates = { ...body.updates };
|
|
8844
|
+
if (updates.cron !== void 0) {
|
|
8845
|
+
updates.scheduleType = "cron";
|
|
8846
|
+
updates.atTime = null;
|
|
8847
|
+
updates.everyMs = null;
|
|
8848
|
+
} else if (updates.atTime !== void 0) {
|
|
8849
|
+
updates.scheduleType = "at";
|
|
8850
|
+
updates.cron = null;
|
|
8851
|
+
updates.everyMs = null;
|
|
8852
|
+
} else if (updates.everyMs !== void 0) {
|
|
8853
|
+
updates.scheduleType = "every";
|
|
8854
|
+
updates.cron = null;
|
|
8855
|
+
updates.atTime = null;
|
|
8856
|
+
}
|
|
8857
|
+
const updated = updateJob2(body.jobId, updates);
|
|
8858
|
+
if (!updated) {
|
|
8859
|
+
return jsonResponse(res, {
|
|
8860
|
+
success: false,
|
|
8861
|
+
error: `No recognized fields to update. Valid fields: cron, atTime, everyMs, title, description, backend, model, thinking, timeout, timezone, sessionType, deliveryMode, channel, target.`
|
|
8862
|
+
}, 400);
|
|
8687
8863
|
}
|
|
8688
|
-
|
|
8864
|
+
stopJobTimer2(body.jobId);
|
|
8865
|
+
const freshJob = getJobById3(body.jobId);
|
|
8866
|
+
if (freshJob && freshJob.active && freshJob.enabled) {
|
|
8867
|
+
startSingleJob2(freshJob);
|
|
8868
|
+
}
|
|
8869
|
+
jsonResponse(res, { success: true });
|
|
8689
8870
|
} catch (err) {
|
|
8690
8871
|
jsonResponse(res, { error: errorMessage(err) }, 400);
|
|
8691
8872
|
}
|
|
@@ -10178,11 +10359,11 @@ var init_evolve = __esm({
|
|
|
10178
10359
|
const body = JSON.parse(await readBody(req));
|
|
10179
10360
|
const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
10180
10361
|
const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
|
|
10181
|
-
const { join:
|
|
10362
|
+
const { join: join34 } = await import("path");
|
|
10182
10363
|
const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
10183
10364
|
const chatId = body.chatId || (process.env.ALLOWED_CHAT_ID ?? "").split(",")[0]?.trim() || "default";
|
|
10184
|
-
const soulPath =
|
|
10185
|
-
const userPath =
|
|
10365
|
+
const soulPath = join34(home, "identity/SOUL.md");
|
|
10366
|
+
const userPath = join34(home, "identity/USER.md");
|
|
10186
10367
|
const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
|
|
10187
10368
|
const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
|
|
10188
10369
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
@@ -10762,6 +10943,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
10762
10943
|
}, effectiveTimeout);
|
|
10763
10944
|
let resultText = "";
|
|
10764
10945
|
let accumulatedText = "";
|
|
10946
|
+
let accumulatedThinking = "";
|
|
10765
10947
|
let sessionId;
|
|
10766
10948
|
let input = 0;
|
|
10767
10949
|
let output2 = 0;
|
|
@@ -10828,6 +11010,19 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
10828
11010
|
if (opts?.onStream) opts.onStream(ev.text);
|
|
10829
11011
|
}
|
|
10830
11012
|
break;
|
|
11013
|
+
case "thinking":
|
|
11014
|
+
if (!gotModelContent) {
|
|
11015
|
+
gotModelContent = true;
|
|
11016
|
+
if (firstResponseTimer) {
|
|
11017
|
+
clearTimeout(firstResponseTimer);
|
|
11018
|
+
firstResponseTimer = void 0;
|
|
11019
|
+
}
|
|
11020
|
+
}
|
|
11021
|
+
if (ev.text) {
|
|
11022
|
+
accumulatedThinking = appendTextChunk(accumulatedThinking, ev.text);
|
|
11023
|
+
if (opts?.onThinking) opts.onThinking(ev.text);
|
|
11024
|
+
}
|
|
11025
|
+
break;
|
|
10831
11026
|
case "tool_start":
|
|
10832
11027
|
if (!gotModelContent) {
|
|
10833
11028
|
gotModelContent = true;
|
|
@@ -10968,7 +11163,7 @@ Partial output: ${accumulatedText.slice(-500)}`;
|
|
|
10968
11163
|
return;
|
|
10969
11164
|
}
|
|
10970
11165
|
const cleanedResult = stripThinkingContent(resultText || accumulatedText);
|
|
10971
|
-
resolve({ resultText: cleanedResult, sessionId, input, output: output2, cacheRead, contextSize, sawToolEvents, sawResultEvent });
|
|
11166
|
+
resolve({ resultText: cleanedResult, thinkingText: accumulatedThinking, sessionId, input, output: output2, cacheRead, contextSize, sawToolEvents, sawResultEvent });
|
|
10972
11167
|
});
|
|
10973
11168
|
});
|
|
10974
11169
|
}
|
|
@@ -11128,7 +11323,7 @@ function askAgent(chatId, userMessage, opts) {
|
|
|
11128
11323
|
return withChatLock(chatId, () => askAgentImpl(chatId, userMessage, opts));
|
|
11129
11324
|
}
|
|
11130
11325
|
async function askAgentImpl(chatId, userMessage, opts) {
|
|
11131
|
-
const { cwd, onStream, model: model2, backend: backend2, permMode, onToolAction, bootstrapTier, timeoutMs, maxTurns, onSlotRotation, onModelDowngrade, agentMode: optsAgentMode, onSubagentActivity, settingsSourceChatId, planningDirective } = opts ?? {};
|
|
11326
|
+
const { cwd, onStream, model: model2, backend: backend2, permMode, onToolAction, bootstrapTier, timeoutMs, maxTurns, onSlotRotation, onModelDowngrade, agentMode: optsAgentMode, onSubagentActivity, settingsSourceChatId, planningDirective, onThinking } = opts ?? {};
|
|
11132
11327
|
const settingsChat = settingsSourceChatId ?? chatId;
|
|
11133
11328
|
const adapter = backend2 ? getAdapter(backend2) : getAdapterForChat(settingsChat);
|
|
11134
11329
|
const mode = permMode ?? getMode(settingsChat);
|
|
@@ -11176,6 +11371,7 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
11176
11371
|
onStream,
|
|
11177
11372
|
onToolAction,
|
|
11178
11373
|
onSubagentActivity,
|
|
11374
|
+
onThinking,
|
|
11179
11375
|
// First-response timeout: only arm for fresh Gemini sessions (cold-start).
|
|
11180
11376
|
// If Gemini has already responded at least once (existingSessionId is set),
|
|
11181
11377
|
// the session is established — mid-conversation silence is a legitimate long task,
|
|
@@ -11369,6 +11565,7 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
11369
11565
|
}
|
|
11370
11566
|
return {
|
|
11371
11567
|
text: result.resultText || `(No response from ${adapter.displayName})`,
|
|
11568
|
+
thinkingText: result.thinkingText,
|
|
11372
11569
|
sessionId: result.sessionId,
|
|
11373
11570
|
usage: { input: result.input, output: result.output, cacheRead: result.cacheRead, contextSize: result.contextSize },
|
|
11374
11571
|
resolvedModel: result.resolvedModel
|
|
@@ -11741,9 +11938,15 @@ function buildReviewCompleteMessage(results) {
|
|
|
11741
11938
|
Skipped proposals will appear in your next review.`;
|
|
11742
11939
|
}
|
|
11743
11940
|
function formatNightlySummary(insights, totalPending) {
|
|
11744
|
-
const
|
|
11745
|
-
const
|
|
11746
|
-
|
|
11941
|
+
const newCount = insights.length;
|
|
11942
|
+
const total = totalPending ?? newCount;
|
|
11943
|
+
let header2;
|
|
11944
|
+
if (total > newCount) {
|
|
11945
|
+
header2 = `Nightly Reflection \u2014 ${newCount} new proposal${newCount === 1 ? "" : "s"} (${total} total pending)`;
|
|
11946
|
+
} else {
|
|
11947
|
+
header2 = `Nightly Reflection \u2014 ${newCount} proposal${newCount === 1 ? "" : "s"} ready`;
|
|
11948
|
+
}
|
|
11949
|
+
const list = insights.map((ins, i) => `\u2022 [${ins.category}] ${ins.insight}`).join("\n");
|
|
11747
11950
|
return `${header2}
|
|
11748
11951
|
|
|
11749
11952
|
${list}
|
|
@@ -12023,6 +12226,7 @@ function classifyIntent(text, chatId) {
|
|
|
12023
12226
|
if (trimmed.startsWith(">>")) return "agentic";
|
|
12024
12227
|
if (trimmed.startsWith("/")) return "agentic";
|
|
12025
12228
|
const lower = trimmed.toLowerCase();
|
|
12229
|
+
const normalized = trimmed.replace(/^["'\u201C\u201D\u2018\u2019`\s]+|["'\u201C\u201D\u2018\u2019`\s]+$/g, "");
|
|
12026
12230
|
const sessionId = getSessionId(chatId);
|
|
12027
12231
|
if (sessionId) {
|
|
12028
12232
|
const lastTs = getLastMessageTimestamp(chatId);
|
|
@@ -12045,18 +12249,32 @@ function classifyIntent(text, chatId) {
|
|
|
12045
12249
|
intentCounts.chat++;
|
|
12046
12250
|
return "chat";
|
|
12047
12251
|
}
|
|
12048
|
-
for (const pattern of
|
|
12049
|
-
if (pattern.test(
|
|
12050
|
-
log(`[intent] "${trimmed.slice(0,
|
|
12252
|
+
for (const pattern of STRUCTURAL_PATTERNS) {
|
|
12253
|
+
if (pattern.test(normalized)) {
|
|
12254
|
+
log(`[intent] "${trimmed.slice(0, 40)}..." -> agentic (structural: ${pattern})`);
|
|
12255
|
+
intentCounts.agentic++;
|
|
12256
|
+
return "agentic";
|
|
12257
|
+
}
|
|
12258
|
+
}
|
|
12259
|
+
for (const pattern of MUTATION_PATTERNS) {
|
|
12260
|
+
if (pattern.test(normalized)) {
|
|
12261
|
+
log(`[intent] "${trimmed.slice(0, 40)}..." -> agentic (mutation: ${pattern})`);
|
|
12051
12262
|
intentCounts.agentic++;
|
|
12052
12263
|
return "agentic";
|
|
12053
12264
|
}
|
|
12054
12265
|
}
|
|
12055
|
-
|
|
12266
|
+
for (const pattern of CHAT_QUESTION_PATTERNS) {
|
|
12267
|
+
if (pattern.test(normalized)) {
|
|
12268
|
+
log(`[intent] "${trimmed.slice(0, 40)}..." -> chat (question: ${pattern})`);
|
|
12269
|
+
intentCounts.chat++;
|
|
12270
|
+
return "chat";
|
|
12271
|
+
}
|
|
12272
|
+
}
|
|
12273
|
+
log(`[intent] "${trimmed.slice(0, 40)}..." -> agentic (default)`);
|
|
12056
12274
|
intentCounts.agentic++;
|
|
12057
12275
|
return "agentic";
|
|
12058
12276
|
}
|
|
12059
|
-
var intentCounts, CHAT_EXACT,
|
|
12277
|
+
var intentCounts, CHAT_EXACT, MUTATION_PATTERNS, CHAT_QUESTION_PATTERNS, STRUCTURAL_PATTERNS;
|
|
12060
12278
|
var init_classify = __esm({
|
|
12061
12279
|
"src/intent/classify.ts"() {
|
|
12062
12280
|
"use strict";
|
|
@@ -12113,27 +12331,44 @@ var init_classify = __esm({
|
|
|
12113
12331
|
"alright",
|
|
12114
12332
|
"sure"
|
|
12115
12333
|
]);
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12334
|
+
MUTATION_PATTERNS = [
|
|
12335
|
+
/\b(fix|create|build|deploy|install|uninstall|delete|remove|update|edit|write|modify|move|rename|push|pull|commit|merge|rebase|refactor|implement|generate|scaffold|configure|enable|disable|migrate|upgrade|downgrade|seed|reset|rollback|apply|patch|publish|release|format|lint|compile|transpile|bundle|obfuscat)\b/i,
|
|
12336
|
+
/\b(add\s+(?:a|an|the|new|\w+\s+to))/i,
|
|
12337
|
+
// "add a function", "add to the file"
|
|
12338
|
+
/\b(change\s+(?:the|a|my|this|that|\w+\s+to))/i,
|
|
12339
|
+
// "change the config to"
|
|
12340
|
+
/\b(make\s+(?:a|an|it|this|the|sure))\b/i,
|
|
12341
|
+
// "make a new file", "make it work"
|
|
12342
|
+
/\b(set\s+(?:up|the|a|my))\b/i
|
|
12343
|
+
// "set up the database"
|
|
12344
|
+
];
|
|
12345
|
+
CHAT_QUESTION_PATTERNS = [
|
|
12346
|
+
/^(?:what|whats|what's)\s+/i,
|
|
12347
|
+
// "what is", "what version", "what does"
|
|
12348
|
+
/^(?:which|where|when|why|who)\s+/i,
|
|
12349
|
+
// "which file", "where is", "when did"
|
|
12350
|
+
/^(?:how\s+(?:do|does|can|did|many|much|long|often|come))\s+/i,
|
|
12351
|
+
// "how do I", "how many"
|
|
12352
|
+
/^(?:show|tell|list|explain|describe|summarize|display)\s+(?:me\s+)?/i,
|
|
12353
|
+
/^(?:do you|can you|could you|are you|is there|are there)\s+(?:know|have|see|find|show|tell|check|list|explain|describe)\s+/i,
|
|
12354
|
+
/^(?:give\s+me|get\s+me)\s+(?:the|a|my|an|current|latest)\s+/i,
|
|
12355
|
+
/^(?:is|are|was|were|does|did|has|have|had)\s+(?:the|a|my|it|this|that|there)\s+/i
|
|
12356
|
+
];
|
|
12357
|
+
STRUCTURAL_PATTERNS = [
|
|
12358
|
+
/\.[a-z]{1,5}\b/,
|
|
12359
|
+
// file extensions (.ts, .py, .md, .json)
|
|
12360
|
+
/[/\\][\w.-]+/,
|
|
12361
|
+
// file paths (/src/foo, .\bar)
|
|
12121
12362
|
/`[^`]+`/,
|
|
12122
|
-
// inline code
|
|
12363
|
+
// inline code `like this`
|
|
12123
12364
|
/```/,
|
|
12124
12365
|
// code blocks
|
|
12125
|
-
/\b(fix|create|build|deploy|run|execute|install|delete|remove|update|edit|write|read|check|test|debug|refactor|implement|add|change|modify|move|copy|rename|push|pull|commit|merge|rebase)\b/i,
|
|
12126
|
-
// imperative verbs
|
|
12127
|
-
/\b(error|bug|crash|fail|broken|issue|problem|exception|stack ?trace)\b/i,
|
|
12128
|
-
// error keywords
|
|
12129
|
-
/\b(function|class|const|let|var|import|export|return|async|await)\b/i,
|
|
12130
|
-
// code keywords
|
|
12131
12366
|
/[!]{1,2}\s/,
|
|
12132
|
-
// shell prefix
|
|
12367
|
+
// shell prefix (! or !!)
|
|
12133
12368
|
/^\/\//,
|
|
12134
|
-
// backend command prefix
|
|
12135
|
-
/\b(
|
|
12136
|
-
|
|
12369
|
+
// backend command prefix (//)
|
|
12370
|
+
/\b(error|bug|crash|fail|broken|issue|problem|exception|stack\s?trace)\b/i,
|
|
12371
|
+
/\b(function|class|const|let|var|import|export|return|async|await)\b/i
|
|
12137
12372
|
];
|
|
12138
12373
|
}
|
|
12139
12374
|
});
|
|
@@ -12833,7 +13068,7 @@ var init_classify2 = __esm({
|
|
|
12833
13068
|
// src/execution/gate.ts
|
|
12834
13069
|
function shouldRequireApproval(input) {
|
|
12835
13070
|
if (input.execMode !== "approved") return false;
|
|
12836
|
-
if (input.intent
|
|
13071
|
+
if (input.intent === "chat") return false;
|
|
12837
13072
|
if (input.messageText.startsWith(">>")) return false;
|
|
12838
13073
|
if (EXEMPT_TIERS.has(input.bootstrapTier)) return false;
|
|
12839
13074
|
if (input.isSideQuest) return false;
|
|
@@ -12841,28 +13076,40 @@ function shouldRequireApproval(input) {
|
|
|
12841
13076
|
}
|
|
12842
13077
|
function buildPlanningDirective() {
|
|
12843
13078
|
return [
|
|
12844
|
-
"## PLANNING MODE \u2014
|
|
13079
|
+
"## PLANNING MODE \u2014 Describe Only, Do Not Execute",
|
|
12845
13080
|
"",
|
|
12846
|
-
"You are in PLANNING
|
|
13081
|
+
"You are in PLANNING MODE. Your job is to research the request and describe",
|
|
13082
|
+
"what you will do. The user will review and approve before you execute anything.",
|
|
12847
13083
|
"",
|
|
12848
13084
|
"**ALLOWED:**",
|
|
12849
|
-
"- Read
|
|
12850
|
-
"-
|
|
12851
|
-
"-
|
|
12852
|
-
"- Search the web for documentation
|
|
12853
|
-
"
|
|
13085
|
+
"- Read file contents",
|
|
13086
|
+
"- Search/grep the codebase",
|
|
13087
|
+
"- Analyze code and architecture",
|
|
13088
|
+
"- Search the web for documentation",
|
|
13089
|
+
"",
|
|
13090
|
+
"**NOT ALLOWED \u2014 do NOT do any of these, even if they seem harmless:**",
|
|
13091
|
+
"- Run any shell or terminal commands (no node --version, no ls, no cat, no npm, nothing)",
|
|
13092
|
+
"- Create, modify, or delete any files",
|
|
13093
|
+
"- Write or generate code",
|
|
13094
|
+
"- Install or uninstall packages",
|
|
13095
|
+
"- Execute any mutations whatsoever",
|
|
13096
|
+
"",
|
|
13097
|
+
"**IMPORTANT:** Even if you already know the answer (e.g. from training data),",
|
|
13098
|
+
"do NOT run a command to confirm it. Just describe what you WILL do.",
|
|
12854
13099
|
"",
|
|
12855
|
-
"**
|
|
12856
|
-
"-
|
|
12857
|
-
"-
|
|
12858
|
-
"-
|
|
12859
|
-
"-
|
|
13100
|
+
"**OUTPUT FORMAT (strict):**",
|
|
13101
|
+
"- No preamble, no 'Here is my plan:', no closing remarks",
|
|
13102
|
+
"- Start with a bold title: '**Plan: <short description>**'",
|
|
13103
|
+
"- Use bullet points (\u2022) for each step \u2014 max 15 words per bullet",
|
|
13104
|
+
"- Be specific about which files you'll touch and what you'll change",
|
|
13105
|
+
"- Max total output: 3000 characters",
|
|
12860
13106
|
"",
|
|
12861
|
-
"
|
|
12862
|
-
"
|
|
12863
|
-
"
|
|
12864
|
-
"
|
|
12865
|
-
"
|
|
13107
|
+
"Example:",
|
|
13108
|
+
"**Plan: Add retry logic to API client**",
|
|
13109
|
+
"\u2022 Read `src/api/client.ts` \u2014 identify fetch call sites",
|
|
13110
|
+
"\u2022 Add `retryWithBackoff()` helper (max 3 retries, exponential backoff)",
|
|
13111
|
+
"\u2022 Update `src/sync.ts` and `src/scheduler.ts` to use the wrapper",
|
|
13112
|
+
"\u2022 Add unit test in `src/api/client.test.ts`"
|
|
12866
13113
|
].join("\n");
|
|
12867
13114
|
}
|
|
12868
13115
|
function storePendingPlan(chatId, plan, originalMessage) {
|
|
@@ -15826,11 +16073,11 @@ async function sendJobPicker(chatId, channel, action) {
|
|
|
15826
16073
|
}
|
|
15827
16074
|
async function sendCurrentProposal(chatId, channel) {
|
|
15828
16075
|
const { getReviewSession: getReviewSession2, getInsightById: getInsightById2, deleteReviewSession: deleteReviewSession2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
15829
|
-
const { formatProposalCardWithProgress: formatProposalCardWithProgress2, buildProposalKeyboard: buildProposalKeyboard2, buildReviewCompleteMessage:
|
|
16076
|
+
const { formatProposalCardWithProgress: formatProposalCardWithProgress2, buildProposalKeyboard: buildProposalKeyboard2, buildReviewCompleteMessage: buildReviewCompleteMessage3 } = await Promise.resolve().then(() => (init_propose(), propose_exports));
|
|
15830
16077
|
const session2 = getReviewSession2(getDb(), chatId);
|
|
15831
16078
|
if (!session2) return;
|
|
15832
16079
|
if (session2.currentIndex >= session2.insightIds.length) {
|
|
15833
|
-
const summary =
|
|
16080
|
+
const summary = buildReviewCompleteMessage3(session2.results);
|
|
15834
16081
|
deleteReviewSession2(getDb(), chatId);
|
|
15835
16082
|
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
15836
16083
|
return;
|
|
@@ -16070,7 +16317,7 @@ async function handleEvolveCallback(chatId, data, channel) {
|
|
|
16070
16317
|
if (pending.length === 0) {
|
|
16071
16318
|
await channel.sendText(chatId, "No pending proposals.", { parseMode: "plain" });
|
|
16072
16319
|
} else {
|
|
16073
|
-
const insightIds = pending.
|
|
16320
|
+
const insightIds = pending.map((p) => p.id);
|
|
16074
16321
|
createReviewSession2(getDb(), chatId, insightIds);
|
|
16075
16322
|
await channel.sendText(chatId, `${pending.length} proposal(s) ready. Let's review them one by one.`, { parseMode: "plain" });
|
|
16076
16323
|
await sendCurrentProposal(chatId, channel);
|
|
@@ -16231,13 +16478,13 @@ async function handleEvolveCallback(chatId, data, channel) {
|
|
|
16231
16478
|
const { getReflectionStatus: getReflectionStatus2, setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
16232
16479
|
const current = getReflectionStatus2(getDb(), chatId);
|
|
16233
16480
|
if (current === "frozen") {
|
|
16234
|
-
const { readFileSync:
|
|
16235
|
-
const { join:
|
|
16481
|
+
const { readFileSync: readFileSync26, existsSync: existsSync54 } = await import("fs");
|
|
16482
|
+
const { join: join34 } = await import("path");
|
|
16236
16483
|
const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
16237
|
-
const soulPath =
|
|
16238
|
-
const userPath =
|
|
16239
|
-
const soul =
|
|
16240
|
-
const user =
|
|
16484
|
+
const soulPath = join34(CC_CLAW_HOME3, "identity/SOUL.md");
|
|
16485
|
+
const userPath = join34(CC_CLAW_HOME3, "identity/USER.md");
|
|
16486
|
+
const soul = existsSync54(soulPath) ? readFileSync26(soulPath, "utf-8") : "";
|
|
16487
|
+
const user = existsSync54(userPath) ? readFileSync26(userPath, "utf-8") : "";
|
|
16241
16488
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
16242
16489
|
const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
|
|
16243
16490
|
logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
|
|
@@ -16313,107 +16560,1284 @@ var init_evolve2 = __esm({
|
|
|
16313
16560
|
}
|
|
16314
16561
|
});
|
|
16315
16562
|
|
|
16316
|
-
// src/
|
|
16317
|
-
import {
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
return
|
|
16563
|
+
// src/optimizer/identity-audit.ts
|
|
16564
|
+
import { readFileSync as readFileSync10, existsSync as existsSync19, readdirSync as readdirSync9, statSync as statSync6 } from "fs";
|
|
16565
|
+
import { join as join20 } from "path";
|
|
16566
|
+
function readIdentityFile2(filename) {
|
|
16567
|
+
try {
|
|
16568
|
+
return readFileSync10(join20(IDENTITY_PATH, filename), "utf-8");
|
|
16569
|
+
} catch {
|
|
16570
|
+
return "";
|
|
16322
16571
|
}
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
|
|
16326
|
-
|
|
16327
|
-
|
|
16328
|
-
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
|
|
16572
|
+
}
|
|
16573
|
+
function getMtime(filepath) {
|
|
16574
|
+
try {
|
|
16575
|
+
return statSync6(filepath).mtime.toISOString();
|
|
16576
|
+
} catch {
|
|
16577
|
+
return "unknown";
|
|
16578
|
+
}
|
|
16579
|
+
}
|
|
16580
|
+
function findBackupFiles() {
|
|
16581
|
+
const backups = [];
|
|
16582
|
+
const dirs = [IDENTITY_PATH];
|
|
16583
|
+
const contextDir = join20(IDENTITY_PATH, "..", "workspace", "context");
|
|
16584
|
+
if (existsSync19(contextDir)) dirs.push(contextDir);
|
|
16585
|
+
for (const dir of dirs) {
|
|
16586
|
+
try {
|
|
16587
|
+
for (const entry of readdirSync9(dir)) {
|
|
16588
|
+
if (entry.endsWith(".bak") || /\.bak\.\d{4}-\d{2}-\d{2}/.test(entry)) {
|
|
16589
|
+
backups.push(join20(dir, entry));
|
|
16590
|
+
}
|
|
16337
16591
|
}
|
|
16338
|
-
|
|
16592
|
+
} catch {
|
|
16339
16593
|
}
|
|
16340
|
-
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16594
|
+
}
|
|
16595
|
+
return backups;
|
|
16596
|
+
}
|
|
16597
|
+
function computeIdentityStats(pendingProposals, driftPercent) {
|
|
16598
|
+
const soulContent = readIdentityFile2("SOUL.md");
|
|
16599
|
+
const userContent = readIdentityFile2("USER.md");
|
|
16600
|
+
const ccClawContent = readIdentityFile2("CC-CLAW.md");
|
|
16601
|
+
const soulChars = soulContent.length;
|
|
16602
|
+
const userChars = userContent.length;
|
|
16603
|
+
const ccClawChars = ccClawContent.length;
|
|
16604
|
+
const boilerplateChars = Math.max(0, ccClawChars - soulChars - userChars);
|
|
16605
|
+
return {
|
|
16606
|
+
soulChars,
|
|
16607
|
+
userChars,
|
|
16608
|
+
ccClawChars,
|
|
16609
|
+
boilerplateChars,
|
|
16610
|
+
soulMtime: getMtime(join20(IDENTITY_PATH, "SOUL.md")),
|
|
16611
|
+
userMtime: getMtime(join20(IDENTITY_PATH, "USER.md")),
|
|
16612
|
+
ccClawMtime: getMtime(join20(IDENTITY_PATH, "CC-CLAW.md")),
|
|
16613
|
+
backupFiles: findBackupFiles(),
|
|
16614
|
+
estimatedTokens: Math.ceil(ccClawChars / 4),
|
|
16615
|
+
pendingEvolveProposals: pendingProposals,
|
|
16616
|
+
driftPercent
|
|
16617
|
+
};
|
|
16618
|
+
}
|
|
16619
|
+
function buildTokenReport(stats) {
|
|
16620
|
+
return {
|
|
16621
|
+
soulChars: stats.soulChars,
|
|
16622
|
+
userChars: stats.userChars,
|
|
16623
|
+
boilerplateChars: stats.boilerplateChars,
|
|
16624
|
+
totalChars: stats.ccClawChars,
|
|
16625
|
+
estimatedTokens: stats.estimatedTokens
|
|
16626
|
+
};
|
|
16627
|
+
}
|
|
16628
|
+
function buildIdentityAuditPrompt(soulMd, userMd, ccClawMd, stats, contextFiles) {
|
|
16629
|
+
const sections = [];
|
|
16630
|
+
sections.push(`You are an expert prompt engineer and identity file auditor for an AI assistant platform.
|
|
16631
|
+
|
|
16632
|
+
Your task: Analyze the assistant's identity files against a strict rubric and produce ONLY high-confidence, actionable findings. Every finding must earn its place \u2014 no fluff, no generic observations, no "nice to have" suggestions.
|
|
16633
|
+
|
|
16634
|
+
SCRUTINY RULE: Before including ANY finding, ask yourself: "Does this have a clear, specific impact on AI behavior, prompt compliance, or token waste?" If you cannot articulate the exact impact, DO NOT include it.
|
|
16635
|
+
|
|
16636
|
+
Return at most 8 findings. If everything is clean, return NO_FINDINGS.`);
|
|
16637
|
+
sections.push(`[Pre-computed Stats]
|
|
16638
|
+
SOUL.md: ${stats.soulChars} chars (~${Math.ceil(stats.soulChars / 4)} tokens), modified: ${stats.soulMtime}
|
|
16639
|
+
USER.md: ${stats.userChars} chars (~${Math.ceil(stats.userChars / 4)} tokens), modified: ${stats.userMtime}
|
|
16640
|
+
CC-CLAW.md: ${stats.ccClawChars} chars (~${stats.estimatedTokens} tokens), modified: ${stats.ccClawMtime}
|
|
16641
|
+
Boilerplate overhead: ~${stats.boilerplateChars} chars (~${Math.ceil(stats.boilerplateChars / 4)} tokens)
|
|
16642
|
+
Total identity tokens per message: ~${stats.estimatedTokens}
|
|
16643
|
+
Backup files found: ${stats.backupFiles.length > 0 ? stats.backupFiles.join(", ") : "none"}
|
|
16644
|
+
Pending evolve proposals: ${stats.pendingEvolveProposals}
|
|
16645
|
+
Drift from baseline: ${stats.driftPercent !== null ? `${stats.driftPercent}%` : "not calculated"}`);
|
|
16646
|
+
sections.push(`[Rubric \u2014 Evaluate Each Area]
|
|
16647
|
+
|
|
16648
|
+
1. STRUCTURAL HEALTH
|
|
16649
|
+
- Are file sizes reasonable? (SOUL.md >5000 chars or USER.md >3000 chars = bloat risk)
|
|
16650
|
+
- Is CC-CLAW.md stale? (modified before SOUL.md or USER.md = needs regeneration)
|
|
16651
|
+
- Orphan backup files accumulating?
|
|
16652
|
+
- Logical section organization within each file?
|
|
16653
|
+
|
|
16654
|
+
2. CONTENT ROUTING
|
|
16655
|
+
- User profile data (job title, employer, location) misplaced in SOUL.md? \u2192 belongs in USER.md
|
|
16656
|
+
- Personality directives (tone, style rules) misplaced in USER.md? \u2192 belongs in SOUL.md
|
|
16657
|
+
- Secrets, credentials, or API keys in any file?
|
|
16658
|
+
- Temporary content (TODOs, dates, one-off instructions) in identity files?
|
|
16659
|
+
- Content that should live in workspace/context/ files instead?
|
|
16660
|
+
|
|
16661
|
+
3. TOKEN EFFICIENCY
|
|
16662
|
+
- Content duplicated between SOUL.md and USER.md?
|
|
16663
|
+
- Verbose explanations that could be tightened without losing meaning?
|
|
16664
|
+
- Inline lists (emoji lists, tool lists) that are too long?
|
|
16665
|
+
- Content from context files that duplicates identity content?
|
|
16666
|
+
|
|
16667
|
+
4. EVOLVE INTEGRATION
|
|
16668
|
+
- Pending proposal count (${stats.pendingEvolveProposals}) \u2014 are stale proposals accumulating?
|
|
16669
|
+
- Drift from baseline (${stats.driftPercent !== null ? `${stats.driftPercent}%` : "N/A"}) \u2014 is it excessive (>50%)?
|
|
16670
|
+
|
|
16671
|
+
5. QUALITY & CLARITY
|
|
16672
|
+
- Conflicting instructions within the same file (e.g., "be brief" AND "provide detailed explanations")
|
|
16673
|
+
- Vague or ambiguous rules the AI is unlikely to follow consistently
|
|
16674
|
+
- Outdated references (old tool names, deprecated services)
|
|
16675
|
+
- Missing important directives (timezone, OS, communication style preferences)
|
|
16676
|
+
|
|
16677
|
+
6. IDENTITY COMPLETENESS
|
|
16678
|
+
- Does USER.md have enough info for the assistant to be truly personal?
|
|
16679
|
+
- Missing: timezone, work context, communication preferences, personal interests?
|
|
16680
|
+
- Contradictory user info (e.g., conflicting roles, locations, or personal details)?
|
|
16681
|
+
- What additional info could the user provide to improve personalization?`);
|
|
16682
|
+
sections.push("[Current SOUL.md]");
|
|
16683
|
+
sections.push(soulMd || "(empty)");
|
|
16684
|
+
sections.push("[Current USER.md]");
|
|
16685
|
+
sections.push(userMd || "(empty)");
|
|
16686
|
+
sections.push("[Current CC-CLAW.md (generated)]");
|
|
16687
|
+
sections.push(ccClawMd || "(empty)");
|
|
16688
|
+
if (contextFiles.length > 0) {
|
|
16689
|
+
sections.push("[Context Files]");
|
|
16690
|
+
for (const f of contextFiles) {
|
|
16691
|
+
sections.push(`--- ${f.name} ---`);
|
|
16692
|
+
sections.push(f.content.length > 2e3 ? f.content.slice(0, 2e3) + "\n[...truncated]" : f.content);
|
|
16358
16693
|
}
|
|
16359
|
-
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16694
|
+
}
|
|
16695
|
+
sections.push(`[Output Format]
|
|
16696
|
+
For each finding, output EXACTLY this format. Separate multiple findings with "---" on its own line.
|
|
16697
|
+
|
|
16698
|
+
FINDING: <short title, max 80 chars>
|
|
16699
|
+
AREA: <structural | routing | efficiency | evolve | quality | completeness>
|
|
16700
|
+
SEVERITY: <critical | warning | info>
|
|
16701
|
+
DETAIL: <1-3 sentences explaining the issue AND its specific impact on AI behavior>
|
|
16702
|
+
LOCATION: <file:line or file:section, e.g. "SOUL.md:## Communication" or "USER.md:15">
|
|
16703
|
+
SUGGESTION: <specific actionable fix>
|
|
16704
|
+
DIFF:
|
|
16705
|
+
<proposed changes as diff lines, + for additions, - for removals>
|
|
16706
|
+
---
|
|
16707
|
+
|
|
16708
|
+
If no findings are warranted after thorough analysis, output: NO_FINDINGS
|
|
16709
|
+
|
|
16710
|
+
CRITICAL: For COMPLETENESS findings where you suggest the user ADD information, leave DIFF empty and explain in SUGGESTION what the user should provide. You cannot generate personal information \u2014 only the user can.`);
|
|
16711
|
+
return sections.join("\n\n");
|
|
16712
|
+
}
|
|
16713
|
+
var init_identity_audit = __esm({
|
|
16714
|
+
"src/optimizer/identity-audit.ts"() {
|
|
16715
|
+
"use strict";
|
|
16716
|
+
init_paths();
|
|
16717
|
+
}
|
|
16718
|
+
});
|
|
16719
|
+
|
|
16720
|
+
// src/optimizer/skill-audit.ts
|
|
16721
|
+
import { readFileSync as readFileSync11, existsSync as existsSync20 } from "fs";
|
|
16722
|
+
import { join as join21, basename as basename2 } from "path";
|
|
16723
|
+
function parseFrontmatter3(content) {
|
|
16724
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
16725
|
+
if (!fmMatch) return {};
|
|
16726
|
+
const fm = fmMatch[1];
|
|
16727
|
+
const result = {};
|
|
16728
|
+
const nameMatch = fm.match(/^name:\s*(.+)/m);
|
|
16729
|
+
if (nameMatch) result.name = nameMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
16730
|
+
const descMatch = fm.match(/^description:\s*>?\s*\n?([\s\S]*?)(?=\n\w|\n---)/m);
|
|
16731
|
+
if (descMatch) {
|
|
16732
|
+
result.description = descMatch[1].trim().replace(/\n\s+/g, " ");
|
|
16733
|
+
} else {
|
|
16734
|
+
const singleDesc = fm.match(/^description:\s*(.+)/m);
|
|
16735
|
+
if (singleDesc) result.description = singleDesc[1].trim().replace(/^["']|["']$/g, "");
|
|
16736
|
+
}
|
|
16737
|
+
const backendsMatch = fm.match(/^compatible_backends:\s*(.+)/m);
|
|
16738
|
+
if (backendsMatch) result.compatibleBackends = backendsMatch[1].trim();
|
|
16739
|
+
const modelMatch = fm.match(/^recommended_model:\s*(.+)/m);
|
|
16740
|
+
if (modelMatch) result.recommendedModel = modelMatch[1].trim();
|
|
16741
|
+
return result;
|
|
16742
|
+
}
|
|
16743
|
+
function detectDependentSkills(content) {
|
|
16744
|
+
const deps = /* @__PURE__ */ new Set();
|
|
16745
|
+
const loadMatches = content.matchAll(/(?:load|activate|use|invoke)\s+(?:the\s+)?[`"]?([a-z0-9_-]+)[`"]?\s+(?:skill)?/gi);
|
|
16746
|
+
for (const m of loadMatches) {
|
|
16747
|
+
const name = m[1].toLowerCase();
|
|
16748
|
+
if (name.length > 2 && !["the", "this", "that", "skill", "tool"].includes(name)) {
|
|
16749
|
+
deps.add(name);
|
|
16374
16750
|
}
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
...id === currentMode ? { style: "primary" } : {}
|
|
16382
|
-
}]);
|
|
16383
|
-
await channel.sendKeyboard(chatId, "Select permission mode:", buttons);
|
|
16384
|
-
} else {
|
|
16385
|
-
const lines = ["Permission modes:", ""];
|
|
16386
|
-
for (const [id, label2] of Object.entries(PERM_MODES)) {
|
|
16387
|
-
lines.push(`${id === currentMode ? "\u2713 " : " "}/permissions ${id} \u2014 ${label2}`);
|
|
16388
|
-
}
|
|
16389
|
-
await channel.sendText(chatId, lines.join("\n"), { parseMode: "plain" });
|
|
16390
|
-
}
|
|
16391
|
-
break;
|
|
16751
|
+
}
|
|
16752
|
+
const btMatches = content.matchAll(/`([a-z][a-z0-9_-]+(?:-skill)?)`/g);
|
|
16753
|
+
for (const m of btMatches) {
|
|
16754
|
+
const name = m[1];
|
|
16755
|
+
if (!name.includes(".") && !name.startsWith("cc-claw") && name.length > 3) {
|
|
16756
|
+
deps.add(name);
|
|
16392
16757
|
}
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
|
|
16401
|
-
|
|
16402
|
-
|
|
16403
|
-
|
|
16404
|
-
|
|
16405
|
-
|
|
16406
|
-
|
|
16407
|
-
|
|
16408
|
-
|
|
16409
|
-
|
|
16410
|
-
|
|
16758
|
+
}
|
|
16759
|
+
return Array.from(deps);
|
|
16760
|
+
}
|
|
16761
|
+
function computeSkillStats(skillPath) {
|
|
16762
|
+
const content = readFileSync11(skillPath, "utf-8");
|
|
16763
|
+
const lines = content.split("\n");
|
|
16764
|
+
return {
|
|
16765
|
+
skillName: basename2(skillPath, ".md") === "SKILL" ? basename2(join21(skillPath, "..")) : basename2(skillPath, ".md"),
|
|
16766
|
+
skillPath,
|
|
16767
|
+
lineCount: lines.length,
|
|
16768
|
+
charCount: content.length,
|
|
16769
|
+
estimatedTokens: Math.ceil(content.length / 4),
|
|
16770
|
+
frontmatter: parseFrontmatter3(content),
|
|
16771
|
+
dependentSkills: detectDependentSkills(content)
|
|
16772
|
+
};
|
|
16773
|
+
}
|
|
16774
|
+
function buildSkillTokenReport(stats) {
|
|
16775
|
+
return {
|
|
16776
|
+
skillChars: stats.charCount,
|
|
16777
|
+
estimatedTokens: stats.estimatedTokens,
|
|
16778
|
+
lineCount: stats.lineCount
|
|
16779
|
+
};
|
|
16780
|
+
}
|
|
16781
|
+
function loadDependentSkillContents(depNames, ccClawSkillsDir) {
|
|
16782
|
+
const results = [];
|
|
16783
|
+
for (const name of depNames) {
|
|
16784
|
+
const candidates = [
|
|
16785
|
+
join21(ccClawSkillsDir, name, "SKILL.md"),
|
|
16786
|
+
join21(ccClawSkillsDir, `${name}-skill`, "SKILL.md")
|
|
16787
|
+
];
|
|
16788
|
+
for (const candidate of candidates) {
|
|
16789
|
+
if (existsSync20(candidate)) {
|
|
16790
|
+
try {
|
|
16791
|
+
const content = readFileSync11(candidate, "utf-8");
|
|
16792
|
+
results.push({
|
|
16793
|
+
name,
|
|
16794
|
+
content: content.length > 3e3 ? content.slice(0, 3e3) + "\n[...truncated]" : content
|
|
16795
|
+
});
|
|
16796
|
+
} catch {
|
|
16411
16797
|
}
|
|
16412
|
-
|
|
16798
|
+
break;
|
|
16413
16799
|
}
|
|
16414
|
-
break;
|
|
16415
16800
|
}
|
|
16416
|
-
|
|
16801
|
+
}
|
|
16802
|
+
return results;
|
|
16803
|
+
}
|
|
16804
|
+
function buildSkillAuditPrompt(skillContent, stats, soulMd, ccClawSkillsDir) {
|
|
16805
|
+
const sections = [];
|
|
16806
|
+
sections.push(`You are an expert prompt engineer specializing in AI agent skills. Analyze this skill file against a strict rubric derived from Anthropic's skill-creator best practices and prompt engineering research.
|
|
16807
|
+
|
|
16808
|
+
Your task: Produce ONLY high-confidence, actionable findings that will measurably improve how well the AI follows this skill's instructions. Every finding must earn its place.
|
|
16809
|
+
|
|
16810
|
+
SCRUTINY RULE: Before including ANY finding, ask yourself: "Will fixing this change how the AI executes this skill?" If the answer is no or unclear, DO NOT include it. We want zero fluff.
|
|
16811
|
+
|
|
16812
|
+
Return at most 8 findings. If the skill is well-constructed, return NO_FINDINGS.`);
|
|
16813
|
+
sections.push(`[Skill Stats]
|
|
16814
|
+
Name: ${stats.skillName}
|
|
16815
|
+
Path: ${stats.skillPath}
|
|
16816
|
+
Lines: ${stats.lineCount} (cap: 500 \u2014 over 500 = progressive disclosure needed)
|
|
16817
|
+
Chars: ${stats.charCount} (~${stats.estimatedTokens} tokens)
|
|
16818
|
+
Frontmatter name: ${stats.frontmatter.name || "(missing)"}
|
|
16819
|
+
Frontmatter description: ${stats.frontmatter.description ? stats.frontmatter.description.slice(0, 200) : "(missing)"}
|
|
16820
|
+
Compatible backends: ${stats.frontmatter.compatibleBackends || "(not specified)"}
|
|
16821
|
+
Recommended model: ${stats.frontmatter.recommendedModel || "(not specified)"}
|
|
16822
|
+
Referenced skills: ${stats.dependentSkills.length > 0 ? stats.dependentSkills.join(", ") : "none"}`);
|
|
16823
|
+
sections.push(`[Rubric \u2014 Evaluate Each Area]
|
|
16824
|
+
|
|
16825
|
+
1. FRONTMATTER QUALITY
|
|
16826
|
+
- Is 'name' present and descriptive?
|
|
16827
|
+
- Does 'description' include BOTH what the skill does AND trigger info (when to use it)?
|
|
16828
|
+
- A good description tells the AI exactly when to activate this skill
|
|
16829
|
+
- Should 'compatible_backends' or 'recommended_model' be specified?
|
|
16830
|
+
|
|
16831
|
+
2. BODY STRUCTURE
|
|
16832
|
+
- Over 500 lines? \u2192 needs progressive disclosure (essentials in body, details in references/)
|
|
16833
|
+
- Is there a "When to Use" section in the body? \u2192 that belongs in the frontmatter description
|
|
16834
|
+
- Are workflow steps clear and sequential?
|
|
16835
|
+
- Are phases/steps numbered for easy reference?
|
|
16836
|
+
- Is there a clear guard clause (preconditions before starting)?
|
|
16837
|
+
|
|
16838
|
+
3. TOKEN EFFICIENCY
|
|
16839
|
+
- Verbose explanations that could be condensed without losing meaning?
|
|
16840
|
+
- Redundant examples (one clear example > three repetitive ones)?
|
|
16841
|
+
- Reference material that should be in a references/ subdirectory?
|
|
16842
|
+
- Emotional emphasis (bold, caps, exclamation marks) that wastes tokens without improving adherence?
|
|
16843
|
+
- Duplicated instructions (same rule stated multiple times in different sections)?
|
|
16844
|
+
|
|
16845
|
+
4. CONTRADICTION DETECTION
|
|
16846
|
+
- Instructions that conflict with SOUL.md behavioral rules?
|
|
16847
|
+
(e.g., skill says "be thorough and detailed" but SOUL.md says "be concise")
|
|
16848
|
+
- Tone mismatches between skill and personality?
|
|
16849
|
+
- Conflicting tool usage patterns?
|
|
16850
|
+
- Internal contradictions within the skill itself?
|
|
16851
|
+
|
|
16852
|
+
5. COMPLIANCE & CLARITY
|
|
16853
|
+
- Negative framing ("DO NOT do X") that should be positive ("do Y instead")?
|
|
16854
|
+
- Vague rules the AI is unlikely to follow consistently?
|
|
16855
|
+
- Emotional escalation ("NEVER EVER", "THIS IS CRITICAL") \u2014 does it add compliance or just tokens?
|
|
16856
|
+
- Instructions that rely on the AI "remembering" without structural enforcement?`);
|
|
16857
|
+
sections.push("[Skill File Content]");
|
|
16858
|
+
sections.push(skillContent);
|
|
16859
|
+
sections.push("[SOUL.md (for contradiction check)]");
|
|
16860
|
+
sections.push(soulMd || "(empty)");
|
|
16861
|
+
if (stats.dependentSkills.length > 0) {
|
|
16862
|
+
const depContents = loadDependentSkillContents(stats.dependentSkills, ccClawSkillsDir);
|
|
16863
|
+
if (depContents.length > 0) {
|
|
16864
|
+
sections.push("[Referenced Skill Contents]");
|
|
16865
|
+
for (const dep of depContents) {
|
|
16866
|
+
sections.push(`--- ${dep.name} ---`);
|
|
16867
|
+
sections.push(dep.content);
|
|
16868
|
+
}
|
|
16869
|
+
}
|
|
16870
|
+
}
|
|
16871
|
+
sections.push(`[Output Format]
|
|
16872
|
+
For each finding, output EXACTLY this format. Separate multiple findings with "---" on its own line.
|
|
16873
|
+
|
|
16874
|
+
FINDING: <short title, max 80 chars>
|
|
16875
|
+
AREA: <frontmatter | body | efficiency | contradiction | compliance>
|
|
16876
|
+
SEVERITY: <critical | warning | info>
|
|
16877
|
+
DETAIL: <1-3 sentences explaining the issue AND its specific impact on AI compliance>
|
|
16878
|
+
LOCATION: <SKILL.md:line or SKILL.md:section, e.g. "SKILL.md:## Phase 1" or "SKILL.md:45">
|
|
16879
|
+
SUGGESTION: <specific actionable fix>
|
|
16880
|
+
DIFF:
|
|
16881
|
+
<proposed changes as diff lines, + for additions, - for removals>
|
|
16882
|
+
---
|
|
16883
|
+
|
|
16884
|
+
If the skill is well-constructed after thorough analysis, output: NO_FINDINGS`);
|
|
16885
|
+
return sections.join("\n\n");
|
|
16886
|
+
}
|
|
16887
|
+
var init_skill_audit = __esm({
|
|
16888
|
+
"src/optimizer/skill-audit.ts"() {
|
|
16889
|
+
"use strict";
|
|
16890
|
+
}
|
|
16891
|
+
});
|
|
16892
|
+
|
|
16893
|
+
// src/optimizer/analyze.ts
|
|
16894
|
+
var analyze_exports2 = {};
|
|
16895
|
+
__export(analyze_exports2, {
|
|
16896
|
+
getModelDisplayInfo: () => getModelDisplayInfo,
|
|
16897
|
+
isWeakModel: () => isWeakModel,
|
|
16898
|
+
listCcClawSkills: () => listCcClawSkills,
|
|
16899
|
+
parseOptimizeOutput: () => parseOptimizeOutput,
|
|
16900
|
+
resolveOptimizeAdapter: () => resolveOptimizeAdapter,
|
|
16901
|
+
runIdentityAudit: () => runIdentityAudit,
|
|
16902
|
+
runSkillAudit: () => runSkillAudit
|
|
16903
|
+
});
|
|
16904
|
+
import { spawn as spawn6 } from "child_process";
|
|
16905
|
+
import { createInterface as createInterface5 } from "readline";
|
|
16906
|
+
import { readFileSync as readFileSync12, existsSync as existsSync21, readdirSync as readdirSync11 } from "fs";
|
|
16907
|
+
import { join as join22 } from "path";
|
|
16908
|
+
import { homedir as homedir7 } from "os";
|
|
16909
|
+
function parseOptimizeOutput(raw, validAreas) {
|
|
16910
|
+
if (!raw || raw.includes("NO_FINDINGS")) return [];
|
|
16911
|
+
if (!raw.includes("FINDING:")) return [];
|
|
16912
|
+
const blocks = raw.split(/\n---\n/).slice(0, MAX_FINDINGS);
|
|
16913
|
+
const results = [];
|
|
16914
|
+
for (const block of blocks) {
|
|
16915
|
+
const findingMatch = block.match(/^FINDING:\s*(.+)/m);
|
|
16916
|
+
const areaMatch = block.match(/^AREA:\s*(.+)/m);
|
|
16917
|
+
const severityMatch = block.match(/^SEVERITY:\s*(.+)/m);
|
|
16918
|
+
const detailMatch = block.match(/^DETAIL:\s*(.+)/m);
|
|
16919
|
+
const locationMatch = block.match(/^LOCATION:\s*(.+)/m);
|
|
16920
|
+
const suggestionMatch = block.match(/^SUGGESTION:\s*(.+)/m);
|
|
16921
|
+
const diffMatch = block.match(/^DIFF:\n([\s\S]*?)$/m);
|
|
16922
|
+
if (!findingMatch || !areaMatch) continue;
|
|
16923
|
+
const area = areaMatch[1].trim().toLowerCase();
|
|
16924
|
+
if (!validAreas.includes(area)) continue;
|
|
16925
|
+
const severity = severityMatch?.[1]?.trim().toLowerCase() ?? "info";
|
|
16926
|
+
if (!VALID_SEVERITIES.includes(severity)) continue;
|
|
16927
|
+
results.push({
|
|
16928
|
+
title: findingMatch[1].trim().slice(0, 80),
|
|
16929
|
+
area,
|
|
16930
|
+
severity,
|
|
16931
|
+
detail: detailMatch?.[1]?.trim() ?? "",
|
|
16932
|
+
location: locationMatch?.[1]?.trim() ?? "",
|
|
16933
|
+
suggestion: suggestionMatch?.[1]?.trim() ?? "",
|
|
16934
|
+
proposedDiff: diffMatch?.[1]?.trim() ?? ""
|
|
16935
|
+
});
|
|
16936
|
+
}
|
|
16937
|
+
return results;
|
|
16938
|
+
}
|
|
16939
|
+
async function spawnAnalysis2(adapter, model2, prompt, timeoutMs = ANALYSIS_TIMEOUT_MS2) {
|
|
16940
|
+
const config2 = adapter.buildSpawnConfig({
|
|
16941
|
+
prompt,
|
|
16942
|
+
model: model2,
|
|
16943
|
+
permMode: "yolo",
|
|
16944
|
+
allowedTools: []
|
|
16945
|
+
});
|
|
16946
|
+
const env = adapter.getEnv();
|
|
16947
|
+
let resultText = "";
|
|
16948
|
+
let accumulatedText = "";
|
|
16949
|
+
await new Promise((resolve) => {
|
|
16950
|
+
const proc = spawn6(config2.executable, config2.args, {
|
|
16951
|
+
env,
|
|
16952
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
16953
|
+
...config2.cwd ? { cwd: config2.cwd } : {}
|
|
16954
|
+
});
|
|
16955
|
+
proc.stderr?.resume();
|
|
16956
|
+
const rl2 = createInterface5({ input: proc.stdout });
|
|
16957
|
+
const timeout = setTimeout(() => {
|
|
16958
|
+
warn(`[optimizer] Analysis timeout (${adapter.id}:${model2})`);
|
|
16959
|
+
rl2.close();
|
|
16960
|
+
proc.kill("SIGTERM");
|
|
16961
|
+
setTimeout(() => proc.kill("SIGKILL"), 2e3);
|
|
16962
|
+
}, timeoutMs);
|
|
16963
|
+
rl2.on("line", (line) => {
|
|
16964
|
+
if (!line.trim()) return;
|
|
16965
|
+
let msg;
|
|
16966
|
+
try {
|
|
16967
|
+
msg = JSON.parse(line);
|
|
16968
|
+
} catch {
|
|
16969
|
+
return;
|
|
16970
|
+
}
|
|
16971
|
+
const events = adapter.parseLine(msg);
|
|
16972
|
+
for (const ev of events) {
|
|
16973
|
+
if (ev.type === "text" && ev.text) accumulatedText = appendTextChunk(accumulatedText, ev.text);
|
|
16974
|
+
if (ev.type === "result") {
|
|
16975
|
+
resultText = ev.resultText || accumulatedText;
|
|
16976
|
+
if (adapter.shouldKillOnResult()) {
|
|
16977
|
+
rl2.close();
|
|
16978
|
+
proc.kill("SIGTERM");
|
|
16979
|
+
}
|
|
16980
|
+
}
|
|
16981
|
+
}
|
|
16982
|
+
});
|
|
16983
|
+
proc.on("error", () => {
|
|
16984
|
+
clearTimeout(timeout);
|
|
16985
|
+
resolve();
|
|
16986
|
+
});
|
|
16987
|
+
proc.on("close", () => {
|
|
16988
|
+
clearTimeout(timeout);
|
|
16989
|
+
resolve();
|
|
16990
|
+
});
|
|
16991
|
+
});
|
|
16992
|
+
if (!resultText) resultText = accumulatedText;
|
|
16993
|
+
return resultText;
|
|
16994
|
+
}
|
|
16995
|
+
function resolveOptimizeAdapter(chatId) {
|
|
16996
|
+
try {
|
|
16997
|
+
const adapter = getAdapterForChat(chatId);
|
|
16998
|
+
return { adapter, model: adapter.defaultModel };
|
|
16999
|
+
} catch {
|
|
17000
|
+
try {
|
|
17001
|
+
const adapter = getAdapter("claude");
|
|
17002
|
+
return { adapter, model: adapter.defaultModel };
|
|
17003
|
+
} catch {
|
|
17004
|
+
return null;
|
|
17005
|
+
}
|
|
17006
|
+
}
|
|
17007
|
+
}
|
|
17008
|
+
function isWeakModel(adapter, model2) {
|
|
17009
|
+
const weakPatterns = [
|
|
17010
|
+
"flash",
|
|
17011
|
+
"haiku",
|
|
17012
|
+
"mini",
|
|
17013
|
+
"4o-mini",
|
|
17014
|
+
"gpt-4o-mini"
|
|
17015
|
+
];
|
|
17016
|
+
const lower = model2.toLowerCase();
|
|
17017
|
+
return weakPatterns.some((p) => lower.includes(p));
|
|
17018
|
+
}
|
|
17019
|
+
function getModelDisplayInfo(chatId) {
|
|
17020
|
+
const resolved = resolveOptimizeAdapter(chatId);
|
|
17021
|
+
if (!resolved) return null;
|
|
17022
|
+
const { getThinkingLevel: getThinkingLevel2 } = (init_store5(), __toCommonJS(store_exports5));
|
|
17023
|
+
const thinkingLevel = getThinkingLevel2(chatId);
|
|
17024
|
+
return {
|
|
17025
|
+
backend: resolved.adapter.displayName,
|
|
17026
|
+
model: resolved.model,
|
|
17027
|
+
thinkingLevel,
|
|
17028
|
+
isWeak: isWeakModel(resolved.adapter, resolved.model)
|
|
17029
|
+
};
|
|
17030
|
+
}
|
|
17031
|
+
function readIdentityFile3(filename) {
|
|
17032
|
+
try {
|
|
17033
|
+
return readFileSync12(join22(IDENTITY_PATH, filename), "utf-8");
|
|
17034
|
+
} catch {
|
|
17035
|
+
return "";
|
|
17036
|
+
}
|
|
17037
|
+
}
|
|
17038
|
+
function loadContextFiles() {
|
|
17039
|
+
const contextDir = join22(homedir7(), ".cc-claw", "workspace", "context");
|
|
17040
|
+
const results = [];
|
|
17041
|
+
if (!existsSync21(contextDir)) return results;
|
|
17042
|
+
try {
|
|
17043
|
+
for (const entry of readdirSync11(contextDir)) {
|
|
17044
|
+
if (!entry.endsWith(".md")) continue;
|
|
17045
|
+
try {
|
|
17046
|
+
const content = readFileSync12(join22(contextDir, entry), "utf-8");
|
|
17047
|
+
results.push({ name: entry, content });
|
|
17048
|
+
} catch {
|
|
17049
|
+
}
|
|
17050
|
+
}
|
|
17051
|
+
} catch {
|
|
17052
|
+
}
|
|
17053
|
+
return results;
|
|
17054
|
+
}
|
|
17055
|
+
async function runIdentityAudit(chatId) {
|
|
17056
|
+
const resolved = resolveOptimizeAdapter(chatId);
|
|
17057
|
+
if (!resolved) throw new Error("No AI backend available for analysis");
|
|
17058
|
+
const { adapter, model: model2 } = resolved;
|
|
17059
|
+
log(`[optimizer] Running identity audit with ${adapter.id}:${model2}`);
|
|
17060
|
+
let pendingProposals = 0;
|
|
17061
|
+
try {
|
|
17062
|
+
const { getPendingInsightCount: getPendingInsightCount2 } = (init_store4(), __toCommonJS(store_exports4));
|
|
17063
|
+
const { getPrimaryChatId: getPrimaryChatId2 } = (init_resolve(), __toCommonJS(resolve_exports));
|
|
17064
|
+
const reflChatId = getPrimaryChatId2() || chatId;
|
|
17065
|
+
pendingProposals = getPendingInsightCount2(getDb(), reflChatId);
|
|
17066
|
+
} catch {
|
|
17067
|
+
}
|
|
17068
|
+
let driftPercent = null;
|
|
17069
|
+
try {
|
|
17070
|
+
const { calculateDrift: calculateDrift2 } = (init_apply(), __toCommonJS(apply_exports));
|
|
17071
|
+
} catch {
|
|
17072
|
+
}
|
|
17073
|
+
const stats = computeIdentityStats(pendingProposals, driftPercent);
|
|
17074
|
+
const soulMd = readIdentityFile3("SOUL.md");
|
|
17075
|
+
const userMd = readIdentityFile3("USER.md");
|
|
17076
|
+
const ccClawMd = readIdentityFile3("CC-CLAW.md");
|
|
17077
|
+
const contextFiles = loadContextFiles();
|
|
17078
|
+
const prompt = buildIdentityAuditPrompt(soulMd, userMd, ccClawMd, stats, contextFiles);
|
|
17079
|
+
const raw = await spawnAnalysis2(adapter, model2, prompt);
|
|
17080
|
+
const findings = parseOptimizeOutput(raw, VALID_IDENTITY_AREAS);
|
|
17081
|
+
log(`[optimizer] Identity audit complete: ${findings.length} findings`);
|
|
17082
|
+
return {
|
|
17083
|
+
findings,
|
|
17084
|
+
tokenReport: buildTokenReport(stats),
|
|
17085
|
+
model: model2,
|
|
17086
|
+
backend: adapter.id,
|
|
17087
|
+
target: "identity"
|
|
17088
|
+
};
|
|
17089
|
+
}
|
|
17090
|
+
async function runSkillAudit(chatId, skillPath) {
|
|
17091
|
+
const resolved = resolveOptimizeAdapter(chatId);
|
|
17092
|
+
if (!resolved) throw new Error("No AI backend available for analysis");
|
|
17093
|
+
const { adapter, model: model2 } = resolved;
|
|
17094
|
+
const stats = computeSkillStats(skillPath);
|
|
17095
|
+
log(`[optimizer] Running skill audit on ${stats.skillName} with ${adapter.id}:${model2}`);
|
|
17096
|
+
const soulMd = readIdentityFile3("SOUL.md");
|
|
17097
|
+
const ccClawSkillsDir = join22(homedir7(), ".cc-claw", "workspace", "skills");
|
|
17098
|
+
const skillContent = readFileSync12(skillPath, "utf-8");
|
|
17099
|
+
const prompt = buildSkillAuditPrompt(skillContent, stats, soulMd, ccClawSkillsDir);
|
|
17100
|
+
const raw = await spawnAnalysis2(adapter, model2, prompt);
|
|
17101
|
+
const findings = parseOptimizeOutput(raw, VALID_SKILL_AREAS);
|
|
17102
|
+
log(`[optimizer] Skill audit complete for ${stats.skillName}: ${findings.length} findings`);
|
|
17103
|
+
return {
|
|
17104
|
+
findings,
|
|
17105
|
+
tokenReport: buildSkillTokenReport(stats),
|
|
17106
|
+
model: model2,
|
|
17107
|
+
backend: adapter.id,
|
|
17108
|
+
target: stats.skillName
|
|
17109
|
+
};
|
|
17110
|
+
}
|
|
17111
|
+
function listCcClawSkills() {
|
|
17112
|
+
const skillsDir = join22(homedir7(), ".cc-claw", "workspace", "skills");
|
|
17113
|
+
const entries = [];
|
|
17114
|
+
if (!existsSync21(skillsDir)) return entries;
|
|
17115
|
+
try {
|
|
17116
|
+
for (const dir of readdirSync11(skillsDir)) {
|
|
17117
|
+
const skillFile = join22(skillsDir, dir, "SKILL.md");
|
|
17118
|
+
if (!existsSync21(skillFile)) continue;
|
|
17119
|
+
let description = "skill";
|
|
17120
|
+
try {
|
|
17121
|
+
const content = readFileSync12(skillFile, "utf-8");
|
|
17122
|
+
const descMatch = content.match(/description:\s*>?\s*\n?\s*(.+)/);
|
|
17123
|
+
if (descMatch) description = descMatch[1].trim().slice(0, 60);
|
|
17124
|
+
} catch {
|
|
17125
|
+
}
|
|
17126
|
+
entries.push({ name: dir, path: skillFile, description });
|
|
17127
|
+
}
|
|
17128
|
+
} catch {
|
|
17129
|
+
}
|
|
17130
|
+
return entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
17131
|
+
}
|
|
17132
|
+
var ANALYSIS_TIMEOUT_MS2, MAX_FINDINGS, VALID_IDENTITY_AREAS, VALID_SKILL_AREAS, VALID_SEVERITIES;
|
|
17133
|
+
var init_analyze2 = __esm({
|
|
17134
|
+
"src/optimizer/analyze.ts"() {
|
|
17135
|
+
"use strict";
|
|
17136
|
+
init_log();
|
|
17137
|
+
init_text_utils();
|
|
17138
|
+
init_paths();
|
|
17139
|
+
init_backends();
|
|
17140
|
+
init_store5();
|
|
17141
|
+
init_identity_audit();
|
|
17142
|
+
init_skill_audit();
|
|
17143
|
+
ANALYSIS_TIMEOUT_MS2 = 18e4;
|
|
17144
|
+
MAX_FINDINGS = 8;
|
|
17145
|
+
VALID_IDENTITY_AREAS = [
|
|
17146
|
+
"structural",
|
|
17147
|
+
"routing",
|
|
17148
|
+
"efficiency",
|
|
17149
|
+
"evolve",
|
|
17150
|
+
"quality",
|
|
17151
|
+
"completeness"
|
|
17152
|
+
];
|
|
17153
|
+
VALID_SKILL_AREAS = [
|
|
17154
|
+
"frontmatter",
|
|
17155
|
+
"body",
|
|
17156
|
+
"efficiency",
|
|
17157
|
+
"contradiction",
|
|
17158
|
+
"compliance"
|
|
17159
|
+
];
|
|
17160
|
+
VALID_SEVERITIES = ["critical", "warning", "info"];
|
|
17161
|
+
}
|
|
17162
|
+
});
|
|
17163
|
+
|
|
17164
|
+
// src/optimizer/ui.ts
|
|
17165
|
+
var ui_exports = {};
|
|
17166
|
+
__export(ui_exports, {
|
|
17167
|
+
buildFindingKeyboard: () => buildFindingKeyboard,
|
|
17168
|
+
buildFindingMessage: () => buildFindingMessage,
|
|
17169
|
+
buildIdentityAuditKeyboard: () => buildIdentityAuditKeyboard,
|
|
17170
|
+
buildIdentityAuditSummary: () => buildIdentityAuditSummary,
|
|
17171
|
+
buildMainMenuKeyboard: () => buildMainMenuKeyboard,
|
|
17172
|
+
buildMainMenuMessage: () => buildMainMenuMessage,
|
|
17173
|
+
buildModelRecommendationKeyboard: () => buildModelRecommendationKeyboard,
|
|
17174
|
+
buildModelRecommendationMessage: () => buildModelRecommendationMessage,
|
|
17175
|
+
buildProgressMessage: () => buildProgressMessage,
|
|
17176
|
+
buildReviewCompleteKeyboard: () => buildReviewCompleteKeyboard,
|
|
17177
|
+
buildReviewCompleteMessage: () => buildReviewCompleteMessage2,
|
|
17178
|
+
buildSkillAuditKeyboard: () => buildSkillAuditKeyboard,
|
|
17179
|
+
buildSkillAuditSummary: () => buildSkillAuditSummary,
|
|
17180
|
+
buildSkillPickerKeyboard: () => buildSkillPickerKeyboard,
|
|
17181
|
+
buildSkillPickerMessage: () => buildSkillPickerMessage
|
|
17182
|
+
});
|
|
17183
|
+
function severityEmoji(severity) {
|
|
17184
|
+
switch (severity) {
|
|
17185
|
+
case "critical":
|
|
17186
|
+
return "\u{1F534}";
|
|
17187
|
+
case "warning":
|
|
17188
|
+
return "\u26A0\uFE0F";
|
|
17189
|
+
case "info":
|
|
17190
|
+
return "\u2139\uFE0F";
|
|
17191
|
+
default:
|
|
17192
|
+
return "\u2022";
|
|
17193
|
+
}
|
|
17194
|
+
}
|
|
17195
|
+
function areaEmoji(area) {
|
|
17196
|
+
switch (area) {
|
|
17197
|
+
case "structural":
|
|
17198
|
+
return "\u{1F4D0}";
|
|
17199
|
+
case "routing":
|
|
17200
|
+
return "\u{1F4C2}";
|
|
17201
|
+
case "efficiency":
|
|
17202
|
+
return "\u{1F4B0}";
|
|
17203
|
+
case "evolve":
|
|
17204
|
+
return "\u{1F504}";
|
|
17205
|
+
case "quality":
|
|
17206
|
+
return "\u2728";
|
|
17207
|
+
case "completeness":
|
|
17208
|
+
return "\u{1F464}";
|
|
17209
|
+
case "frontmatter":
|
|
17210
|
+
return "\u{1F4CB}";
|
|
17211
|
+
case "body":
|
|
17212
|
+
return "\u{1F4DD}";
|
|
17213
|
+
case "contradiction":
|
|
17214
|
+
return "\u26A1";
|
|
17215
|
+
case "compliance":
|
|
17216
|
+
return "\u2705";
|
|
17217
|
+
default:
|
|
17218
|
+
return "\u2022";
|
|
17219
|
+
}
|
|
17220
|
+
}
|
|
17221
|
+
function buildMainMenuMessage(backend2, model2, thinkingLevel) {
|
|
17222
|
+
const thinkText = thinkingLevel !== "off" && thinkingLevel !== "auto" ? ` | Thinking: ${thinkingLevel}` : thinkingLevel === "auto" ? " | Thinking: auto" : "";
|
|
17223
|
+
return [
|
|
17224
|
+
"\u{1F527} CC-Claw Optimizer",
|
|
17225
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17226
|
+
"",
|
|
17227
|
+
"AI-powered analysis of your identity files and skills.",
|
|
17228
|
+
"Optimize for clarity, efficiency, and compliance.",
|
|
17229
|
+
"",
|
|
17230
|
+
`\u2699\uFE0F Using: ${backend2} ${model2}${thinkText}`
|
|
17231
|
+
].join("\n");
|
|
17232
|
+
}
|
|
17233
|
+
function buildMainMenuKeyboard() {
|
|
17234
|
+
return [
|
|
17235
|
+
[
|
|
17236
|
+
{ label: "\u{1F9E0} Identity Audit", data: "opt:identity" },
|
|
17237
|
+
{ label: "\u{1F9E9} Skill Audit", data: "opt:skill-menu" }
|
|
17238
|
+
],
|
|
17239
|
+
[
|
|
17240
|
+
{ label: "\u274C Close", data: "opt:close" }
|
|
17241
|
+
]
|
|
17242
|
+
];
|
|
17243
|
+
}
|
|
17244
|
+
function buildModelRecommendationMessage(currentModel) {
|
|
17245
|
+
return [
|
|
17246
|
+
"\u{1F527} CC-Claw Optimizer",
|
|
17247
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17248
|
+
"",
|
|
17249
|
+
`\u26A0\uFE0F You're using ${currentModel} \u2014 for best audit results,`,
|
|
17250
|
+
"an advanced model is recommended."
|
|
17251
|
+
].join("\n");
|
|
17252
|
+
}
|
|
17253
|
+
function buildModelRecommendationKeyboard() {
|
|
17254
|
+
return [
|
|
17255
|
+
[
|
|
17256
|
+
{ label: "\u26A1 Continue anyway", data: "opt:model-ok" },
|
|
17257
|
+
{ label: "\u{1F9E0} Switch model first", data: "opt:model-switch", style: "primary" }
|
|
17258
|
+
],
|
|
17259
|
+
[
|
|
17260
|
+
{ label: "\u274C Cancel", data: "opt:close" }
|
|
17261
|
+
]
|
|
17262
|
+
];
|
|
17263
|
+
}
|
|
17264
|
+
function buildProgressMessage(target, backend2, model2, thinkingLevel) {
|
|
17265
|
+
const thinkText = thinkingLevel !== "off" ? ` | Thinking: ${thinkingLevel}` : "";
|
|
17266
|
+
return `\u{1F50D} Analyzing ${target}...
|
|
17267
|
+
Using ${backend2} ${model2}${thinkText}`;
|
|
17268
|
+
}
|
|
17269
|
+
function buildIdentityAuditSummary(result) {
|
|
17270
|
+
const { findings, tokenReport, model: model2, backend: backend2 } = result;
|
|
17271
|
+
const tr = tokenReport;
|
|
17272
|
+
const identityAreas = ["structural", "routing", "efficiency", "evolve", "quality", "completeness"];
|
|
17273
|
+
const lines = [
|
|
17274
|
+
"\u{1F9E0} Identity Audit Complete",
|
|
17275
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17276
|
+
""
|
|
17277
|
+
];
|
|
17278
|
+
for (const area of identityAreas) {
|
|
17279
|
+
const emoji = areaEmoji(area);
|
|
17280
|
+
const label2 = area.charAt(0).toUpperCase() + area.slice(1);
|
|
17281
|
+
const areaFindings = findings.filter((f) => f.area === area);
|
|
17282
|
+
const status = areaFindings.length === 0 ? "\u2705 Clean" : `\u26A0\uFE0F ${areaFindings.length} finding${areaFindings.length > 1 ? "s" : ""}`;
|
|
17283
|
+
lines.push(`${emoji} ${label2.padEnd(14)} ${status}`);
|
|
17284
|
+
}
|
|
17285
|
+
lines.push("");
|
|
17286
|
+
lines.push(`\u{1F4B0} Token footprint: ~${tr.estimatedTokens}/message`);
|
|
17287
|
+
lines.push(` (SOUL: ~${Math.ceil(tr.soulChars / 4)} + USER: ~${Math.ceil(tr.userChars / 4)} + System: ~${Math.ceil(tr.boilerplateChars / 4)})`);
|
|
17288
|
+
if (findings.length > 0) {
|
|
17289
|
+
lines.push("");
|
|
17290
|
+
lines.push(`${findings.length} finding${findings.length > 1 ? "s" : ""} to review`);
|
|
17291
|
+
} else {
|
|
17292
|
+
lines.push("");
|
|
17293
|
+
lines.push("\u2705 All checks passed \u2014 your identity files are clean!");
|
|
17294
|
+
}
|
|
17295
|
+
lines.push("");
|
|
17296
|
+
lines.push(`Analyzed by: ${backend2} ${model2}`);
|
|
17297
|
+
return lines.join("\n");
|
|
17298
|
+
}
|
|
17299
|
+
function buildIdentityAuditKeyboard(findingsCount) {
|
|
17300
|
+
if (findingsCount === 0) {
|
|
17301
|
+
return [[{ label: "\u2705 Done", data: "opt:close" }]];
|
|
17302
|
+
}
|
|
17303
|
+
return [
|
|
17304
|
+
[
|
|
17305
|
+
{ label: "\u{1F4CB} Review Findings", data: "opt:review:0", style: "primary" },
|
|
17306
|
+
{ label: "\u274C Close", data: "opt:close" }
|
|
17307
|
+
]
|
|
17308
|
+
];
|
|
17309
|
+
}
|
|
17310
|
+
function buildSkillAuditSummary(result) {
|
|
17311
|
+
const { findings, tokenReport, model: model2, backend: backend2, target } = result;
|
|
17312
|
+
const tr = tokenReport;
|
|
17313
|
+
const skillAreas = ["frontmatter", "body", "efficiency", "contradiction", "compliance"];
|
|
17314
|
+
const lines = [
|
|
17315
|
+
`\u{1F9E9} Skill Audit: ${target}`,
|
|
17316
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17317
|
+
""
|
|
17318
|
+
];
|
|
17319
|
+
for (const area of skillAreas) {
|
|
17320
|
+
const emoji = areaEmoji(area);
|
|
17321
|
+
const label2 = area.charAt(0).toUpperCase() + area.slice(1);
|
|
17322
|
+
const areaFindings = findings.filter((f) => f.area === area);
|
|
17323
|
+
const status = areaFindings.length === 0 ? "\u2705 Clean" : `\u26A0\uFE0F ${areaFindings.length} finding${areaFindings.length > 1 ? "s" : ""}`;
|
|
17324
|
+
lines.push(`${emoji} ${label2.padEnd(14)} ${status}`);
|
|
17325
|
+
}
|
|
17326
|
+
lines.push("");
|
|
17327
|
+
lines.push(`\u{1F4CA} Skill size: ${tr.lineCount} lines, ~${tr.estimatedTokens} tokens`);
|
|
17328
|
+
if (findings.length > 0) {
|
|
17329
|
+
lines.push("");
|
|
17330
|
+
lines.push(`${findings.length} finding${findings.length > 1 ? "s" : ""} to review`);
|
|
17331
|
+
} else {
|
|
17332
|
+
lines.push("");
|
|
17333
|
+
lines.push("\u2705 All checks passed \u2014 this skill is well-constructed!");
|
|
17334
|
+
}
|
|
17335
|
+
lines.push("");
|
|
17336
|
+
lines.push(`Analyzed by: ${backend2} ${model2}`);
|
|
17337
|
+
return lines.join("\n");
|
|
17338
|
+
}
|
|
17339
|
+
function buildSkillAuditKeyboard(findingsCount) {
|
|
17340
|
+
if (findingsCount === 0) {
|
|
17341
|
+
return [[{ label: "\u2705 Done", data: "opt:close" }]];
|
|
17342
|
+
}
|
|
17343
|
+
return [
|
|
17344
|
+
[
|
|
17345
|
+
{ label: "\u{1F4CB} Review Findings", data: "opt:review:0", style: "primary" },
|
|
17346
|
+
{ label: "\u274C Close", data: "opt:close" }
|
|
17347
|
+
]
|
|
17348
|
+
];
|
|
17349
|
+
}
|
|
17350
|
+
function buildFindingMessage(finding, index, total) {
|
|
17351
|
+
const lines = [
|
|
17352
|
+
`${severityEmoji(finding.severity)} Finding ${index + 1}/${total} \u2014 ${finding.area}`,
|
|
17353
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17354
|
+
"",
|
|
17355
|
+
finding.title,
|
|
17356
|
+
"",
|
|
17357
|
+
`\u{1F4CD} ${finding.location}`,
|
|
17358
|
+
"",
|
|
17359
|
+
finding.detail
|
|
17360
|
+
];
|
|
17361
|
+
if (finding.suggestion) {
|
|
17362
|
+
lines.push("");
|
|
17363
|
+
lines.push(`\u{1F4A1} ${finding.suggestion}`);
|
|
17364
|
+
}
|
|
17365
|
+
if (finding.proposedDiff) {
|
|
17366
|
+
lines.push("");
|
|
17367
|
+
lines.push("Proposed change:");
|
|
17368
|
+
lines.push("```");
|
|
17369
|
+
lines.push(finding.proposedDiff);
|
|
17370
|
+
lines.push("```");
|
|
17371
|
+
}
|
|
17372
|
+
return lines.join("\n");
|
|
17373
|
+
}
|
|
17374
|
+
function buildFindingKeyboard(index, total, hasDiff) {
|
|
17375
|
+
if (hasDiff) {
|
|
17376
|
+
return [[
|
|
17377
|
+
{ label: "\u2705 Apply Fix", data: `opt:fix:${index}`, style: "success" },
|
|
17378
|
+
{ label: "\u23ED\uFE0F Skip", data: `opt:skip:${index}` },
|
|
17379
|
+
{ label: "\u{1F6D1} Stop Review", data: "opt:stop", style: "danger" }
|
|
17380
|
+
]];
|
|
17381
|
+
}
|
|
17382
|
+
return [[
|
|
17383
|
+
{ label: "\u23ED\uFE0F Next", data: `opt:skip:${index}` },
|
|
17384
|
+
{ label: "\u{1F6D1} Stop Review", data: "opt:stop", style: "danger" }
|
|
17385
|
+
]];
|
|
17386
|
+
}
|
|
17387
|
+
function buildSkillPickerMessage(page, totalPages) {
|
|
17388
|
+
return [
|
|
17389
|
+
"\u{1F9E9} Select a Skill to Audit",
|
|
17390
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17391
|
+
"",
|
|
17392
|
+
"Showing CC-Claw skills (~/.cc-claw/workspace/skills/)",
|
|
17393
|
+
...totalPages > 1 ? [`Page ${page + 1}/${totalPages}`] : []
|
|
17394
|
+
].join("\n");
|
|
17395
|
+
}
|
|
17396
|
+
function buildSkillPickerKeyboard(skills2, page) {
|
|
17397
|
+
const totalPages = Math.ceil(skills2.length / SKILLS_PER_PAGE2);
|
|
17398
|
+
const start = page * SKILLS_PER_PAGE2;
|
|
17399
|
+
const pageSkills = skills2.slice(start, start + SKILLS_PER_PAGE2);
|
|
17400
|
+
const rows = [];
|
|
17401
|
+
for (let i = 0; i < pageSkills.length; i += 2) {
|
|
17402
|
+
const row = [];
|
|
17403
|
+
row.push({ label: pageSkills[i].name, data: `opt:skill-pick:${pageSkills[i].name}` });
|
|
17404
|
+
if (pageSkills[i + 1]) {
|
|
17405
|
+
row.push({ label: pageSkills[i + 1].name, data: `opt:skill-pick:${pageSkills[i + 1].name}` });
|
|
17406
|
+
}
|
|
17407
|
+
rows.push(row);
|
|
17408
|
+
}
|
|
17409
|
+
const navRow = [];
|
|
17410
|
+
if (page > 0) navRow.push({ label: "\u2190 Prev", data: `opt:skill-page:${page - 1}` });
|
|
17411
|
+
if (page < totalPages - 1) navRow.push({ label: "Next \u2192", data: `opt:skill-page:${page + 1}` });
|
|
17412
|
+
navRow.push({ label: "\u274C Cancel", data: "opt:close" });
|
|
17413
|
+
rows.push(navRow);
|
|
17414
|
+
return rows;
|
|
17415
|
+
}
|
|
17416
|
+
function buildReviewCompleteMessage2(applied, skipped, total) {
|
|
17417
|
+
return [
|
|
17418
|
+
"\u{1F527} Review Complete",
|
|
17419
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17420
|
+
"",
|
|
17421
|
+
`\u2705 Applied: ${applied}`,
|
|
17422
|
+
`\u23ED\uFE0F Skipped: ${skipped}`,
|
|
17423
|
+
`\u{1F4CA} Total findings: ${total}`
|
|
17424
|
+
].join("\n");
|
|
17425
|
+
}
|
|
17426
|
+
function buildReviewCompleteKeyboard() {
|
|
17427
|
+
return [[{ label: "\u2705 Done", data: "opt:close" }]];
|
|
17428
|
+
}
|
|
17429
|
+
var SKILLS_PER_PAGE2;
|
|
17430
|
+
var init_ui2 = __esm({
|
|
17431
|
+
"src/optimizer/ui.ts"() {
|
|
17432
|
+
"use strict";
|
|
17433
|
+
SKILLS_PER_PAGE2 = 6;
|
|
17434
|
+
}
|
|
17435
|
+
});
|
|
17436
|
+
|
|
17437
|
+
// src/router/optimize.ts
|
|
17438
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, existsSync as existsSync22 } from "fs";
|
|
17439
|
+
import { join as join23 } from "path";
|
|
17440
|
+
import { homedir as homedir8 } from "os";
|
|
17441
|
+
async function handleOptimizeCommand(chatId, channel, _args) {
|
|
17442
|
+
const { getModelDisplayInfo: getModelDisplayInfo2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17443
|
+
const {
|
|
17444
|
+
buildMainMenuMessage: buildMainMenuMessage2,
|
|
17445
|
+
buildMainMenuKeyboard: buildMainMenuKeyboard2,
|
|
17446
|
+
buildModelRecommendationMessage: buildModelRecommendationMessage2,
|
|
17447
|
+
buildModelRecommendationKeyboard: buildModelRecommendationKeyboard2
|
|
17448
|
+
} = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17449
|
+
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17450
|
+
if (!modelInfo) {
|
|
17451
|
+
await channel.sendText(chatId, "No AI backend available. Configure one first.", { parseMode: "plain" });
|
|
17452
|
+
return;
|
|
17453
|
+
}
|
|
17454
|
+
if (modelInfo.isWeak) {
|
|
17455
|
+
const msg2 = buildModelRecommendationMessage2(modelInfo.model);
|
|
17456
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17457
|
+
await channel.sendKeyboard(chatId, msg2, buildModelRecommendationKeyboard2());
|
|
17458
|
+
} else {
|
|
17459
|
+
await channel.sendText(chatId, msg2 + "\n\nSwitch to an advanced model for best results.", { parseMode: "plain" });
|
|
17460
|
+
}
|
|
17461
|
+
return;
|
|
17462
|
+
}
|
|
17463
|
+
const msg = buildMainMenuMessage2(modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel);
|
|
17464
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17465
|
+
await channel.sendKeyboard(chatId, msg, buildMainMenuKeyboard2());
|
|
17466
|
+
} else {
|
|
17467
|
+
await channel.sendText(chatId, msg, { parseMode: "plain" });
|
|
17468
|
+
}
|
|
17469
|
+
}
|
|
17470
|
+
async function handleOptimizeCallback(chatId, data, channel) {
|
|
17471
|
+
const parts = data.split(":");
|
|
17472
|
+
const action = parts[1];
|
|
17473
|
+
switch (action) {
|
|
17474
|
+
case "identity": {
|
|
17475
|
+
await runIdentityAuditFlow(chatId, channel);
|
|
17476
|
+
break;
|
|
17477
|
+
}
|
|
17478
|
+
case "skill-menu": {
|
|
17479
|
+
await showSkillPicker(chatId, channel, 0);
|
|
17480
|
+
break;
|
|
17481
|
+
}
|
|
17482
|
+
case "skill-page": {
|
|
17483
|
+
const page = parseInt(parts[2], 10) || 0;
|
|
17484
|
+
await showSkillPicker(chatId, channel, page);
|
|
17485
|
+
break;
|
|
17486
|
+
}
|
|
17487
|
+
case "skill-pick": {
|
|
17488
|
+
const skillName = parts.slice(2).join(":");
|
|
17489
|
+
await runSkillAuditFlow(chatId, channel, skillName);
|
|
17490
|
+
break;
|
|
17491
|
+
}
|
|
17492
|
+
case "model-ok": {
|
|
17493
|
+
const { getModelDisplayInfo: getModelDisplayInfo2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17494
|
+
const { buildMainMenuMessage: buildMainMenuMessage2, buildMainMenuKeyboard: buildMainMenuKeyboard2 } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17495
|
+
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17496
|
+
if (!modelInfo) return;
|
|
17497
|
+
const msg = buildMainMenuMessage2(modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel);
|
|
17498
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17499
|
+
await channel.sendKeyboard(chatId, msg, buildMainMenuKeyboard2());
|
|
17500
|
+
}
|
|
17501
|
+
break;
|
|
17502
|
+
}
|
|
17503
|
+
case "model-switch": {
|
|
17504
|
+
await channel.sendText(chatId, "Use /model or /backend to switch to a more powerful model, then run /optimize again.", { parseMode: "plain" });
|
|
17505
|
+
break;
|
|
17506
|
+
}
|
|
17507
|
+
case "review": {
|
|
17508
|
+
const index = parseInt(parts[2], 10) || 0;
|
|
17509
|
+
await showFinding(chatId, channel, index);
|
|
17510
|
+
break;
|
|
17511
|
+
}
|
|
17512
|
+
case "fix": {
|
|
17513
|
+
const fixIndex = parseInt(parts[2], 10) || 0;
|
|
17514
|
+
await applyFinding(chatId, channel, fixIndex);
|
|
17515
|
+
break;
|
|
17516
|
+
}
|
|
17517
|
+
case "skip": {
|
|
17518
|
+
const skipIndex = parseInt(parts[2], 10) || 0;
|
|
17519
|
+
await skipFinding(chatId, channel, skipIndex);
|
|
17520
|
+
break;
|
|
17521
|
+
}
|
|
17522
|
+
case "stop": {
|
|
17523
|
+
await stopReview(chatId, channel);
|
|
17524
|
+
break;
|
|
17525
|
+
}
|
|
17526
|
+
case "close": {
|
|
17527
|
+
activeSessions.delete(chatId);
|
|
17528
|
+
await channel.sendText(chatId, "Optimizer closed.", { parseMode: "plain" });
|
|
17529
|
+
break;
|
|
17530
|
+
}
|
|
17531
|
+
default:
|
|
17532
|
+
break;
|
|
17533
|
+
}
|
|
17534
|
+
}
|
|
17535
|
+
async function runIdentityAuditFlow(chatId, channel) {
|
|
17536
|
+
const { getModelDisplayInfo: getModelDisplayInfo2, runIdentityAudit: runIdentityAudit2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17537
|
+
const {
|
|
17538
|
+
buildProgressMessage: buildProgressMessage2,
|
|
17539
|
+
buildIdentityAuditSummary: buildIdentityAuditSummary2,
|
|
17540
|
+
buildIdentityAuditKeyboard: buildIdentityAuditKeyboard2
|
|
17541
|
+
} = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17542
|
+
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17543
|
+
if (!modelInfo) return;
|
|
17544
|
+
await channel.sendText(
|
|
17545
|
+
chatId,
|
|
17546
|
+
buildProgressMessage2("identity files", modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
|
|
17547
|
+
{ parseMode: "plain" }
|
|
17548
|
+
);
|
|
17549
|
+
try {
|
|
17550
|
+
const result = await runIdentityAudit2(chatId);
|
|
17551
|
+
activeSessions.set(chatId, {
|
|
17552
|
+
chatId,
|
|
17553
|
+
result,
|
|
17554
|
+
currentIndex: 0,
|
|
17555
|
+
applied: [],
|
|
17556
|
+
skipped: []
|
|
17557
|
+
});
|
|
17558
|
+
const summary = buildIdentityAuditSummary2(result);
|
|
17559
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17560
|
+
await channel.sendKeyboard(chatId, summary, buildIdentityAuditKeyboard2(result.findings.length));
|
|
17561
|
+
} else {
|
|
17562
|
+
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
17563
|
+
}
|
|
17564
|
+
} catch (e) {
|
|
17565
|
+
await channel.sendText(chatId, `Identity audit failed: ${e}`, { parseMode: "plain" });
|
|
17566
|
+
}
|
|
17567
|
+
}
|
|
17568
|
+
async function showSkillPicker(chatId, channel, page) {
|
|
17569
|
+
const { listCcClawSkills: listCcClawSkills2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17570
|
+
const { buildSkillPickerMessage: buildSkillPickerMessage2, buildSkillPickerKeyboard: buildSkillPickerKeyboard2 } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17571
|
+
const skills2 = listCcClawSkills2();
|
|
17572
|
+
if (skills2.length === 0) {
|
|
17573
|
+
await channel.sendText(chatId, "No CC-Claw skills found in ~/.cc-claw/workspace/skills/", { parseMode: "plain" });
|
|
17574
|
+
return;
|
|
17575
|
+
}
|
|
17576
|
+
const totalPages = Math.ceil(skills2.length / 6);
|
|
17577
|
+
const msg = buildSkillPickerMessage2(page, totalPages);
|
|
17578
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17579
|
+
await channel.sendKeyboard(chatId, msg, buildSkillPickerKeyboard2(skills2, page));
|
|
17580
|
+
} else {
|
|
17581
|
+
const list = skills2.map((s) => `\u2022 ${s.name} \u2014 ${s.description}`).join("\n");
|
|
17582
|
+
await channel.sendText(chatId, msg + "\n\n" + list, { parseMode: "plain" });
|
|
17583
|
+
}
|
|
17584
|
+
}
|
|
17585
|
+
async function runSkillAuditFlow(chatId, channel, skillName) {
|
|
17586
|
+
const { getModelDisplayInfo: getModelDisplayInfo2, runSkillAudit: runSkillAudit2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17587
|
+
const {
|
|
17588
|
+
buildProgressMessage: buildProgressMessage2,
|
|
17589
|
+
buildSkillAuditSummary: buildSkillAuditSummary2,
|
|
17590
|
+
buildSkillAuditKeyboard: buildSkillAuditKeyboard2
|
|
17591
|
+
} = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17592
|
+
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17593
|
+
if (!modelInfo) return;
|
|
17594
|
+
const skillPath = join23(homedir8(), ".cc-claw", "workspace", "skills", skillName, "SKILL.md");
|
|
17595
|
+
await channel.sendText(
|
|
17596
|
+
chatId,
|
|
17597
|
+
buildProgressMessage2(`skill: ${skillName}`, modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
|
|
17598
|
+
{ parseMode: "plain" }
|
|
17599
|
+
);
|
|
17600
|
+
try {
|
|
17601
|
+
const result = await runSkillAudit2(chatId, skillPath);
|
|
17602
|
+
activeSessions.set(chatId, {
|
|
17603
|
+
chatId,
|
|
17604
|
+
result,
|
|
17605
|
+
currentIndex: 0,
|
|
17606
|
+
applied: [],
|
|
17607
|
+
skipped: []
|
|
17608
|
+
});
|
|
17609
|
+
const summary = buildSkillAuditSummary2(result);
|
|
17610
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17611
|
+
await channel.sendKeyboard(chatId, summary, buildSkillAuditKeyboard2(result.findings.length));
|
|
17612
|
+
} else {
|
|
17613
|
+
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
17614
|
+
}
|
|
17615
|
+
} catch (e) {
|
|
17616
|
+
await channel.sendText(chatId, `Skill audit failed: ${e}`, { parseMode: "plain" });
|
|
17617
|
+
}
|
|
17618
|
+
}
|
|
17619
|
+
async function showFinding(chatId, channel, index) {
|
|
17620
|
+
const session2 = activeSessions.get(chatId);
|
|
17621
|
+
if (!session2) {
|
|
17622
|
+
await channel.sendText(chatId, "No active optimizer session. Run /optimize first.", { parseMode: "plain" });
|
|
17623
|
+
return;
|
|
17624
|
+
}
|
|
17625
|
+
const { findings } = session2.result;
|
|
17626
|
+
if (index >= findings.length) {
|
|
17627
|
+
await finishReview(chatId, channel);
|
|
17628
|
+
return;
|
|
17629
|
+
}
|
|
17630
|
+
session2.currentIndex = index;
|
|
17631
|
+
const finding = findings[index];
|
|
17632
|
+
const { buildFindingMessage: buildFindingMessage2, buildFindingKeyboard: buildFindingKeyboard2 } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17633
|
+
const msg = buildFindingMessage2(finding, index, findings.length);
|
|
17634
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17635
|
+
await channel.sendKeyboard(chatId, msg, buildFindingKeyboard2(index, findings.length, !!finding.proposedDiff));
|
|
17636
|
+
} else {
|
|
17637
|
+
await channel.sendText(chatId, msg, { parseMode: "plain" });
|
|
17638
|
+
}
|
|
17639
|
+
}
|
|
17640
|
+
async function applyFinding(chatId, channel, index) {
|
|
17641
|
+
const session2 = activeSessions.get(chatId);
|
|
17642
|
+
if (!session2) return;
|
|
17643
|
+
const finding = session2.result.findings[index];
|
|
17644
|
+
if (!finding || !finding.proposedDiff) {
|
|
17645
|
+
await channel.sendText(chatId, "No diff to apply for this finding.", { parseMode: "plain" });
|
|
17646
|
+
await showFinding(chatId, channel, index + 1);
|
|
17647
|
+
return;
|
|
17648
|
+
}
|
|
17649
|
+
try {
|
|
17650
|
+
const targetPath = resolveTargetFile(finding.location, session2.result.target);
|
|
17651
|
+
if (!targetPath) {
|
|
17652
|
+
await channel.sendText(chatId, `Cannot determine target file from location: ${finding.location}`, { parseMode: "plain" });
|
|
17653
|
+
session2.skipped.push(index);
|
|
17654
|
+
await showFinding(chatId, channel, index + 1);
|
|
17655
|
+
return;
|
|
17656
|
+
}
|
|
17657
|
+
if (!existsSync22(targetPath)) {
|
|
17658
|
+
await channel.sendText(chatId, `Target file not found: ${targetPath}`, { parseMode: "plain" });
|
|
17659
|
+
session2.skipped.push(index);
|
|
17660
|
+
await showFinding(chatId, channel, index + 1);
|
|
17661
|
+
return;
|
|
17662
|
+
}
|
|
17663
|
+
const original = readFileSync13(targetPath, "utf-8");
|
|
17664
|
+
const backupPath = targetPath + `.bak.${Date.now()}`;
|
|
17665
|
+
writeFileSync7(backupPath, original, "utf-8");
|
|
17666
|
+
pruneBackups2(targetPath);
|
|
17667
|
+
const { applyDiff: applyDiff2 } = await Promise.resolve().then(() => (init_apply(), apply_exports));
|
|
17668
|
+
const newContent = applyDiff2(original, finding.proposedDiff, "replace");
|
|
17669
|
+
if (newContent === original) {
|
|
17670
|
+
await channel.sendText(chatId, `\u26A0\uFE0F Diff produced no changes. The content may have already been modified.`, { parseMode: "plain" });
|
|
17671
|
+
session2.skipped.push(index);
|
|
17672
|
+
await showFinding(chatId, channel, index + 1);
|
|
17673
|
+
return;
|
|
17674
|
+
}
|
|
17675
|
+
writeFileSync7(targetPath, newContent, "utf-8");
|
|
17676
|
+
session2.applied.push(index);
|
|
17677
|
+
if (targetPath.includes("identity/")) {
|
|
17678
|
+
try {
|
|
17679
|
+
const { syncNativeCliFiles: syncNativeCliFiles2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
17680
|
+
await syncNativeCliFiles2();
|
|
17681
|
+
} catch {
|
|
17682
|
+
}
|
|
17683
|
+
}
|
|
17684
|
+
await channel.sendText(chatId, `\u2705 Applied: ${finding.title}`, { parseMode: "plain" });
|
|
17685
|
+
} catch (e) {
|
|
17686
|
+
const errorMsg = e?.message ?? String(e);
|
|
17687
|
+
await channel.sendText(chatId, `\u274C Failed to apply fix: ${errorMsg}`, { parseMode: "plain" });
|
|
17688
|
+
session2.skipped.push(index);
|
|
17689
|
+
}
|
|
17690
|
+
await showFinding(chatId, channel, index + 1);
|
|
17691
|
+
}
|
|
17692
|
+
async function skipFinding(chatId, channel, index) {
|
|
17693
|
+
const session2 = activeSessions.get(chatId);
|
|
17694
|
+
if (!session2) return;
|
|
17695
|
+
session2.skipped.push(index);
|
|
17696
|
+
await showFinding(chatId, channel, index + 1);
|
|
17697
|
+
}
|
|
17698
|
+
async function stopReview(chatId, channel) {
|
|
17699
|
+
await finishReview(chatId, channel);
|
|
17700
|
+
}
|
|
17701
|
+
async function finishReview(chatId, channel) {
|
|
17702
|
+
const session2 = activeSessions.get(chatId);
|
|
17703
|
+
if (!session2) return;
|
|
17704
|
+
const { buildReviewCompleteMessage: buildReviewCompleteMessage3, buildReviewCompleteKeyboard: buildReviewCompleteKeyboard2 } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17705
|
+
const msg = buildReviewCompleteMessage3(
|
|
17706
|
+
session2.applied.length,
|
|
17707
|
+
session2.skipped.length,
|
|
17708
|
+
session2.result.findings.length
|
|
17709
|
+
);
|
|
17710
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17711
|
+
await channel.sendKeyboard(chatId, msg, buildReviewCompleteKeyboard2());
|
|
17712
|
+
} else {
|
|
17713
|
+
await channel.sendText(chatId, msg, { parseMode: "plain" });
|
|
17714
|
+
}
|
|
17715
|
+
activeSessions.delete(chatId);
|
|
17716
|
+
}
|
|
17717
|
+
function resolveTargetFile(location, auditTarget) {
|
|
17718
|
+
const ccClawHome = join23(homedir8(), ".cc-claw");
|
|
17719
|
+
const filePart = location.split(":")[0]?.trim();
|
|
17720
|
+
if (!filePart) return null;
|
|
17721
|
+
if (filePart === "SOUL.md") return join23(ccClawHome, "identity", "SOUL.md");
|
|
17722
|
+
if (filePart === "USER.md") return join23(ccClawHome, "identity", "USER.md");
|
|
17723
|
+
if (filePart === "CC-CLAW.md") return join23(ccClawHome, "identity", "CC-CLAW.md");
|
|
17724
|
+
if (filePart === "SKILL.md" && auditTarget !== "identity") {
|
|
17725
|
+
return join23(ccClawHome, "workspace", "skills", auditTarget, "SKILL.md");
|
|
17726
|
+
}
|
|
17727
|
+
return null;
|
|
17728
|
+
}
|
|
17729
|
+
function pruneBackups2(absolutePath) {
|
|
17730
|
+
const { readdirSync: readDir, unlinkSync: unlink4 } = __require("fs");
|
|
17731
|
+
const { dirname: dirName } = __require("path");
|
|
17732
|
+
const dir = dirName(absolutePath);
|
|
17733
|
+
const baseName = absolutePath.split("/").pop() ?? "";
|
|
17734
|
+
try {
|
|
17735
|
+
const backups = readDir(dir).filter((f) => f.startsWith(baseName + ".bak.")).sort().map((f) => join23(dir, f));
|
|
17736
|
+
while (backups.length > 3) {
|
|
17737
|
+
const oldest = backups.shift();
|
|
17738
|
+
try {
|
|
17739
|
+
unlink4(oldest);
|
|
17740
|
+
} catch {
|
|
17741
|
+
}
|
|
17742
|
+
}
|
|
17743
|
+
} catch {
|
|
17744
|
+
}
|
|
17745
|
+
}
|
|
17746
|
+
var activeSessions;
|
|
17747
|
+
var init_optimize = __esm({
|
|
17748
|
+
"src/router/optimize.ts"() {
|
|
17749
|
+
"use strict";
|
|
17750
|
+
activeSessions = /* @__PURE__ */ new Map();
|
|
17751
|
+
}
|
|
17752
|
+
});
|
|
17753
|
+
|
|
17754
|
+
// src/router/commands.ts
|
|
17755
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
17756
|
+
async function handleCommand(msg, channel) {
|
|
17757
|
+
const { chatId, command, commandArgs } = msg;
|
|
17758
|
+
if (command?.startsWith("/")) {
|
|
17759
|
+
return handleBackendCommand(command, chatId, channel);
|
|
17760
|
+
}
|
|
17761
|
+
switch (command) {
|
|
17762
|
+
case "start":
|
|
17763
|
+
case "help": {
|
|
17764
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17765
|
+
await sendHelpCategories(chatId, channel);
|
|
17766
|
+
} else {
|
|
17767
|
+
await channel.sendText(
|
|
17768
|
+
chatId,
|
|
17769
|
+
"CC-Claw Commands\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n" + Object.entries(HELP_CATEGORIES).map(
|
|
17770
|
+
([cat, cmds]) => `${cat}:
|
|
17771
|
+
${cmds.map((c) => ` ${c.cmd} \u2014 ${c.desc}`).join("\n")}`
|
|
17772
|
+
).join("\n\n"),
|
|
17773
|
+
{ parseMode: "plain" }
|
|
17774
|
+
);
|
|
17775
|
+
}
|
|
17776
|
+
break;
|
|
17777
|
+
}
|
|
17778
|
+
case "menu":
|
|
17779
|
+
case "m": {
|
|
17780
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17781
|
+
const header2 = `\u{1F43E} ${buildSectionHeader("CC-Claw")}`;
|
|
17782
|
+
await channel.sendKeyboard(chatId, header2, [
|
|
17783
|
+
[{ label: "New Chat", data: "menu:newchat" }, { label: "Status", data: "menu:status" }],
|
|
17784
|
+
[{ label: "Backend", data: "menu:backend" }, { label: "Model", data: "menu:model" }],
|
|
17785
|
+
[{ label: "Jobs", data: "menu:jobs" }, { label: "Memory", data: "menu:memory" }],
|
|
17786
|
+
[{ label: "History", data: "menu:history" }, { label: "Help", data: "menu:help" }]
|
|
17787
|
+
]);
|
|
17788
|
+
} else {
|
|
17789
|
+
await channel.sendText(
|
|
17790
|
+
chatId,
|
|
17791
|
+
"CC-Claw Menu:\n/newchat \xB7 /status \xB7 /backend \xB7 /model\n/jobs \xB7 /memory \xB7 /history \xB7 /help",
|
|
17792
|
+
{ parseMode: "plain" }
|
|
17793
|
+
);
|
|
17794
|
+
}
|
|
17795
|
+
break;
|
|
17796
|
+
}
|
|
17797
|
+
case "stop": {
|
|
17798
|
+
const stopped = stopAgent(chatId);
|
|
17799
|
+
stopAllSideQuests(chatId);
|
|
17800
|
+
cancelAllAgents(chatId);
|
|
17801
|
+
await channel.sendText(
|
|
17802
|
+
chatId,
|
|
17803
|
+
stopped ? "Stopping current task..." : "Nothing is running.",
|
|
17804
|
+
{ parseMode: "plain" }
|
|
17805
|
+
);
|
|
17806
|
+
if (stopped && typeof channel.sendKeyboard === "function") {
|
|
17807
|
+
await channel.sendKeyboard(chatId, "", [
|
|
17808
|
+
[{ label: "\u{1F195} New Chat", data: "menu:newchat" }]
|
|
17809
|
+
]);
|
|
17810
|
+
}
|
|
17811
|
+
break;
|
|
17812
|
+
}
|
|
17813
|
+
case "permissions": {
|
|
17814
|
+
const currentMode = getMode(chatId);
|
|
17815
|
+
const currentExecMode = getExecMode(chatId);
|
|
17816
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17817
|
+
const permButtons = Object.entries(PERM_MODES).map(([id, label2]) => [{
|
|
17818
|
+
label: `${id === currentMode ? "\u2713 " : ""}${label2}`,
|
|
17819
|
+
data: `perms:${id}`,
|
|
17820
|
+
...id === currentMode ? { style: "primary" } : {}
|
|
17821
|
+
}]);
|
|
17822
|
+
const approvalOn = currentExecMode === "approved";
|
|
17823
|
+
permButtons.push([{
|
|
17824
|
+
label: `${approvalOn ? "\u2713 " : ""}\u{1F512} Approve Before Execute: ${approvalOn ? "ON" : "OFF"}`,
|
|
17825
|
+
data: `execmode:${approvalOn ? "yolo" : "approved"}`,
|
|
17826
|
+
...approvalOn ? { style: "primary" } : {}
|
|
17827
|
+
}]);
|
|
17828
|
+
await channel.sendKeyboard(chatId, "Permission & Execution Settings:", permButtons);
|
|
17829
|
+
} else {
|
|
17830
|
+
const lines = ["Permission modes:", ""];
|
|
17831
|
+
for (const [id, label2] of Object.entries(PERM_MODES)) {
|
|
17832
|
+
lines.push(`${id === currentMode ? "\u2713 " : " "}/permissions ${id} \u2014 ${label2}`);
|
|
17833
|
+
}
|
|
17834
|
+
lines.push("");
|
|
17835
|
+
lines.push(`Approve Before Execute: ${currentExecMode === "approved" ? "ON" : "OFF"}`);
|
|
17836
|
+
await channel.sendText(chatId, lines.join("\n"), { parseMode: "plain" });
|
|
17837
|
+
}
|
|
17838
|
+
break;
|
|
17839
|
+
}
|
|
17840
|
+
case "verbose": {
|
|
16417
17841
|
const currentVerbose = getVerboseLevel(chatId);
|
|
16418
17842
|
const buttons = Object.entries(VERBOSE_LEVELS).map(([id, label2]) => [{
|
|
16419
17843
|
label: `${id === currentVerbose ? "\u2713 " : ""}${label2}`,
|
|
@@ -16971,8 +18395,8 @@ ${lines.join("\n")}`, { parseMode: "plain" });
|
|
|
16971
18395
|
if (arg.startsWith("/") || arg.startsWith("~")) {
|
|
16972
18396
|
const resolvedPath = arg.startsWith("~") ? arg.replace("~", process.env.HOME ?? "") : arg;
|
|
16973
18397
|
setCwd(chatId, resolvedPath);
|
|
16974
|
-
const
|
|
16975
|
-
if (
|
|
18398
|
+
const basename3 = resolvedPath.split("/").filter(Boolean).pop();
|
|
18399
|
+
if (basename3) upsertBookmark(chatId, basename3, resolvedPath, false);
|
|
16976
18400
|
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Working directory set to ${resolvedPath}`, detail: { field: "cwd", value: resolvedPath } });
|
|
16977
18401
|
await sendCwdSessionChoice(chatId, resolvedPath, channel);
|
|
16978
18402
|
return;
|
|
@@ -17133,20 +18557,29 @@ Use /model to pick a model with \u26A1 thinking support.`, { parseMode: "plain"
|
|
|
17133
18557
|
break;
|
|
17134
18558
|
}
|
|
17135
18559
|
if (typeof channel.sendKeyboard === "function") {
|
|
18560
|
+
const showThinkingUi = getShowThinkingUi(chatId);
|
|
17136
18561
|
const buttons = modelInfo.thinkingLevels.map((level) => [{
|
|
17137
18562
|
label: `${level === currentLevel ? "\u2713 " : ""}${level === "auto" ? "Auto" : capitalize(level)}`,
|
|
17138
18563
|
data: `thinking:${level}`,
|
|
17139
18564
|
...level === currentLevel ? { style: "primary" } : {}
|
|
17140
18565
|
}]);
|
|
18566
|
+
buttons.push([{
|
|
18567
|
+
label: `${showThinkingUi ? "\u2713 " : ""}\u{1F4AD} Show Thinking`,
|
|
18568
|
+
data: "thinking_show_ui:toggle",
|
|
18569
|
+
...showThinkingUi ? { style: "primary" } : {}
|
|
18570
|
+
}]);
|
|
17141
18571
|
await channel.sendKeyboard(
|
|
17142
18572
|
chatId,
|
|
17143
18573
|
`\u{1F4AD} Thinking Level \u2014 ${shortModelName(currentModel)}
|
|
17144
|
-
Current: ${capitalize(currentLevel)}
|
|
18574
|
+
Current: ${capitalize(currentLevel)}
|
|
18575
|
+
Show thinking tokens: ${showThinkingUi ? "On" : "Off"}${adapter.id === "gemini" ? "\n\n\u26A0\uFE0F Gemini CLI doesn't stream thinking tokens" : ""}`,
|
|
17145
18576
|
buttons
|
|
17146
18577
|
);
|
|
17147
18578
|
} else {
|
|
18579
|
+
const showThinkingUi = getShowThinkingUi(chatId);
|
|
17148
18580
|
await channel.sendText(chatId, `Thinking: ${capitalize(currentLevel)}
|
|
17149
18581
|
Levels: ${modelInfo.thinkingLevels.join(", ")}
|
|
18582
|
+
Show thinking tokens: ${showThinkingUi ? "On" : "Off"}
|
|
17150
18583
|
Set via callback (keyboard required).`, { parseMode: "plain" });
|
|
17151
18584
|
}
|
|
17152
18585
|
break;
|
|
@@ -17744,8 +19177,8 @@ ${agentLines.join("\n")}`, buttons);
|
|
|
17744
19177
|
lines.push(` \u2705 <b>cc-claw</b> <i>Agent orchestrator (spawn, tasks, inbox)</i>`);
|
|
17745
19178
|
}
|
|
17746
19179
|
const { execFile: execFile5 } = await import("child_process");
|
|
17747
|
-
const { homedir:
|
|
17748
|
-
const discoveryCwd =
|
|
19180
|
+
const { homedir: homedir12 } = await import("os");
|
|
19181
|
+
const discoveryCwd = homedir12();
|
|
17749
19182
|
const runnerResults = await Promise.allSettled(
|
|
17750
19183
|
getAllRunners().map((runner) => {
|
|
17751
19184
|
const listCmd = runner.getMcpListCommand();
|
|
@@ -17887,6 +19320,10 @@ Message: "${testMsg}"`, { parseMode: "plain" });
|
|
|
17887
19320
|
await handleEvolveCommand(chatId, channel);
|
|
17888
19321
|
break;
|
|
17889
19322
|
}
|
|
19323
|
+
case "optimize": {
|
|
19324
|
+
await handleOptimizeCommand(chatId, channel, commandArgs);
|
|
19325
|
+
break;
|
|
19326
|
+
}
|
|
17890
19327
|
default:
|
|
17891
19328
|
await channel.sendText(chatId, `Unknown command: /${command}. Type /help for available commands.`, { parseMode: "plain" });
|
|
17892
19329
|
}
|
|
@@ -17925,6 +19362,7 @@ var init_commands = __esm({
|
|
|
17925
19362
|
init_ui();
|
|
17926
19363
|
init_state();
|
|
17927
19364
|
init_evolve2();
|
|
19365
|
+
init_optimize();
|
|
17928
19366
|
}
|
|
17929
19367
|
});
|
|
17930
19368
|
|
|
@@ -18046,6 +19484,21 @@ Select thinking/effort level:`,
|
|
|
18046
19484
|
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Thinking level set to ${level}`, detail: { field: "thinking", value: level } });
|
|
18047
19485
|
const label2 = level === "auto" ? "Auto" : level.replace("_", " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
18048
19486
|
await channel.sendText(chatId, `Thinking level set to: ${label2}`, { parseMode: "plain" });
|
|
19487
|
+
} else if (data === "thinking_show_ui:toggle") {
|
|
19488
|
+
const newState = toggleShowThinkingUi(chatId);
|
|
19489
|
+
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Show thinking UI ${newState ? "enabled" : "disabled"}`, detail: { field: "show_thinking_ui", value: String(newState) } });
|
|
19490
|
+
let msg;
|
|
19491
|
+
if (newState) {
|
|
19492
|
+
let backendId;
|
|
19493
|
+
try {
|
|
19494
|
+
backendId = getAdapterForChat(chatId).id;
|
|
19495
|
+
} catch {
|
|
19496
|
+
}
|
|
19497
|
+
msg = backendId === "gemini" ? "\u{1F4AD} Thinking tokens enabled \u2014 but Gemini CLI doesn't stream them." : "\u{1F4AD} Thinking tokens will now stream live in the status message.";
|
|
19498
|
+
} else {
|
|
19499
|
+
msg = "\u{1F4AD} Thinking tokens hidden. Toggle on again via /thinking.";
|
|
19500
|
+
}
|
|
19501
|
+
await channel.sendText(chatId, msg, { parseMode: "plain" });
|
|
18049
19502
|
} else if (data.startsWith("summarizer:")) {
|
|
18050
19503
|
const rest = data.slice(11);
|
|
18051
19504
|
if (rest === "auto") {
|
|
@@ -18144,9 +19597,12 @@ ${PERM_MODES[chosen]}`,
|
|
|
18144
19597
|
}
|
|
18145
19598
|
removePendingPlan(chatId);
|
|
18146
19599
|
await channel.sendText(chatId, "\u2705 Approved. Executing...", { parseMode: "plain" });
|
|
19600
|
+
bypassBusyCheck.add(chatId);
|
|
18147
19601
|
const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router(), router_exports));
|
|
19602
|
+
const overrideMsg = `[SYSTEM: Planning mode disabled. Execution APPROVED. Please execute the plan.]
|
|
19603
|
+
${plan.originalMessage}`;
|
|
18148
19604
|
await handleMessage2(
|
|
18149
|
-
{ text: `>>${
|
|
19605
|
+
{ text: `>>${overrideMsg}`, chatId, source: "telegram", type: "text", senderName: "", messageId: "" },
|
|
18150
19606
|
channel
|
|
18151
19607
|
);
|
|
18152
19608
|
return;
|
|
@@ -18169,9 +19625,12 @@ ${PERM_MODES[chosen]}`,
|
|
|
18169
19625
|
removePendingPlan(chatId);
|
|
18170
19626
|
setExecMode(chatId, "yolo");
|
|
18171
19627
|
await channel.sendText(chatId, "\u26A1 Switched to YOLO mode. Executing without approval gate...", { parseMode: "plain" });
|
|
19628
|
+
bypassBusyCheck.add(chatId);
|
|
18172
19629
|
const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router(), router_exports));
|
|
19630
|
+
const overrideMsg = `[SYSTEM: Planning mode disabled. YOLO mode enabled. Proceed immediately without asking for approval.]
|
|
19631
|
+
${plan.originalMessage}`;
|
|
18173
19632
|
await handleMessage2(
|
|
18174
|
-
{ text: `>>${
|
|
19633
|
+
{ text: `>>${overrideMsg}`, chatId, source: "telegram", type: "text", senderName: "", messageId: "" },
|
|
18175
19634
|
channel
|
|
18176
19635
|
);
|
|
18177
19636
|
return;
|
|
@@ -18179,9 +19638,8 @@ ${PERM_MODES[chosen]}`,
|
|
|
18179
19638
|
const mode = data.split(":")[1];
|
|
18180
19639
|
if (mode === "approved" || mode === "yolo") {
|
|
18181
19640
|
setExecMode(chatId, mode);
|
|
18182
|
-
const
|
|
18183
|
-
await channel.sendText(chatId,
|
|
18184
|
-
${desc}`, { parseMode: "html" });
|
|
19641
|
+
const msg = mode === "approved" ? "\u{1F512} Approve Before Execute: <b>ON</b>\nAI will show a plan for your approval before acting." : "\u26A1 Approve Before Execute: <b>OFF</b>\nAI will execute immediately (YOLO mode).";
|
|
19642
|
+
await channel.sendText(chatId, msg, { parseMode: "html" });
|
|
18185
19643
|
}
|
|
18186
19644
|
return;
|
|
18187
19645
|
} else if (data.startsWith("model_sig:")) {
|
|
@@ -18611,6 +20069,9 @@ ${rotationNote}`, { parseMode: "html" });
|
|
|
18611
20069
|
} else if (data.startsWith("reflect:")) {
|
|
18612
20070
|
await handleReflectCallback(chatId, data, channel);
|
|
18613
20071
|
return;
|
|
20072
|
+
} else if (data.startsWith("opt:")) {
|
|
20073
|
+
await handleOptimizeCallback(chatId, data, channel);
|
|
20074
|
+
return;
|
|
18614
20075
|
} else if (data.startsWith("summ:")) {
|
|
18615
20076
|
const action = data.slice(5);
|
|
18616
20077
|
if (action === "all") {
|
|
@@ -18951,10 +20412,216 @@ var init_callbacks = __esm({
|
|
|
18951
20412
|
init_state();
|
|
18952
20413
|
init_sidequest();
|
|
18953
20414
|
init_evolve2();
|
|
20415
|
+
init_optimize();
|
|
18954
20416
|
init_commands();
|
|
18955
20417
|
}
|
|
18956
20418
|
});
|
|
18957
20419
|
|
|
20420
|
+
// src/router/live-status.ts
|
|
20421
|
+
var live_status_exports = {};
|
|
20422
|
+
__export(live_status_exports, {
|
|
20423
|
+
LiveStatusMessage: () => LiveStatusMessage,
|
|
20424
|
+
makeLiveStatus: () => makeLiveStatus
|
|
20425
|
+
});
|
|
20426
|
+
function dedupThinking(entries) {
|
|
20427
|
+
const out = [];
|
|
20428
|
+
for (const e of entries) {
|
|
20429
|
+
const last = out[out.length - 1];
|
|
20430
|
+
if (e.kind === "thinking" && last?.kind === "thinking" && last.text === e.text) continue;
|
|
20431
|
+
out.push(e);
|
|
20432
|
+
}
|
|
20433
|
+
return out;
|
|
20434
|
+
}
|
|
20435
|
+
function renderEntry(e) {
|
|
20436
|
+
if (e.kind === "thinking") {
|
|
20437
|
+
const truncated = e.text.length > MAX_THINKING_CHARS ? e.text.slice(0, MAX_THINKING_CHARS) + "\u2026" : e.text;
|
|
20438
|
+
return `\u{1F4AD} ${truncated}`;
|
|
20439
|
+
}
|
|
20440
|
+
return e.text;
|
|
20441
|
+
}
|
|
20442
|
+
function renderEntries(entries, modelLabel, elapsedMs) {
|
|
20443
|
+
const elapsedSec = (elapsedMs / 1e3).toFixed(1);
|
|
20444
|
+
const lines = [`\u23F3 ${modelLabel} \xB7 ${elapsedSec}s`, ""];
|
|
20445
|
+
for (const e of entries) lines.push(renderEntry(e));
|
|
20446
|
+
return lines.join("\n");
|
|
20447
|
+
}
|
|
20448
|
+
function renderFinal(entries, modelLabel, elapsedSec) {
|
|
20449
|
+
const lines = [`\u2705 ${modelLabel} \xB7 ${elapsedSec}s`, ""];
|
|
20450
|
+
for (const e of entries) lines.push(renderEntry(e));
|
|
20451
|
+
if (lines.length === 2) return `\u2705 ${modelLabel} \xB7 ${elapsedSec}s`;
|
|
20452
|
+
return lines.join("\n");
|
|
20453
|
+
}
|
|
20454
|
+
function renderFrozen(entries, modelLabel, elapsedSec) {
|
|
20455
|
+
const lines = [`\u{1F4CE} ${modelLabel} \xB7 ${elapsedSec}s`, ""];
|
|
20456
|
+
for (const e of entries) lines.push(renderEntry(e));
|
|
20457
|
+
if (lines.length === 2) return `\u{1F4CE} ${modelLabel} \xB7 ${elapsedSec}s`;
|
|
20458
|
+
return lines.join("\n");
|
|
20459
|
+
}
|
|
20460
|
+
function makeLiveStatus(chatId, channel, modelLabel, verboseLevel, showThinking) {
|
|
20461
|
+
const liveStatus = new LiveStatusMessage(chatId, channel, modelLabel, verboseLevel, showThinking);
|
|
20462
|
+
const toolCb = async (toolName, input, result) => {
|
|
20463
|
+
if (result === void 0) {
|
|
20464
|
+
liveStatus.addToolStart(toolName, input);
|
|
20465
|
+
} else {
|
|
20466
|
+
liveStatus.addToolEnd(toolName, result);
|
|
20467
|
+
}
|
|
20468
|
+
};
|
|
20469
|
+
return { liveStatus, toolCb };
|
|
20470
|
+
}
|
|
20471
|
+
var FLUSH_INTERVAL_MS, MAX_ENTRIES, MAX_THINKING_CHARS, SPILLOVER_THRESHOLD, LiveStatusMessage;
|
|
20472
|
+
var init_live_status = __esm({
|
|
20473
|
+
"src/router/live-status.ts"() {
|
|
20474
|
+
"use strict";
|
|
20475
|
+
init_log();
|
|
20476
|
+
init_helpers();
|
|
20477
|
+
FLUSH_INTERVAL_MS = 1e3;
|
|
20478
|
+
MAX_ENTRIES = 50;
|
|
20479
|
+
MAX_THINKING_CHARS = 800;
|
|
20480
|
+
SPILLOVER_THRESHOLD = 3800;
|
|
20481
|
+
LiveStatusMessage = class {
|
|
20482
|
+
constructor(chatId, channel, modelLabel, verboseLevel, showThinking = false) {
|
|
20483
|
+
this.chatId = chatId;
|
|
20484
|
+
this.channel = channel;
|
|
20485
|
+
this.modelLabel = modelLabel;
|
|
20486
|
+
this.verboseLevel = verboseLevel;
|
|
20487
|
+
this.showThinking = showThinking;
|
|
20488
|
+
}
|
|
20489
|
+
messageId = null;
|
|
20490
|
+
entries = [];
|
|
20491
|
+
startTime = Date.now();
|
|
20492
|
+
flushTimer = null;
|
|
20493
|
+
lastRendered = "";
|
|
20494
|
+
finalized = false;
|
|
20495
|
+
/**
|
|
20496
|
+
* Entries already frozen in previous spillover messages.
|
|
20497
|
+
* Tracked so we only render NEW entries in the current message.
|
|
20498
|
+
*/
|
|
20499
|
+
frozenEntryCount = 0;
|
|
20500
|
+
/** Send the initial status message. Must be called before adding entries. */
|
|
20501
|
+
async init() {
|
|
20502
|
+
if (!this.channel.sendTextReturningId) return;
|
|
20503
|
+
try {
|
|
20504
|
+
const initial = `\u23F3 ${this.modelLabel} \xB7 Processing\u2026`;
|
|
20505
|
+
this.messageId = await this.channel.sendTextReturningId(this.chatId, initial, "plain") ?? null;
|
|
20506
|
+
if (this.messageId) {
|
|
20507
|
+
this.flushTimer = setInterval(() => this.flush().catch(() => {
|
|
20508
|
+
}), FLUSH_INTERVAL_MS);
|
|
20509
|
+
}
|
|
20510
|
+
} catch (err) {
|
|
20511
|
+
log(`[live-status] init failed: ${err}`);
|
|
20512
|
+
}
|
|
20513
|
+
}
|
|
20514
|
+
/** Add a thinking token preview (from NdjsonEvent type "thinking"). */
|
|
20515
|
+
addThinking(text) {
|
|
20516
|
+
if (!this.showThinking) return;
|
|
20517
|
+
if (!this.messageId || this.finalized) return;
|
|
20518
|
+
const trimmed = text.trim();
|
|
20519
|
+
if (!trimmed) return;
|
|
20520
|
+
this.entries.push({ kind: "thinking", text: trimmed, ts: Date.now() });
|
|
20521
|
+
this.trimEntries();
|
|
20522
|
+
}
|
|
20523
|
+
/** Add a tool start event. */
|
|
20524
|
+
addToolStart(toolName, input, toolId) {
|
|
20525
|
+
if (!this.messageId || this.finalized) return;
|
|
20526
|
+
const formatted = formatToolStart(toolName, input, this.verboseLevel);
|
|
20527
|
+
this.entries.push({ kind: "tool_start", text: formatted, toolId, ts: Date.now() });
|
|
20528
|
+
this.trimEntries();
|
|
20529
|
+
}
|
|
20530
|
+
/** Add a tool result event. */
|
|
20531
|
+
addToolEnd(toolName, result, toolId) {
|
|
20532
|
+
if (!this.messageId || this.finalized) return;
|
|
20533
|
+
if (this.verboseLevel !== "verbose") return;
|
|
20534
|
+
const formatted = formatToolResult(toolName, result ?? "");
|
|
20535
|
+
if (formatted) {
|
|
20536
|
+
this.entries.push({ kind: "tool_end", text: formatted, toolId, ts: Date.now() });
|
|
20537
|
+
this.trimEntries();
|
|
20538
|
+
}
|
|
20539
|
+
}
|
|
20540
|
+
/** Add an informational entry (e.g. backend capability notes). */
|
|
20541
|
+
addInfo(text) {
|
|
20542
|
+
if (!this.messageId || this.finalized) return;
|
|
20543
|
+
this.entries.push({ kind: "info", text, ts: Date.now() });
|
|
20544
|
+
this.trimEntries();
|
|
20545
|
+
}
|
|
20546
|
+
/**
|
|
20547
|
+
* Finalize the status message: replace the spinner with ✅ and elapsed time.
|
|
20548
|
+
* Stops the flush loop. No-op if no message was created (channel doesn't support editing).
|
|
20549
|
+
*/
|
|
20550
|
+
async finalize(elapsedMs) {
|
|
20551
|
+
this.finalized = true;
|
|
20552
|
+
if (this.flushTimer) {
|
|
20553
|
+
clearInterval(this.flushTimer);
|
|
20554
|
+
this.flushTimer = null;
|
|
20555
|
+
}
|
|
20556
|
+
if (!this.messageId || !this.channel.editText) return;
|
|
20557
|
+
const elapsedSec = (elapsedMs / 1e3).toFixed(1);
|
|
20558
|
+
const currentEntries = dedupThinking(this.entries.slice(this.frozenEntryCount));
|
|
20559
|
+
const body = renderFinal(currentEntries, this.modelLabel, elapsedSec);
|
|
20560
|
+
try {
|
|
20561
|
+
await this.channel.editText(this.chatId, this.messageId, body, "plain");
|
|
20562
|
+
} catch (err) {
|
|
20563
|
+
log(`[live-status] finalize edit failed: ${err}`);
|
|
20564
|
+
}
|
|
20565
|
+
}
|
|
20566
|
+
/** Returns the messageId of the status message (if created). */
|
|
20567
|
+
getMessageId() {
|
|
20568
|
+
return this.messageId;
|
|
20569
|
+
}
|
|
20570
|
+
// ── Internal ──────────────────────────────────────────────────────────
|
|
20571
|
+
async flush() {
|
|
20572
|
+
if (this.finalized || !this.messageId || !this.channel.editText) return;
|
|
20573
|
+
const currentEntries = dedupThinking(this.entries.slice(this.frozenEntryCount));
|
|
20574
|
+
const body = renderEntries(currentEntries, this.modelLabel, Date.now() - this.startTime);
|
|
20575
|
+
if (body.length > SPILLOVER_THRESHOLD && currentEntries.length > 1) {
|
|
20576
|
+
await this.spillover();
|
|
20577
|
+
return;
|
|
20578
|
+
}
|
|
20579
|
+
if (body === this.lastRendered) return;
|
|
20580
|
+
this.lastRendered = body;
|
|
20581
|
+
try {
|
|
20582
|
+
await this.channel.editText(this.chatId, this.messageId, body, "plain");
|
|
20583
|
+
} catch (err) {
|
|
20584
|
+
log(`[live-status] flush edit failed: ${err}`);
|
|
20585
|
+
}
|
|
20586
|
+
}
|
|
20587
|
+
/**
|
|
20588
|
+
* Freeze the current message and start a new continuation message.
|
|
20589
|
+
* The frozen message keeps its content (with 📎 prefix) — nothing is lost.
|
|
20590
|
+
*/
|
|
20591
|
+
async spillover() {
|
|
20592
|
+
if (!this.channel.editText || !this.channel.sendTextReturningId || !this.messageId) return;
|
|
20593
|
+
const elapsedSec = ((Date.now() - this.startTime) / 1e3).toFixed(1);
|
|
20594
|
+
const currentEntries = dedupThinking(this.entries.slice(this.frozenEntryCount));
|
|
20595
|
+
const frozenBody = renderFrozen(currentEntries, this.modelLabel, elapsedSec);
|
|
20596
|
+
try {
|
|
20597
|
+
await this.channel.editText(this.chatId, this.messageId, frozenBody, "plain");
|
|
20598
|
+
} catch (err) {
|
|
20599
|
+
log(`[live-status] spillover freeze failed: ${err}`);
|
|
20600
|
+
}
|
|
20601
|
+
this.frozenEntryCount = this.entries.length;
|
|
20602
|
+
try {
|
|
20603
|
+
const initial = `\u23F3 ${this.modelLabel} \xB7 ${elapsedSec}s (continued)`;
|
|
20604
|
+
const newId = await this.channel.sendTextReturningId(this.chatId, initial, "plain") ?? null;
|
|
20605
|
+
if (newId) {
|
|
20606
|
+
this.messageId = newId;
|
|
20607
|
+
this.lastRendered = "";
|
|
20608
|
+
}
|
|
20609
|
+
} catch (err) {
|
|
20610
|
+
log(`[live-status] spillover new message failed: ${err}`);
|
|
20611
|
+
}
|
|
20612
|
+
}
|
|
20613
|
+
trimEntries() {
|
|
20614
|
+
if (this.entries.length > MAX_ENTRIES + this.frozenEntryCount) {
|
|
20615
|
+
const keep = this.entries.slice(0, this.frozenEntryCount);
|
|
20616
|
+
const current = this.entries.slice(this.frozenEntryCount);
|
|
20617
|
+
const trimmed = current.slice(current.length - MAX_ENTRIES);
|
|
20618
|
+
this.entries = [...keep, ...trimmed];
|
|
20619
|
+
}
|
|
20620
|
+
}
|
|
20621
|
+
};
|
|
20622
|
+
}
|
|
20623
|
+
});
|
|
20624
|
+
|
|
18958
20625
|
// src/router.ts
|
|
18959
20626
|
var router_exports = {};
|
|
18960
20627
|
__export(router_exports, {
|
|
@@ -19072,7 +20739,7 @@ async function handleText(msg, channel) {
|
|
|
19072
20739
|
let intent = classifyIntent(text, chatId);
|
|
19073
20740
|
const cleanText = text.startsWith(">>") ? text.slice(2).trim() : text;
|
|
19074
20741
|
let bootstrapTier = intent === "chat" ? "chat" : void 0;
|
|
19075
|
-
let maxTurns =
|
|
20742
|
+
let maxTurns = void 0;
|
|
19076
20743
|
let effectiveAgentMode = msg.agentMode ?? getAgentMode(chatId);
|
|
19077
20744
|
const observedSubagents = /* @__PURE__ */ new Set();
|
|
19078
20745
|
if (effectiveAgentMode === "auto" && !text.startsWith(">>")) {
|
|
@@ -19238,15 +20905,20 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19238
20905
|
});
|
|
19239
20906
|
typingActive2 = false;
|
|
19240
20907
|
if (planResponse.text) {
|
|
19241
|
-
|
|
20908
|
+
let planText = planResponse.text.replace(/\[REACT:.+?\]/g, "").replace(/\[SEND_FILE:.+?\]/g, "").replace(/\[GENERATE_IMAGE:.+?\]/g, "").replace(/\[HISTORY_SEARCH:[^\]]+\]/g, "").trim();
|
|
20909
|
+
const PLAN_DISPLAY_LIMIT = 3500;
|
|
20910
|
+
if (planText.length > PLAN_DISPLAY_LIMIT) {
|
|
20911
|
+
planText = planText.slice(0, PLAN_DISPLAY_LIMIT) + "\n\u2026(truncated \u2014 tap Approve to proceed)";
|
|
20912
|
+
}
|
|
20913
|
+
storePendingPlan(chatId, planText, cleanText || text);
|
|
19242
20914
|
if (typeof channel.sendKeyboard === "function") {
|
|
19243
|
-
await channel.sendKeyboard(chatId, `\u{1F50D} ${
|
|
20915
|
+
await channel.sendKeyboard(chatId, `\u{1F50D} ${planText}`, [
|
|
19244
20916
|
[
|
|
19245
20917
|
{ label: "\u2705 Approve", data: "exec:approve", style: "success" },
|
|
19246
20918
|
{ label: "\u274C Reject", data: "exec:reject", style: "danger" }
|
|
19247
20919
|
],
|
|
19248
20920
|
[
|
|
19249
|
-
{ label: "\u26A1
|
|
20921
|
+
{ label: "\u26A1 Approve & Switch to YOLO", data: "exec:yolo" }
|
|
19250
20922
|
]
|
|
19251
20923
|
]);
|
|
19252
20924
|
} else {
|
|
@@ -19276,7 +20948,24 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19276
20948
|
try {
|
|
19277
20949
|
const tMode = getMode(chatId);
|
|
19278
20950
|
const tVerbose = getVerboseLevel(chatId);
|
|
19279
|
-
const
|
|
20951
|
+
const adapter = getAdapterForChat(chatId);
|
|
20952
|
+
const modelLabel = formatModelShort(model2 ?? adapter.defaultModel);
|
|
20953
|
+
const { getShowThinkingUi: getShowThinkingUi3 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
20954
|
+
const showThinkingUi = getShowThinkingUi3(chatId);
|
|
20955
|
+
const needsLiveStatus = tVerbose !== "off" || showThinkingUi;
|
|
20956
|
+
let liveStatus = null;
|
|
20957
|
+
let tToolCb;
|
|
20958
|
+
if (needsLiveStatus) {
|
|
20959
|
+
const { makeLiveStatus: makeLiveStatus2 } = await Promise.resolve().then(() => (init_live_status(), live_status_exports));
|
|
20960
|
+
const effectiveVerbose = tVerbose === "off" ? "normal" : tVerbose;
|
|
20961
|
+
const ls = makeLiveStatus2(chatId, channel, modelLabel, effectiveVerbose, showThinkingUi);
|
|
20962
|
+
liveStatus = ls.liveStatus;
|
|
20963
|
+
tToolCb = tVerbose !== "off" ? ls.toolCb : void 0;
|
|
20964
|
+
await liveStatus.init();
|
|
20965
|
+
if (showThinkingUi && adapter.id === "gemini") {
|
|
20966
|
+
liveStatus.addInfo("\u{1F4AD} Thinking display not available for Gemini");
|
|
20967
|
+
}
|
|
20968
|
+
}
|
|
19280
20969
|
const sigT0 = Date.now();
|
|
19281
20970
|
const response = await askAgent(chatId, cleanText || text, {
|
|
19282
20971
|
cwd: getCwd(chatId),
|
|
@@ -19286,6 +20975,7 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19286
20975
|
bootstrapTier,
|
|
19287
20976
|
maxTurns,
|
|
19288
20977
|
agentMode: effectiveAgentMode,
|
|
20978
|
+
onThinking: liveStatus ? (chunk) => liveStatus.addThinking(chunk) : void 0,
|
|
19289
20979
|
onSubagentActivity: (backendId2, info) => {
|
|
19290
20980
|
observedSubagents.add(info.name);
|
|
19291
20981
|
try {
|
|
@@ -19319,26 +21009,31 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19319
21009
|
});
|
|
19320
21010
|
}
|
|
19321
21011
|
});
|
|
19322
|
-
const
|
|
21012
|
+
const elapsedMs = Date.now() - sigT0;
|
|
21013
|
+
const elapsedSec = (elapsedMs / 1e3).toFixed(1);
|
|
21014
|
+
if (liveStatus && response.thinkingText?.trim()) {
|
|
21015
|
+
liveStatus.addThinking(response.thinkingText.trim());
|
|
21016
|
+
}
|
|
21017
|
+
if (liveStatus) await liveStatus.finalize(elapsedMs);
|
|
19323
21018
|
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, model2, void 0, response.usage.contextSize);
|
|
19324
21019
|
let responseText = response.text;
|
|
19325
21020
|
const sigEnabled = getModelSignature(chatId);
|
|
19326
21021
|
if (sigEnabled === "on" && responseText && !responseText.startsWith("(No response")) {
|
|
19327
|
-
const
|
|
19328
|
-
const modelId = response.resolvedModel ?? model2 ??
|
|
21022
|
+
const adapter2 = getAdapterForChat(chatId);
|
|
21023
|
+
const modelId = response.resolvedModel ?? model2 ?? adapter2.defaultModel;
|
|
19329
21024
|
const thinking2 = getThinkingLevel(chatId) || "auto";
|
|
19330
21025
|
const shortModel = formatModelShort(modelId);
|
|
19331
21026
|
let slotTag = "";
|
|
19332
|
-
if (
|
|
21027
|
+
if (adapter2.id === "gemini") {
|
|
19333
21028
|
const slotId = getChatGeminiSlotId(chatId);
|
|
19334
21029
|
if (slotId) {
|
|
19335
21030
|
const slot = getGeminiSlots().find((s) => s.id === slotId);
|
|
19336
21031
|
if (slot) slotTag = ` \xB7 ${slot.label || `slot-${slot.id}`}`;
|
|
19337
21032
|
}
|
|
19338
|
-
} else if (
|
|
19339
|
-
const slotId = getChatBackendSlotId(chatId,
|
|
21033
|
+
} else if (adapter2.id === "claude" || adapter2.id === "codex") {
|
|
21034
|
+
const slotId = getChatBackendSlotId(chatId, adapter2.id);
|
|
19340
21035
|
if (slotId) {
|
|
19341
|
-
const slot = getBackendSlots(
|
|
21036
|
+
const slot = getBackendSlots(adapter2.id).find((s) => s.id === slotId);
|
|
19342
21037
|
if (slot) slotTag = ` \xB7 ${slot.label || `slot-${slot.id}`}`;
|
|
19343
21038
|
}
|
|
19344
21039
|
}
|
|
@@ -19372,10 +21067,10 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19372
21067
|
await sendResponse(chatId, channel, responseText, msg.messageId);
|
|
19373
21068
|
try {
|
|
19374
21069
|
const { detectAndLogSignals: detectAndLogSignals2 } = await Promise.resolve().then(() => (init_detect(), detect_exports));
|
|
19375
|
-
const
|
|
21070
|
+
const adapter2 = getAdapterForChat(chatId);
|
|
19376
21071
|
detectAndLogSignals2(chatId, cleanText || text, responseText, {
|
|
19377
|
-
backendId:
|
|
19378
|
-
model: model2 ??
|
|
21072
|
+
backendId: adapter2.id,
|
|
21073
|
+
model: model2 ?? adapter2.defaultModel,
|
|
19379
21074
|
thinkingLevel: getThinkingLevel(chatId) || void 0
|
|
19380
21075
|
});
|
|
19381
21076
|
} catch (e) {
|
|
@@ -19828,7 +21523,7 @@ var init_cron = __esm({
|
|
|
19828
21523
|
});
|
|
19829
21524
|
|
|
19830
21525
|
// src/agents/runners/wrap-backend.ts
|
|
19831
|
-
import { join as
|
|
21526
|
+
import { join as join24 } from "path";
|
|
19832
21527
|
function buildMcpCommands(backendId) {
|
|
19833
21528
|
const exe = backendId === "cursor" ? "agent" : backendId;
|
|
19834
21529
|
return {
|
|
@@ -19922,7 +21617,7 @@ function wrapBackendAdapter(adapter) {
|
|
|
19922
21617
|
const configPath = writeMcpConfigFile(server);
|
|
19923
21618
|
return ["--mcp-config", configPath];
|
|
19924
21619
|
},
|
|
19925
|
-
getSkillPath: () =>
|
|
21620
|
+
getSkillPath: () => join24(SKILLS_PATH, `agent-${adapter.id}.md`)
|
|
19926
21621
|
};
|
|
19927
21622
|
}
|
|
19928
21623
|
var BACKEND_CAPABILITIES;
|
|
@@ -19973,18 +21668,18 @@ var init_wrap_backend = __esm({
|
|
|
19973
21668
|
});
|
|
19974
21669
|
|
|
19975
21670
|
// src/agents/runners/config-loader.ts
|
|
19976
|
-
import { readFileSync as
|
|
19977
|
-
import { join as
|
|
21671
|
+
import { readFileSync as readFileSync14, readdirSync as readdirSync12, existsSync as existsSync23, mkdirSync as mkdirSync9, watchFile, unwatchFile } from "fs";
|
|
21672
|
+
import { join as join25 } from "path";
|
|
19978
21673
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
19979
21674
|
function resolveExecutable(config2) {
|
|
19980
|
-
if (
|
|
21675
|
+
if (existsSync23(config2.executable)) return config2.executable;
|
|
19981
21676
|
try {
|
|
19982
21677
|
return execFileSync2("which", [config2.executable], { encoding: "utf-8" }).trim();
|
|
19983
21678
|
} catch {
|
|
19984
21679
|
}
|
|
19985
21680
|
for (const fallback of config2.executableFallbacks ?? []) {
|
|
19986
21681
|
const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
|
|
19987
|
-
if (
|
|
21682
|
+
if (existsSync23(resolved)) return resolved;
|
|
19988
21683
|
}
|
|
19989
21684
|
return config2.executable;
|
|
19990
21685
|
}
|
|
@@ -20110,12 +21805,12 @@ function configToRunner(config2) {
|
|
|
20110
21805
|
prepareMcpInjection() {
|
|
20111
21806
|
return [];
|
|
20112
21807
|
},
|
|
20113
|
-
getSkillPath: () =>
|
|
21808
|
+
getSkillPath: () => join25(SKILLS_PATH, `agent-${config2.id}.md`)
|
|
20114
21809
|
};
|
|
20115
21810
|
}
|
|
20116
21811
|
function loadRunnerConfig(filePath) {
|
|
20117
21812
|
try {
|
|
20118
|
-
const content =
|
|
21813
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
20119
21814
|
return JSON.parse(content);
|
|
20120
21815
|
} catch (err) {
|
|
20121
21816
|
warn(`[runners] Failed to load config ${filePath}: ${err}`);
|
|
@@ -20123,14 +21818,14 @@ function loadRunnerConfig(filePath) {
|
|
|
20123
21818
|
}
|
|
20124
21819
|
}
|
|
20125
21820
|
function loadAllRunnerConfigs() {
|
|
20126
|
-
if (!
|
|
21821
|
+
if (!existsSync23(RUNNERS_PATH)) {
|
|
20127
21822
|
mkdirSync9(RUNNERS_PATH, { recursive: true });
|
|
20128
21823
|
return [];
|
|
20129
21824
|
}
|
|
20130
|
-
const files =
|
|
21825
|
+
const files = readdirSync12(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
20131
21826
|
const configs = [];
|
|
20132
21827
|
for (const file of files) {
|
|
20133
|
-
const config2 = loadRunnerConfig(
|
|
21828
|
+
const config2 = loadRunnerConfig(join25(RUNNERS_PATH, file));
|
|
20134
21829
|
if (config2) configs.push(config2);
|
|
20135
21830
|
}
|
|
20136
21831
|
return configs;
|
|
@@ -20151,16 +21846,16 @@ function registerConfigRunners() {
|
|
|
20151
21846
|
return count;
|
|
20152
21847
|
}
|
|
20153
21848
|
function watchRunnerConfigs(onChange) {
|
|
20154
|
-
if (!
|
|
21849
|
+
if (!existsSync23(RUNNERS_PATH)) return;
|
|
20155
21850
|
for (const prev of watchedFiles) {
|
|
20156
|
-
if (!
|
|
21851
|
+
if (!existsSync23(prev)) {
|
|
20157
21852
|
unwatchFile(prev);
|
|
20158
21853
|
watchedFiles.delete(prev);
|
|
20159
21854
|
}
|
|
20160
21855
|
}
|
|
20161
|
-
const files =
|
|
21856
|
+
const files = readdirSync12(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
20162
21857
|
for (const file of files) {
|
|
20163
|
-
const fullPath =
|
|
21858
|
+
const fullPath = join25(RUNNERS_PATH, file);
|
|
20164
21859
|
if (watchedFiles.has(fullPath)) continue;
|
|
20165
21860
|
watchedFiles.add(fullPath);
|
|
20166
21861
|
watchFile(fullPath, { interval: 5e3 }, () => {
|
|
@@ -20601,7 +22296,8 @@ var init_telegram2 = __esm({
|
|
|
20601
22296
|
{ command: "chats", description: "Manage multi-chat aliases" },
|
|
20602
22297
|
{ command: "intent", description: "Test intent classifier on a message" },
|
|
20603
22298
|
{ command: "evolve", description: "Self-learning & evolution controls" },
|
|
20604
|
-
{ command: "reflect", description: "Trigger reflection analysis" }
|
|
22299
|
+
{ command: "reflect", description: "Trigger reflection analysis" },
|
|
22300
|
+
{ command: "optimize", description: "Audit identity files and skills" }
|
|
20605
22301
|
]);
|
|
20606
22302
|
this.bot.on("message", async (ctx) => {
|
|
20607
22303
|
const chatId = ctx.chat.id.toString();
|
|
@@ -20785,13 +22481,24 @@ var init_telegram2 = __esm({
|
|
|
20785
22481
|
}
|
|
20786
22482
|
keyboard.row();
|
|
20787
22483
|
}
|
|
22484
|
+
const MAX_KEYBOARD_TEXT = 4e3;
|
|
22485
|
+
const safeText = text.length > MAX_KEYBOARD_TEXT ? text.slice(0, MAX_KEYBOARD_TEXT) + "\n\n\u2026(truncated)" : text;
|
|
20788
22486
|
try {
|
|
20789
|
-
const msg = await this.bot.api.sendMessage(numericChatId(chatId),
|
|
22487
|
+
const msg = await this.bot.api.sendMessage(numericChatId(chatId), safeText, {
|
|
20790
22488
|
reply_markup: keyboard
|
|
20791
22489
|
});
|
|
20792
22490
|
return msg.message_id.toString();
|
|
20793
|
-
} catch {
|
|
20794
|
-
|
|
22491
|
+
} catch (err) {
|
|
22492
|
+
error(`[telegram] sendKeyboard failed (chat=${chatId}, textLen=${text.length}):`, err);
|
|
22493
|
+
try {
|
|
22494
|
+
const fallbackMsg = await this.bot.api.sendMessage(numericChatId(chatId), "\u2B06\uFE0F (see above for details)", {
|
|
22495
|
+
reply_markup: keyboard
|
|
22496
|
+
});
|
|
22497
|
+
return fallbackMsg.message_id.toString();
|
|
22498
|
+
} catch (fallbackErr) {
|
|
22499
|
+
error(`[telegram] sendKeyboard fallback also failed:`, fallbackErr);
|
|
22500
|
+
return void 0;
|
|
22501
|
+
}
|
|
20795
22502
|
}
|
|
20796
22503
|
}
|
|
20797
22504
|
async reactToMessage(chatId, messageId, emoji) {
|
|
@@ -20995,19 +22702,19 @@ var init_telegram2 = __esm({
|
|
|
20995
22702
|
});
|
|
20996
22703
|
|
|
20997
22704
|
// src/skills/bootstrap.ts
|
|
20998
|
-
import { existsSync as
|
|
22705
|
+
import { existsSync as existsSync24 } from "fs";
|
|
20999
22706
|
import { readdir as readdir6, readFile as readFile8, writeFile as writeFile5, copyFile } from "fs/promises";
|
|
21000
|
-
import { join as
|
|
22707
|
+
import { join as join26, dirname as dirname5 } from "path";
|
|
21001
22708
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21002
22709
|
async function copyAgentManifestSkills() {
|
|
21003
|
-
if (!
|
|
22710
|
+
if (!existsSync24(PKG_SKILLS)) return;
|
|
21004
22711
|
try {
|
|
21005
22712
|
const entries = await readdir6(PKG_SKILLS, { withFileTypes: true });
|
|
21006
22713
|
for (const entry of entries) {
|
|
21007
22714
|
if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
|
|
21008
|
-
const src =
|
|
21009
|
-
const dest =
|
|
21010
|
-
if (
|
|
22715
|
+
const src = join26(PKG_SKILLS, entry.name);
|
|
22716
|
+
const dest = join26(SKILLS_PATH, entry.name);
|
|
22717
|
+
if (existsSync24(dest)) continue;
|
|
21011
22718
|
await copyFile(src, dest);
|
|
21012
22719
|
log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
|
|
21013
22720
|
}
|
|
@@ -21017,8 +22724,8 @@ async function copyAgentManifestSkills() {
|
|
|
21017
22724
|
}
|
|
21018
22725
|
async function bootstrapSkills() {
|
|
21019
22726
|
await copyAgentManifestSkills();
|
|
21020
|
-
const usmDir =
|
|
21021
|
-
if (
|
|
22727
|
+
const usmDir = join26(SKILLS_PATH, USM_DIR_NAME);
|
|
22728
|
+
if (existsSync24(usmDir)) return;
|
|
21022
22729
|
try {
|
|
21023
22730
|
const entries = await readdir6(SKILLS_PATH);
|
|
21024
22731
|
const dirs = entries.filter((e) => !e.startsWith("."));
|
|
@@ -21040,8 +22747,8 @@ async function bootstrapSkills() {
|
|
|
21040
22747
|
}
|
|
21041
22748
|
}
|
|
21042
22749
|
async function patchUsmForCcClaw(usmDir) {
|
|
21043
|
-
const skillPath =
|
|
21044
|
-
if (!
|
|
22750
|
+
const skillPath = join26(usmDir, "SKILL.md");
|
|
22751
|
+
if (!existsSync24(skillPath)) return;
|
|
21045
22752
|
try {
|
|
21046
22753
|
let content = await readFile8(skillPath, "utf-8");
|
|
21047
22754
|
let patched = false;
|
|
@@ -21086,8 +22793,8 @@ var init_bootstrap = __esm({
|
|
|
21086
22793
|
USM_REPO = "jacob-bd/universal-skills-manager";
|
|
21087
22794
|
USM_DIR_NAME = "universal-skills-manager";
|
|
21088
22795
|
CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
|
|
21089
|
-
PKG_ROOT =
|
|
21090
|
-
PKG_SKILLS =
|
|
22796
|
+
PKG_ROOT = join26(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
|
|
22797
|
+
PKG_SKILLS = join26(PKG_ROOT, "skills");
|
|
21091
22798
|
}
|
|
21092
22799
|
});
|
|
21093
22800
|
|
|
@@ -21309,13 +23016,13 @@ __export(ai_skill_exports, {
|
|
|
21309
23016
|
generateAiSkill: () => generateAiSkill,
|
|
21310
23017
|
installAiSkill: () => installAiSkill
|
|
21311
23018
|
});
|
|
21312
|
-
import { existsSync as
|
|
21313
|
-
import { join as
|
|
21314
|
-
import { homedir as
|
|
23019
|
+
import { existsSync as existsSync25, writeFileSync as writeFileSync8, mkdirSync as mkdirSync10 } from "fs";
|
|
23020
|
+
import { join as join27 } from "path";
|
|
23021
|
+
import { homedir as homedir9 } from "os";
|
|
21315
23022
|
function generateAiSkill() {
|
|
21316
23023
|
const version = VERSION;
|
|
21317
23024
|
let systemState = "";
|
|
21318
|
-
if (
|
|
23025
|
+
if (existsSync25(DB_PATH)) {
|
|
21319
23026
|
try {
|
|
21320
23027
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
|
|
21321
23028
|
const readDb = openDatabaseReadOnly2();
|
|
@@ -21719,11 +23426,11 @@ function installAiSkill() {
|
|
|
21719
23426
|
const failed = [];
|
|
21720
23427
|
for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
|
|
21721
23428
|
for (const dir of dirs) {
|
|
21722
|
-
const skillDir =
|
|
21723
|
-
const skillPath =
|
|
23429
|
+
const skillDir = join27(dir, "cc-claw-cli");
|
|
23430
|
+
const skillPath = join27(skillDir, "SKILL.md");
|
|
21724
23431
|
try {
|
|
21725
23432
|
mkdirSync10(skillDir, { recursive: true });
|
|
21726
|
-
|
|
23433
|
+
writeFileSync8(skillPath, skill, "utf-8");
|
|
21727
23434
|
installed.push(skillPath);
|
|
21728
23435
|
} catch {
|
|
21729
23436
|
failed.push(skillPath);
|
|
@@ -21739,11 +23446,11 @@ var init_ai_skill = __esm({
|
|
|
21739
23446
|
init_paths();
|
|
21740
23447
|
init_version();
|
|
21741
23448
|
BACKEND_SKILL_DIRS2 = {
|
|
21742
|
-
"cc-claw": [
|
|
21743
|
-
claude: [
|
|
21744
|
-
gemini: [
|
|
21745
|
-
codex: [
|
|
21746
|
-
cursor: [
|
|
23449
|
+
"cc-claw": [join27(homedir9(), ".cc-claw", "workspace", "skills")],
|
|
23450
|
+
claude: [join27(homedir9(), ".claude", "skills")],
|
|
23451
|
+
gemini: [join27(homedir9(), ".gemini", "skills")],
|
|
23452
|
+
codex: [join27(homedir9(), ".agents", "skills")],
|
|
23453
|
+
cursor: [join27(homedir9(), ".cursor", "skills"), join27(homedir9(), ".cursor", "skills-cursor")]
|
|
21747
23454
|
};
|
|
21748
23455
|
}
|
|
21749
23456
|
});
|
|
@@ -21753,21 +23460,21 @@ var index_exports = {};
|
|
|
21753
23460
|
__export(index_exports, {
|
|
21754
23461
|
main: () => main
|
|
21755
23462
|
});
|
|
21756
|
-
import { mkdirSync as mkdirSync11, existsSync as
|
|
21757
|
-
import { join as
|
|
23463
|
+
import { mkdirSync as mkdirSync11, existsSync as existsSync26, renameSync as renameSync2, statSync as statSync7, readFileSync as readFileSync16 } from "fs";
|
|
23464
|
+
import { join as join28 } from "path";
|
|
21758
23465
|
import dotenv from "dotenv";
|
|
21759
23466
|
function migrateLayout() {
|
|
21760
23467
|
const moves = [
|
|
21761
|
-
[
|
|
21762
|
-
[
|
|
21763
|
-
[
|
|
21764
|
-
[
|
|
21765
|
-
[
|
|
21766
|
-
[
|
|
21767
|
-
[
|
|
23468
|
+
[join28(CC_CLAW_HOME, "cc-claw.db"), join28(DATA_PATH, "cc-claw.db")],
|
|
23469
|
+
[join28(CC_CLAW_HOME, "cc-claw.db-shm"), join28(DATA_PATH, "cc-claw.db-shm")],
|
|
23470
|
+
[join28(CC_CLAW_HOME, "cc-claw.db-wal"), join28(DATA_PATH, "cc-claw.db-wal")],
|
|
23471
|
+
[join28(CC_CLAW_HOME, "cc-claw.log"), join28(LOGS_PATH, "cc-claw.log")],
|
|
23472
|
+
[join28(CC_CLAW_HOME, "cc-claw.log.1"), join28(LOGS_PATH, "cc-claw.log.1")],
|
|
23473
|
+
[join28(CC_CLAW_HOME, "cc-claw.error.log"), join28(LOGS_PATH, "cc-claw.error.log")],
|
|
23474
|
+
[join28(CC_CLAW_HOME, "cc-claw.error.log.1"), join28(LOGS_PATH, "cc-claw.error.log.1")]
|
|
21768
23475
|
];
|
|
21769
23476
|
for (const [from, to] of moves) {
|
|
21770
|
-
if (
|
|
23477
|
+
if (existsSync26(from) && !existsSync26(to)) {
|
|
21771
23478
|
try {
|
|
21772
23479
|
renameSync2(from, to);
|
|
21773
23480
|
} catch {
|
|
@@ -21778,7 +23485,7 @@ function migrateLayout() {
|
|
|
21778
23485
|
function rotateLogs() {
|
|
21779
23486
|
for (const file of [LOG_PATH, ERROR_LOG_PATH]) {
|
|
21780
23487
|
try {
|
|
21781
|
-
const { size } =
|
|
23488
|
+
const { size } = statSync7(file);
|
|
21782
23489
|
if (size > LOG_MAX_BYTES) {
|
|
21783
23490
|
const archivePath = `${file}.1`;
|
|
21784
23491
|
try {
|
|
@@ -21796,7 +23503,7 @@ async function main() {
|
|
|
21796
23503
|
let version = "unknown";
|
|
21797
23504
|
try {
|
|
21798
23505
|
const pkgPath = new URL("../package.json", import.meta.url);
|
|
21799
|
-
version = JSON.parse(
|
|
23506
|
+
version = JSON.parse(readFileSync16(pkgPath, "utf-8")).version;
|
|
21800
23507
|
} catch {
|
|
21801
23508
|
}
|
|
21802
23509
|
log(`[cc-claw] Starting v${version}`);
|
|
@@ -21912,11 +23619,11 @@ async function main() {
|
|
|
21912
23619
|
bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
|
|
21913
23620
|
try {
|
|
21914
23621
|
const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
|
|
21915
|
-
const { writeFileSync:
|
|
21916
|
-
const { join:
|
|
21917
|
-
const skillDir =
|
|
23622
|
+
const { writeFileSync: writeFileSync13, mkdirSync: mkdirSync18 } = await import("fs");
|
|
23623
|
+
const { join: join34 } = await import("path");
|
|
23624
|
+
const skillDir = join34(SKILLS_PATH, "cc-claw-cli");
|
|
21918
23625
|
mkdirSync18(skillDir, { recursive: true });
|
|
21919
|
-
|
|
23626
|
+
writeFileSync13(join34(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
|
|
21920
23627
|
log("[cc-claw] AI skill updated");
|
|
21921
23628
|
} catch {
|
|
21922
23629
|
}
|
|
@@ -21989,10 +23696,10 @@ var init_index = __esm({
|
|
|
21989
23696
|
init_health3();
|
|
21990
23697
|
init_image_gen();
|
|
21991
23698
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
21992
|
-
if (!
|
|
23699
|
+
if (!existsSync26(dir)) mkdirSync11(dir, { recursive: true });
|
|
21993
23700
|
}
|
|
21994
23701
|
migrateLayout();
|
|
21995
|
-
if (
|
|
23702
|
+
if (existsSync26(ENV_PATH)) {
|
|
21996
23703
|
dotenv.config({ path: ENV_PATH });
|
|
21997
23704
|
} else {
|
|
21998
23705
|
console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
|
|
@@ -22013,12 +23720,12 @@ __export(api_client_exports, {
|
|
|
22013
23720
|
apiPost: () => apiPost,
|
|
22014
23721
|
isDaemonRunning: () => isDaemonRunning
|
|
22015
23722
|
});
|
|
22016
|
-
import { readFileSync as
|
|
23723
|
+
import { readFileSync as readFileSync17, existsSync as existsSync27 } from "fs";
|
|
22017
23724
|
import { request as httpRequest, Agent } from "http";
|
|
22018
23725
|
function getToken() {
|
|
22019
23726
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
22020
23727
|
try {
|
|
22021
|
-
if (
|
|
23728
|
+
if (existsSync27(TOKEN_PATH)) return readFileSync17(TOKEN_PATH, "utf-8").trim();
|
|
22022
23729
|
} catch {
|
|
22023
23730
|
}
|
|
22024
23731
|
return null;
|
|
@@ -22117,10 +23824,10 @@ __export(service_exports, {
|
|
|
22117
23824
|
serviceStatus: () => serviceStatus,
|
|
22118
23825
|
uninstallService: () => uninstallService
|
|
22119
23826
|
});
|
|
22120
|
-
import { existsSync as
|
|
23827
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync12, writeFileSync as writeFileSync9, unlinkSync as unlinkSync6 } from "fs";
|
|
22121
23828
|
import { execFileSync as execFileSync3, execSync as execSync6 } from "child_process";
|
|
22122
|
-
import { homedir as
|
|
22123
|
-
import { join as
|
|
23829
|
+
import { homedir as homedir10, platform } from "os";
|
|
23830
|
+
import { join as join29, dirname as dirname6 } from "path";
|
|
22124
23831
|
function xmlEscape(s) {
|
|
22125
23832
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
22126
23833
|
}
|
|
@@ -22129,23 +23836,23 @@ function resolveExecutable2(name) {
|
|
|
22129
23836
|
return execFileSync3("which", [name], { encoding: "utf-8" }).trim();
|
|
22130
23837
|
} catch {
|
|
22131
23838
|
const fallback = process.argv[1];
|
|
22132
|
-
if (fallback &&
|
|
23839
|
+
if (fallback && existsSync28(fallback)) return fallback;
|
|
22133
23840
|
throw new Error(`Cannot find '${name}' executable. Install globally: npm install -g cc-claw`);
|
|
22134
23841
|
}
|
|
22135
23842
|
}
|
|
22136
23843
|
function getPathDirs() {
|
|
22137
|
-
const nodeBin =
|
|
22138
|
-
const home =
|
|
23844
|
+
const nodeBin = dirname6(process.execPath);
|
|
23845
|
+
const home = homedir10();
|
|
22139
23846
|
const dirs = /* @__PURE__ */ new Set([
|
|
22140
23847
|
nodeBin,
|
|
22141
|
-
|
|
23848
|
+
join29(home, ".local", "bin"),
|
|
22142
23849
|
"/usr/local/bin",
|
|
22143
23850
|
"/usr/bin",
|
|
22144
23851
|
"/bin"
|
|
22145
23852
|
]);
|
|
22146
23853
|
try {
|
|
22147
23854
|
const prefix = execSync6("npm config get prefix", { encoding: "utf-8" }).trim();
|
|
22148
|
-
if (prefix) dirs.add(
|
|
23855
|
+
if (prefix) dirs.add(join29(prefix, "bin"));
|
|
22149
23856
|
} catch {
|
|
22150
23857
|
}
|
|
22151
23858
|
return [...dirs].join(":");
|
|
@@ -22153,7 +23860,7 @@ function getPathDirs() {
|
|
|
22153
23860
|
function generatePlist() {
|
|
22154
23861
|
const ccClawBin = resolveExecutable2("cc-claw");
|
|
22155
23862
|
const pathDirs = getPathDirs();
|
|
22156
|
-
const home =
|
|
23863
|
+
const home = homedir10();
|
|
22157
23864
|
const safeBin = xmlEscape(ccClawBin);
|
|
22158
23865
|
const safePaths = xmlEscape(pathDirs);
|
|
22159
23866
|
const safeHome = xmlEscape(home);
|
|
@@ -22203,22 +23910,22 @@ function generatePlist() {
|
|
|
22203
23910
|
</plist>`;
|
|
22204
23911
|
}
|
|
22205
23912
|
function installMacOS() {
|
|
22206
|
-
const agentsDir =
|
|
22207
|
-
if (!
|
|
22208
|
-
if (!
|
|
22209
|
-
if (
|
|
23913
|
+
const agentsDir = dirname6(PLIST_PATH);
|
|
23914
|
+
if (!existsSync28(agentsDir)) mkdirSync12(agentsDir, { recursive: true });
|
|
23915
|
+
if (!existsSync28(LOGS_PATH)) mkdirSync12(LOGS_PATH, { recursive: true });
|
|
23916
|
+
if (existsSync28(PLIST_PATH)) {
|
|
22210
23917
|
try {
|
|
22211
23918
|
execFileSync3("launchctl", ["unload", PLIST_PATH]);
|
|
22212
23919
|
} catch {
|
|
22213
23920
|
}
|
|
22214
23921
|
}
|
|
22215
|
-
|
|
23922
|
+
writeFileSync9(PLIST_PATH, generatePlist());
|
|
22216
23923
|
console.log(` Installed: ${PLIST_PATH}`);
|
|
22217
23924
|
execFileSync3("launchctl", ["load", PLIST_PATH]);
|
|
22218
23925
|
console.log(" Service loaded and starting.");
|
|
22219
23926
|
}
|
|
22220
23927
|
function uninstallMacOS() {
|
|
22221
|
-
if (!
|
|
23928
|
+
if (!existsSync28(PLIST_PATH)) {
|
|
22222
23929
|
console.log(" No service found to uninstall.");
|
|
22223
23930
|
return;
|
|
22224
23931
|
}
|
|
@@ -22286,16 +23993,16 @@ Restart=on-failure
|
|
|
22286
23993
|
RestartSec=10
|
|
22287
23994
|
WorkingDirectory=${CC_CLAW_HOME}
|
|
22288
23995
|
Environment=PATH=${pathDirs}
|
|
22289
|
-
Environment=HOME=${
|
|
23996
|
+
Environment=HOME=${homedir10()}
|
|
22290
23997
|
|
|
22291
23998
|
[Install]
|
|
22292
23999
|
WantedBy=default.target
|
|
22293
24000
|
`;
|
|
22294
24001
|
}
|
|
22295
24002
|
function installLinux() {
|
|
22296
|
-
if (!
|
|
22297
|
-
if (!
|
|
22298
|
-
|
|
24003
|
+
if (!existsSync28(SYSTEMD_DIR)) mkdirSync12(SYSTEMD_DIR, { recursive: true });
|
|
24004
|
+
if (!existsSync28(LOGS_PATH)) mkdirSync12(LOGS_PATH, { recursive: true });
|
|
24005
|
+
writeFileSync9(UNIT_PATH, generateUnit());
|
|
22299
24006
|
console.log(` Installed: ${UNIT_PATH}`);
|
|
22300
24007
|
execFileSync3("systemctl", ["--user", "daemon-reload"]);
|
|
22301
24008
|
execFileSync3("systemctl", ["--user", "enable", "cc-claw"]);
|
|
@@ -22303,7 +24010,7 @@ function installLinux() {
|
|
|
22303
24010
|
console.log(" Service enabled and started.");
|
|
22304
24011
|
}
|
|
22305
24012
|
function uninstallLinux() {
|
|
22306
|
-
if (!
|
|
24013
|
+
if (!existsSync28(UNIT_PATH)) {
|
|
22307
24014
|
console.log(" No service found to uninstall.");
|
|
22308
24015
|
return;
|
|
22309
24016
|
}
|
|
@@ -22328,7 +24035,7 @@ function statusLinux() {
|
|
|
22328
24035
|
}
|
|
22329
24036
|
}
|
|
22330
24037
|
function installService() {
|
|
22331
|
-
if (!
|
|
24038
|
+
if (!existsSync28(join29(CC_CLAW_HOME, ".env"))) {
|
|
22332
24039
|
console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
|
|
22333
24040
|
console.error(" Run 'cc-claw setup' before installing the service.");
|
|
22334
24041
|
process.exitCode = 1;
|
|
@@ -22357,9 +24064,9 @@ var init_service = __esm({
|
|
|
22357
24064
|
"use strict";
|
|
22358
24065
|
init_paths();
|
|
22359
24066
|
PLIST_LABEL = "com.cc-claw";
|
|
22360
|
-
PLIST_PATH =
|
|
22361
|
-
SYSTEMD_DIR =
|
|
22362
|
-
UNIT_PATH =
|
|
24067
|
+
PLIST_PATH = join29(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
24068
|
+
SYSTEMD_DIR = join29(homedir10(), ".config", "systemd", "user");
|
|
24069
|
+
UNIT_PATH = join29(SYSTEMD_DIR, "cc-claw.service");
|
|
22363
24070
|
}
|
|
22364
24071
|
});
|
|
22365
24072
|
|
|
@@ -22526,13 +24233,13 @@ var init_daemon = __esm({
|
|
|
22526
24233
|
});
|
|
22527
24234
|
|
|
22528
24235
|
// src/cli/resolve-chat.ts
|
|
22529
|
-
import { readFileSync as
|
|
24236
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
22530
24237
|
function resolveChatId(globalOpts) {
|
|
22531
24238
|
const explicit = globalOpts.chat;
|
|
22532
24239
|
if (explicit) return explicit;
|
|
22533
24240
|
if (_cachedDefault) return _cachedDefault;
|
|
22534
24241
|
try {
|
|
22535
|
-
const content =
|
|
24242
|
+
const content = readFileSync19(ENV_PATH, "utf-8");
|
|
22536
24243
|
const match = content.match(/^ALLOWED_CHAT_ID=(.+)$/m);
|
|
22537
24244
|
if (match) {
|
|
22538
24245
|
_cachedDefault = match[1].split(",")[0].trim();
|
|
@@ -22556,7 +24263,7 @@ var status_exports = {};
|
|
|
22556
24263
|
__export(status_exports, {
|
|
22557
24264
|
statusCommand: () => statusCommand
|
|
22558
24265
|
});
|
|
22559
|
-
import { existsSync as
|
|
24266
|
+
import { existsSync as existsSync29, statSync as statSync8 } from "fs";
|
|
22560
24267
|
async function statusCommand(globalOpts, localOpts) {
|
|
22561
24268
|
try {
|
|
22562
24269
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
@@ -22596,7 +24303,7 @@ async function statusCommand(globalOpts, localOpts) {
|
|
|
22596
24303
|
const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
|
|
22597
24304
|
const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
|
|
22598
24305
|
const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
|
|
22599
|
-
const dbStat =
|
|
24306
|
+
const dbStat = existsSync29(DB_PATH) ? statSync8(DB_PATH) : null;
|
|
22600
24307
|
let daemonRunning = false;
|
|
22601
24308
|
let daemonInfo = {};
|
|
22602
24309
|
try {
|
|
@@ -22685,12 +24392,12 @@ var doctor_exports = {};
|
|
|
22685
24392
|
__export(doctor_exports, {
|
|
22686
24393
|
doctorCommand: () => doctorCommand
|
|
22687
24394
|
});
|
|
22688
|
-
import { existsSync as
|
|
24395
|
+
import { existsSync as existsSync30, statSync as statSync9, accessSync, constants } from "fs";
|
|
22689
24396
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
22690
24397
|
async function doctorCommand(globalOpts, localOpts) {
|
|
22691
24398
|
const checks = [];
|
|
22692
|
-
if (
|
|
22693
|
-
const size =
|
|
24399
|
+
if (existsSync30(DB_PATH)) {
|
|
24400
|
+
const size = statSync9(DB_PATH).size;
|
|
22694
24401
|
checks.push({ name: "Database", status: "ok", message: `${DB_PATH} (${(size / 1024).toFixed(0)}KB)` });
|
|
22695
24402
|
try {
|
|
22696
24403
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
@@ -22719,7 +24426,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
22719
24426
|
} else {
|
|
22720
24427
|
checks.push({ name: "Database", status: "error", message: `Not found at ${DB_PATH}`, fix: "cc-claw setup" });
|
|
22721
24428
|
}
|
|
22722
|
-
if (
|
|
24429
|
+
if (existsSync30(ENV_PATH)) {
|
|
22723
24430
|
checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
|
|
22724
24431
|
} else {
|
|
22725
24432
|
checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
|
|
@@ -22774,7 +24481,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
22774
24481
|
} catch {
|
|
22775
24482
|
}
|
|
22776
24483
|
const tokenPath = `${DATA_PATH}/api-token`;
|
|
22777
|
-
if (
|
|
24484
|
+
if (existsSync30(tokenPath)) {
|
|
22778
24485
|
try {
|
|
22779
24486
|
accessSync(tokenPath, constants.R_OK);
|
|
22780
24487
|
checks.push({ name: "API token", status: "ok", message: "token file readable" });
|
|
@@ -22799,10 +24506,10 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
22799
24506
|
}
|
|
22800
24507
|
} catch {
|
|
22801
24508
|
}
|
|
22802
|
-
if (
|
|
24509
|
+
if (existsSync30(ERROR_LOG_PATH)) {
|
|
22803
24510
|
try {
|
|
22804
|
-
const { readFileSync:
|
|
22805
|
-
const logContent =
|
|
24511
|
+
const { readFileSync: readFileSync26 } = await import("fs");
|
|
24512
|
+
const logContent = readFileSync26(ERROR_LOG_PATH, "utf-8");
|
|
22806
24513
|
const recentLines = logContent.split("\n").filter(Boolean).slice(-100);
|
|
22807
24514
|
const last24h = Date.now() - 864e5;
|
|
22808
24515
|
const recentErrors = recentLines.filter((line) => {
|
|
@@ -22925,15 +24632,15 @@ var logs_exports = {};
|
|
|
22925
24632
|
__export(logs_exports, {
|
|
22926
24633
|
logsCommand: () => logsCommand
|
|
22927
24634
|
});
|
|
22928
|
-
import { existsSync as
|
|
24635
|
+
import { existsSync as existsSync31, readFileSync as readFileSync20, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
|
|
22929
24636
|
async function logsCommand(opts) {
|
|
22930
24637
|
const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
|
|
22931
|
-
if (!
|
|
24638
|
+
if (!existsSync31(logFile)) {
|
|
22932
24639
|
outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
|
|
22933
24640
|
process.exit(1);
|
|
22934
24641
|
}
|
|
22935
24642
|
const maxLines = parseInt(opts.lines ?? "100", 10);
|
|
22936
|
-
const content =
|
|
24643
|
+
const content = readFileSync20(logFile, "utf-8");
|
|
22937
24644
|
const allLines = content.split("\n");
|
|
22938
24645
|
const tailLines = allLines.slice(-maxLines);
|
|
22939
24646
|
console.log(muted(` \u2500\u2500 ${logFile} (last ${tailLines.length} lines) \u2500\u2500`));
|
|
@@ -22943,7 +24650,7 @@ async function logsCommand(opts) {
|
|
|
22943
24650
|
let lastLength = content.length;
|
|
22944
24651
|
watchFile2(logFile, { interval: 500 }, () => {
|
|
22945
24652
|
try {
|
|
22946
|
-
const newContent =
|
|
24653
|
+
const newContent = readFileSync20(logFile, "utf-8");
|
|
22947
24654
|
if (newContent.length > lastLength) {
|
|
22948
24655
|
const newPart = newContent.slice(lastLength);
|
|
22949
24656
|
process.stdout.write(newPart);
|
|
@@ -22980,11 +24687,11 @@ __export(gemini_exports, {
|
|
|
22980
24687
|
geminiReorder: () => geminiReorder,
|
|
22981
24688
|
geminiRotation: () => geminiRotation
|
|
22982
24689
|
});
|
|
22983
|
-
import { existsSync as
|
|
22984
|
-
import { join as
|
|
22985
|
-
import { createInterface as
|
|
24690
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync13, writeFileSync as writeFileSync10, readFileSync as readFileSync21, chmodSync } from "fs";
|
|
24691
|
+
import { join as join30 } from "path";
|
|
24692
|
+
import { createInterface as createInterface6 } from "readline";
|
|
22986
24693
|
function requireDb() {
|
|
22987
|
-
if (!
|
|
24694
|
+
if (!existsSync32(DB_PATH)) {
|
|
22988
24695
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
22989
24696
|
process.exit(1);
|
|
22990
24697
|
}
|
|
@@ -23009,9 +24716,9 @@ async function resolveSlotId(idOrLabel) {
|
|
|
23009
24716
|
function resolveOAuthEmail(configHome) {
|
|
23010
24717
|
if (!configHome) return null;
|
|
23011
24718
|
try {
|
|
23012
|
-
const accountsPath =
|
|
23013
|
-
if (!
|
|
23014
|
-
const accounts = JSON.parse(
|
|
24719
|
+
const accountsPath = join30(configHome, ".gemini", "google_accounts.json");
|
|
24720
|
+
if (!existsSync32(accountsPath)) return null;
|
|
24721
|
+
const accounts = JSON.parse(readFileSync21(accountsPath, "utf-8"));
|
|
23015
24722
|
return accounts.active || null;
|
|
23016
24723
|
} catch {
|
|
23017
24724
|
return null;
|
|
@@ -23055,7 +24762,7 @@ async function geminiList(globalOpts) {
|
|
|
23055
24762
|
}
|
|
23056
24763
|
async function geminiAddKey(globalOpts, opts) {
|
|
23057
24764
|
await requireWriteDb();
|
|
23058
|
-
const rl2 =
|
|
24765
|
+
const rl2 = createInterface6({ input: process.stdin, output: process.stdout });
|
|
23059
24766
|
const ask2 = (q) => new Promise((r) => rl2.question(q, r));
|
|
23060
24767
|
const key = await ask2("Paste your Gemini API key: ");
|
|
23061
24768
|
rl2.close();
|
|
@@ -23093,14 +24800,14 @@ async function geminiAddKey(globalOpts, opts) {
|
|
|
23093
24800
|
}
|
|
23094
24801
|
async function geminiAddAccount(globalOpts, opts) {
|
|
23095
24802
|
await requireWriteDb();
|
|
23096
|
-
const slotsDir =
|
|
23097
|
-
if (!
|
|
24803
|
+
const slotsDir = join30(CC_CLAW_HOME, "gemini-slots");
|
|
24804
|
+
if (!existsSync32(slotsDir)) mkdirSync13(slotsDir, { recursive: true });
|
|
23098
24805
|
const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
23099
24806
|
const tempId = Date.now();
|
|
23100
|
-
const slotDir =
|
|
24807
|
+
const slotDir = join30(slotsDir, `slot-${tempId}`);
|
|
23101
24808
|
mkdirSync13(slotDir, { recursive: true, mode: 448 });
|
|
23102
|
-
mkdirSync13(
|
|
23103
|
-
|
|
24809
|
+
mkdirSync13(join30(slotDir, ".gemini"), { recursive: true });
|
|
24810
|
+
writeFileSync10(join30(slotDir, ".gemini", "settings.json"), JSON.stringify({
|
|
23104
24811
|
security: { auth: { selectedType: "oauth-personal" } }
|
|
23105
24812
|
}, null, 2));
|
|
23106
24813
|
console.log("");
|
|
@@ -23117,8 +24824,8 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
23117
24824
|
});
|
|
23118
24825
|
} catch {
|
|
23119
24826
|
}
|
|
23120
|
-
const oauthPath =
|
|
23121
|
-
if (!
|
|
24827
|
+
const oauthPath = join30(slotDir, ".gemini", "oauth_creds.json");
|
|
24828
|
+
if (!existsSync32(oauthPath)) {
|
|
23122
24829
|
console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
|
|
23123
24830
|
console.log(" The slot directory is preserved at: " + slotDir);
|
|
23124
24831
|
console.log(" Re-run: cc-claw gemini add-account\n");
|
|
@@ -23126,7 +24833,7 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
23126
24833
|
}
|
|
23127
24834
|
let accountEmail = "unknown";
|
|
23128
24835
|
try {
|
|
23129
|
-
const accounts = JSON.parse(__require("fs").readFileSync(
|
|
24836
|
+
const accounts = JSON.parse(__require("fs").readFileSync(join30(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
|
|
23130
24837
|
accountEmail = accounts.active || accountEmail;
|
|
23131
24838
|
} catch {
|
|
23132
24839
|
}
|
|
@@ -23245,11 +24952,11 @@ __export(backend_cmd_factory_exports, {
|
|
|
23245
24952
|
makeReorder: () => makeReorder,
|
|
23246
24953
|
registerBackendSlotCommands: () => registerBackendSlotCommands
|
|
23247
24954
|
});
|
|
23248
|
-
import { existsSync as
|
|
23249
|
-
import { join as
|
|
23250
|
-
import { createInterface as
|
|
24955
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync14, readFileSync as readFileSync22 } from "fs";
|
|
24956
|
+
import { join as join31 } from "path";
|
|
24957
|
+
import { createInterface as createInterface7 } from "readline";
|
|
23251
24958
|
function requireDb2() {
|
|
23252
|
-
if (!
|
|
24959
|
+
if (!existsSync33(DB_PATH)) {
|
|
23253
24960
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
23254
24961
|
process.exit(1);
|
|
23255
24962
|
}
|
|
@@ -23308,7 +25015,7 @@ Add one with: cc-claw ${backend2} add-account or cc-claw ${backend2} add-key`)
|
|
|
23308
25015
|
function makeAddKey(backend2, displayName) {
|
|
23309
25016
|
return async function addKey(_globalOpts, opts) {
|
|
23310
25017
|
await requireWriteDb2();
|
|
23311
|
-
const rl2 =
|
|
25018
|
+
const rl2 = createInterface7({ input: process.stdin, output: process.stdout });
|
|
23312
25019
|
const ask2 = (q) => new Promise((r) => rl2.question(q, r));
|
|
23313
25020
|
const key = await ask2(`Paste your ${displayName} API key: `);
|
|
23314
25021
|
rl2.close();
|
|
@@ -23338,10 +25045,10 @@ function makeAddAccount(backend2, displayName) {
|
|
|
23338
25045
|
process.exit(1);
|
|
23339
25046
|
}
|
|
23340
25047
|
await requireWriteDb2();
|
|
23341
|
-
const slotsDir =
|
|
23342
|
-
if (!
|
|
25048
|
+
const slotsDir = join31(CC_CLAW_HOME, config2.slotsSubdir);
|
|
25049
|
+
if (!existsSync33(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
|
|
23343
25050
|
const tempId = Date.now();
|
|
23344
|
-
const slotDir =
|
|
25051
|
+
const slotDir = join31(slotsDir, `slot-${tempId}`);
|
|
23345
25052
|
mkdirSync14(slotDir, { recursive: true, mode: 448 });
|
|
23346
25053
|
if (config2.preSetup) config2.preSetup(slotDir);
|
|
23347
25054
|
console.log("");
|
|
@@ -23510,22 +25217,22 @@ var init_backend_cmd_factory = __esm({
|
|
|
23510
25217
|
envValue: (slotDir) => slotDir,
|
|
23511
25218
|
envOverrides: { ANTHROPIC_API_KEY: void 0 },
|
|
23512
25219
|
preSetup: (slotDir) => {
|
|
23513
|
-
mkdirSync14(
|
|
25220
|
+
mkdirSync14(join31(slotDir, ".claude"), { recursive: true });
|
|
23514
25221
|
},
|
|
23515
25222
|
verifyCredentials: (slotDir) => {
|
|
23516
|
-
const claudeJson =
|
|
23517
|
-
const claudeJsonNested =
|
|
23518
|
-
if (
|
|
25223
|
+
const claudeJson = join31(slotDir, ".claude.json");
|
|
25224
|
+
const claudeJsonNested = join31(slotDir, ".claude", ".claude.json");
|
|
25225
|
+
if (existsSync33(claudeJson)) {
|
|
23519
25226
|
try {
|
|
23520
|
-
const data = JSON.parse(
|
|
25227
|
+
const data = JSON.parse(readFileSync22(claudeJson, "utf-8"));
|
|
23521
25228
|
return Boolean(data.oauthAccount);
|
|
23522
25229
|
} catch {
|
|
23523
25230
|
return false;
|
|
23524
25231
|
}
|
|
23525
25232
|
}
|
|
23526
|
-
if (
|
|
25233
|
+
if (existsSync33(claudeJsonNested)) {
|
|
23527
25234
|
try {
|
|
23528
|
-
const data = JSON.parse(
|
|
25235
|
+
const data = JSON.parse(readFileSync22(claudeJsonNested, "utf-8"));
|
|
23529
25236
|
return Boolean(data.oauthAccount);
|
|
23530
25237
|
} catch {
|
|
23531
25238
|
return false;
|
|
@@ -23546,9 +25253,9 @@ var init_backend_cmd_factory = __esm({
|
|
|
23546
25253
|
} catch {
|
|
23547
25254
|
}
|
|
23548
25255
|
try {
|
|
23549
|
-
const claudeJson =
|
|
23550
|
-
if (
|
|
23551
|
-
const data = JSON.parse(
|
|
25256
|
+
const claudeJson = join31(slotDir, ".claude.json");
|
|
25257
|
+
if (existsSync33(claudeJson)) {
|
|
25258
|
+
const data = JSON.parse(readFileSync22(claudeJson, "utf-8"));
|
|
23552
25259
|
if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
|
|
23553
25260
|
}
|
|
23554
25261
|
} catch {
|
|
@@ -23563,11 +25270,11 @@ var init_backend_cmd_factory = __esm({
|
|
|
23563
25270
|
envValue: (slotDir) => slotDir,
|
|
23564
25271
|
envOverrides: { OPENAI_API_KEY: void 0 },
|
|
23565
25272
|
verifyCredentials: (slotDir) => {
|
|
23566
|
-
return
|
|
25273
|
+
return existsSync33(join31(slotDir, "auth.json"));
|
|
23567
25274
|
},
|
|
23568
25275
|
extractLabel: (slotDir) => {
|
|
23569
25276
|
try {
|
|
23570
|
-
const authData = JSON.parse(
|
|
25277
|
+
const authData = JSON.parse(readFileSync22(join31(slotDir, "auth.json"), "utf-8"));
|
|
23571
25278
|
if (authData.email) return authData.email;
|
|
23572
25279
|
if (authData.account_name) return authData.account_name;
|
|
23573
25280
|
if (authData.user?.email) return authData.user.email;
|
|
@@ -23587,12 +25294,12 @@ __export(backend_exports, {
|
|
|
23587
25294
|
backendList: () => backendList,
|
|
23588
25295
|
backendSet: () => backendSet
|
|
23589
25296
|
});
|
|
23590
|
-
import { existsSync as
|
|
25297
|
+
import { existsSync as existsSync34 } from "fs";
|
|
23591
25298
|
async function backendList(globalOpts) {
|
|
23592
25299
|
const { getAvailableAdapters: getAvailableAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
23593
25300
|
const chatId = resolveChatId(globalOpts);
|
|
23594
25301
|
let activeBackend = null;
|
|
23595
|
-
if (
|
|
25302
|
+
if (existsSync34(DB_PATH)) {
|
|
23596
25303
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
23597
25304
|
const readDb = openDatabaseReadOnly2();
|
|
23598
25305
|
try {
|
|
@@ -23623,7 +25330,7 @@ async function backendList(globalOpts) {
|
|
|
23623
25330
|
}
|
|
23624
25331
|
async function backendGet(globalOpts) {
|
|
23625
25332
|
const chatId = resolveChatId(globalOpts);
|
|
23626
|
-
if (!
|
|
25333
|
+
if (!existsSync34(DB_PATH)) {
|
|
23627
25334
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
23628
25335
|
process.exit(1);
|
|
23629
25336
|
}
|
|
@@ -23667,13 +25374,13 @@ __export(model_exports, {
|
|
|
23667
25374
|
modelList: () => modelList,
|
|
23668
25375
|
modelSet: () => modelSet
|
|
23669
25376
|
});
|
|
23670
|
-
import { existsSync as
|
|
25377
|
+
import { existsSync as existsSync35 } from "fs";
|
|
23671
25378
|
async function modelList(globalOpts) {
|
|
23672
25379
|
const chatId = resolveChatId(globalOpts);
|
|
23673
25380
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
23674
25381
|
const { getAdapter: getAdapter4, getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
23675
25382
|
let backendId = "claude";
|
|
23676
|
-
if (
|
|
25383
|
+
if (existsSync35(DB_PATH)) {
|
|
23677
25384
|
const readDb = openDatabaseReadOnly2();
|
|
23678
25385
|
try {
|
|
23679
25386
|
const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
|
|
@@ -23706,7 +25413,7 @@ async function modelList(globalOpts) {
|
|
|
23706
25413
|
}
|
|
23707
25414
|
async function modelGet(globalOpts) {
|
|
23708
25415
|
const chatId = resolveChatId(globalOpts);
|
|
23709
|
-
if (!
|
|
25416
|
+
if (!existsSync35(DB_PATH)) {
|
|
23710
25417
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23711
25418
|
process.exit(1);
|
|
23712
25419
|
}
|
|
@@ -23750,9 +25457,9 @@ __export(memory_exports2, {
|
|
|
23750
25457
|
memoryList: () => memoryList,
|
|
23751
25458
|
memorySearch: () => memorySearch
|
|
23752
25459
|
});
|
|
23753
|
-
import { existsSync as
|
|
25460
|
+
import { existsSync as existsSync36 } from "fs";
|
|
23754
25461
|
async function memoryList(globalOpts) {
|
|
23755
|
-
if (!
|
|
25462
|
+
if (!existsSync36(DB_PATH)) {
|
|
23756
25463
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
23757
25464
|
process.exit(1);
|
|
23758
25465
|
}
|
|
@@ -23776,7 +25483,7 @@ async function memoryList(globalOpts) {
|
|
|
23776
25483
|
});
|
|
23777
25484
|
}
|
|
23778
25485
|
async function memorySearch(globalOpts, query) {
|
|
23779
|
-
if (!
|
|
25486
|
+
if (!existsSync36(DB_PATH)) {
|
|
23780
25487
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23781
25488
|
process.exit(1);
|
|
23782
25489
|
}
|
|
@@ -23798,7 +25505,7 @@ async function memorySearch(globalOpts, query) {
|
|
|
23798
25505
|
});
|
|
23799
25506
|
}
|
|
23800
25507
|
async function memoryHistory(globalOpts, opts) {
|
|
23801
|
-
if (!
|
|
25508
|
+
if (!existsSync36(DB_PATH)) {
|
|
23802
25509
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23803
25510
|
process.exit(1);
|
|
23804
25511
|
}
|
|
@@ -23846,7 +25553,7 @@ __export(cron_exports2, {
|
|
|
23846
25553
|
cronList: () => cronList,
|
|
23847
25554
|
cronRuns: () => cronRuns
|
|
23848
25555
|
});
|
|
23849
|
-
import { existsSync as
|
|
25556
|
+
import { existsSync as existsSync37 } from "fs";
|
|
23850
25557
|
function parseFallbacks(raw) {
|
|
23851
25558
|
return raw.slice(0, 3).map((f) => {
|
|
23852
25559
|
const [backend2, ...rest] = f.split(":");
|
|
@@ -23867,7 +25574,7 @@ function parseAndValidateTimeout(raw) {
|
|
|
23867
25574
|
return val;
|
|
23868
25575
|
}
|
|
23869
25576
|
async function cronList(globalOpts) {
|
|
23870
|
-
if (!
|
|
25577
|
+
if (!existsSync37(DB_PATH)) {
|
|
23871
25578
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23872
25579
|
process.exit(1);
|
|
23873
25580
|
}
|
|
@@ -23905,7 +25612,7 @@ async function cronList(globalOpts) {
|
|
|
23905
25612
|
});
|
|
23906
25613
|
}
|
|
23907
25614
|
async function cronHealth(globalOpts) {
|
|
23908
|
-
if (!
|
|
25615
|
+
if (!existsSync37(DB_PATH)) {
|
|
23909
25616
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23910
25617
|
process.exit(1);
|
|
23911
25618
|
}
|
|
@@ -24064,7 +25771,7 @@ async function cronEdit(globalOpts, id, opts) {
|
|
|
24064
25771
|
}
|
|
24065
25772
|
}
|
|
24066
25773
|
async function cronRuns(globalOpts, jobId, opts) {
|
|
24067
|
-
if (!
|
|
25774
|
+
if (!existsSync37(DB_PATH)) {
|
|
24068
25775
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24069
25776
|
process.exit(1);
|
|
24070
25777
|
}
|
|
@@ -24111,9 +25818,9 @@ __export(agents_exports, {
|
|
|
24111
25818
|
runnersList: () => runnersList,
|
|
24112
25819
|
tasksList: () => tasksList
|
|
24113
25820
|
});
|
|
24114
|
-
import { existsSync as
|
|
25821
|
+
import { existsSync as existsSync38 } from "fs";
|
|
24115
25822
|
async function agentsList(globalOpts) {
|
|
24116
|
-
if (!
|
|
25823
|
+
if (!existsSync38(DB_PATH)) {
|
|
24117
25824
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24118
25825
|
process.exit(1);
|
|
24119
25826
|
}
|
|
@@ -24144,7 +25851,7 @@ async function agentsList(globalOpts) {
|
|
|
24144
25851
|
});
|
|
24145
25852
|
}
|
|
24146
25853
|
async function tasksList(globalOpts) {
|
|
24147
|
-
if (!
|
|
25854
|
+
if (!existsSync38(DB_PATH)) {
|
|
24148
25855
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24149
25856
|
process.exit(1);
|
|
24150
25857
|
}
|
|
@@ -24272,18 +25979,18 @@ __export(db_exports, {
|
|
|
24272
25979
|
dbPath: () => dbPath,
|
|
24273
25980
|
dbStats: () => dbStats
|
|
24274
25981
|
});
|
|
24275
|
-
import { existsSync as
|
|
24276
|
-
import { dirname as
|
|
25982
|
+
import { existsSync as existsSync39, statSync as statSync10, copyFileSync as copyFileSync3, mkdirSync as mkdirSync15 } from "fs";
|
|
25983
|
+
import { dirname as dirname7 } from "path";
|
|
24277
25984
|
async function dbStats(globalOpts) {
|
|
24278
|
-
if (!
|
|
25985
|
+
if (!existsSync39(DB_PATH)) {
|
|
24279
25986
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
24280
25987
|
process.exit(1);
|
|
24281
25988
|
}
|
|
24282
25989
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
24283
25990
|
const readDb = openDatabaseReadOnly2();
|
|
24284
|
-
const mainSize =
|
|
25991
|
+
const mainSize = statSync10(DB_PATH).size;
|
|
24285
25992
|
const walPath = DB_PATH + "-wal";
|
|
24286
|
-
const walSize =
|
|
25993
|
+
const walSize = existsSync39(walPath) ? statSync10(walPath).size : 0;
|
|
24287
25994
|
const tableNames = readDb.prepare(
|
|
24288
25995
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
|
|
24289
25996
|
).all();
|
|
@@ -24317,17 +26024,17 @@ async function dbPath(globalOpts) {
|
|
|
24317
26024
|
output({ path: DB_PATH }, (d) => d.path);
|
|
24318
26025
|
}
|
|
24319
26026
|
async function dbBackup(globalOpts, destPath) {
|
|
24320
|
-
if (!
|
|
26027
|
+
if (!existsSync39(DB_PATH)) {
|
|
24321
26028
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
24322
26029
|
process.exit(1);
|
|
24323
26030
|
}
|
|
24324
26031
|
const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
24325
26032
|
try {
|
|
24326
|
-
mkdirSync15(
|
|
26033
|
+
mkdirSync15(dirname7(dest), { recursive: true });
|
|
24327
26034
|
copyFileSync3(DB_PATH, dest);
|
|
24328
26035
|
const walPath = DB_PATH + "-wal";
|
|
24329
|
-
if (
|
|
24330
|
-
output({ path: dest, sizeBytes:
|
|
26036
|
+
if (existsSync39(walPath)) copyFileSync3(walPath, dest + "-wal");
|
|
26037
|
+
output({ path: dest, sizeBytes: statSync10(dest).size }, (d) => {
|
|
24331
26038
|
const b = d;
|
|
24332
26039
|
return `
|
|
24333
26040
|
${success("Backup created:")} ${b.path} (${(b.sizeBytes / 1024).toFixed(0)}KB)
|
|
@@ -24355,9 +26062,9 @@ __export(usage_exports, {
|
|
|
24355
26062
|
usageCost: () => usageCost,
|
|
24356
26063
|
usageTokens: () => usageTokens
|
|
24357
26064
|
});
|
|
24358
|
-
import { existsSync as
|
|
26065
|
+
import { existsSync as existsSync40 } from "fs";
|
|
24359
26066
|
function ensureDb() {
|
|
24360
|
-
if (!
|
|
26067
|
+
if (!existsSync40(DB_PATH)) {
|
|
24361
26068
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
24362
26069
|
process.exit(1);
|
|
24363
26070
|
}
|
|
@@ -24547,9 +26254,9 @@ __export(config_exports2, {
|
|
|
24547
26254
|
configList: () => configList,
|
|
24548
26255
|
configSet: () => configSet
|
|
24549
26256
|
});
|
|
24550
|
-
import { existsSync as
|
|
26257
|
+
import { existsSync as existsSync41, readFileSync as readFileSync23 } from "fs";
|
|
24551
26258
|
async function configList(globalOpts) {
|
|
24552
|
-
if (!
|
|
26259
|
+
if (!existsSync41(DB_PATH)) {
|
|
24553
26260
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24554
26261
|
process.exit(1);
|
|
24555
26262
|
}
|
|
@@ -24583,7 +26290,7 @@ async function configGet(globalOpts, key) {
|
|
|
24583
26290
|
outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
|
|
24584
26291
|
process.exit(1);
|
|
24585
26292
|
}
|
|
24586
|
-
if (!
|
|
26293
|
+
if (!existsSync41(DB_PATH)) {
|
|
24587
26294
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24588
26295
|
process.exit(1);
|
|
24589
26296
|
}
|
|
@@ -24629,11 +26336,11 @@ async function configSet(globalOpts, key, value) {
|
|
|
24629
26336
|
}
|
|
24630
26337
|
}
|
|
24631
26338
|
async function configEnv(_globalOpts) {
|
|
24632
|
-
if (!
|
|
26339
|
+
if (!existsSync41(ENV_PATH)) {
|
|
24633
26340
|
outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
|
|
24634
26341
|
process.exit(1);
|
|
24635
26342
|
}
|
|
24636
|
-
const content =
|
|
26343
|
+
const content = readFileSync23(ENV_PATH, "utf-8");
|
|
24637
26344
|
const entries = {};
|
|
24638
26345
|
const secretPatterns = /TOKEN|KEY|SECRET|PASSWORD|CREDENTIALS/i;
|
|
24639
26346
|
for (const line of content.split("\n")) {
|
|
@@ -24683,9 +26390,9 @@ __export(session_exports, {
|
|
|
24683
26390
|
sessionGet: () => sessionGet,
|
|
24684
26391
|
sessionNew: () => sessionNew
|
|
24685
26392
|
});
|
|
24686
|
-
import { existsSync as
|
|
26393
|
+
import { existsSync as existsSync42 } from "fs";
|
|
24687
26394
|
async function sessionGet(globalOpts) {
|
|
24688
|
-
if (!
|
|
26395
|
+
if (!existsSync42(DB_PATH)) {
|
|
24689
26396
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24690
26397
|
process.exit(1);
|
|
24691
26398
|
}
|
|
@@ -24746,9 +26453,9 @@ __export(permissions_exports, {
|
|
|
24746
26453
|
verboseGet: () => verboseGet,
|
|
24747
26454
|
verboseSet: () => verboseSet
|
|
24748
26455
|
});
|
|
24749
|
-
import { existsSync as
|
|
26456
|
+
import { existsSync as existsSync43 } from "fs";
|
|
24750
26457
|
function ensureDb2() {
|
|
24751
|
-
if (!
|
|
26458
|
+
if (!existsSync43(DB_PATH)) {
|
|
24752
26459
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24753
26460
|
process.exit(1);
|
|
24754
26461
|
}
|
|
@@ -24895,9 +26602,9 @@ __export(cwd_exports, {
|
|
|
24895
26602
|
cwdGet: () => cwdGet,
|
|
24896
26603
|
cwdSet: () => cwdSet
|
|
24897
26604
|
});
|
|
24898
|
-
import { existsSync as
|
|
26605
|
+
import { existsSync as existsSync44 } from "fs";
|
|
24899
26606
|
async function cwdGet(globalOpts) {
|
|
24900
|
-
if (!
|
|
26607
|
+
if (!existsSync44(DB_PATH)) {
|
|
24901
26608
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24902
26609
|
process.exit(1);
|
|
24903
26610
|
}
|
|
@@ -24959,9 +26666,9 @@ __export(voice_exports, {
|
|
|
24959
26666
|
voiceGet: () => voiceGet,
|
|
24960
26667
|
voiceSet: () => voiceSet
|
|
24961
26668
|
});
|
|
24962
|
-
import { existsSync as
|
|
26669
|
+
import { existsSync as existsSync45 } from "fs";
|
|
24963
26670
|
async function voiceGet(globalOpts) {
|
|
24964
|
-
if (!
|
|
26671
|
+
if (!existsSync45(DB_PATH)) {
|
|
24965
26672
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24966
26673
|
process.exit(1);
|
|
24967
26674
|
}
|
|
@@ -25010,9 +26717,9 @@ __export(heartbeat_exports, {
|
|
|
25010
26717
|
heartbeatGet: () => heartbeatGet,
|
|
25011
26718
|
heartbeatSet: () => heartbeatSet
|
|
25012
26719
|
});
|
|
25013
|
-
import { existsSync as
|
|
26720
|
+
import { existsSync as existsSync46 } from "fs";
|
|
25014
26721
|
async function heartbeatGet(globalOpts) {
|
|
25015
|
-
if (!
|
|
26722
|
+
if (!existsSync46(DB_PATH)) {
|
|
25016
26723
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25017
26724
|
process.exit(1);
|
|
25018
26725
|
}
|
|
@@ -25121,9 +26828,9 @@ __export(summarizer_exports, {
|
|
|
25121
26828
|
summarizerGet: () => summarizerGet,
|
|
25122
26829
|
summarizerSet: () => summarizerSet
|
|
25123
26830
|
});
|
|
25124
|
-
import { existsSync as
|
|
26831
|
+
import { existsSync as existsSync47 } from "fs";
|
|
25125
26832
|
async function summarizerGet(globalOpts) {
|
|
25126
|
-
if (!
|
|
26833
|
+
if (!existsSync47(DB_PATH)) {
|
|
25127
26834
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25128
26835
|
process.exit(1);
|
|
25129
26836
|
}
|
|
@@ -25167,9 +26874,9 @@ __export(thinking_exports, {
|
|
|
25167
26874
|
thinkingGet: () => thinkingGet,
|
|
25168
26875
|
thinkingSet: () => thinkingSet
|
|
25169
26876
|
});
|
|
25170
|
-
import { existsSync as
|
|
26877
|
+
import { existsSync as existsSync48 } from "fs";
|
|
25171
26878
|
async function thinkingGet(globalOpts) {
|
|
25172
|
-
if (!
|
|
26879
|
+
if (!existsSync48(DB_PATH)) {
|
|
25173
26880
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25174
26881
|
process.exit(1);
|
|
25175
26882
|
}
|
|
@@ -25213,9 +26920,9 @@ __export(chats_exports, {
|
|
|
25213
26920
|
chatsList: () => chatsList,
|
|
25214
26921
|
chatsRemoveAlias: () => chatsRemoveAlias
|
|
25215
26922
|
});
|
|
25216
|
-
import { existsSync as
|
|
26923
|
+
import { existsSync as existsSync49 } from "fs";
|
|
25217
26924
|
async function chatsList(_globalOpts) {
|
|
25218
|
-
if (!
|
|
26925
|
+
if (!existsSync49(DB_PATH)) {
|
|
25219
26926
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25220
26927
|
process.exit(1);
|
|
25221
26928
|
}
|
|
@@ -25343,9 +27050,9 @@ var mcps_exports2 = {};
|
|
|
25343
27050
|
__export(mcps_exports2, {
|
|
25344
27051
|
mcpsList: () => mcpsList
|
|
25345
27052
|
});
|
|
25346
|
-
import { existsSync as
|
|
27053
|
+
import { existsSync as existsSync50 } from "fs";
|
|
25347
27054
|
async function mcpsList(_globalOpts) {
|
|
25348
|
-
if (!
|
|
27055
|
+
if (!existsSync50(DB_PATH)) {
|
|
25349
27056
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25350
27057
|
process.exit(1);
|
|
25351
27058
|
}
|
|
@@ -25382,11 +27089,11 @@ __export(chat_exports2, {
|
|
|
25382
27089
|
chatSend: () => chatSend
|
|
25383
27090
|
});
|
|
25384
27091
|
import { request as httpRequest2 } from "http";
|
|
25385
|
-
import { readFileSync as
|
|
27092
|
+
import { readFileSync as readFileSync24, existsSync as existsSync51 } from "fs";
|
|
25386
27093
|
function getToken2() {
|
|
25387
27094
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
25388
27095
|
try {
|
|
25389
|
-
if (
|
|
27096
|
+
if (existsSync51(TOKEN_PATH2)) return readFileSync24(TOKEN_PATH2, "utf-8").trim();
|
|
25390
27097
|
} catch {
|
|
25391
27098
|
}
|
|
25392
27099
|
return null;
|
|
@@ -25523,7 +27230,7 @@ var tui_exports = {};
|
|
|
25523
27230
|
__export(tui_exports, {
|
|
25524
27231
|
tuiCommand: () => tuiCommand
|
|
25525
27232
|
});
|
|
25526
|
-
import { createInterface as
|
|
27233
|
+
import { createInterface as createInterface8 } from "readline";
|
|
25527
27234
|
import pc2 from "picocolors";
|
|
25528
27235
|
async function tuiCommand(globalOpts, cmdOpts) {
|
|
25529
27236
|
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
@@ -25533,7 +27240,7 @@ async function tuiCommand(globalOpts, cmdOpts) {
|
|
|
25533
27240
|
}
|
|
25534
27241
|
const chatId = resolveChatId(globalOpts);
|
|
25535
27242
|
const { chatSend: chatSend2 } = await Promise.resolve().then(() => (init_chat2(), chat_exports2));
|
|
25536
|
-
const rl2 =
|
|
27243
|
+
const rl2 = createInterface8({
|
|
25537
27244
|
input: process.stdin,
|
|
25538
27245
|
output: process.stdout,
|
|
25539
27246
|
prompt: pc2.cyan("you > "),
|
|
@@ -25665,9 +27372,9 @@ var completion_exports = {};
|
|
|
25665
27372
|
__export(completion_exports, {
|
|
25666
27373
|
completionCommand: () => completionCommand
|
|
25667
27374
|
});
|
|
25668
|
-
import { writeFileSync as
|
|
25669
|
-
import { join as
|
|
25670
|
-
import { homedir as
|
|
27375
|
+
import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync16 } from "fs";
|
|
27376
|
+
import { join as join32 } from "path";
|
|
27377
|
+
import { homedir as homedir11 } from "os";
|
|
25671
27378
|
async function completionCommand(opts) {
|
|
25672
27379
|
const shell = opts.shell ?? detectShell();
|
|
25673
27380
|
let script;
|
|
@@ -25682,11 +27389,11 @@ async function completionCommand(opts) {
|
|
|
25682
27389
|
process.exit(1);
|
|
25683
27390
|
}
|
|
25684
27391
|
if (opts.install) {
|
|
25685
|
-
const dir =
|
|
27392
|
+
const dir = join32(homedir11(), ".config", "cc-claw", "completions");
|
|
25686
27393
|
mkdirSync16(dir, { recursive: true });
|
|
25687
27394
|
const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
|
|
25688
|
-
const filepath =
|
|
25689
|
-
|
|
27395
|
+
const filepath = join32(dir, filename);
|
|
27396
|
+
writeFileSync11(filepath, script, "utf-8");
|
|
25690
27397
|
console.log(`\u2713 Completion script written to ${filepath}
|
|
25691
27398
|
`);
|
|
25692
27399
|
if (shell === "zsh") {
|
|
@@ -25856,9 +27563,9 @@ __export(evolve_exports2, {
|
|
|
25856
27563
|
evolveStatus: () => evolveStatus,
|
|
25857
27564
|
evolveUndo: () => evolveUndo
|
|
25858
27565
|
});
|
|
25859
|
-
import { existsSync as
|
|
27566
|
+
import { existsSync as existsSync52 } from "fs";
|
|
25860
27567
|
function ensureDb3() {
|
|
25861
|
-
if (!
|
|
27568
|
+
if (!existsSync52(DB_PATH)) {
|
|
25862
27569
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
25863
27570
|
process.exit(1);
|
|
25864
27571
|
}
|
|
@@ -26272,12 +27979,70 @@ var init_evolve3 = __esm({
|
|
|
26272
27979
|
}
|
|
26273
27980
|
});
|
|
26274
27981
|
|
|
27982
|
+
// src/cli/commands/optimize.ts
|
|
27983
|
+
var optimize_exports = {};
|
|
27984
|
+
__export(optimize_exports, {
|
|
27985
|
+
optimizeSkills: () => optimizeSkills,
|
|
27986
|
+
optimizeStatus: () => optimizeStatus
|
|
27987
|
+
});
|
|
27988
|
+
async function optimizeStatus() {
|
|
27989
|
+
const { listCcClawSkills: listCcClawSkills2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
27990
|
+
const skills2 = listCcClawSkills2();
|
|
27991
|
+
output({
|
|
27992
|
+
status: "ok",
|
|
27993
|
+
description: "Run identity and skill audits via Telegram with /optimize",
|
|
27994
|
+
availableSkills: skills2.length,
|
|
27995
|
+
skillNames: skills2.map((s) => s.name)
|
|
27996
|
+
}, () => {
|
|
27997
|
+
const lines = [
|
|
27998
|
+
box("\u{1F527} CC-Claw Optimizer"),
|
|
27999
|
+
"",
|
|
28000
|
+
" Use /optimize in Telegram for the interactive audit experience.",
|
|
28001
|
+
"",
|
|
28002
|
+
divider("CLI subcommands"),
|
|
28003
|
+
kvLine("skills", "List available CC-Claw skills"),
|
|
28004
|
+
"",
|
|
28005
|
+
muted(` \u{1F4CA} ${skills2.length} skill(s) available for audit`),
|
|
28006
|
+
""
|
|
28007
|
+
];
|
|
28008
|
+
return lines.join("\n");
|
|
28009
|
+
});
|
|
28010
|
+
}
|
|
28011
|
+
async function optimizeSkills() {
|
|
28012
|
+
const { listCcClawSkills: listCcClawSkills2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
28013
|
+
const skills2 = listCcClawSkills2();
|
|
28014
|
+
output({
|
|
28015
|
+
status: "ok",
|
|
28016
|
+
skills: skills2.map((s) => ({ name: s.name, path: s.path, description: s.description })),
|
|
28017
|
+
count: skills2.length
|
|
28018
|
+
}, () => {
|
|
28019
|
+
if (skills2.length === 0) {
|
|
28020
|
+
return " No CC-Claw skills found in ~/.cc-claw/workspace/skills/";
|
|
28021
|
+
}
|
|
28022
|
+
const lines = [
|
|
28023
|
+
box("\u{1F9E9} CC-Claw Skills"),
|
|
28024
|
+
"",
|
|
28025
|
+
...skills2.map((s) => kvLine(s.name, s.description)),
|
|
28026
|
+
"",
|
|
28027
|
+
muted(` ${skills2.length} skill(s) \u2014 use /optimize in Telegram to audit`),
|
|
28028
|
+
""
|
|
28029
|
+
];
|
|
28030
|
+
return lines.join("\n");
|
|
28031
|
+
});
|
|
28032
|
+
}
|
|
28033
|
+
var init_optimize2 = __esm({
|
|
28034
|
+
"src/cli/commands/optimize.ts"() {
|
|
28035
|
+
"use strict";
|
|
28036
|
+
init_format2();
|
|
28037
|
+
}
|
|
28038
|
+
});
|
|
28039
|
+
|
|
26275
28040
|
// src/setup.ts
|
|
26276
28041
|
var setup_exports = {};
|
|
26277
|
-
import { existsSync as
|
|
28042
|
+
import { existsSync as existsSync53, writeFileSync as writeFileSync12, readFileSync as readFileSync25, copyFileSync as copyFileSync4, mkdirSync as mkdirSync17, statSync as statSync11 } from "fs";
|
|
26278
28043
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
26279
|
-
import { createInterface as
|
|
26280
|
-
import { join as
|
|
28044
|
+
import { createInterface as createInterface9 } from "readline";
|
|
28045
|
+
import { join as join33 } from "path";
|
|
26281
28046
|
function divider2() {
|
|
26282
28047
|
console.log(dim("\u2500".repeat(55)));
|
|
26283
28048
|
}
|
|
@@ -26352,22 +28117,22 @@ async function setup() {
|
|
|
26352
28117
|
}
|
|
26353
28118
|
console.log("");
|
|
26354
28119
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
26355
|
-
if (!
|
|
28120
|
+
if (!existsSync53(dir)) mkdirSync17(dir, { recursive: true });
|
|
26356
28121
|
}
|
|
26357
28122
|
const env = {};
|
|
26358
|
-
const envSource =
|
|
28123
|
+
const envSource = existsSync53(ENV_PATH) ? ENV_PATH : existsSync53(".env") ? ".env" : null;
|
|
26359
28124
|
if (envSource) {
|
|
26360
28125
|
console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
|
|
26361
28126
|
console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
|
|
26362
|
-
const existing =
|
|
28127
|
+
const existing = readFileSync25(envSource, "utf-8");
|
|
26363
28128
|
for (const line of existing.split("\n")) {
|
|
26364
28129
|
const match = line.match(/^([^#=]+)=(.*)$/);
|
|
26365
28130
|
if (match) env[match[1].trim()] = match[2].trim();
|
|
26366
28131
|
}
|
|
26367
28132
|
}
|
|
26368
|
-
const cwdDb =
|
|
26369
|
-
if (
|
|
26370
|
-
const { size } =
|
|
28133
|
+
const cwdDb = join33(process.cwd(), "cc-claw.db");
|
|
28134
|
+
if (existsSync53(cwdDb) && !existsSync53(DB_PATH)) {
|
|
28135
|
+
const { size } = statSync11(cwdDb);
|
|
26371
28136
|
console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
|
|
26372
28137
|
const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
|
|
26373
28138
|
if (migrate) {
|
|
@@ -26583,7 +28348,7 @@ async function setup() {
|
|
|
26583
28348
|
envLines.push("", "# Video Analysis", `GEMINI_API_KEY=${env.GEMINI_API_KEY}`);
|
|
26584
28349
|
}
|
|
26585
28350
|
const envContent = envLines.join("\n") + "\n";
|
|
26586
|
-
|
|
28351
|
+
writeFileSync12(ENV_PATH, envContent, { mode: 384 });
|
|
26587
28352
|
console.log(green(` Config saved to ${ENV_PATH} (permissions: owner-only)`));
|
|
26588
28353
|
header(6, TOTAL_STEPS, "Run on Startup (Daemon)");
|
|
26589
28354
|
console.log(" CC-Claw can run automatically in the background, starting");
|
|
@@ -26639,7 +28404,7 @@ var init_setup = __esm({
|
|
|
26639
28404
|
"src/setup.ts"() {
|
|
26640
28405
|
"use strict";
|
|
26641
28406
|
init_paths();
|
|
26642
|
-
rl =
|
|
28407
|
+
rl = createInterface9({ input: process.stdin, output: process.stdout });
|
|
26643
28408
|
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
26644
28409
|
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
26645
28410
|
green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
@@ -27164,6 +28929,15 @@ evolve.command("settings").description("View or update reflection settings").opt
|
|
|
27164
28929
|
const { evolveSettings: evolveSettings2 } = await Promise.resolve().then(() => (init_evolve3(), evolve_exports2));
|
|
27165
28930
|
await evolveSettings2(program.opts(), opts);
|
|
27166
28931
|
});
|
|
28932
|
+
var optimize = program.command("optimize").description("Audit identity files and skills");
|
|
28933
|
+
optimize.action(async () => {
|
|
28934
|
+
const { optimizeStatus: optimizeStatus2 } = await Promise.resolve().then(() => (init_optimize2(), optimize_exports));
|
|
28935
|
+
await optimizeStatus2();
|
|
28936
|
+
});
|
|
28937
|
+
optimize.command("skills").description("List available CC-Claw skills").action(async () => {
|
|
28938
|
+
const { optimizeSkills: optimizeSkills2 } = await Promise.resolve().then(() => (init_optimize2(), optimize_exports));
|
|
28939
|
+
await optimizeSkills2();
|
|
28940
|
+
});
|
|
27167
28941
|
program.command("start", { hidden: true }).description("Run the bot in the foreground (use 'service start' for background daemon)").action(async () => {
|
|
27168
28942
|
await Promise.resolve().then(() => (init_index(), index_exports));
|
|
27169
28943
|
});
|