cc-claw 0.17.2 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/mcp-server.js +1 -1
- package/dist/cli.js +2635 -455
- 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.1" : (() => {
|
|
37
37
|
try {
|
|
38
38
|
return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
39
39
|
} catch {
|
|
@@ -57,16 +57,25 @@ __export(paths_exports, {
|
|
|
57
57
|
LOG_PATH: () => LOG_PATH,
|
|
58
58
|
MEDIA_PATH: () => MEDIA_PATH,
|
|
59
59
|
RUNNERS_PATH: () => RUNNERS_PATH,
|
|
60
|
+
SESSION_LOGS_PATH: () => SESSION_LOGS_PATH,
|
|
60
61
|
SKILLS_PATH: () => SKILLS_PATH,
|
|
61
62
|
WORKSPACE_PATH: () => WORKSPACE_PATH
|
|
62
63
|
});
|
|
63
|
-
import { homedir } from "os";
|
|
64
|
+
import { homedir, userInfo } from "os";
|
|
64
65
|
import { join as join2 } from "path";
|
|
65
|
-
|
|
66
|
+
function resolveRealHome() {
|
|
67
|
+
try {
|
|
68
|
+
const info = userInfo();
|
|
69
|
+
if (info.homedir) return info.homedir;
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
return homedir();
|
|
73
|
+
}
|
|
74
|
+
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, SESSION_LOGS_PATH, MEDIA_PATH;
|
|
66
75
|
var init_paths = __esm({
|
|
67
76
|
"src/paths.ts"() {
|
|
68
77
|
"use strict";
|
|
69
|
-
CC_CLAW_HOME = process.env.CC_CLAW_HOME ?? join2(
|
|
78
|
+
CC_CLAW_HOME = process.env.CC_CLAW_HOME ?? join2(resolveRealHome(), ".cc-claw");
|
|
70
79
|
ENV_PATH = join2(CC_CLAW_HOME, ".env");
|
|
71
80
|
DATA_PATH = join2(CC_CLAW_HOME, "data");
|
|
72
81
|
DB_PATH = process.env.DB_PATH ?? join2(DATA_PATH, "cc-claw.db");
|
|
@@ -78,6 +87,7 @@ var init_paths = __esm({
|
|
|
78
87
|
SKILLS_PATH = join2(WORKSPACE_PATH, "skills");
|
|
79
88
|
RUNNERS_PATH = join2(CC_CLAW_HOME, "runners");
|
|
80
89
|
AGENTS_PATH = join2(CC_CLAW_HOME, "agents");
|
|
90
|
+
SESSION_LOGS_PATH = join2(LOGS_PATH, "sessions");
|
|
81
91
|
MEDIA_PATH = join2(CC_CLAW_HOME, "media");
|
|
82
92
|
}
|
|
83
93
|
});
|
|
@@ -1735,6 +1745,18 @@ function initSchema(db3) {
|
|
|
1735
1745
|
mode TEXT NOT NULL DEFAULT 'approved'
|
|
1736
1746
|
);
|
|
1737
1747
|
`);
|
|
1748
|
+
db3.exec(`
|
|
1749
|
+
CREATE TABLE IF NOT EXISTS chat_show_thinking_ui (
|
|
1750
|
+
chat_id TEXT PRIMARY KEY,
|
|
1751
|
+
value INTEGER NOT NULL DEFAULT 0
|
|
1752
|
+
);
|
|
1753
|
+
`);
|
|
1754
|
+
db3.exec(`
|
|
1755
|
+
CREATE TABLE IF NOT EXISTS chat_session_log (
|
|
1756
|
+
chat_id TEXT PRIMARY KEY,
|
|
1757
|
+
value INTEGER NOT NULL DEFAULT 0
|
|
1758
|
+
);
|
|
1759
|
+
`);
|
|
1738
1760
|
db3.exec(`
|
|
1739
1761
|
CREATE TABLE IF NOT EXISTS backend_credentials (
|
|
1740
1762
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -2419,6 +2441,55 @@ var init_sessions = __esm({
|
|
|
2419
2441
|
});
|
|
2420
2442
|
|
|
2421
2443
|
// src/memory/chat-settings.ts
|
|
2444
|
+
var chat_settings_exports = {};
|
|
2445
|
+
__export(chat_settings_exports, {
|
|
2446
|
+
ALL_TOOLS: () => ALL_TOOLS,
|
|
2447
|
+
clearAgentMode: () => clearAgentMode,
|
|
2448
|
+
clearCwd: () => clearCwd,
|
|
2449
|
+
clearExecMode: () => clearExecMode,
|
|
2450
|
+
clearModel: () => clearModel,
|
|
2451
|
+
clearSummarizer: () => clearSummarizer,
|
|
2452
|
+
clearThinkingLevel: () => clearThinkingLevel,
|
|
2453
|
+
deleteBookmark: () => deleteBookmark,
|
|
2454
|
+
determineEscalationTarget: () => determineEscalationTarget,
|
|
2455
|
+
findBookmarksByPrefix: () => findBookmarksByPrefix,
|
|
2456
|
+
getAgentMode: () => getAgentMode,
|
|
2457
|
+
getAllBookmarks: () => getAllBookmarks,
|
|
2458
|
+
getBackend: () => getBackend,
|
|
2459
|
+
getBookmark: () => getBookmark,
|
|
2460
|
+
getCwd: () => getCwd,
|
|
2461
|
+
getEnabledTools: () => getEnabledTools,
|
|
2462
|
+
getExecMode: () => getExecMode,
|
|
2463
|
+
getMode: () => getMode,
|
|
2464
|
+
getModel: () => getModel,
|
|
2465
|
+
getPendingEscalation: () => getPendingEscalation,
|
|
2466
|
+
getRecentBookmarks: () => getRecentBookmarks,
|
|
2467
|
+
getSessionLogEnabled: () => getSessionLogEnabled,
|
|
2468
|
+
getShowThinkingUi: () => getShowThinkingUi,
|
|
2469
|
+
getSummarizer: () => getSummarizer,
|
|
2470
|
+
getThinkingLevel: () => getThinkingLevel,
|
|
2471
|
+
getToolsMap: () => getToolsMap,
|
|
2472
|
+
getVerboseLevel: () => getVerboseLevel,
|
|
2473
|
+
removePendingEscalation: () => removePendingEscalation,
|
|
2474
|
+
resetTools: () => resetTools,
|
|
2475
|
+
setAgentMode: () => setAgentMode,
|
|
2476
|
+
setBackend: () => setBackend,
|
|
2477
|
+
setCwd: () => setCwd,
|
|
2478
|
+
setExecMode: () => setExecMode,
|
|
2479
|
+
setMode: () => setMode,
|
|
2480
|
+
setModel: () => setModel,
|
|
2481
|
+
setSessionLogEnabled: () => setSessionLogEnabled,
|
|
2482
|
+
setShowThinkingUi: () => setShowThinkingUi,
|
|
2483
|
+
setSummarizer: () => setSummarizer,
|
|
2484
|
+
setThinkingLevel: () => setThinkingLevel,
|
|
2485
|
+
setVerboseLevel: () => setVerboseLevel,
|
|
2486
|
+
storePendingEscalation: () => storePendingEscalation,
|
|
2487
|
+
toggleSessionLogEnabled: () => toggleSessionLogEnabled,
|
|
2488
|
+
toggleShowThinkingUi: () => toggleShowThinkingUi,
|
|
2489
|
+
toggleTool: () => toggleTool,
|
|
2490
|
+
touchBookmark: () => touchBookmark,
|
|
2491
|
+
upsertBookmark: () => upsertBookmark
|
|
2492
|
+
});
|
|
2422
2493
|
function getCwd(chatId) {
|
|
2423
2494
|
const row = getDb().prepare(
|
|
2424
2495
|
"SELECT cwd FROM chat_cwd WHERE chat_id = ?"
|
|
@@ -2517,6 +2588,25 @@ function setVerboseLevel(chatId, level) {
|
|
|
2517
2588
|
ON CONFLICT(chat_id) DO UPDATE SET level = ?
|
|
2518
2589
|
`).run(chatId, level, level);
|
|
2519
2590
|
}
|
|
2591
|
+
function getShowThinkingUi(chatId) {
|
|
2592
|
+
const row = getDb().prepare(
|
|
2593
|
+
"SELECT value FROM chat_show_thinking_ui WHERE chat_id = ?"
|
|
2594
|
+
).get(chatId);
|
|
2595
|
+
return (row?.value ?? 0) === 1;
|
|
2596
|
+
}
|
|
2597
|
+
function setShowThinkingUi(chatId, enabled) {
|
|
2598
|
+
getDb().prepare(`
|
|
2599
|
+
INSERT INTO chat_show_thinking_ui (chat_id, value)
|
|
2600
|
+
VALUES (?, ?)
|
|
2601
|
+
ON CONFLICT(chat_id) DO UPDATE SET value = ?
|
|
2602
|
+
`).run(chatId, enabled ? 1 : 0, enabled ? 1 : 0);
|
|
2603
|
+
}
|
|
2604
|
+
function toggleShowThinkingUi(chatId) {
|
|
2605
|
+
const current = getShowThinkingUi(chatId);
|
|
2606
|
+
const next = !current;
|
|
2607
|
+
setShowThinkingUi(chatId, next);
|
|
2608
|
+
return next;
|
|
2609
|
+
}
|
|
2520
2610
|
function getMode(chatId) {
|
|
2521
2611
|
const row = getDb().prepare(
|
|
2522
2612
|
"SELECT mode FROM chat_mode WHERE chat_id = ?"
|
|
@@ -2665,6 +2755,25 @@ function setExecMode(chatId, mode) {
|
|
|
2665
2755
|
function clearExecMode(chatId) {
|
|
2666
2756
|
getDb().prepare("DELETE FROM chat_exec_mode WHERE chat_id = ?").run(chatId);
|
|
2667
2757
|
}
|
|
2758
|
+
function getSessionLogEnabled(chatId) {
|
|
2759
|
+
const row = getDb().prepare(
|
|
2760
|
+
"SELECT value FROM chat_session_log WHERE chat_id = ?"
|
|
2761
|
+
).get(chatId);
|
|
2762
|
+
return (row?.value ?? 0) === 1;
|
|
2763
|
+
}
|
|
2764
|
+
function setSessionLogEnabled(chatId, enabled) {
|
|
2765
|
+
getDb().prepare(`
|
|
2766
|
+
INSERT INTO chat_session_log (chat_id, value)
|
|
2767
|
+
VALUES (?, ?)
|
|
2768
|
+
ON CONFLICT(chat_id) DO UPDATE SET value = ?
|
|
2769
|
+
`).run(chatId, enabled ? 1 : 0, enabled ? 1 : 0);
|
|
2770
|
+
}
|
|
2771
|
+
function toggleSessionLogEnabled(chatId) {
|
|
2772
|
+
const current = getSessionLogEnabled(chatId);
|
|
2773
|
+
const next = !current;
|
|
2774
|
+
setSessionLogEnabled(chatId, next);
|
|
2775
|
+
return next;
|
|
2776
|
+
}
|
|
2668
2777
|
var pendingEscalations, ESCALATION_TTL_MS, ALL_TOOLS;
|
|
2669
2778
|
var init_chat_settings = __esm({
|
|
2670
2779
|
"src/memory/chat-settings.ts"() {
|
|
@@ -3529,9 +3638,11 @@ __export(store_exports5, {
|
|
|
3529
3638
|
getRecentMessageLog: () => getRecentMessageLog,
|
|
3530
3639
|
getResponseStyle: () => getResponseStyle,
|
|
3531
3640
|
getSessionId: () => getSessionId,
|
|
3641
|
+
getSessionLogEnabled: () => getSessionLogEnabled,
|
|
3532
3642
|
getSessionStartedAt: () => getSessionStartedAt,
|
|
3533
3643
|
getSessionSummaries: () => getSessionSummaries,
|
|
3534
3644
|
getSessionSummariesWithoutEmbeddings: () => getSessionSummariesWithoutEmbeddings,
|
|
3645
|
+
getShowThinkingUi: () => getShowThinkingUi,
|
|
3535
3646
|
getSummarizer: () => getSummarizer,
|
|
3536
3647
|
getThinkingLevel: () => getThinkingLevel,
|
|
3537
3648
|
getToolsMap: () => getToolsMap,
|
|
@@ -3590,12 +3701,16 @@ __export(store_exports5, {
|
|
|
3590
3701
|
setModelSignature: () => setModelSignature,
|
|
3591
3702
|
setResponseStyle: () => setResponseStyle,
|
|
3592
3703
|
setSessionId: () => setSessionId,
|
|
3704
|
+
setSessionLogEnabled: () => setSessionLogEnabled,
|
|
3593
3705
|
setSessionStartedAt: () => setSessionStartedAt,
|
|
3706
|
+
setShowThinkingUi: () => setShowThinkingUi,
|
|
3594
3707
|
setSummarizer: () => setSummarizer,
|
|
3595
3708
|
setThinkingLevel: () => setThinkingLevel,
|
|
3596
3709
|
setVerboseLevel: () => setVerboseLevel,
|
|
3597
3710
|
storePendingEscalation: () => storePendingEscalation,
|
|
3598
3711
|
toFts5Query: () => toFts5Query,
|
|
3712
|
+
toggleSessionLogEnabled: () => toggleSessionLogEnabled,
|
|
3713
|
+
toggleShowThinkingUi: () => toggleShowThinkingUi,
|
|
3599
3714
|
toggleTool: () => toggleTool,
|
|
3600
3715
|
touchBookmark: () => touchBookmark,
|
|
3601
3716
|
updateHeartbeatTimestamps: () => updateHeartbeatTimestamps,
|
|
@@ -3914,10 +4029,16 @@ var init_claude = __esm({
|
|
|
3914
4029
|
});
|
|
3915
4030
|
}
|
|
3916
4031
|
const content = message?.content ?? [];
|
|
3917
|
-
|
|
4032
|
+
let hasTextContent = false;
|
|
4033
|
+
let textContent = "";
|
|
3918
4034
|
for (const block of content) {
|
|
3919
4035
|
if (block.type === "text" && block.text) {
|
|
3920
|
-
|
|
4036
|
+
textContent += block.text;
|
|
4037
|
+
hasTextContent = true;
|
|
4038
|
+
} else if (block.type === "thinking" && block.thinking) {
|
|
4039
|
+
events.push({ type: "thinking", text: block.thinking });
|
|
4040
|
+
} else if (block.type === "redacted_thinking") {
|
|
4041
|
+
events.push({ type: "thinking", text: "[Redacted Thinking]" });
|
|
3921
4042
|
} else if (block.type === "tool_use") {
|
|
3922
4043
|
events.push({
|
|
3923
4044
|
type: "tool_start",
|
|
@@ -3927,8 +4048,16 @@ var init_claude = __esm({
|
|
|
3927
4048
|
});
|
|
3928
4049
|
}
|
|
3929
4050
|
}
|
|
3930
|
-
if (
|
|
3931
|
-
const
|
|
4051
|
+
if (hasTextContent) {
|
|
4052
|
+
const matches = [...textContent.matchAll(/<thinking>([\s\S]*?)<\/thinking>/gi)];
|
|
4053
|
+
for (const match of matches) {
|
|
4054
|
+
events.push({ type: "thinking", text: match[1].trim() });
|
|
4055
|
+
}
|
|
4056
|
+
const matchesThink = [...textContent.matchAll(/<think>([\s\S]*?)<\/think>/gi)];
|
|
4057
|
+
for (const match of matchesThink) {
|
|
4058
|
+
events.push({ type: "thinking", text: match[1].trim() });
|
|
4059
|
+
}
|
|
4060
|
+
const cleaned = stripThinkingContent(textContent);
|
|
3932
4061
|
if (cleaned) events.push({ type: "text", text: cleaned });
|
|
3933
4062
|
}
|
|
3934
4063
|
} else if (line.type === "user") {
|
|
@@ -4282,8 +4411,18 @@ var init_gemini = __esm({
|
|
|
4282
4411
|
events.push({ type: "init", sessionId: line.session_id });
|
|
4283
4412
|
} else if (line.type === "message" && line.role === "assistant") {
|
|
4284
4413
|
if (line.thought === true) {
|
|
4414
|
+
events.push({ type: "thinking", text: String(line.content ?? "") });
|
|
4285
4415
|
} else if (line.content) {
|
|
4286
|
-
|
|
4416
|
+
let contentStr = line.content;
|
|
4417
|
+
const matches = [...contentStr.matchAll(/<thinking>([\s\S]*?)<\/thinking>/gi)];
|
|
4418
|
+
for (const match of matches) {
|
|
4419
|
+
events.push({ type: "thinking", text: match[1].trim() });
|
|
4420
|
+
}
|
|
4421
|
+
const matchesThink = [...contentStr.matchAll(/<think>([\s\S]*?)<\/think>/gi)];
|
|
4422
|
+
for (const match of matchesThink) {
|
|
4423
|
+
events.push({ type: "thinking", text: match[1].trim() });
|
|
4424
|
+
}
|
|
4425
|
+
const cleaned = stripThinkingContent(contentStr);
|
|
4287
4426
|
if (cleaned) {
|
|
4288
4427
|
events.push({ type: "text", text: cleaned });
|
|
4289
4428
|
}
|
|
@@ -4490,26 +4629,74 @@ var init_codex = __esm({
|
|
|
4490
4629
|
events.push({ type: "init", sessionId: line.thread_id });
|
|
4491
4630
|
} else if (line.type === "item.completed") {
|
|
4492
4631
|
const item = line.item;
|
|
4493
|
-
if (item
|
|
4632
|
+
if (!item) return events;
|
|
4633
|
+
if (item.type === "agent_message" && item.text) {
|
|
4494
4634
|
const cleaned = stripThinkingContent(item.text);
|
|
4495
4635
|
if (cleaned) events.push({ type: "text", text: cleaned });
|
|
4496
|
-
} else if (item
|
|
4636
|
+
} else if (item.type === "command_execution") {
|
|
4497
4637
|
events.push({
|
|
4498
4638
|
type: "tool_end",
|
|
4499
4639
|
toolName: "Shell",
|
|
4500
4640
|
toolId: item.id,
|
|
4501
4641
|
toolOutput: item.aggregated_output ?? ""
|
|
4502
4642
|
});
|
|
4643
|
+
} else if (item.type === "web_search") {
|
|
4644
|
+
const action = item.action;
|
|
4645
|
+
const query = action?.query || item.query || "";
|
|
4646
|
+
events.push({
|
|
4647
|
+
type: "tool_end",
|
|
4648
|
+
toolName: "Web Search",
|
|
4649
|
+
toolId: item.id,
|
|
4650
|
+
toolOutput: query ? `Searched: ${query}` : "Search completed"
|
|
4651
|
+
});
|
|
4652
|
+
} else if (item.type === "file_search") {
|
|
4653
|
+
events.push({
|
|
4654
|
+
type: "tool_end",
|
|
4655
|
+
toolName: "File Search",
|
|
4656
|
+
toolId: item.id,
|
|
4657
|
+
toolOutput: item.query ?? ""
|
|
4658
|
+
});
|
|
4659
|
+
} else if (item.type === "mcp_tool_call") {
|
|
4660
|
+
events.push({
|
|
4661
|
+
type: "tool_end",
|
|
4662
|
+
toolName: item.name ?? "MCP Tool",
|
|
4663
|
+
toolId: item.id,
|
|
4664
|
+
toolOutput: typeof item.output === "string" ? item.output : ""
|
|
4665
|
+
});
|
|
4503
4666
|
}
|
|
4504
4667
|
} else if (line.type === "item.started") {
|
|
4505
4668
|
const item = line.item;
|
|
4506
|
-
if (item
|
|
4669
|
+
if (!item) return events;
|
|
4670
|
+
if (item.type === "command_execution") {
|
|
4507
4671
|
events.push({
|
|
4508
4672
|
type: "tool_start",
|
|
4509
4673
|
toolName: "Shell",
|
|
4510
4674
|
toolId: item.id,
|
|
4511
4675
|
toolInput: { command: item.command ?? "" }
|
|
4512
4676
|
});
|
|
4677
|
+
} else if (item.type === "web_search") {
|
|
4678
|
+
const action = item.action;
|
|
4679
|
+
const query = action?.query || item.query || "";
|
|
4680
|
+
events.push({
|
|
4681
|
+
type: "tool_start",
|
|
4682
|
+
toolName: "Web Search",
|
|
4683
|
+
toolId: item.id,
|
|
4684
|
+
toolInput: { query: query || "Searching\u2026" }
|
|
4685
|
+
});
|
|
4686
|
+
} else if (item.type === "file_search") {
|
|
4687
|
+
events.push({
|
|
4688
|
+
type: "tool_start",
|
|
4689
|
+
toolName: "File Search",
|
|
4690
|
+
toolId: item.id,
|
|
4691
|
+
toolInput: { query: item.query ?? "" }
|
|
4692
|
+
});
|
|
4693
|
+
} else if (item.type === "mcp_tool_call") {
|
|
4694
|
+
events.push({
|
|
4695
|
+
type: "tool_start",
|
|
4696
|
+
toolName: item.name ?? "MCP Tool",
|
|
4697
|
+
toolId: item.id,
|
|
4698
|
+
toolInput: item.arguments ?? {}
|
|
4699
|
+
});
|
|
4513
4700
|
}
|
|
4514
4701
|
} else if (line.type === "turn.completed") {
|
|
4515
4702
|
const u = line.usage;
|
|
@@ -5292,6 +5479,11 @@ If the user asks *how* to do something with CC-Claw, use this expertise to sugge
|
|
|
5292
5479
|
});
|
|
5293
5480
|
|
|
5294
5481
|
// src/bootstrap/init.ts
|
|
5482
|
+
var init_exports = {};
|
|
5483
|
+
__export(init_exports, {
|
|
5484
|
+
bootstrapWorkspaceFiles: () => bootstrapWorkspaceFiles,
|
|
5485
|
+
syncNativeCliFiles: () => syncNativeCliFiles
|
|
5486
|
+
});
|
|
5295
5487
|
import {
|
|
5296
5488
|
existsSync as existsSync8,
|
|
5297
5489
|
writeFileSync,
|
|
@@ -8677,15 +8869,37 @@ var init_scheduler = __esm({
|
|
|
8677
8869
|
validateAgentIdentity(req, body);
|
|
8678
8870
|
const { updateJob: updateJob2, getJobById: getJobById3 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
8679
8871
|
const { stopJobTimer: stopJobTimer2, startSingleJob: startSingleJob2 } = await Promise.resolve().then(() => (init_cron(), cron_exports));
|
|
8680
|
-
const
|
|
8681
|
-
if (
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8872
|
+
const existing = getJobById3(body.jobId);
|
|
8873
|
+
if (!existing) {
|
|
8874
|
+
return jsonResponse(res, { success: false, error: `Job #${body.jobId} not found.` }, 404);
|
|
8875
|
+
}
|
|
8876
|
+
const updates = { ...body.updates };
|
|
8877
|
+
if (updates.cron !== void 0) {
|
|
8878
|
+
updates.scheduleType = "cron";
|
|
8879
|
+
updates.atTime = null;
|
|
8880
|
+
updates.everyMs = null;
|
|
8881
|
+
} else if (updates.atTime !== void 0) {
|
|
8882
|
+
updates.scheduleType = "at";
|
|
8883
|
+
updates.cron = null;
|
|
8884
|
+
updates.everyMs = null;
|
|
8885
|
+
} else if (updates.everyMs !== void 0) {
|
|
8886
|
+
updates.scheduleType = "every";
|
|
8887
|
+
updates.cron = null;
|
|
8888
|
+
updates.atTime = null;
|
|
8889
|
+
}
|
|
8890
|
+
const updated = updateJob2(body.jobId, updates);
|
|
8891
|
+
if (!updated) {
|
|
8892
|
+
return jsonResponse(res, {
|
|
8893
|
+
success: false,
|
|
8894
|
+
error: `No recognized fields to update. Valid fields: cron, atTime, everyMs, title, description, backend, model, thinking, timeout, timezone, sessionType, deliveryMode, channel, target.`
|
|
8895
|
+
}, 400);
|
|
8687
8896
|
}
|
|
8688
|
-
|
|
8897
|
+
stopJobTimer2(body.jobId);
|
|
8898
|
+
const freshJob = getJobById3(body.jobId);
|
|
8899
|
+
if (freshJob && freshJob.active && freshJob.enabled) {
|
|
8900
|
+
startSingleJob2(freshJob);
|
|
8901
|
+
}
|
|
8902
|
+
jsonResponse(res, { success: true });
|
|
8689
8903
|
} catch (err) {
|
|
8690
8904
|
jsonResponse(res, { error: errorMessage(err) }, 400);
|
|
8691
8905
|
}
|
|
@@ -10178,11 +10392,11 @@ var init_evolve = __esm({
|
|
|
10178
10392
|
const body = JSON.parse(await readBody(req));
|
|
10179
10393
|
const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
10180
10394
|
const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
|
|
10181
|
-
const { join:
|
|
10395
|
+
const { join: join35 } = await import("path");
|
|
10182
10396
|
const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
10183
10397
|
const chatId = body.chatId || (process.env.ALLOWED_CHAT_ID ?? "").split(",")[0]?.trim() || "default";
|
|
10184
|
-
const soulPath =
|
|
10185
|
-
const userPath =
|
|
10398
|
+
const soulPath = join35(home, "identity/SOUL.md");
|
|
10399
|
+
const userPath = join35(home, "identity/USER.md");
|
|
10186
10400
|
const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
|
|
10187
10401
|
const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
|
|
10188
10402
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
@@ -10762,6 +10976,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
10762
10976
|
}, effectiveTimeout);
|
|
10763
10977
|
let resultText = "";
|
|
10764
10978
|
let accumulatedText = "";
|
|
10979
|
+
let accumulatedThinking = "";
|
|
10765
10980
|
let sessionId;
|
|
10766
10981
|
let input = 0;
|
|
10767
10982
|
let output2 = 0;
|
|
@@ -10828,6 +11043,19 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
10828
11043
|
if (opts?.onStream) opts.onStream(ev.text);
|
|
10829
11044
|
}
|
|
10830
11045
|
break;
|
|
11046
|
+
case "thinking":
|
|
11047
|
+
if (!gotModelContent) {
|
|
11048
|
+
gotModelContent = true;
|
|
11049
|
+
if (firstResponseTimer) {
|
|
11050
|
+
clearTimeout(firstResponseTimer);
|
|
11051
|
+
firstResponseTimer = void 0;
|
|
11052
|
+
}
|
|
11053
|
+
}
|
|
11054
|
+
if (ev.text) {
|
|
11055
|
+
accumulatedThinking = appendTextChunk(accumulatedThinking, ev.text);
|
|
11056
|
+
if (opts?.onThinking) opts.onThinking(ev.text);
|
|
11057
|
+
}
|
|
11058
|
+
break;
|
|
10831
11059
|
case "tool_start":
|
|
10832
11060
|
if (!gotModelContent) {
|
|
10833
11061
|
gotModelContent = true;
|
|
@@ -10968,7 +11196,7 @@ Partial output: ${accumulatedText.slice(-500)}`;
|
|
|
10968
11196
|
return;
|
|
10969
11197
|
}
|
|
10970
11198
|
const cleanedResult = stripThinkingContent(resultText || accumulatedText);
|
|
10971
|
-
resolve({ resultText: cleanedResult, sessionId, input, output: output2, cacheRead, contextSize, sawToolEvents, sawResultEvent });
|
|
11199
|
+
resolve({ resultText: cleanedResult, thinkingText: accumulatedThinking, sessionId, input, output: output2, cacheRead, contextSize, sawToolEvents, sawResultEvent });
|
|
10972
11200
|
});
|
|
10973
11201
|
});
|
|
10974
11202
|
}
|
|
@@ -11128,7 +11356,7 @@ function askAgent(chatId, userMessage, opts) {
|
|
|
11128
11356
|
return withChatLock(chatId, () => askAgentImpl(chatId, userMessage, opts));
|
|
11129
11357
|
}
|
|
11130
11358
|
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 ?? {};
|
|
11359
|
+
const { cwd, onStream, model: model2, backend: backend2, permMode, onToolAction, bootstrapTier, timeoutMs, maxTurns, onSlotRotation, onModelDowngrade, agentMode: optsAgentMode, onSubagentActivity, settingsSourceChatId, planningDirective, onThinking } = opts ?? {};
|
|
11132
11360
|
const settingsChat = settingsSourceChatId ?? chatId;
|
|
11133
11361
|
const adapter = backend2 ? getAdapter(backend2) : getAdapterForChat(settingsChat);
|
|
11134
11362
|
const mode = permMode ?? getMode(settingsChat);
|
|
@@ -11176,6 +11404,7 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
11176
11404
|
onStream,
|
|
11177
11405
|
onToolAction,
|
|
11178
11406
|
onSubagentActivity,
|
|
11407
|
+
onThinking,
|
|
11179
11408
|
// First-response timeout: only arm for fresh Gemini sessions (cold-start).
|
|
11180
11409
|
// If Gemini has already responded at least once (existingSessionId is set),
|
|
11181
11410
|
// the session is established — mid-conversation silence is a legitimate long task,
|
|
@@ -11369,6 +11598,7 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
11369
11598
|
}
|
|
11370
11599
|
return {
|
|
11371
11600
|
text: result.resultText || `(No response from ${adapter.displayName})`,
|
|
11601
|
+
thinkingText: result.thinkingText,
|
|
11372
11602
|
sessionId: result.sessionId,
|
|
11373
11603
|
usage: { input: result.input, output: result.output, cacheRead: result.cacheRead, contextSize: result.contextSize },
|
|
11374
11604
|
resolvedModel: result.resolvedModel
|
|
@@ -11741,9 +11971,15 @@ function buildReviewCompleteMessage(results) {
|
|
|
11741
11971
|
Skipped proposals will appear in your next review.`;
|
|
11742
11972
|
}
|
|
11743
11973
|
function formatNightlySummary(insights, totalPending) {
|
|
11744
|
-
const
|
|
11745
|
-
const
|
|
11746
|
-
|
|
11974
|
+
const newCount = insights.length;
|
|
11975
|
+
const total = totalPending ?? newCount;
|
|
11976
|
+
let header2;
|
|
11977
|
+
if (total > newCount) {
|
|
11978
|
+
header2 = `Nightly Reflection \u2014 ${newCount} new proposal${newCount === 1 ? "" : "s"} (${total} total pending)`;
|
|
11979
|
+
} else {
|
|
11980
|
+
header2 = `Nightly Reflection \u2014 ${newCount} proposal${newCount === 1 ? "" : "s"} ready`;
|
|
11981
|
+
}
|
|
11982
|
+
const list = insights.map((ins, i) => `\u2022 [${ins.category}] ${ins.insight}`).join("\n");
|
|
11747
11983
|
return `${header2}
|
|
11748
11984
|
|
|
11749
11985
|
${list}
|
|
@@ -12023,6 +12259,7 @@ function classifyIntent(text, chatId) {
|
|
|
12023
12259
|
if (trimmed.startsWith(">>")) return "agentic";
|
|
12024
12260
|
if (trimmed.startsWith("/")) return "agentic";
|
|
12025
12261
|
const lower = trimmed.toLowerCase();
|
|
12262
|
+
const normalized = trimmed.replace(/^["'\u201C\u201D\u2018\u2019`\s]+|["'\u201C\u201D\u2018\u2019`\s]+$/g, "");
|
|
12026
12263
|
const sessionId = getSessionId(chatId);
|
|
12027
12264
|
if (sessionId) {
|
|
12028
12265
|
const lastTs = getLastMessageTimestamp(chatId);
|
|
@@ -12045,18 +12282,32 @@ function classifyIntent(text, chatId) {
|
|
|
12045
12282
|
intentCounts.chat++;
|
|
12046
12283
|
return "chat";
|
|
12047
12284
|
}
|
|
12048
|
-
for (const pattern of
|
|
12049
|
-
if (pattern.test(
|
|
12050
|
-
log(`[intent] "${trimmed.slice(0,
|
|
12285
|
+
for (const pattern of STRUCTURAL_PATTERNS) {
|
|
12286
|
+
if (pattern.test(normalized)) {
|
|
12287
|
+
log(`[intent] "${trimmed.slice(0, 40)}..." -> agentic (structural: ${pattern})`);
|
|
12288
|
+
intentCounts.agentic++;
|
|
12289
|
+
return "agentic";
|
|
12290
|
+
}
|
|
12291
|
+
}
|
|
12292
|
+
for (const pattern of MUTATION_PATTERNS) {
|
|
12293
|
+
if (pattern.test(normalized)) {
|
|
12294
|
+
log(`[intent] "${trimmed.slice(0, 40)}..." -> agentic (mutation: ${pattern})`);
|
|
12051
12295
|
intentCounts.agentic++;
|
|
12052
12296
|
return "agentic";
|
|
12053
12297
|
}
|
|
12054
12298
|
}
|
|
12055
|
-
|
|
12299
|
+
for (const pattern of CHAT_QUESTION_PATTERNS) {
|
|
12300
|
+
if (pattern.test(normalized)) {
|
|
12301
|
+
log(`[intent] "${trimmed.slice(0, 40)}..." -> chat (question: ${pattern})`);
|
|
12302
|
+
intentCounts.chat++;
|
|
12303
|
+
return "chat";
|
|
12304
|
+
}
|
|
12305
|
+
}
|
|
12306
|
+
log(`[intent] "${trimmed.slice(0, 40)}..." -> agentic (default)`);
|
|
12056
12307
|
intentCounts.agentic++;
|
|
12057
12308
|
return "agentic";
|
|
12058
12309
|
}
|
|
12059
|
-
var intentCounts, CHAT_EXACT,
|
|
12310
|
+
var intentCounts, CHAT_EXACT, MUTATION_PATTERNS, CHAT_QUESTION_PATTERNS, STRUCTURAL_PATTERNS;
|
|
12060
12311
|
var init_classify = __esm({
|
|
12061
12312
|
"src/intent/classify.ts"() {
|
|
12062
12313
|
"use strict";
|
|
@@ -12113,27 +12364,44 @@ var init_classify = __esm({
|
|
|
12113
12364
|
"alright",
|
|
12114
12365
|
"sure"
|
|
12115
12366
|
]);
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12367
|
+
MUTATION_PATTERNS = [
|
|
12368
|
+
/\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,
|
|
12369
|
+
/\b(add\s+(?:a|an|the|new|\w+\s+to))/i,
|
|
12370
|
+
// "add a function", "add to the file"
|
|
12371
|
+
/\b(change\s+(?:the|a|my|this|that|\w+\s+to))/i,
|
|
12372
|
+
// "change the config to"
|
|
12373
|
+
/\b(make\s+(?:a|an|it|this|the|sure))\b/i,
|
|
12374
|
+
// "make a new file", "make it work"
|
|
12375
|
+
/\b(set\s+(?:up|the|a|my))\b/i
|
|
12376
|
+
// "set up the database"
|
|
12377
|
+
];
|
|
12378
|
+
CHAT_QUESTION_PATTERNS = [
|
|
12379
|
+
/^(?:what|whats|what's)\s+/i,
|
|
12380
|
+
// "what is", "what version", "what does"
|
|
12381
|
+
/^(?:which|where|when|why|who)\s+/i,
|
|
12382
|
+
// "which file", "where is", "when did"
|
|
12383
|
+
/^(?:how\s+(?:do|does|can|did|many|much|long|often|come))\s+/i,
|
|
12384
|
+
// "how do I", "how many"
|
|
12385
|
+
/^(?:show|tell|list|explain|describe|summarize|display)\s+(?:me\s+)?/i,
|
|
12386
|
+
/^(?: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,
|
|
12387
|
+
/^(?:give\s+me|get\s+me)\s+(?:the|a|my|an|current|latest)\s+/i,
|
|
12388
|
+
/^(?:is|are|was|were|does|did|has|have|had)\s+(?:the|a|my|it|this|that|there)\s+/i
|
|
12389
|
+
];
|
|
12390
|
+
STRUCTURAL_PATTERNS = [
|
|
12391
|
+
/\.[a-z]{1,5}\b/,
|
|
12392
|
+
// file extensions (.ts, .py, .md, .json)
|
|
12393
|
+
/[/\\][\w.-]+/,
|
|
12394
|
+
// file paths (/src/foo, .\bar)
|
|
12121
12395
|
/`[^`]+`/,
|
|
12122
|
-
// inline code
|
|
12396
|
+
// inline code `like this`
|
|
12123
12397
|
/```/,
|
|
12124
12398
|
// 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
12399
|
/[!]{1,2}\s/,
|
|
12132
|
-
// shell prefix
|
|
12400
|
+
// shell prefix (! or !!)
|
|
12133
12401
|
/^\/\//,
|
|
12134
|
-
// backend command prefix
|
|
12135
|
-
/\b(
|
|
12136
|
-
|
|
12402
|
+
// backend command prefix (//)
|
|
12403
|
+
/\b(error|bug|crash|fail|broken|issue|problem|exception|stack\s?trace)\b/i,
|
|
12404
|
+
/\b(function|class|const|let|var|import|export|return|async|await)\b/i
|
|
12137
12405
|
];
|
|
12138
12406
|
}
|
|
12139
12407
|
});
|
|
@@ -12833,7 +13101,7 @@ var init_classify2 = __esm({
|
|
|
12833
13101
|
// src/execution/gate.ts
|
|
12834
13102
|
function shouldRequireApproval(input) {
|
|
12835
13103
|
if (input.execMode !== "approved") return false;
|
|
12836
|
-
if (input.intent
|
|
13104
|
+
if (input.intent === "chat") return false;
|
|
12837
13105
|
if (input.messageText.startsWith(">>")) return false;
|
|
12838
13106
|
if (EXEMPT_TIERS.has(input.bootstrapTier)) return false;
|
|
12839
13107
|
if (input.isSideQuest) return false;
|
|
@@ -12841,28 +13109,40 @@ function shouldRequireApproval(input) {
|
|
|
12841
13109
|
}
|
|
12842
13110
|
function buildPlanningDirective() {
|
|
12843
13111
|
return [
|
|
12844
|
-
"## PLANNING MODE \u2014
|
|
13112
|
+
"## PLANNING MODE \u2014 Describe Only, Do Not Execute",
|
|
12845
13113
|
"",
|
|
12846
|
-
"You are in PLANNING
|
|
13114
|
+
"You are in PLANNING MODE. Your job is to research the request and describe",
|
|
13115
|
+
"what you will do. The user will review and approve before you execute anything.",
|
|
12847
13116
|
"",
|
|
12848
13117
|
"**ALLOWED:**",
|
|
12849
|
-
"- Read
|
|
12850
|
-
"-
|
|
12851
|
-
"-
|
|
12852
|
-
"- Search the web for documentation
|
|
12853
|
-
"
|
|
13118
|
+
"- Read file contents",
|
|
13119
|
+
"- Search/grep the codebase",
|
|
13120
|
+
"- Analyze code and architecture",
|
|
13121
|
+
"- Search the web for documentation",
|
|
13122
|
+
"",
|
|
13123
|
+
"**NOT ALLOWED \u2014 do NOT do any of these, even if they seem harmless:**",
|
|
13124
|
+
"- Run any shell or terminal commands (no node --version, no ls, no cat, no npm, nothing)",
|
|
13125
|
+
"- Create, modify, or delete any files",
|
|
13126
|
+
"- Write or generate code",
|
|
13127
|
+
"- Install or uninstall packages",
|
|
13128
|
+
"- Execute any mutations whatsoever",
|
|
13129
|
+
"",
|
|
13130
|
+
"**IMPORTANT:** Even if you already know the answer (e.g. from training data),",
|
|
13131
|
+
"do NOT run a command to confirm it. Just describe what you WILL do.",
|
|
12854
13132
|
"",
|
|
12855
|
-
"**
|
|
12856
|
-
"-
|
|
12857
|
-
"-
|
|
12858
|
-
"-
|
|
12859
|
-
"-
|
|
13133
|
+
"**OUTPUT FORMAT (strict):**",
|
|
13134
|
+
"- No preamble, no 'Here is my plan:', no closing remarks",
|
|
13135
|
+
"- Start with a bold title: '**Plan: <short description>**'",
|
|
13136
|
+
"- Use bullet points (\u2022) for each step \u2014 max 15 words per bullet",
|
|
13137
|
+
"- Be specific about which files you'll touch and what you'll change",
|
|
13138
|
+
"- Max total output: 3000 characters",
|
|
12860
13139
|
"",
|
|
12861
|
-
"
|
|
12862
|
-
"
|
|
12863
|
-
"
|
|
12864
|
-
"
|
|
12865
|
-
"
|
|
13140
|
+
"Example:",
|
|
13141
|
+
"**Plan: Add retry logic to API client**",
|
|
13142
|
+
"\u2022 Read `src/api/client.ts` \u2014 identify fetch call sites",
|
|
13143
|
+
"\u2022 Add `retryWithBackoff()` helper (max 3 retries, exponential backoff)",
|
|
13144
|
+
"\u2022 Update `src/sync.ts` and `src/scheduler.ts` to use the wrapper",
|
|
13145
|
+
"\u2022 Add unit test in `src/api/client.test.ts`"
|
|
12866
13146
|
].join("\n");
|
|
12867
13147
|
}
|
|
12868
13148
|
function storePendingPlan(chatId, plan, originalMessage) {
|
|
@@ -13153,18 +13433,18 @@ function formatToolStart(toolName, input, level) {
|
|
|
13153
13433
|
return `\u{1F527} ${toolName}${cmd ? `: ${cmd}` : path ? `: ${path}` : query ? `: ${query}` : ""}`;
|
|
13154
13434
|
}
|
|
13155
13435
|
}
|
|
13156
|
-
const inputStr = JSON.stringify(input, null, 2).slice(0,
|
|
13436
|
+
const inputStr = JSON.stringify(input, null, 2).slice(0, 300);
|
|
13157
13437
|
return `\u{1F527} ${toolName}:
|
|
13158
13438
|
\`\`\`json
|
|
13159
13439
|
${inputStr}
|
|
13160
13440
|
\`\`\``;
|
|
13161
13441
|
}
|
|
13162
13442
|
function formatToolResult(toolName, result) {
|
|
13163
|
-
const trimmed = result.trim().slice(0,
|
|
13443
|
+
const trimmed = result.trim().slice(0, 250);
|
|
13164
13444
|
if (!trimmed) return "";
|
|
13165
13445
|
const firstLine = trimmed.split("\n")[0] ?? "";
|
|
13166
13446
|
const isError = /error|failed|exception/i.test(firstLine);
|
|
13167
|
-
return isError ? `\u274C ${firstLine.slice(0, 120)}` : `\u{
|
|
13447
|
+
return isError ? `\u274C ${firstLine.slice(0, 120)}` : `\u{1F4EC} Result:
|
|
13168
13448
|
\`\`\`
|
|
13169
13449
|
${trimmed}
|
|
13170
13450
|
\`\`\``;
|
|
@@ -15826,11 +16106,11 @@ async function sendJobPicker(chatId, channel, action) {
|
|
|
15826
16106
|
}
|
|
15827
16107
|
async function sendCurrentProposal(chatId, channel) {
|
|
15828
16108
|
const { getReviewSession: getReviewSession2, getInsightById: getInsightById2, deleteReviewSession: deleteReviewSession2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
15829
|
-
const { formatProposalCardWithProgress: formatProposalCardWithProgress2, buildProposalKeyboard: buildProposalKeyboard2, buildReviewCompleteMessage:
|
|
16109
|
+
const { formatProposalCardWithProgress: formatProposalCardWithProgress2, buildProposalKeyboard: buildProposalKeyboard2, buildReviewCompleteMessage: buildReviewCompleteMessage3 } = await Promise.resolve().then(() => (init_propose(), propose_exports));
|
|
15830
16110
|
const session2 = getReviewSession2(getDb(), chatId);
|
|
15831
16111
|
if (!session2) return;
|
|
15832
16112
|
if (session2.currentIndex >= session2.insightIds.length) {
|
|
15833
|
-
const summary =
|
|
16113
|
+
const summary = buildReviewCompleteMessage3(session2.results);
|
|
15834
16114
|
deleteReviewSession2(getDb(), chatId);
|
|
15835
16115
|
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
15836
16116
|
return;
|
|
@@ -16070,7 +16350,7 @@ async function handleEvolveCallback(chatId, data, channel) {
|
|
|
16070
16350
|
if (pending.length === 0) {
|
|
16071
16351
|
await channel.sendText(chatId, "No pending proposals.", { parseMode: "plain" });
|
|
16072
16352
|
} else {
|
|
16073
|
-
const insightIds = pending.
|
|
16353
|
+
const insightIds = pending.map((p) => p.id);
|
|
16074
16354
|
createReviewSession2(getDb(), chatId, insightIds);
|
|
16075
16355
|
await channel.sendText(chatId, `${pending.length} proposal(s) ready. Let's review them one by one.`, { parseMode: "plain" });
|
|
16076
16356
|
await sendCurrentProposal(chatId, channel);
|
|
@@ -16231,13 +16511,13 @@ async function handleEvolveCallback(chatId, data, channel) {
|
|
|
16231
16511
|
const { getReflectionStatus: getReflectionStatus2, setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
16232
16512
|
const current = getReflectionStatus2(getDb(), chatId);
|
|
16233
16513
|
if (current === "frozen") {
|
|
16234
|
-
const { readFileSync:
|
|
16235
|
-
const { join:
|
|
16514
|
+
const { readFileSync: readFileSync27, existsSync: existsSync56 } = await import("fs");
|
|
16515
|
+
const { join: join35 } = await import("path");
|
|
16236
16516
|
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 =
|
|
16517
|
+
const soulPath = join35(CC_CLAW_HOME3, "identity/SOUL.md");
|
|
16518
|
+
const userPath = join35(CC_CLAW_HOME3, "identity/USER.md");
|
|
16519
|
+
const soul = existsSync56(soulPath) ? readFileSync27(soulPath, "utf-8") : "";
|
|
16520
|
+
const user = existsSync56(userPath) ? readFileSync27(userPath, "utf-8") : "";
|
|
16241
16521
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
16242
16522
|
const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
|
|
16243
16523
|
logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
|
|
@@ -16313,102 +16593,1279 @@ var init_evolve2 = __esm({
|
|
|
16313
16593
|
}
|
|
16314
16594
|
});
|
|
16315
16595
|
|
|
16316
|
-
// src/
|
|
16317
|
-
import {
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
return
|
|
16596
|
+
// src/optimizer/identity-audit.ts
|
|
16597
|
+
import { readFileSync as readFileSync10, existsSync as existsSync19, readdirSync as readdirSync9, statSync as statSync6 } from "fs";
|
|
16598
|
+
import { join as join20 } from "path";
|
|
16599
|
+
function readIdentityFile2(filename) {
|
|
16600
|
+
try {
|
|
16601
|
+
return readFileSync10(join20(IDENTITY_PATH, filename), "utf-8");
|
|
16602
|
+
} catch {
|
|
16603
|
+
return "";
|
|
16322
16604
|
}
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
|
|
16326
|
-
|
|
16327
|
-
|
|
16328
|
-
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
|
|
16605
|
+
}
|
|
16606
|
+
function getMtime(filepath) {
|
|
16607
|
+
try {
|
|
16608
|
+
return statSync6(filepath).mtime.toISOString();
|
|
16609
|
+
} catch {
|
|
16610
|
+
return "unknown";
|
|
16611
|
+
}
|
|
16612
|
+
}
|
|
16613
|
+
function findBackupFiles() {
|
|
16614
|
+
const backups = [];
|
|
16615
|
+
const dirs = [IDENTITY_PATH];
|
|
16616
|
+
const contextDir = join20(IDENTITY_PATH, "..", "workspace", "context");
|
|
16617
|
+
if (existsSync19(contextDir)) dirs.push(contextDir);
|
|
16618
|
+
for (const dir of dirs) {
|
|
16619
|
+
try {
|
|
16620
|
+
for (const entry of readdirSync9(dir)) {
|
|
16621
|
+
if (entry.endsWith(".bak") || /\.bak\.\d{4}-\d{2}-\d{2}/.test(entry)) {
|
|
16622
|
+
backups.push(join20(dir, entry));
|
|
16623
|
+
}
|
|
16337
16624
|
}
|
|
16338
|
-
|
|
16625
|
+
} catch {
|
|
16339
16626
|
}
|
|
16340
|
-
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16355
|
-
|
|
16627
|
+
}
|
|
16628
|
+
return backups;
|
|
16629
|
+
}
|
|
16630
|
+
function computeIdentityStats(pendingProposals, driftPercent) {
|
|
16631
|
+
const soulContent = readIdentityFile2("SOUL.md");
|
|
16632
|
+
const userContent = readIdentityFile2("USER.md");
|
|
16633
|
+
const ccClawContent = readIdentityFile2("CC-CLAW.md");
|
|
16634
|
+
const soulChars = soulContent.length;
|
|
16635
|
+
const userChars = userContent.length;
|
|
16636
|
+
const ccClawChars = ccClawContent.length;
|
|
16637
|
+
const boilerplateChars = Math.max(0, ccClawChars - soulChars - userChars);
|
|
16638
|
+
return {
|
|
16639
|
+
soulChars,
|
|
16640
|
+
userChars,
|
|
16641
|
+
ccClawChars,
|
|
16642
|
+
boilerplateChars,
|
|
16643
|
+
soulMtime: getMtime(join20(IDENTITY_PATH, "SOUL.md")),
|
|
16644
|
+
userMtime: getMtime(join20(IDENTITY_PATH, "USER.md")),
|
|
16645
|
+
ccClawMtime: getMtime(join20(IDENTITY_PATH, "CC-CLAW.md")),
|
|
16646
|
+
backupFiles: findBackupFiles(),
|
|
16647
|
+
estimatedTokens: Math.ceil(ccClawChars / 4),
|
|
16648
|
+
pendingEvolveProposals: pendingProposals,
|
|
16649
|
+
driftPercent
|
|
16650
|
+
};
|
|
16651
|
+
}
|
|
16652
|
+
function buildTokenReport(stats) {
|
|
16653
|
+
return {
|
|
16654
|
+
soulChars: stats.soulChars,
|
|
16655
|
+
userChars: stats.userChars,
|
|
16656
|
+
boilerplateChars: stats.boilerplateChars,
|
|
16657
|
+
totalChars: stats.ccClawChars,
|
|
16658
|
+
estimatedTokens: stats.estimatedTokens
|
|
16659
|
+
};
|
|
16660
|
+
}
|
|
16661
|
+
function buildIdentityAuditPrompt(soulMd, userMd, ccClawMd, stats, contextFiles) {
|
|
16662
|
+
const sections = [];
|
|
16663
|
+
sections.push(`You are an expert prompt engineer and identity file auditor for an AI assistant platform.
|
|
16664
|
+
|
|
16665
|
+
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.
|
|
16666
|
+
|
|
16667
|
+
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.
|
|
16668
|
+
|
|
16669
|
+
Return at most 8 findings. If everything is clean, return NO_FINDINGS.`);
|
|
16670
|
+
sections.push(`[Pre-computed Stats]
|
|
16671
|
+
SOUL.md: ${stats.soulChars} chars (~${Math.ceil(stats.soulChars / 4)} tokens), modified: ${stats.soulMtime}
|
|
16672
|
+
USER.md: ${stats.userChars} chars (~${Math.ceil(stats.userChars / 4)} tokens), modified: ${stats.userMtime}
|
|
16673
|
+
CC-CLAW.md: ${stats.ccClawChars} chars (~${stats.estimatedTokens} tokens), modified: ${stats.ccClawMtime}
|
|
16674
|
+
Boilerplate overhead: ~${stats.boilerplateChars} chars (~${Math.ceil(stats.boilerplateChars / 4)} tokens)
|
|
16675
|
+
Total identity tokens per message: ~${stats.estimatedTokens}
|
|
16676
|
+
Backup files found: ${stats.backupFiles.length > 0 ? stats.backupFiles.join(", ") : "none"}
|
|
16677
|
+
Pending evolve proposals: ${stats.pendingEvolveProposals}
|
|
16678
|
+
Drift from baseline: ${stats.driftPercent !== null ? `${stats.driftPercent}%` : "not calculated"}`);
|
|
16679
|
+
sections.push(`[Rubric \u2014 Evaluate Each Area]
|
|
16680
|
+
|
|
16681
|
+
1. STRUCTURAL HEALTH
|
|
16682
|
+
- Are file sizes reasonable? (SOUL.md >5000 chars or USER.md >3000 chars = bloat risk)
|
|
16683
|
+
- Is CC-CLAW.md stale? (modified before SOUL.md or USER.md = needs regeneration)
|
|
16684
|
+
- Orphan backup files accumulating?
|
|
16685
|
+
- Logical section organization within each file?
|
|
16686
|
+
|
|
16687
|
+
2. CONTENT ROUTING
|
|
16688
|
+
- User profile data (job title, employer, location) misplaced in SOUL.md? \u2192 belongs in USER.md
|
|
16689
|
+
- Personality directives (tone, style rules) misplaced in USER.md? \u2192 belongs in SOUL.md
|
|
16690
|
+
- Secrets, credentials, or API keys in any file?
|
|
16691
|
+
- Temporary content (TODOs, dates, one-off instructions) in identity files?
|
|
16692
|
+
- Content that should live in workspace/context/ files instead?
|
|
16693
|
+
|
|
16694
|
+
3. TOKEN EFFICIENCY
|
|
16695
|
+
- Content duplicated between SOUL.md and USER.md?
|
|
16696
|
+
- Verbose explanations that could be tightened without losing meaning?
|
|
16697
|
+
- Inline lists (emoji lists, tool lists) that are too long?
|
|
16698
|
+
- Content from context files that duplicates identity content?
|
|
16699
|
+
|
|
16700
|
+
4. EVOLVE INTEGRATION
|
|
16701
|
+
- Pending proposal count (${stats.pendingEvolveProposals}) \u2014 are stale proposals accumulating?
|
|
16702
|
+
- Drift from baseline (${stats.driftPercent !== null ? `${stats.driftPercent}%` : "N/A"}) \u2014 is it excessive (>50%)?
|
|
16703
|
+
|
|
16704
|
+
5. QUALITY & CLARITY
|
|
16705
|
+
- Conflicting instructions within the same file (e.g., "be brief" AND "provide detailed explanations")
|
|
16706
|
+
- Vague or ambiguous rules the AI is unlikely to follow consistently
|
|
16707
|
+
- Outdated references (old tool names, deprecated services)
|
|
16708
|
+
- Missing important directives (timezone, OS, communication style preferences)
|
|
16709
|
+
|
|
16710
|
+
6. IDENTITY COMPLETENESS
|
|
16711
|
+
- Does USER.md have enough info for the assistant to be truly personal?
|
|
16712
|
+
- Missing: timezone, work context, communication preferences, personal interests?
|
|
16713
|
+
- Contradictory user info (e.g., conflicting roles, locations, or personal details)?
|
|
16714
|
+
- What additional info could the user provide to improve personalization?`);
|
|
16715
|
+
sections.push("[Current SOUL.md]");
|
|
16716
|
+
sections.push(soulMd || "(empty)");
|
|
16717
|
+
sections.push("[Current USER.md]");
|
|
16718
|
+
sections.push(userMd || "(empty)");
|
|
16719
|
+
sections.push("[Current CC-CLAW.md (generated)]");
|
|
16720
|
+
sections.push(ccClawMd || "(empty)");
|
|
16721
|
+
if (contextFiles.length > 0) {
|
|
16722
|
+
sections.push("[Context Files]");
|
|
16723
|
+
for (const f of contextFiles) {
|
|
16724
|
+
sections.push(`--- ${f.name} ---`);
|
|
16725
|
+
sections.push(f.content.length > 2e3 ? f.content.slice(0, 2e3) + "\n[...truncated]" : f.content);
|
|
16726
|
+
}
|
|
16727
|
+
}
|
|
16728
|
+
sections.push(`[Output Format]
|
|
16729
|
+
For each finding, output EXACTLY this format. Separate multiple findings with "---" on its own line.
|
|
16730
|
+
|
|
16731
|
+
FINDING: <short title, max 80 chars>
|
|
16732
|
+
AREA: <structural | routing | efficiency | evolve | quality | completeness>
|
|
16733
|
+
SEVERITY: <critical | warning | info>
|
|
16734
|
+
DETAIL: <1-3 sentences explaining the issue AND its specific impact on AI behavior>
|
|
16735
|
+
LOCATION: <file:line or file:section, e.g. "SOUL.md:## Communication" or "USER.md:15">
|
|
16736
|
+
SUGGESTION: <specific actionable fix>
|
|
16737
|
+
DIFF:
|
|
16738
|
+
<proposed changes as diff lines, + for additions, - for removals>
|
|
16739
|
+
---
|
|
16740
|
+
|
|
16741
|
+
If no findings are warranted after thorough analysis, output: NO_FINDINGS
|
|
16742
|
+
|
|
16743
|
+
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.`);
|
|
16744
|
+
return sections.join("\n\n");
|
|
16745
|
+
}
|
|
16746
|
+
var init_identity_audit = __esm({
|
|
16747
|
+
"src/optimizer/identity-audit.ts"() {
|
|
16748
|
+
"use strict";
|
|
16749
|
+
init_paths();
|
|
16750
|
+
}
|
|
16751
|
+
});
|
|
16752
|
+
|
|
16753
|
+
// src/optimizer/skill-audit.ts
|
|
16754
|
+
import { readFileSync as readFileSync11, existsSync as existsSync20 } from "fs";
|
|
16755
|
+
import { join as join21, basename as basename2 } from "path";
|
|
16756
|
+
function parseFrontmatter3(content) {
|
|
16757
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
16758
|
+
if (!fmMatch) return {};
|
|
16759
|
+
const fm = fmMatch[1];
|
|
16760
|
+
const result = {};
|
|
16761
|
+
const nameMatch = fm.match(/^name:\s*(.+)/m);
|
|
16762
|
+
if (nameMatch) result.name = nameMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
16763
|
+
const descMatch = fm.match(/^description:\s*>?\s*\n?([\s\S]*?)(?=\n\w|\n---)/m);
|
|
16764
|
+
if (descMatch) {
|
|
16765
|
+
result.description = descMatch[1].trim().replace(/\n\s+/g, " ");
|
|
16766
|
+
} else {
|
|
16767
|
+
const singleDesc = fm.match(/^description:\s*(.+)/m);
|
|
16768
|
+
if (singleDesc) result.description = singleDesc[1].trim().replace(/^["']|["']$/g, "");
|
|
16769
|
+
}
|
|
16770
|
+
const backendsMatch = fm.match(/^compatible_backends:\s*(.+)/m);
|
|
16771
|
+
if (backendsMatch) result.compatibleBackends = backendsMatch[1].trim();
|
|
16772
|
+
const modelMatch = fm.match(/^recommended_model:\s*(.+)/m);
|
|
16773
|
+
if (modelMatch) result.recommendedModel = modelMatch[1].trim();
|
|
16774
|
+
return result;
|
|
16775
|
+
}
|
|
16776
|
+
function detectDependentSkills(content) {
|
|
16777
|
+
const deps = /* @__PURE__ */ new Set();
|
|
16778
|
+
const loadMatches = content.matchAll(/(?:load|activate|use|invoke)\s+(?:the\s+)?[`"]?([a-z0-9_-]+)[`"]?\s+(?:skill)?/gi);
|
|
16779
|
+
for (const m of loadMatches) {
|
|
16780
|
+
const name = m[1].toLowerCase();
|
|
16781
|
+
if (name.length > 2 && !["the", "this", "that", "skill", "tool"].includes(name)) {
|
|
16782
|
+
deps.add(name);
|
|
16783
|
+
}
|
|
16784
|
+
}
|
|
16785
|
+
const btMatches = content.matchAll(/`([a-z][a-z0-9_-]+(?:-skill)?)`/g);
|
|
16786
|
+
for (const m of btMatches) {
|
|
16787
|
+
const name = m[1];
|
|
16788
|
+
if (!name.includes(".") && !name.startsWith("cc-claw") && name.length > 3) {
|
|
16789
|
+
deps.add(name);
|
|
16790
|
+
}
|
|
16791
|
+
}
|
|
16792
|
+
return Array.from(deps);
|
|
16793
|
+
}
|
|
16794
|
+
function computeSkillStats(skillPath) {
|
|
16795
|
+
const content = readFileSync11(skillPath, "utf-8");
|
|
16796
|
+
const lines = content.split("\n");
|
|
16797
|
+
return {
|
|
16798
|
+
skillName: basename2(skillPath, ".md") === "SKILL" ? basename2(join21(skillPath, "..")) : basename2(skillPath, ".md"),
|
|
16799
|
+
skillPath,
|
|
16800
|
+
lineCount: lines.length,
|
|
16801
|
+
charCount: content.length,
|
|
16802
|
+
estimatedTokens: Math.ceil(content.length / 4),
|
|
16803
|
+
frontmatter: parseFrontmatter3(content),
|
|
16804
|
+
dependentSkills: detectDependentSkills(content)
|
|
16805
|
+
};
|
|
16806
|
+
}
|
|
16807
|
+
function buildSkillTokenReport(stats) {
|
|
16808
|
+
return {
|
|
16809
|
+
skillChars: stats.charCount,
|
|
16810
|
+
estimatedTokens: stats.estimatedTokens,
|
|
16811
|
+
lineCount: stats.lineCount
|
|
16812
|
+
};
|
|
16813
|
+
}
|
|
16814
|
+
function loadDependentSkillContents(depNames, ccClawSkillsDir) {
|
|
16815
|
+
const results = [];
|
|
16816
|
+
for (const name of depNames) {
|
|
16817
|
+
const candidates = [
|
|
16818
|
+
join21(ccClawSkillsDir, name, "SKILL.md"),
|
|
16819
|
+
join21(ccClawSkillsDir, `${name}-skill`, "SKILL.md")
|
|
16820
|
+
];
|
|
16821
|
+
for (const candidate of candidates) {
|
|
16822
|
+
if (existsSync20(candidate)) {
|
|
16823
|
+
try {
|
|
16824
|
+
const content = readFileSync11(candidate, "utf-8");
|
|
16825
|
+
results.push({
|
|
16826
|
+
name,
|
|
16827
|
+
content: content.length > 3e3 ? content.slice(0, 3e3) + "\n[...truncated]" : content
|
|
16828
|
+
});
|
|
16829
|
+
} catch {
|
|
16830
|
+
}
|
|
16831
|
+
break;
|
|
16356
16832
|
}
|
|
16357
|
-
break;
|
|
16358
16833
|
}
|
|
16359
|
-
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16834
|
+
}
|
|
16835
|
+
return results;
|
|
16836
|
+
}
|
|
16837
|
+
function buildSkillAuditPrompt(skillContent, stats, soulMd, ccClawSkillsDir) {
|
|
16838
|
+
const sections = [];
|
|
16839
|
+
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.
|
|
16840
|
+
|
|
16841
|
+
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.
|
|
16842
|
+
|
|
16843
|
+
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.
|
|
16844
|
+
|
|
16845
|
+
Return at most 8 findings. If the skill is well-constructed, return NO_FINDINGS.`);
|
|
16846
|
+
sections.push(`[Skill Stats]
|
|
16847
|
+
Name: ${stats.skillName}
|
|
16848
|
+
Path: ${stats.skillPath}
|
|
16849
|
+
Lines: ${stats.lineCount} (cap: 500 \u2014 over 500 = progressive disclosure needed)
|
|
16850
|
+
Chars: ${stats.charCount} (~${stats.estimatedTokens} tokens)
|
|
16851
|
+
Frontmatter name: ${stats.frontmatter.name || "(missing)"}
|
|
16852
|
+
Frontmatter description: ${stats.frontmatter.description ? stats.frontmatter.description.slice(0, 200) : "(missing)"}
|
|
16853
|
+
Compatible backends: ${stats.frontmatter.compatibleBackends || "(not specified)"}
|
|
16854
|
+
Recommended model: ${stats.frontmatter.recommendedModel || "(not specified)"}
|
|
16855
|
+
Referenced skills: ${stats.dependentSkills.length > 0 ? stats.dependentSkills.join(", ") : "none"}`);
|
|
16856
|
+
sections.push(`[Rubric \u2014 Evaluate Each Area]
|
|
16857
|
+
|
|
16858
|
+
1. FRONTMATTER QUALITY
|
|
16859
|
+
- Is 'name' present and descriptive?
|
|
16860
|
+
- Does 'description' include BOTH what the skill does AND trigger info (when to use it)?
|
|
16861
|
+
- A good description tells the AI exactly when to activate this skill
|
|
16862
|
+
- Should 'compatible_backends' or 'recommended_model' be specified?
|
|
16863
|
+
|
|
16864
|
+
2. BODY STRUCTURE
|
|
16865
|
+
- Over 500 lines? \u2192 needs progressive disclosure (essentials in body, details in references/)
|
|
16866
|
+
- Is there a "When to Use" section in the body? \u2192 that belongs in the frontmatter description
|
|
16867
|
+
- Are workflow steps clear and sequential?
|
|
16868
|
+
- Are phases/steps numbered for easy reference?
|
|
16869
|
+
- Is there a clear guard clause (preconditions before starting)?
|
|
16870
|
+
|
|
16871
|
+
3. TOKEN EFFICIENCY
|
|
16872
|
+
- Verbose explanations that could be condensed without losing meaning?
|
|
16873
|
+
- Redundant examples (one clear example > three repetitive ones)?
|
|
16874
|
+
- Reference material that should be in a references/ subdirectory?
|
|
16875
|
+
- Emotional emphasis (bold, caps, exclamation marks) that wastes tokens without improving adherence?
|
|
16876
|
+
- Duplicated instructions (same rule stated multiple times in different sections)?
|
|
16877
|
+
|
|
16878
|
+
4. CONTRADICTION DETECTION
|
|
16879
|
+
- Instructions that conflict with SOUL.md behavioral rules?
|
|
16880
|
+
(e.g., skill says "be thorough and detailed" but SOUL.md says "be concise")
|
|
16881
|
+
- Tone mismatches between skill and personality?
|
|
16882
|
+
- Conflicting tool usage patterns?
|
|
16883
|
+
- Internal contradictions within the skill itself?
|
|
16884
|
+
|
|
16885
|
+
5. COMPLIANCE & CLARITY
|
|
16886
|
+
- Negative framing ("DO NOT do X") that should be positive ("do Y instead")?
|
|
16887
|
+
- Vague rules the AI is unlikely to follow consistently?
|
|
16888
|
+
- Emotional escalation ("NEVER EVER", "THIS IS CRITICAL") \u2014 does it add compliance or just tokens?
|
|
16889
|
+
- Instructions that rely on the AI "remembering" without structural enforcement?`);
|
|
16890
|
+
sections.push("[Skill File Content]");
|
|
16891
|
+
sections.push(skillContent);
|
|
16892
|
+
sections.push("[SOUL.md (for contradiction check)]");
|
|
16893
|
+
sections.push(soulMd || "(empty)");
|
|
16894
|
+
if (stats.dependentSkills.length > 0) {
|
|
16895
|
+
const depContents = loadDependentSkillContents(stats.dependentSkills, ccClawSkillsDir);
|
|
16896
|
+
if (depContents.length > 0) {
|
|
16897
|
+
sections.push("[Referenced Skill Contents]");
|
|
16898
|
+
for (const dep of depContents) {
|
|
16899
|
+
sections.push(`--- ${dep.name} ---`);
|
|
16900
|
+
sections.push(dep.content);
|
|
16372
16901
|
}
|
|
16373
|
-
break;
|
|
16374
16902
|
}
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16903
|
+
}
|
|
16904
|
+
sections.push(`[Output Format]
|
|
16905
|
+
For each finding, output EXACTLY this format. Separate multiple findings with "---" on its own line.
|
|
16906
|
+
|
|
16907
|
+
FINDING: <short title, max 80 chars>
|
|
16908
|
+
AREA: <frontmatter | body | efficiency | contradiction | compliance>
|
|
16909
|
+
SEVERITY: <critical | warning | info>
|
|
16910
|
+
DETAIL: <1-3 sentences explaining the issue AND its specific impact on AI compliance>
|
|
16911
|
+
LOCATION: <SKILL.md:line or SKILL.md:section, e.g. "SKILL.md:## Phase 1" or "SKILL.md:45">
|
|
16912
|
+
SUGGESTION: <specific actionable fix>
|
|
16913
|
+
DIFF:
|
|
16914
|
+
<proposed changes as diff lines, + for additions, - for removals>
|
|
16915
|
+
---
|
|
16916
|
+
|
|
16917
|
+
If the skill is well-constructed after thorough analysis, output: NO_FINDINGS`);
|
|
16918
|
+
return sections.join("\n\n");
|
|
16919
|
+
}
|
|
16920
|
+
var init_skill_audit = __esm({
|
|
16921
|
+
"src/optimizer/skill-audit.ts"() {
|
|
16922
|
+
"use strict";
|
|
16923
|
+
}
|
|
16924
|
+
});
|
|
16925
|
+
|
|
16926
|
+
// src/optimizer/analyze.ts
|
|
16927
|
+
var analyze_exports2 = {};
|
|
16928
|
+
__export(analyze_exports2, {
|
|
16929
|
+
getModelDisplayInfo: () => getModelDisplayInfo,
|
|
16930
|
+
isWeakModel: () => isWeakModel,
|
|
16931
|
+
listCcClawSkills: () => listCcClawSkills,
|
|
16932
|
+
parseOptimizeOutput: () => parseOptimizeOutput,
|
|
16933
|
+
resolveOptimizeAdapter: () => resolveOptimizeAdapter,
|
|
16934
|
+
runIdentityAudit: () => runIdentityAudit,
|
|
16935
|
+
runSkillAudit: () => runSkillAudit
|
|
16936
|
+
});
|
|
16937
|
+
import { spawn as spawn6 } from "child_process";
|
|
16938
|
+
import { createInterface as createInterface5 } from "readline";
|
|
16939
|
+
import { readFileSync as readFileSync12, existsSync as existsSync21, readdirSync as readdirSync11 } from "fs";
|
|
16940
|
+
import { join as join22 } from "path";
|
|
16941
|
+
import { homedir as homedir7 } from "os";
|
|
16942
|
+
function parseOptimizeOutput(raw, validAreas) {
|
|
16943
|
+
if (!raw || raw.includes("NO_FINDINGS")) return [];
|
|
16944
|
+
if (!raw.includes("FINDING:")) return [];
|
|
16945
|
+
const blocks = raw.split(/\n---\n/).slice(0, MAX_FINDINGS);
|
|
16946
|
+
const results = [];
|
|
16947
|
+
for (const block of blocks) {
|
|
16948
|
+
const findingMatch = block.match(/^FINDING:\s*(.+)/m);
|
|
16949
|
+
const areaMatch = block.match(/^AREA:\s*(.+)/m);
|
|
16950
|
+
const severityMatch = block.match(/^SEVERITY:\s*(.+)/m);
|
|
16951
|
+
const detailMatch = block.match(/^DETAIL:\s*(.+)/m);
|
|
16952
|
+
const locationMatch = block.match(/^LOCATION:\s*(.+)/m);
|
|
16953
|
+
const suggestionMatch = block.match(/^SUGGESTION:\s*(.+)/m);
|
|
16954
|
+
const diffMatch = block.match(/^DIFF:\n([\s\S]*?)$/m);
|
|
16955
|
+
if (!findingMatch || !areaMatch) continue;
|
|
16956
|
+
const area = areaMatch[1].trim().toLowerCase();
|
|
16957
|
+
if (!validAreas.includes(area)) continue;
|
|
16958
|
+
const severity = severityMatch?.[1]?.trim().toLowerCase() ?? "info";
|
|
16959
|
+
if (!VALID_SEVERITIES.includes(severity)) continue;
|
|
16960
|
+
results.push({
|
|
16961
|
+
title: findingMatch[1].trim().slice(0, 80),
|
|
16962
|
+
area,
|
|
16963
|
+
severity,
|
|
16964
|
+
detail: detailMatch?.[1]?.trim() ?? "",
|
|
16965
|
+
location: locationMatch?.[1]?.trim() ?? "",
|
|
16966
|
+
suggestion: suggestionMatch?.[1]?.trim() ?? "",
|
|
16967
|
+
proposedDiff: diffMatch?.[1]?.trim() ?? ""
|
|
16968
|
+
});
|
|
16969
|
+
}
|
|
16970
|
+
return results;
|
|
16971
|
+
}
|
|
16972
|
+
async function spawnAnalysis2(adapter, model2, prompt, timeoutMs = ANALYSIS_TIMEOUT_MS2) {
|
|
16973
|
+
const config2 = adapter.buildSpawnConfig({
|
|
16974
|
+
prompt,
|
|
16975
|
+
model: model2,
|
|
16976
|
+
permMode: "yolo",
|
|
16977
|
+
allowedTools: []
|
|
16978
|
+
});
|
|
16979
|
+
const env = adapter.getEnv();
|
|
16980
|
+
let resultText = "";
|
|
16981
|
+
let accumulatedText = "";
|
|
16982
|
+
await new Promise((resolve) => {
|
|
16983
|
+
const proc = spawn6(config2.executable, config2.args, {
|
|
16984
|
+
env,
|
|
16985
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
16986
|
+
...config2.cwd ? { cwd: config2.cwd } : {}
|
|
16987
|
+
});
|
|
16988
|
+
proc.stderr?.resume();
|
|
16989
|
+
const rl2 = createInterface5({ input: proc.stdout });
|
|
16990
|
+
const timeout = setTimeout(() => {
|
|
16991
|
+
warn(`[optimizer] Analysis timeout (${adapter.id}:${model2})`);
|
|
16992
|
+
rl2.close();
|
|
16993
|
+
proc.kill("SIGTERM");
|
|
16994
|
+
setTimeout(() => proc.kill("SIGKILL"), 2e3);
|
|
16995
|
+
}, timeoutMs);
|
|
16996
|
+
rl2.on("line", (line) => {
|
|
16997
|
+
if (!line.trim()) return;
|
|
16998
|
+
let msg;
|
|
16999
|
+
try {
|
|
17000
|
+
msg = JSON.parse(line);
|
|
17001
|
+
} catch {
|
|
17002
|
+
return;
|
|
17003
|
+
}
|
|
17004
|
+
const events = adapter.parseLine(msg);
|
|
17005
|
+
for (const ev of events) {
|
|
17006
|
+
if (ev.type === "text" && ev.text) accumulatedText = appendTextChunk(accumulatedText, ev.text);
|
|
17007
|
+
if (ev.type === "result") {
|
|
17008
|
+
resultText = ev.resultText || accumulatedText;
|
|
17009
|
+
if (adapter.shouldKillOnResult()) {
|
|
17010
|
+
rl2.close();
|
|
17011
|
+
proc.kill("SIGTERM");
|
|
17012
|
+
}
|
|
17013
|
+
}
|
|
17014
|
+
}
|
|
17015
|
+
});
|
|
17016
|
+
proc.on("error", () => {
|
|
17017
|
+
clearTimeout(timeout);
|
|
17018
|
+
resolve();
|
|
17019
|
+
});
|
|
17020
|
+
proc.on("close", () => {
|
|
17021
|
+
clearTimeout(timeout);
|
|
17022
|
+
resolve();
|
|
17023
|
+
});
|
|
17024
|
+
});
|
|
17025
|
+
if (!resultText) resultText = accumulatedText;
|
|
17026
|
+
return resultText;
|
|
17027
|
+
}
|
|
17028
|
+
function resolveOptimizeAdapter(chatId) {
|
|
17029
|
+
try {
|
|
17030
|
+
const adapter = getAdapterForChat(chatId);
|
|
17031
|
+
return { adapter, model: adapter.defaultModel };
|
|
17032
|
+
} catch {
|
|
17033
|
+
try {
|
|
17034
|
+
const adapter = getAdapter("claude");
|
|
17035
|
+
return { adapter, model: adapter.defaultModel };
|
|
17036
|
+
} catch {
|
|
17037
|
+
return null;
|
|
17038
|
+
}
|
|
17039
|
+
}
|
|
17040
|
+
}
|
|
17041
|
+
function isWeakModel(adapter, model2) {
|
|
17042
|
+
const weakPatterns = [
|
|
17043
|
+
"flash",
|
|
17044
|
+
"haiku",
|
|
17045
|
+
"mini",
|
|
17046
|
+
"4o-mini",
|
|
17047
|
+
"gpt-4o-mini"
|
|
17048
|
+
];
|
|
17049
|
+
const lower = model2.toLowerCase();
|
|
17050
|
+
return weakPatterns.some((p) => lower.includes(p));
|
|
17051
|
+
}
|
|
17052
|
+
function getModelDisplayInfo(chatId) {
|
|
17053
|
+
const resolved = resolveOptimizeAdapter(chatId);
|
|
17054
|
+
if (!resolved) return null;
|
|
17055
|
+
const { getThinkingLevel: getThinkingLevel2 } = (init_store5(), __toCommonJS(store_exports5));
|
|
17056
|
+
const thinkingLevel = getThinkingLevel2(chatId);
|
|
17057
|
+
return {
|
|
17058
|
+
backend: resolved.adapter.displayName,
|
|
17059
|
+
model: resolved.model,
|
|
17060
|
+
thinkingLevel,
|
|
17061
|
+
isWeak: isWeakModel(resolved.adapter, resolved.model)
|
|
17062
|
+
};
|
|
17063
|
+
}
|
|
17064
|
+
function readIdentityFile3(filename) {
|
|
17065
|
+
try {
|
|
17066
|
+
return readFileSync12(join22(IDENTITY_PATH, filename), "utf-8");
|
|
17067
|
+
} catch {
|
|
17068
|
+
return "";
|
|
17069
|
+
}
|
|
17070
|
+
}
|
|
17071
|
+
function loadContextFiles() {
|
|
17072
|
+
const contextDir = join22(homedir7(), ".cc-claw", "workspace", "context");
|
|
17073
|
+
const results = [];
|
|
17074
|
+
if (!existsSync21(contextDir)) return results;
|
|
17075
|
+
try {
|
|
17076
|
+
for (const entry of readdirSync11(contextDir)) {
|
|
17077
|
+
if (!entry.endsWith(".md")) continue;
|
|
17078
|
+
try {
|
|
17079
|
+
const content = readFileSync12(join22(contextDir, entry), "utf-8");
|
|
17080
|
+
results.push({ name: entry, content });
|
|
17081
|
+
} catch {
|
|
17082
|
+
}
|
|
17083
|
+
}
|
|
17084
|
+
} catch {
|
|
17085
|
+
}
|
|
17086
|
+
return results;
|
|
17087
|
+
}
|
|
17088
|
+
async function runIdentityAudit(chatId) {
|
|
17089
|
+
const resolved = resolveOptimizeAdapter(chatId);
|
|
17090
|
+
if (!resolved) throw new Error("No AI backend available for analysis");
|
|
17091
|
+
const { adapter, model: model2 } = resolved;
|
|
17092
|
+
log(`[optimizer] Running identity audit with ${adapter.id}:${model2}`);
|
|
17093
|
+
let pendingProposals = 0;
|
|
17094
|
+
try {
|
|
17095
|
+
const { getPendingInsightCount: getPendingInsightCount2 } = (init_store4(), __toCommonJS(store_exports4));
|
|
17096
|
+
const { getPrimaryChatId: getPrimaryChatId2 } = (init_resolve(), __toCommonJS(resolve_exports));
|
|
17097
|
+
const reflChatId = getPrimaryChatId2() || chatId;
|
|
17098
|
+
pendingProposals = getPendingInsightCount2(getDb(), reflChatId);
|
|
17099
|
+
} catch {
|
|
17100
|
+
}
|
|
17101
|
+
let driftPercent = null;
|
|
17102
|
+
try {
|
|
17103
|
+
const { calculateDrift: calculateDrift2 } = (init_apply(), __toCommonJS(apply_exports));
|
|
17104
|
+
} catch {
|
|
17105
|
+
}
|
|
17106
|
+
const stats = computeIdentityStats(pendingProposals, driftPercent);
|
|
17107
|
+
const soulMd = readIdentityFile3("SOUL.md");
|
|
17108
|
+
const userMd = readIdentityFile3("USER.md");
|
|
17109
|
+
const ccClawMd = readIdentityFile3("CC-CLAW.md");
|
|
17110
|
+
const contextFiles = loadContextFiles();
|
|
17111
|
+
const prompt = buildIdentityAuditPrompt(soulMd, userMd, ccClawMd, stats, contextFiles);
|
|
17112
|
+
const raw = await spawnAnalysis2(adapter, model2, prompt);
|
|
17113
|
+
const findings = parseOptimizeOutput(raw, VALID_IDENTITY_AREAS);
|
|
17114
|
+
log(`[optimizer] Identity audit complete: ${findings.length} findings`);
|
|
17115
|
+
return {
|
|
17116
|
+
findings,
|
|
17117
|
+
tokenReport: buildTokenReport(stats),
|
|
17118
|
+
model: model2,
|
|
17119
|
+
backend: adapter.id,
|
|
17120
|
+
target: "identity"
|
|
17121
|
+
};
|
|
17122
|
+
}
|
|
17123
|
+
async function runSkillAudit(chatId, skillPath) {
|
|
17124
|
+
const resolved = resolveOptimizeAdapter(chatId);
|
|
17125
|
+
if (!resolved) throw new Error("No AI backend available for analysis");
|
|
17126
|
+
const { adapter, model: model2 } = resolved;
|
|
17127
|
+
const stats = computeSkillStats(skillPath);
|
|
17128
|
+
log(`[optimizer] Running skill audit on ${stats.skillName} with ${adapter.id}:${model2}`);
|
|
17129
|
+
const soulMd = readIdentityFile3("SOUL.md");
|
|
17130
|
+
const ccClawSkillsDir = join22(homedir7(), ".cc-claw", "workspace", "skills");
|
|
17131
|
+
const skillContent = readFileSync12(skillPath, "utf-8");
|
|
17132
|
+
const prompt = buildSkillAuditPrompt(skillContent, stats, soulMd, ccClawSkillsDir);
|
|
17133
|
+
const raw = await spawnAnalysis2(adapter, model2, prompt);
|
|
17134
|
+
const findings = parseOptimizeOutput(raw, VALID_SKILL_AREAS);
|
|
17135
|
+
log(`[optimizer] Skill audit complete for ${stats.skillName}: ${findings.length} findings`);
|
|
17136
|
+
return {
|
|
17137
|
+
findings,
|
|
17138
|
+
tokenReport: buildSkillTokenReport(stats),
|
|
17139
|
+
model: model2,
|
|
17140
|
+
backend: adapter.id,
|
|
17141
|
+
target: stats.skillName
|
|
17142
|
+
};
|
|
17143
|
+
}
|
|
17144
|
+
function listCcClawSkills() {
|
|
17145
|
+
const skillsDir = join22(homedir7(), ".cc-claw", "workspace", "skills");
|
|
17146
|
+
const entries = [];
|
|
17147
|
+
if (!existsSync21(skillsDir)) return entries;
|
|
17148
|
+
try {
|
|
17149
|
+
for (const dir of readdirSync11(skillsDir)) {
|
|
17150
|
+
const skillFile = join22(skillsDir, dir, "SKILL.md");
|
|
17151
|
+
if (!existsSync21(skillFile)) continue;
|
|
17152
|
+
let description = "skill";
|
|
17153
|
+
try {
|
|
17154
|
+
const content = readFileSync12(skillFile, "utf-8");
|
|
17155
|
+
const descMatch = content.match(/description:\s*>?\s*\n?\s*(.+)/);
|
|
17156
|
+
if (descMatch) description = descMatch[1].trim().slice(0, 60);
|
|
17157
|
+
} catch {
|
|
17158
|
+
}
|
|
17159
|
+
entries.push({ name: dir, path: skillFile, description });
|
|
17160
|
+
}
|
|
17161
|
+
} catch {
|
|
17162
|
+
}
|
|
17163
|
+
return entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
17164
|
+
}
|
|
17165
|
+
var ANALYSIS_TIMEOUT_MS2, MAX_FINDINGS, VALID_IDENTITY_AREAS, VALID_SKILL_AREAS, VALID_SEVERITIES;
|
|
17166
|
+
var init_analyze2 = __esm({
|
|
17167
|
+
"src/optimizer/analyze.ts"() {
|
|
17168
|
+
"use strict";
|
|
17169
|
+
init_log();
|
|
17170
|
+
init_text_utils();
|
|
17171
|
+
init_paths();
|
|
17172
|
+
init_backends();
|
|
17173
|
+
init_store5();
|
|
17174
|
+
init_identity_audit();
|
|
17175
|
+
init_skill_audit();
|
|
17176
|
+
ANALYSIS_TIMEOUT_MS2 = 18e4;
|
|
17177
|
+
MAX_FINDINGS = 8;
|
|
17178
|
+
VALID_IDENTITY_AREAS = [
|
|
17179
|
+
"structural",
|
|
17180
|
+
"routing",
|
|
17181
|
+
"efficiency",
|
|
17182
|
+
"evolve",
|
|
17183
|
+
"quality",
|
|
17184
|
+
"completeness"
|
|
17185
|
+
];
|
|
17186
|
+
VALID_SKILL_AREAS = [
|
|
17187
|
+
"frontmatter",
|
|
17188
|
+
"body",
|
|
17189
|
+
"efficiency",
|
|
17190
|
+
"contradiction",
|
|
17191
|
+
"compliance"
|
|
17192
|
+
];
|
|
17193
|
+
VALID_SEVERITIES = ["critical", "warning", "info"];
|
|
17194
|
+
}
|
|
17195
|
+
});
|
|
17196
|
+
|
|
17197
|
+
// src/optimizer/ui.ts
|
|
17198
|
+
var ui_exports = {};
|
|
17199
|
+
__export(ui_exports, {
|
|
17200
|
+
buildFindingKeyboard: () => buildFindingKeyboard,
|
|
17201
|
+
buildFindingMessage: () => buildFindingMessage,
|
|
17202
|
+
buildIdentityAuditKeyboard: () => buildIdentityAuditKeyboard,
|
|
17203
|
+
buildIdentityAuditSummary: () => buildIdentityAuditSummary,
|
|
17204
|
+
buildMainMenuKeyboard: () => buildMainMenuKeyboard,
|
|
17205
|
+
buildMainMenuMessage: () => buildMainMenuMessage,
|
|
17206
|
+
buildModelRecommendationKeyboard: () => buildModelRecommendationKeyboard,
|
|
17207
|
+
buildModelRecommendationMessage: () => buildModelRecommendationMessage,
|
|
17208
|
+
buildProgressMessage: () => buildProgressMessage,
|
|
17209
|
+
buildReviewCompleteKeyboard: () => buildReviewCompleteKeyboard,
|
|
17210
|
+
buildReviewCompleteMessage: () => buildReviewCompleteMessage2,
|
|
17211
|
+
buildSkillAuditKeyboard: () => buildSkillAuditKeyboard,
|
|
17212
|
+
buildSkillAuditSummary: () => buildSkillAuditSummary,
|
|
17213
|
+
buildSkillPickerKeyboard: () => buildSkillPickerKeyboard,
|
|
17214
|
+
buildSkillPickerMessage: () => buildSkillPickerMessage
|
|
17215
|
+
});
|
|
17216
|
+
function severityEmoji(severity) {
|
|
17217
|
+
switch (severity) {
|
|
17218
|
+
case "critical":
|
|
17219
|
+
return "\u{1F534}";
|
|
17220
|
+
case "warning":
|
|
17221
|
+
return "\u26A0\uFE0F";
|
|
17222
|
+
case "info":
|
|
17223
|
+
return "\u2139\uFE0F";
|
|
17224
|
+
default:
|
|
17225
|
+
return "\u2022";
|
|
17226
|
+
}
|
|
17227
|
+
}
|
|
17228
|
+
function areaEmoji(area) {
|
|
17229
|
+
switch (area) {
|
|
17230
|
+
case "structural":
|
|
17231
|
+
return "\u{1F4D0}";
|
|
17232
|
+
case "routing":
|
|
17233
|
+
return "\u{1F4C2}";
|
|
17234
|
+
case "efficiency":
|
|
17235
|
+
return "\u{1F4B0}";
|
|
17236
|
+
case "evolve":
|
|
17237
|
+
return "\u{1F504}";
|
|
17238
|
+
case "quality":
|
|
17239
|
+
return "\u2728";
|
|
17240
|
+
case "completeness":
|
|
17241
|
+
return "\u{1F464}";
|
|
17242
|
+
case "frontmatter":
|
|
17243
|
+
return "\u{1F4CB}";
|
|
17244
|
+
case "body":
|
|
17245
|
+
return "\u{1F4DD}";
|
|
17246
|
+
case "contradiction":
|
|
17247
|
+
return "\u26A1";
|
|
17248
|
+
case "compliance":
|
|
17249
|
+
return "\u2705";
|
|
17250
|
+
default:
|
|
17251
|
+
return "\u2022";
|
|
17252
|
+
}
|
|
17253
|
+
}
|
|
17254
|
+
function buildMainMenuMessage(backend2, model2, thinkingLevel) {
|
|
17255
|
+
const thinkText = thinkingLevel !== "off" && thinkingLevel !== "auto" ? ` | Thinking: ${thinkingLevel}` : thinkingLevel === "auto" ? " | Thinking: auto" : "";
|
|
17256
|
+
return [
|
|
17257
|
+
"\u{1F527} CC-Claw Optimizer",
|
|
17258
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17259
|
+
"",
|
|
17260
|
+
"AI-powered analysis of your identity files and skills.",
|
|
17261
|
+
"Optimize for clarity, efficiency, and compliance.",
|
|
17262
|
+
"",
|
|
17263
|
+
`\u2699\uFE0F Using: ${backend2} ${model2}${thinkText}`
|
|
17264
|
+
].join("\n");
|
|
17265
|
+
}
|
|
17266
|
+
function buildMainMenuKeyboard() {
|
|
17267
|
+
return [
|
|
17268
|
+
[
|
|
17269
|
+
{ label: "\u{1F9E0} Identity Audit", data: "opt:identity" },
|
|
17270
|
+
{ label: "\u{1F9E9} Skill Audit", data: "opt:skill-menu" }
|
|
17271
|
+
],
|
|
17272
|
+
[
|
|
17273
|
+
{ label: "\u274C Close", data: "opt:close" }
|
|
17274
|
+
]
|
|
17275
|
+
];
|
|
17276
|
+
}
|
|
17277
|
+
function buildModelRecommendationMessage(currentModel) {
|
|
17278
|
+
return [
|
|
17279
|
+
"\u{1F527} CC-Claw Optimizer",
|
|
17280
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17281
|
+
"",
|
|
17282
|
+
`\u26A0\uFE0F You're using ${currentModel} \u2014 for best audit results,`,
|
|
17283
|
+
"an advanced model is recommended."
|
|
17284
|
+
].join("\n");
|
|
17285
|
+
}
|
|
17286
|
+
function buildModelRecommendationKeyboard() {
|
|
17287
|
+
return [
|
|
17288
|
+
[
|
|
17289
|
+
{ label: "\u26A1 Continue anyway", data: "opt:model-ok" },
|
|
17290
|
+
{ label: "\u{1F9E0} Switch model first", data: "opt:model-switch", style: "primary" }
|
|
17291
|
+
],
|
|
17292
|
+
[
|
|
17293
|
+
{ label: "\u274C Cancel", data: "opt:close" }
|
|
17294
|
+
]
|
|
17295
|
+
];
|
|
17296
|
+
}
|
|
17297
|
+
function buildProgressMessage(target, backend2, model2, thinkingLevel) {
|
|
17298
|
+
const thinkText = thinkingLevel !== "off" ? ` | Thinking: ${thinkingLevel}` : "";
|
|
17299
|
+
return `\u{1F50D} Analyzing ${target}...
|
|
17300
|
+
Using ${backend2} ${model2}${thinkText}`;
|
|
17301
|
+
}
|
|
17302
|
+
function buildIdentityAuditSummary(result) {
|
|
17303
|
+
const { findings, tokenReport, model: model2, backend: backend2 } = result;
|
|
17304
|
+
const tr = tokenReport;
|
|
17305
|
+
const identityAreas = ["structural", "routing", "efficiency", "evolve", "quality", "completeness"];
|
|
17306
|
+
const lines = [
|
|
17307
|
+
"\u{1F9E0} Identity Audit Complete",
|
|
17308
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17309
|
+
""
|
|
17310
|
+
];
|
|
17311
|
+
for (const area of identityAreas) {
|
|
17312
|
+
const emoji = areaEmoji(area);
|
|
17313
|
+
const label2 = area.charAt(0).toUpperCase() + area.slice(1);
|
|
17314
|
+
const areaFindings = findings.filter((f) => f.area === area);
|
|
17315
|
+
const status = areaFindings.length === 0 ? "\u2705 Clean" : `\u26A0\uFE0F ${areaFindings.length} finding${areaFindings.length > 1 ? "s" : ""}`;
|
|
17316
|
+
lines.push(`${emoji} ${label2.padEnd(14)} ${status}`);
|
|
17317
|
+
}
|
|
17318
|
+
lines.push("");
|
|
17319
|
+
lines.push(`\u{1F4B0} Token footprint: ~${tr.estimatedTokens}/message`);
|
|
17320
|
+
lines.push(` (SOUL: ~${Math.ceil(tr.soulChars / 4)} + USER: ~${Math.ceil(tr.userChars / 4)} + System: ~${Math.ceil(tr.boilerplateChars / 4)})`);
|
|
17321
|
+
if (findings.length > 0) {
|
|
17322
|
+
lines.push("");
|
|
17323
|
+
lines.push(`${findings.length} finding${findings.length > 1 ? "s" : ""} to review`);
|
|
17324
|
+
} else {
|
|
17325
|
+
lines.push("");
|
|
17326
|
+
lines.push("\u2705 All checks passed \u2014 your identity files are clean!");
|
|
17327
|
+
}
|
|
17328
|
+
lines.push("");
|
|
17329
|
+
lines.push(`Analyzed by: ${backend2} ${model2}`);
|
|
17330
|
+
return lines.join("\n");
|
|
17331
|
+
}
|
|
17332
|
+
function buildIdentityAuditKeyboard(findingsCount) {
|
|
17333
|
+
if (findingsCount === 0) {
|
|
17334
|
+
return [[{ label: "\u2705 Done", data: "opt:close" }]];
|
|
17335
|
+
}
|
|
17336
|
+
return [
|
|
17337
|
+
[
|
|
17338
|
+
{ label: "\u{1F4CB} Review Findings", data: "opt:review:0", style: "primary" },
|
|
17339
|
+
{ label: "\u274C Close", data: "opt:close" }
|
|
17340
|
+
]
|
|
17341
|
+
];
|
|
17342
|
+
}
|
|
17343
|
+
function buildSkillAuditSummary(result) {
|
|
17344
|
+
const { findings, tokenReport, model: model2, backend: backend2, target } = result;
|
|
17345
|
+
const tr = tokenReport;
|
|
17346
|
+
const skillAreas = ["frontmatter", "body", "efficiency", "contradiction", "compliance"];
|
|
17347
|
+
const lines = [
|
|
17348
|
+
`\u{1F9E9} Skill Audit: ${target}`,
|
|
17349
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17350
|
+
""
|
|
17351
|
+
];
|
|
17352
|
+
for (const area of skillAreas) {
|
|
17353
|
+
const emoji = areaEmoji(area);
|
|
17354
|
+
const label2 = area.charAt(0).toUpperCase() + area.slice(1);
|
|
17355
|
+
const areaFindings = findings.filter((f) => f.area === area);
|
|
17356
|
+
const status = areaFindings.length === 0 ? "\u2705 Clean" : `\u26A0\uFE0F ${areaFindings.length} finding${areaFindings.length > 1 ? "s" : ""}`;
|
|
17357
|
+
lines.push(`${emoji} ${label2.padEnd(14)} ${status}`);
|
|
17358
|
+
}
|
|
17359
|
+
lines.push("");
|
|
17360
|
+
lines.push(`\u{1F4CA} Skill size: ${tr.lineCount} lines, ~${tr.estimatedTokens} tokens`);
|
|
17361
|
+
if (findings.length > 0) {
|
|
17362
|
+
lines.push("");
|
|
17363
|
+
lines.push(`${findings.length} finding${findings.length > 1 ? "s" : ""} to review`);
|
|
17364
|
+
} else {
|
|
17365
|
+
lines.push("");
|
|
17366
|
+
lines.push("\u2705 All checks passed \u2014 this skill is well-constructed!");
|
|
17367
|
+
}
|
|
17368
|
+
lines.push("");
|
|
17369
|
+
lines.push(`Analyzed by: ${backend2} ${model2}`);
|
|
17370
|
+
return lines.join("\n");
|
|
17371
|
+
}
|
|
17372
|
+
function buildSkillAuditKeyboard(findingsCount) {
|
|
17373
|
+
if (findingsCount === 0) {
|
|
17374
|
+
return [[{ label: "\u2705 Done", data: "opt:close" }]];
|
|
17375
|
+
}
|
|
17376
|
+
return [
|
|
17377
|
+
[
|
|
17378
|
+
{ label: "\u{1F4CB} Review Findings", data: "opt:review:0", style: "primary" },
|
|
17379
|
+
{ label: "\u274C Close", data: "opt:close" }
|
|
17380
|
+
]
|
|
17381
|
+
];
|
|
17382
|
+
}
|
|
17383
|
+
function buildFindingMessage(finding, index, total) {
|
|
17384
|
+
const lines = [
|
|
17385
|
+
`${severityEmoji(finding.severity)} Finding ${index + 1}/${total} \u2014 ${finding.area}`,
|
|
17386
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17387
|
+
"",
|
|
17388
|
+
finding.title,
|
|
17389
|
+
"",
|
|
17390
|
+
`\u{1F4CD} ${finding.location}`,
|
|
17391
|
+
"",
|
|
17392
|
+
finding.detail
|
|
17393
|
+
];
|
|
17394
|
+
if (finding.suggestion) {
|
|
17395
|
+
lines.push("");
|
|
17396
|
+
lines.push(`\u{1F4A1} ${finding.suggestion}`);
|
|
17397
|
+
}
|
|
17398
|
+
if (finding.proposedDiff) {
|
|
17399
|
+
lines.push("");
|
|
17400
|
+
lines.push("Proposed change:");
|
|
17401
|
+
lines.push("```");
|
|
17402
|
+
lines.push(finding.proposedDiff);
|
|
17403
|
+
lines.push("```");
|
|
17404
|
+
}
|
|
17405
|
+
return lines.join("\n");
|
|
17406
|
+
}
|
|
17407
|
+
function buildFindingKeyboard(index, total, hasDiff) {
|
|
17408
|
+
if (hasDiff) {
|
|
17409
|
+
return [[
|
|
17410
|
+
{ label: "\u2705 Apply Fix", data: `opt:fix:${index}`, style: "success" },
|
|
17411
|
+
{ label: "\u23ED\uFE0F Skip", data: `opt:skip:${index}` },
|
|
17412
|
+
{ label: "\u{1F6D1} Stop Review", data: "opt:stop", style: "danger" }
|
|
17413
|
+
]];
|
|
17414
|
+
}
|
|
17415
|
+
return [[
|
|
17416
|
+
{ label: "\u23ED\uFE0F Next", data: `opt:skip:${index}` },
|
|
17417
|
+
{ label: "\u{1F6D1} Stop Review", data: "opt:stop", style: "danger" }
|
|
17418
|
+
]];
|
|
17419
|
+
}
|
|
17420
|
+
function buildSkillPickerMessage(page, totalPages) {
|
|
17421
|
+
return [
|
|
17422
|
+
"\u{1F9E9} Select a Skill to Audit",
|
|
17423
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17424
|
+
"",
|
|
17425
|
+
"Showing CC-Claw skills (~/.cc-claw/workspace/skills/)",
|
|
17426
|
+
...totalPages > 1 ? [`Page ${page + 1}/${totalPages}`] : []
|
|
17427
|
+
].join("\n");
|
|
17428
|
+
}
|
|
17429
|
+
function buildSkillPickerKeyboard(skills2, page) {
|
|
17430
|
+
const totalPages = Math.ceil(skills2.length / SKILLS_PER_PAGE2);
|
|
17431
|
+
const start = page * SKILLS_PER_PAGE2;
|
|
17432
|
+
const pageSkills = skills2.slice(start, start + SKILLS_PER_PAGE2);
|
|
17433
|
+
const rows = [];
|
|
17434
|
+
for (let i = 0; i < pageSkills.length; i += 2) {
|
|
17435
|
+
const row = [];
|
|
17436
|
+
row.push({ label: pageSkills[i].name, data: `opt:skill-pick:${pageSkills[i].name}` });
|
|
17437
|
+
if (pageSkills[i + 1]) {
|
|
17438
|
+
row.push({ label: pageSkills[i + 1].name, data: `opt:skill-pick:${pageSkills[i + 1].name}` });
|
|
17439
|
+
}
|
|
17440
|
+
rows.push(row);
|
|
17441
|
+
}
|
|
17442
|
+
const navRow = [];
|
|
17443
|
+
if (page > 0) navRow.push({ label: "\u2190 Prev", data: `opt:skill-page:${page - 1}` });
|
|
17444
|
+
if (page < totalPages - 1) navRow.push({ label: "Next \u2192", data: `opt:skill-page:${page + 1}` });
|
|
17445
|
+
navRow.push({ label: "\u274C Cancel", data: "opt:close" });
|
|
17446
|
+
rows.push(navRow);
|
|
17447
|
+
return rows;
|
|
17448
|
+
}
|
|
17449
|
+
function buildReviewCompleteMessage2(applied, skipped, total) {
|
|
17450
|
+
return [
|
|
17451
|
+
"\u{1F527} Review Complete",
|
|
17452
|
+
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
17453
|
+
"",
|
|
17454
|
+
`\u2705 Applied: ${applied}`,
|
|
17455
|
+
`\u23ED\uFE0F Skipped: ${skipped}`,
|
|
17456
|
+
`\u{1F4CA} Total findings: ${total}`
|
|
17457
|
+
].join("\n");
|
|
17458
|
+
}
|
|
17459
|
+
function buildReviewCompleteKeyboard() {
|
|
17460
|
+
return [[{ label: "\u2705 Done", data: "opt:close" }]];
|
|
17461
|
+
}
|
|
17462
|
+
var SKILLS_PER_PAGE2;
|
|
17463
|
+
var init_ui2 = __esm({
|
|
17464
|
+
"src/optimizer/ui.ts"() {
|
|
17465
|
+
"use strict";
|
|
17466
|
+
SKILLS_PER_PAGE2 = 6;
|
|
17467
|
+
}
|
|
17468
|
+
});
|
|
17469
|
+
|
|
17470
|
+
// src/router/optimize.ts
|
|
17471
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, existsSync as existsSync22 } from "fs";
|
|
17472
|
+
import { join as join23 } from "path";
|
|
17473
|
+
import { homedir as homedir8 } from "os";
|
|
17474
|
+
async function handleOptimizeCommand(chatId, channel, _args) {
|
|
17475
|
+
const { getModelDisplayInfo: getModelDisplayInfo2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17476
|
+
const {
|
|
17477
|
+
buildMainMenuMessage: buildMainMenuMessage2,
|
|
17478
|
+
buildMainMenuKeyboard: buildMainMenuKeyboard2,
|
|
17479
|
+
buildModelRecommendationMessage: buildModelRecommendationMessage2,
|
|
17480
|
+
buildModelRecommendationKeyboard: buildModelRecommendationKeyboard2
|
|
17481
|
+
} = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17482
|
+
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17483
|
+
if (!modelInfo) {
|
|
17484
|
+
await channel.sendText(chatId, "No AI backend available. Configure one first.", { parseMode: "plain" });
|
|
17485
|
+
return;
|
|
17486
|
+
}
|
|
17487
|
+
if (modelInfo.isWeak) {
|
|
17488
|
+
const msg2 = buildModelRecommendationMessage2(modelInfo.model);
|
|
17489
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17490
|
+
await channel.sendKeyboard(chatId, msg2, buildModelRecommendationKeyboard2());
|
|
17491
|
+
} else {
|
|
17492
|
+
await channel.sendText(chatId, msg2 + "\n\nSwitch to an advanced model for best results.", { parseMode: "plain" });
|
|
17493
|
+
}
|
|
17494
|
+
return;
|
|
17495
|
+
}
|
|
17496
|
+
const msg = buildMainMenuMessage2(modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel);
|
|
17497
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17498
|
+
await channel.sendKeyboard(chatId, msg, buildMainMenuKeyboard2());
|
|
17499
|
+
} else {
|
|
17500
|
+
await channel.sendText(chatId, msg, { parseMode: "plain" });
|
|
17501
|
+
}
|
|
17502
|
+
}
|
|
17503
|
+
async function handleOptimizeCallback(chatId, data, channel) {
|
|
17504
|
+
const parts = data.split(":");
|
|
17505
|
+
const action = parts[1];
|
|
17506
|
+
switch (action) {
|
|
17507
|
+
case "identity": {
|
|
17508
|
+
await runIdentityAuditFlow(chatId, channel);
|
|
17509
|
+
break;
|
|
17510
|
+
}
|
|
17511
|
+
case "skill-menu": {
|
|
17512
|
+
await showSkillPicker(chatId, channel, 0);
|
|
17513
|
+
break;
|
|
17514
|
+
}
|
|
17515
|
+
case "skill-page": {
|
|
17516
|
+
const page = parseInt(parts[2], 10) || 0;
|
|
17517
|
+
await showSkillPicker(chatId, channel, page);
|
|
17518
|
+
break;
|
|
17519
|
+
}
|
|
17520
|
+
case "skill-pick": {
|
|
17521
|
+
const skillName = parts.slice(2).join(":");
|
|
17522
|
+
await runSkillAuditFlow(chatId, channel, skillName);
|
|
17523
|
+
break;
|
|
17524
|
+
}
|
|
17525
|
+
case "model-ok": {
|
|
17526
|
+
const { getModelDisplayInfo: getModelDisplayInfo2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17527
|
+
const { buildMainMenuMessage: buildMainMenuMessage2, buildMainMenuKeyboard: buildMainMenuKeyboard2 } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17528
|
+
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17529
|
+
if (!modelInfo) return;
|
|
17530
|
+
const msg = buildMainMenuMessage2(modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel);
|
|
17531
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17532
|
+
await channel.sendKeyboard(chatId, msg, buildMainMenuKeyboard2());
|
|
17533
|
+
}
|
|
17534
|
+
break;
|
|
17535
|
+
}
|
|
17536
|
+
case "model-switch": {
|
|
17537
|
+
await channel.sendText(chatId, "Use /model or /backend to switch to a more powerful model, then run /optimize again.", { parseMode: "plain" });
|
|
17538
|
+
break;
|
|
17539
|
+
}
|
|
17540
|
+
case "review": {
|
|
17541
|
+
const index = parseInt(parts[2], 10) || 0;
|
|
17542
|
+
await showFinding(chatId, channel, index);
|
|
17543
|
+
break;
|
|
17544
|
+
}
|
|
17545
|
+
case "fix": {
|
|
17546
|
+
const fixIndex = parseInt(parts[2], 10) || 0;
|
|
17547
|
+
await applyFinding(chatId, channel, fixIndex);
|
|
17548
|
+
break;
|
|
17549
|
+
}
|
|
17550
|
+
case "skip": {
|
|
17551
|
+
const skipIndex = parseInt(parts[2], 10) || 0;
|
|
17552
|
+
await skipFinding(chatId, channel, skipIndex);
|
|
17553
|
+
break;
|
|
17554
|
+
}
|
|
17555
|
+
case "stop": {
|
|
17556
|
+
await stopReview(chatId, channel);
|
|
17557
|
+
break;
|
|
17558
|
+
}
|
|
17559
|
+
case "close": {
|
|
17560
|
+
activeSessions.delete(chatId);
|
|
17561
|
+
await channel.sendText(chatId, "Optimizer closed.", { parseMode: "plain" });
|
|
17562
|
+
break;
|
|
17563
|
+
}
|
|
17564
|
+
default:
|
|
17565
|
+
break;
|
|
17566
|
+
}
|
|
17567
|
+
}
|
|
17568
|
+
async function runIdentityAuditFlow(chatId, channel) {
|
|
17569
|
+
const { getModelDisplayInfo: getModelDisplayInfo2, runIdentityAudit: runIdentityAudit2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17570
|
+
const {
|
|
17571
|
+
buildProgressMessage: buildProgressMessage2,
|
|
17572
|
+
buildIdentityAuditSummary: buildIdentityAuditSummary2,
|
|
17573
|
+
buildIdentityAuditKeyboard: buildIdentityAuditKeyboard2
|
|
17574
|
+
} = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17575
|
+
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17576
|
+
if (!modelInfo) return;
|
|
17577
|
+
await channel.sendText(
|
|
17578
|
+
chatId,
|
|
17579
|
+
buildProgressMessage2("identity files", modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
|
|
17580
|
+
{ parseMode: "plain" }
|
|
17581
|
+
);
|
|
17582
|
+
try {
|
|
17583
|
+
const result = await runIdentityAudit2(chatId);
|
|
17584
|
+
activeSessions.set(chatId, {
|
|
17585
|
+
chatId,
|
|
17586
|
+
result,
|
|
17587
|
+
currentIndex: 0,
|
|
17588
|
+
applied: [],
|
|
17589
|
+
skipped: []
|
|
17590
|
+
});
|
|
17591
|
+
const summary = buildIdentityAuditSummary2(result);
|
|
17592
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17593
|
+
await channel.sendKeyboard(chatId, summary, buildIdentityAuditKeyboard2(result.findings.length));
|
|
17594
|
+
} else {
|
|
17595
|
+
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
17596
|
+
}
|
|
17597
|
+
} catch (e) {
|
|
17598
|
+
await channel.sendText(chatId, `Identity audit failed: ${e}`, { parseMode: "plain" });
|
|
17599
|
+
}
|
|
17600
|
+
}
|
|
17601
|
+
async function showSkillPicker(chatId, channel, page) {
|
|
17602
|
+
const { listCcClawSkills: listCcClawSkills2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17603
|
+
const { buildSkillPickerMessage: buildSkillPickerMessage2, buildSkillPickerKeyboard: buildSkillPickerKeyboard2 } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17604
|
+
const skills2 = listCcClawSkills2();
|
|
17605
|
+
if (skills2.length === 0) {
|
|
17606
|
+
await channel.sendText(chatId, "No CC-Claw skills found in ~/.cc-claw/workspace/skills/", { parseMode: "plain" });
|
|
17607
|
+
return;
|
|
17608
|
+
}
|
|
17609
|
+
const totalPages = Math.ceil(skills2.length / 6);
|
|
17610
|
+
const msg = buildSkillPickerMessage2(page, totalPages);
|
|
17611
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17612
|
+
await channel.sendKeyboard(chatId, msg, buildSkillPickerKeyboard2(skills2, page));
|
|
17613
|
+
} else {
|
|
17614
|
+
const list = skills2.map((s) => `\u2022 ${s.name} \u2014 ${s.description}`).join("\n");
|
|
17615
|
+
await channel.sendText(chatId, msg + "\n\n" + list, { parseMode: "plain" });
|
|
17616
|
+
}
|
|
17617
|
+
}
|
|
17618
|
+
async function runSkillAuditFlow(chatId, channel, skillName) {
|
|
17619
|
+
const { getModelDisplayInfo: getModelDisplayInfo2, runSkillAudit: runSkillAudit2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
17620
|
+
const {
|
|
17621
|
+
buildProgressMessage: buildProgressMessage2,
|
|
17622
|
+
buildSkillAuditSummary: buildSkillAuditSummary2,
|
|
17623
|
+
buildSkillAuditKeyboard: buildSkillAuditKeyboard2
|
|
17624
|
+
} = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17625
|
+
const modelInfo = getModelDisplayInfo2(chatId);
|
|
17626
|
+
if (!modelInfo) return;
|
|
17627
|
+
const skillPath = join23(homedir8(), ".cc-claw", "workspace", "skills", skillName, "SKILL.md");
|
|
17628
|
+
await channel.sendText(
|
|
17629
|
+
chatId,
|
|
17630
|
+
buildProgressMessage2(`skill: ${skillName}`, modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
|
|
17631
|
+
{ parseMode: "plain" }
|
|
17632
|
+
);
|
|
17633
|
+
try {
|
|
17634
|
+
const result = await runSkillAudit2(chatId, skillPath);
|
|
17635
|
+
activeSessions.set(chatId, {
|
|
17636
|
+
chatId,
|
|
17637
|
+
result,
|
|
17638
|
+
currentIndex: 0,
|
|
17639
|
+
applied: [],
|
|
17640
|
+
skipped: []
|
|
17641
|
+
});
|
|
17642
|
+
const summary = buildSkillAuditSummary2(result);
|
|
17643
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17644
|
+
await channel.sendKeyboard(chatId, summary, buildSkillAuditKeyboard2(result.findings.length));
|
|
17645
|
+
} else {
|
|
17646
|
+
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
17647
|
+
}
|
|
17648
|
+
} catch (e) {
|
|
17649
|
+
await channel.sendText(chatId, `Skill audit failed: ${e}`, { parseMode: "plain" });
|
|
17650
|
+
}
|
|
17651
|
+
}
|
|
17652
|
+
async function showFinding(chatId, channel, index) {
|
|
17653
|
+
const session2 = activeSessions.get(chatId);
|
|
17654
|
+
if (!session2) {
|
|
17655
|
+
await channel.sendText(chatId, "No active optimizer session. Run /optimize first.", { parseMode: "plain" });
|
|
17656
|
+
return;
|
|
17657
|
+
}
|
|
17658
|
+
const { findings } = session2.result;
|
|
17659
|
+
if (index >= findings.length) {
|
|
17660
|
+
await finishReview(chatId, channel);
|
|
17661
|
+
return;
|
|
17662
|
+
}
|
|
17663
|
+
session2.currentIndex = index;
|
|
17664
|
+
const finding = findings[index];
|
|
17665
|
+
const { buildFindingMessage: buildFindingMessage2, buildFindingKeyboard: buildFindingKeyboard2 } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17666
|
+
const msg = buildFindingMessage2(finding, index, findings.length);
|
|
17667
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17668
|
+
await channel.sendKeyboard(chatId, msg, buildFindingKeyboard2(index, findings.length, !!finding.proposedDiff));
|
|
17669
|
+
} else {
|
|
17670
|
+
await channel.sendText(chatId, msg, { parseMode: "plain" });
|
|
17671
|
+
}
|
|
17672
|
+
}
|
|
17673
|
+
async function applyFinding(chatId, channel, index) {
|
|
17674
|
+
const session2 = activeSessions.get(chatId);
|
|
17675
|
+
if (!session2) return;
|
|
17676
|
+
const finding = session2.result.findings[index];
|
|
17677
|
+
if (!finding || !finding.proposedDiff) {
|
|
17678
|
+
await channel.sendText(chatId, "No diff to apply for this finding.", { parseMode: "plain" });
|
|
17679
|
+
await showFinding(chatId, channel, index + 1);
|
|
17680
|
+
return;
|
|
17681
|
+
}
|
|
17682
|
+
try {
|
|
17683
|
+
const targetPath = resolveTargetFile(finding.location, session2.result.target);
|
|
17684
|
+
if (!targetPath) {
|
|
17685
|
+
await channel.sendText(chatId, `Cannot determine target file from location: ${finding.location}`, { parseMode: "plain" });
|
|
17686
|
+
session2.skipped.push(index);
|
|
17687
|
+
await showFinding(chatId, channel, index + 1);
|
|
17688
|
+
return;
|
|
17689
|
+
}
|
|
17690
|
+
if (!existsSync22(targetPath)) {
|
|
17691
|
+
await channel.sendText(chatId, `Target file not found: ${targetPath}`, { parseMode: "plain" });
|
|
17692
|
+
session2.skipped.push(index);
|
|
17693
|
+
await showFinding(chatId, channel, index + 1);
|
|
17694
|
+
return;
|
|
17695
|
+
}
|
|
17696
|
+
const original = readFileSync13(targetPath, "utf-8");
|
|
17697
|
+
const backupPath = targetPath + `.bak.${Date.now()}`;
|
|
17698
|
+
writeFileSync7(backupPath, original, "utf-8");
|
|
17699
|
+
pruneBackups2(targetPath);
|
|
17700
|
+
const { applyDiff: applyDiff2 } = await Promise.resolve().then(() => (init_apply(), apply_exports));
|
|
17701
|
+
const newContent = applyDiff2(original, finding.proposedDiff, "replace");
|
|
17702
|
+
if (newContent === original) {
|
|
17703
|
+
await channel.sendText(chatId, `\u26A0\uFE0F Diff produced no changes. The content may have already been modified.`, { parseMode: "plain" });
|
|
17704
|
+
session2.skipped.push(index);
|
|
17705
|
+
await showFinding(chatId, channel, index + 1);
|
|
17706
|
+
return;
|
|
17707
|
+
}
|
|
17708
|
+
writeFileSync7(targetPath, newContent, "utf-8");
|
|
17709
|
+
session2.applied.push(index);
|
|
17710
|
+
if (targetPath.includes("identity/")) {
|
|
17711
|
+
try {
|
|
17712
|
+
const { syncNativeCliFiles: syncNativeCliFiles2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
17713
|
+
await syncNativeCliFiles2();
|
|
17714
|
+
} catch {
|
|
17715
|
+
}
|
|
17716
|
+
}
|
|
17717
|
+
await channel.sendText(chatId, `\u2705 Applied: ${finding.title}`, { parseMode: "plain" });
|
|
17718
|
+
} catch (e) {
|
|
17719
|
+
const errorMsg = e?.message ?? String(e);
|
|
17720
|
+
await channel.sendText(chatId, `\u274C Failed to apply fix: ${errorMsg}`, { parseMode: "plain" });
|
|
17721
|
+
session2.skipped.push(index);
|
|
17722
|
+
}
|
|
17723
|
+
await showFinding(chatId, channel, index + 1);
|
|
17724
|
+
}
|
|
17725
|
+
async function skipFinding(chatId, channel, index) {
|
|
17726
|
+
const session2 = activeSessions.get(chatId);
|
|
17727
|
+
if (!session2) return;
|
|
17728
|
+
session2.skipped.push(index);
|
|
17729
|
+
await showFinding(chatId, channel, index + 1);
|
|
17730
|
+
}
|
|
17731
|
+
async function stopReview(chatId, channel) {
|
|
17732
|
+
await finishReview(chatId, channel);
|
|
17733
|
+
}
|
|
17734
|
+
async function finishReview(chatId, channel) {
|
|
17735
|
+
const session2 = activeSessions.get(chatId);
|
|
17736
|
+
if (!session2) return;
|
|
17737
|
+
const { buildReviewCompleteMessage: buildReviewCompleteMessage3, buildReviewCompleteKeyboard: buildReviewCompleteKeyboard2 } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
|
|
17738
|
+
const msg = buildReviewCompleteMessage3(
|
|
17739
|
+
session2.applied.length,
|
|
17740
|
+
session2.skipped.length,
|
|
17741
|
+
session2.result.findings.length
|
|
17742
|
+
);
|
|
17743
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17744
|
+
await channel.sendKeyboard(chatId, msg, buildReviewCompleteKeyboard2());
|
|
17745
|
+
} else {
|
|
17746
|
+
await channel.sendText(chatId, msg, { parseMode: "plain" });
|
|
17747
|
+
}
|
|
17748
|
+
activeSessions.delete(chatId);
|
|
17749
|
+
}
|
|
17750
|
+
function resolveTargetFile(location, auditTarget) {
|
|
17751
|
+
const ccClawHome = join23(homedir8(), ".cc-claw");
|
|
17752
|
+
const filePart = location.split(":")[0]?.trim();
|
|
17753
|
+
if (!filePart) return null;
|
|
17754
|
+
if (filePart === "SOUL.md") return join23(ccClawHome, "identity", "SOUL.md");
|
|
17755
|
+
if (filePart === "USER.md") return join23(ccClawHome, "identity", "USER.md");
|
|
17756
|
+
if (filePart === "CC-CLAW.md") return join23(ccClawHome, "identity", "CC-CLAW.md");
|
|
17757
|
+
if (filePart === "SKILL.md" && auditTarget !== "identity") {
|
|
17758
|
+
return join23(ccClawHome, "workspace", "skills", auditTarget, "SKILL.md");
|
|
17759
|
+
}
|
|
17760
|
+
return null;
|
|
17761
|
+
}
|
|
17762
|
+
function pruneBackups2(absolutePath) {
|
|
17763
|
+
const { readdirSync: readDir, unlinkSync: unlink4 } = __require("fs");
|
|
17764
|
+
const { dirname: dirName } = __require("path");
|
|
17765
|
+
const dir = dirName(absolutePath);
|
|
17766
|
+
const baseName = absolutePath.split("/").pop() ?? "";
|
|
17767
|
+
try {
|
|
17768
|
+
const backups = readDir(dir).filter((f) => f.startsWith(baseName + ".bak.")).sort().map((f) => join23(dir, f));
|
|
17769
|
+
while (backups.length > 3) {
|
|
17770
|
+
const oldest = backups.shift();
|
|
17771
|
+
try {
|
|
17772
|
+
unlink4(oldest);
|
|
17773
|
+
} catch {
|
|
17774
|
+
}
|
|
17775
|
+
}
|
|
17776
|
+
} catch {
|
|
17777
|
+
}
|
|
17778
|
+
}
|
|
17779
|
+
var activeSessions;
|
|
17780
|
+
var init_optimize = __esm({
|
|
17781
|
+
"src/router/optimize.ts"() {
|
|
17782
|
+
"use strict";
|
|
17783
|
+
activeSessions = /* @__PURE__ */ new Map();
|
|
17784
|
+
}
|
|
17785
|
+
});
|
|
17786
|
+
|
|
17787
|
+
// src/router/commands.ts
|
|
17788
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
17789
|
+
async function handleCommand(msg, channel) {
|
|
17790
|
+
const { chatId, command, commandArgs } = msg;
|
|
17791
|
+
if (command?.startsWith("/")) {
|
|
17792
|
+
return handleBackendCommand(command, chatId, channel);
|
|
17793
|
+
}
|
|
17794
|
+
switch (command) {
|
|
17795
|
+
case "start":
|
|
17796
|
+
case "help": {
|
|
17797
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17798
|
+
await sendHelpCategories(chatId, channel);
|
|
16384
17799
|
} else {
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16388
|
-
|
|
16389
|
-
|
|
17800
|
+
await channel.sendText(
|
|
17801
|
+
chatId,
|
|
17802
|
+
"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(
|
|
17803
|
+
([cat, cmds]) => `${cat}:
|
|
17804
|
+
${cmds.map((c) => ` ${c.cmd} \u2014 ${c.desc}`).join("\n")}`
|
|
17805
|
+
).join("\n\n"),
|
|
17806
|
+
{ parseMode: "plain" }
|
|
17807
|
+
);
|
|
17808
|
+
}
|
|
17809
|
+
break;
|
|
17810
|
+
}
|
|
17811
|
+
case "menu":
|
|
17812
|
+
case "m": {
|
|
17813
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
17814
|
+
const header2 = `\u{1F43E} ${buildSectionHeader("CC-Claw")}`;
|
|
17815
|
+
await channel.sendKeyboard(chatId, header2, [
|
|
17816
|
+
[{ label: "New Chat", data: "menu:newchat" }, { label: "Status", data: "menu:status" }],
|
|
17817
|
+
[{ label: "Backend", data: "menu:backend" }, { label: "Model", data: "menu:model" }],
|
|
17818
|
+
[{ label: "Jobs", data: "menu:jobs" }, { label: "Memory", data: "menu:memory" }],
|
|
17819
|
+
[{ label: "History", data: "menu:history" }, { label: "Help", data: "menu:help" }]
|
|
17820
|
+
]);
|
|
17821
|
+
} else {
|
|
17822
|
+
await channel.sendText(
|
|
17823
|
+
chatId,
|
|
17824
|
+
"CC-Claw Menu:\n/newchat \xB7 /status \xB7 /backend \xB7 /model\n/jobs \xB7 /memory \xB7 /history \xB7 /help",
|
|
17825
|
+
{ parseMode: "plain" }
|
|
17826
|
+
);
|
|
17827
|
+
}
|
|
17828
|
+
break;
|
|
17829
|
+
}
|
|
17830
|
+
case "stop": {
|
|
17831
|
+
const stopped = stopAgent(chatId);
|
|
17832
|
+
stopAllSideQuests(chatId);
|
|
17833
|
+
cancelAllAgents(chatId);
|
|
17834
|
+
await channel.sendText(
|
|
17835
|
+
chatId,
|
|
17836
|
+
stopped ? "Stopping current task..." : "Nothing is running.",
|
|
17837
|
+
{ parseMode: "plain" }
|
|
17838
|
+
);
|
|
17839
|
+
if (stopped && typeof channel.sendKeyboard === "function") {
|
|
17840
|
+
await channel.sendKeyboard(chatId, "", [
|
|
17841
|
+
[{ label: "\u{1F195} New Chat", data: "menu:newchat" }]
|
|
17842
|
+
]);
|
|
16390
17843
|
}
|
|
16391
17844
|
break;
|
|
16392
17845
|
}
|
|
16393
|
-
case "
|
|
16394
|
-
|
|
17846
|
+
case "permissions": {
|
|
17847
|
+
const currentMode = getMode(chatId);
|
|
16395
17848
|
const currentExecMode = getExecMode(chatId);
|
|
16396
|
-
const EXEC_MODES = {
|
|
16397
|
-
approved: "\u2705 Approved \u2014 AI shows a plan before acting",
|
|
16398
|
-
yolo: "\u26A1 YOLO \u2014 AI executes immediately"
|
|
16399
|
-
};
|
|
16400
17849
|
if (typeof channel.sendKeyboard === "function") {
|
|
16401
|
-
const
|
|
16402
|
-
label: `${id ===
|
|
16403
|
-
data: `
|
|
16404
|
-
...id ===
|
|
17850
|
+
const permButtons = Object.entries(PERM_MODES).map(([id, label2]) => [{
|
|
17851
|
+
label: `${id === currentMode ? "\u2713 " : ""}${label2}`,
|
|
17852
|
+
data: `perms:${id}`,
|
|
17853
|
+
...id === currentMode ? { style: "primary" } : {}
|
|
17854
|
+
}]);
|
|
17855
|
+
const approvalOn = currentExecMode === "approved";
|
|
17856
|
+
permButtons.push([{
|
|
17857
|
+
label: `${approvalOn ? "\u2713 " : ""}\u{1F512} Approve Before Execute: ${approvalOn ? "ON" : "OFF"}`,
|
|
17858
|
+
data: `execmode:${approvalOn ? "yolo" : "approved"}`,
|
|
17859
|
+
...approvalOn ? { style: "primary" } : {}
|
|
16405
17860
|
}]);
|
|
16406
|
-
await channel.sendKeyboard(chatId,
|
|
17861
|
+
await channel.sendKeyboard(chatId, "Permission & Execution Settings:", permButtons);
|
|
16407
17862
|
} else {
|
|
16408
|
-
const lines = ["
|
|
16409
|
-
for (const [id, label2] of Object.entries(
|
|
16410
|
-
lines.push(`${id ===
|
|
17863
|
+
const lines = ["Permission modes:", ""];
|
|
17864
|
+
for (const [id, label2] of Object.entries(PERM_MODES)) {
|
|
17865
|
+
lines.push(`${id === currentMode ? "\u2713 " : " "}/permissions ${id} \u2014 ${label2}`);
|
|
16411
17866
|
}
|
|
17867
|
+
lines.push("");
|
|
17868
|
+
lines.push(`Approve Before Execute: ${currentExecMode === "approved" ? "ON" : "OFF"}`);
|
|
16412
17869
|
await channel.sendText(chatId, lines.join("\n"), { parseMode: "plain" });
|
|
16413
17870
|
}
|
|
16414
17871
|
break;
|
|
@@ -16971,8 +18428,8 @@ ${lines.join("\n")}`, { parseMode: "plain" });
|
|
|
16971
18428
|
if (arg.startsWith("/") || arg.startsWith("~")) {
|
|
16972
18429
|
const resolvedPath = arg.startsWith("~") ? arg.replace("~", process.env.HOME ?? "") : arg;
|
|
16973
18430
|
setCwd(chatId, resolvedPath);
|
|
16974
|
-
const
|
|
16975
|
-
if (
|
|
18431
|
+
const basename4 = resolvedPath.split("/").filter(Boolean).pop();
|
|
18432
|
+
if (basename4) upsertBookmark(chatId, basename4, resolvedPath, false);
|
|
16976
18433
|
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Working directory set to ${resolvedPath}`, detail: { field: "cwd", value: resolvedPath } });
|
|
16977
18434
|
await sendCwdSessionChoice(chatId, resolvedPath, channel);
|
|
16978
18435
|
return;
|
|
@@ -17133,24 +18590,66 @@ Use /model to pick a model with \u26A1 thinking support.`, { parseMode: "plain"
|
|
|
17133
18590
|
break;
|
|
17134
18591
|
}
|
|
17135
18592
|
if (typeof channel.sendKeyboard === "function") {
|
|
18593
|
+
const showThinkingUi = getShowThinkingUi(chatId);
|
|
17136
18594
|
const buttons = modelInfo.thinkingLevels.map((level) => [{
|
|
17137
18595
|
label: `${level === currentLevel ? "\u2713 " : ""}${level === "auto" ? "Auto" : capitalize(level)}`,
|
|
17138
18596
|
data: `thinking:${level}`,
|
|
17139
18597
|
...level === currentLevel ? { style: "primary" } : {}
|
|
17140
18598
|
}]);
|
|
18599
|
+
buttons.push([{
|
|
18600
|
+
label: `${showThinkingUi ? "\u2713 " : ""}\u{1F4AD} Show Thinking`,
|
|
18601
|
+
data: "thinking_show_ui:toggle",
|
|
18602
|
+
...showThinkingUi ? { style: "primary" } : {}
|
|
18603
|
+
}]);
|
|
17141
18604
|
await channel.sendKeyboard(
|
|
17142
18605
|
chatId,
|
|
17143
18606
|
`\u{1F4AD} Thinking Level \u2014 ${shortModelName(currentModel)}
|
|
17144
|
-
Current: ${capitalize(currentLevel)}
|
|
18607
|
+
Current: ${capitalize(currentLevel)}
|
|
18608
|
+
Show thinking tokens: ${showThinkingUi ? "On" : "Off"}${adapter.id !== "claude" ? `
|
|
18609
|
+
|
|
18610
|
+
\u26A0\uFE0F ${adapter.displayName} CLI doesn't stream thinking tokens` : ""}`,
|
|
17145
18611
|
buttons
|
|
17146
18612
|
);
|
|
17147
18613
|
} else {
|
|
18614
|
+
const showThinkingUi = getShowThinkingUi(chatId);
|
|
17148
18615
|
await channel.sendText(chatId, `Thinking: ${capitalize(currentLevel)}
|
|
17149
18616
|
Levels: ${modelInfo.thinkingLevels.join(", ")}
|
|
18617
|
+
Show thinking tokens: ${showThinkingUi ? "On" : "Off"}
|
|
17150
18618
|
Set via callback (keyboard required).`, { parseMode: "plain" });
|
|
17151
18619
|
}
|
|
17152
18620
|
break;
|
|
17153
18621
|
}
|
|
18622
|
+
case "debug": {
|
|
18623
|
+
const { getSessionLogEnabled: getSessionLogEnabled2, toggleSessionLogEnabled: toggleSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
18624
|
+
const current = getSessionLogEnabled2(chatId);
|
|
18625
|
+
if (commandArgs === "on" || commandArgs === "off") {
|
|
18626
|
+
const { setSessionLogEnabled: setSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
18627
|
+
const value = commandArgs === "on";
|
|
18628
|
+
setSessionLogEnabled2(chatId, value);
|
|
18629
|
+
await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${value ? "ON" : "OFF"}
|
|
18630
|
+
|
|
18631
|
+
${value ? "Full tool inputs/results will be saved to ~/.cc-claw/logs/sessions/\nUse 'cc-claw logs session list' or 'cc-claw logs session tail' to inspect." : "Session logs disabled."}`, { parseMode: "plain" });
|
|
18632
|
+
} else if (typeof channel.sendKeyboard === "function") {
|
|
18633
|
+
await channel.sendKeyboard(
|
|
18634
|
+
chatId,
|
|
18635
|
+
`\u{1F52C} Session Debug Logging
|
|
18636
|
+
|
|
18637
|
+
Records full, untruncated tool inputs and results to disk for debugging.
|
|
18638
|
+
Logs: ~/.cc-claw/logs/sessions/
|
|
18639
|
+
Retention: ${process.env.SESSION_LOG_RETENTION_DAYS ?? "7"} day(s)
|
|
18640
|
+
|
|
18641
|
+
Currently: ${current ? "ON" : "OFF"}`,
|
|
18642
|
+
[[
|
|
18643
|
+
{ label: current ? "\u2713 ON" : "ON", data: "debug_log:on", ...current ? { style: "primary" } : {} },
|
|
18644
|
+
{ label: !current ? "\u2713 OFF" : "OFF", data: "debug_log:off", ...!current ? { style: "primary" } : {} }
|
|
18645
|
+
]]
|
|
18646
|
+
);
|
|
18647
|
+
} else {
|
|
18648
|
+
const next = toggleSessionLogEnabled2(chatId);
|
|
18649
|
+
await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${next ? "ON" : "OFF"}`, { parseMode: "plain" });
|
|
18650
|
+
}
|
|
18651
|
+
break;
|
|
18652
|
+
}
|
|
17154
18653
|
case "imagine":
|
|
17155
18654
|
case "image": {
|
|
17156
18655
|
if (!commandArgs) {
|
|
@@ -17744,8 +19243,8 @@ ${agentLines.join("\n")}`, buttons);
|
|
|
17744
19243
|
lines.push(` \u2705 <b>cc-claw</b> <i>Agent orchestrator (spawn, tasks, inbox)</i>`);
|
|
17745
19244
|
}
|
|
17746
19245
|
const { execFile: execFile5 } = await import("child_process");
|
|
17747
|
-
const { homedir:
|
|
17748
|
-
const discoveryCwd =
|
|
19246
|
+
const { homedir: homedir12 } = await import("os");
|
|
19247
|
+
const discoveryCwd = homedir12();
|
|
17749
19248
|
const runnerResults = await Promise.allSettled(
|
|
17750
19249
|
getAllRunners().map((runner) => {
|
|
17751
19250
|
const listCmd = runner.getMcpListCommand();
|
|
@@ -17887,6 +19386,10 @@ Message: "${testMsg}"`, { parseMode: "plain" });
|
|
|
17887
19386
|
await handleEvolveCommand(chatId, channel);
|
|
17888
19387
|
break;
|
|
17889
19388
|
}
|
|
19389
|
+
case "optimize": {
|
|
19390
|
+
await handleOptimizeCommand(chatId, channel, commandArgs);
|
|
19391
|
+
break;
|
|
19392
|
+
}
|
|
17890
19393
|
default:
|
|
17891
19394
|
await channel.sendText(chatId, `Unknown command: /${command}. Type /help for available commands.`, { parseMode: "plain" });
|
|
17892
19395
|
}
|
|
@@ -17925,6 +19428,7 @@ var init_commands = __esm({
|
|
|
17925
19428
|
init_ui();
|
|
17926
19429
|
init_state();
|
|
17927
19430
|
init_evolve2();
|
|
19431
|
+
init_optimize();
|
|
17928
19432
|
}
|
|
17929
19433
|
});
|
|
17930
19434
|
|
|
@@ -18046,6 +19550,29 @@ Select thinking/effort level:`,
|
|
|
18046
19550
|
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Thinking level set to ${level}`, detail: { field: "thinking", value: level } });
|
|
18047
19551
|
const label2 = level === "auto" ? "Auto" : level.replace("_", " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
18048
19552
|
await channel.sendText(chatId, `Thinking level set to: ${label2}`, { parseMode: "plain" });
|
|
19553
|
+
} else if (data === "thinking_show_ui:toggle") {
|
|
19554
|
+
const newState = toggleShowThinkingUi(chatId);
|
|
19555
|
+
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Show thinking UI ${newState ? "enabled" : "disabled"}`, detail: { field: "show_thinking_ui", value: String(newState) } });
|
|
19556
|
+
let msg;
|
|
19557
|
+
if (newState) {
|
|
19558
|
+
let backendId;
|
|
19559
|
+
try {
|
|
19560
|
+
backendId = getAdapterForChat(chatId).id;
|
|
19561
|
+
} catch {
|
|
19562
|
+
}
|
|
19563
|
+
msg = backendId && backendId !== "claude" ? `\u{1F4AD} Thinking tokens enabled \u2014 but ${backendId.charAt(0).toUpperCase() + backendId.slice(1)} CLI doesn't stream them.` : "\u{1F4AD} Thinking tokens will now stream live in the status message.";
|
|
19564
|
+
} else {
|
|
19565
|
+
msg = "\u{1F4AD} Thinking tokens hidden. Toggle on again via /thinking.";
|
|
19566
|
+
}
|
|
19567
|
+
await channel.sendText(chatId, msg, { parseMode: "plain" });
|
|
19568
|
+
} else if (data.startsWith("debug_log:")) {
|
|
19569
|
+
const value = data.slice(10) === "on";
|
|
19570
|
+
const { setSessionLogEnabled: setSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
19571
|
+
setSessionLogEnabled2(chatId, value);
|
|
19572
|
+
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Session debug log ${value ? "enabled" : "disabled"}`, detail: { field: "session_log", value: String(value) } });
|
|
19573
|
+
await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${value ? "ON" : "OFF"}
|
|
19574
|
+
|
|
19575
|
+
${value ? "Full tool inputs/results will be saved to ~/.cc-claw/logs/sessions/" : "Session logs disabled."}`, { parseMode: "plain" });
|
|
18049
19576
|
} else if (data.startsWith("summarizer:")) {
|
|
18050
19577
|
const rest = data.slice(11);
|
|
18051
19578
|
if (rest === "auto") {
|
|
@@ -18185,9 +19712,8 @@ ${plan.originalMessage}`;
|
|
|
18185
19712
|
const mode = data.split(":")[1];
|
|
18186
19713
|
if (mode === "approved" || mode === "yolo") {
|
|
18187
19714
|
setExecMode(chatId, mode);
|
|
18188
|
-
const
|
|
18189
|
-
await channel.sendText(chatId,
|
|
18190
|
-
${desc}`, { parseMode: "html" });
|
|
19715
|
+
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).";
|
|
19716
|
+
await channel.sendText(chatId, msg, { parseMode: "html" });
|
|
18191
19717
|
}
|
|
18192
19718
|
return;
|
|
18193
19719
|
} else if (data.startsWith("model_sig:")) {
|
|
@@ -18617,6 +20143,9 @@ ${rotationNote}`, { parseMode: "html" });
|
|
|
18617
20143
|
} else if (data.startsWith("reflect:")) {
|
|
18618
20144
|
await handleReflectCallback(chatId, data, channel);
|
|
18619
20145
|
return;
|
|
20146
|
+
} else if (data.startsWith("opt:")) {
|
|
20147
|
+
await handleOptimizeCallback(chatId, data, channel);
|
|
20148
|
+
return;
|
|
18620
20149
|
} else if (data.startsWith("summ:")) {
|
|
18621
20150
|
const action = data.slice(5);
|
|
18622
20151
|
if (action === "all") {
|
|
@@ -18897,67 +20426,465 @@ Example: /limits ${bid} daily 500000`, { parseMode: "plain" });
|
|
|
18897
20426
|
skillSource = parts[0];
|
|
18898
20427
|
skillName = parts.slice(1).join(":");
|
|
18899
20428
|
} else {
|
|
18900
|
-
skillName = parts[0];
|
|
18901
|
-
}
|
|
18902
|
-
const skills2 = await discoverAllSkills();
|
|
18903
|
-
const skill = skillSource ? skills2.find((s) => s.name === skillName && s.source === skillSource) : skills2.find((s) => s.name === skillName);
|
|
18904
|
-
if (!skill) {
|
|
18905
|
-
await channel.sendText(chatId, `Skill "${skillName}" not found.`, { parseMode: "plain" });
|
|
18906
|
-
return;
|
|
18907
|
-
}
|
|
18908
|
-
const activeBackend = getBackend(chatId) ?? "claude";
|
|
18909
|
-
if (skill.compatibleBackends && !skill.compatibleBackends.includes(activeBackend)) {
|
|
18910
|
-
await channel.sendText(
|
|
18911
|
-
chatId,
|
|
18912
|
-
`Note: "${skillName}" lists compatible backends as [${skill.compatibleBackends.join(", ")}], but active backend is ${activeBackend}. Proceeding anyway.`,
|
|
18913
|
-
{ parseMode: "plain" }
|
|
18914
|
-
);
|
|
20429
|
+
skillName = parts[0];
|
|
20430
|
+
}
|
|
20431
|
+
const skills2 = await discoverAllSkills();
|
|
20432
|
+
const skill = skillSource ? skills2.find((s) => s.name === skillName && s.source === skillSource) : skills2.find((s) => s.name === skillName);
|
|
20433
|
+
if (!skill) {
|
|
20434
|
+
await channel.sendText(chatId, `Skill "${skillName}" not found.`, { parseMode: "plain" });
|
|
20435
|
+
return;
|
|
20436
|
+
}
|
|
20437
|
+
const activeBackend = getBackend(chatId) ?? "claude";
|
|
20438
|
+
if (skill.compatibleBackends && !skill.compatibleBackends.includes(activeBackend)) {
|
|
20439
|
+
await channel.sendText(
|
|
20440
|
+
chatId,
|
|
20441
|
+
`Note: "${skillName}" lists compatible backends as [${skill.compatibleBackends.join(", ")}], but active backend is ${activeBackend}. Proceeding anyway.`,
|
|
20442
|
+
{ parseMode: "plain" }
|
|
20443
|
+
);
|
|
20444
|
+
}
|
|
20445
|
+
const raw = await readFile7(skill.filePath, "utf-8");
|
|
20446
|
+
const skillContent = stripFrontmatter2(raw);
|
|
20447
|
+
const tags = skill.sources.join(", ");
|
|
20448
|
+
await channel.sendText(chatId, `Loading skill: ${skillName} [${tags}]...`, { parseMode: "plain" });
|
|
20449
|
+
const skillModel = resolveModel(chatId);
|
|
20450
|
+
const sMode = getMode(chatId);
|
|
20451
|
+
const sVerbose = getVerboseLevel(chatId);
|
|
20452
|
+
const sToolCb = sVerbose !== "off" ? makeToolActionCallback(chatId, channel, sVerbose) : void 0;
|
|
20453
|
+
const response = await askAgent(chatId, skillContent, { cwd: getCwd(chatId), model: skillModel, permMode: sMode, onToolAction: sToolCb });
|
|
20454
|
+
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, skillModel, void 0, response.usage.contextSize);
|
|
20455
|
+
await sendResponse(chatId, channel, response.text);
|
|
20456
|
+
}
|
|
20457
|
+
}
|
|
20458
|
+
var init_callbacks = __esm({
|
|
20459
|
+
"src/router/callbacks.ts"() {
|
|
20460
|
+
"use strict";
|
|
20461
|
+
init_format();
|
|
20462
|
+
init_log();
|
|
20463
|
+
init_agent();
|
|
20464
|
+
init_discover();
|
|
20465
|
+
init_profile();
|
|
20466
|
+
init_profile();
|
|
20467
|
+
init_heartbeat2();
|
|
20468
|
+
init_store5();
|
|
20469
|
+
init_summarize();
|
|
20470
|
+
init_inject();
|
|
20471
|
+
init_session_log();
|
|
20472
|
+
init_backends();
|
|
20473
|
+
init_cron();
|
|
20474
|
+
init_wizard();
|
|
20475
|
+
init_store();
|
|
20476
|
+
init_orchestrator();
|
|
20477
|
+
init_store3();
|
|
20478
|
+
init_guard();
|
|
20479
|
+
init_pagination();
|
|
20480
|
+
init_stt();
|
|
20481
|
+
init_gate();
|
|
20482
|
+
init_helpers();
|
|
20483
|
+
init_response();
|
|
20484
|
+
init_shell();
|
|
20485
|
+
init_ui();
|
|
20486
|
+
init_state();
|
|
20487
|
+
init_sidequest();
|
|
20488
|
+
init_evolve2();
|
|
20489
|
+
init_optimize();
|
|
20490
|
+
init_commands();
|
|
20491
|
+
}
|
|
20492
|
+
});
|
|
20493
|
+
|
|
20494
|
+
// src/router/session-log.ts
|
|
20495
|
+
var session_log_exports2 = {};
|
|
20496
|
+
__export(session_log_exports2, {
|
|
20497
|
+
SessionLogFile: () => SessionLogFile,
|
|
20498
|
+
cleanupSessionLogs: () => cleanupSessionLogs,
|
|
20499
|
+
getRetentionDays: () => getRetentionDays,
|
|
20500
|
+
listSessionLogs: () => listSessionLogs,
|
|
20501
|
+
startSessionLogCleanupTimer: () => startSessionLogCleanupTimer,
|
|
20502
|
+
tailSessionLog: () => tailSessionLog
|
|
20503
|
+
});
|
|
20504
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync9, appendFileSync, readdirSync as readdirSync12, unlinkSync as unlinkSync6, statSync as statSync7, createReadStream } from "fs";
|
|
20505
|
+
import { join as join24, basename as basename3 } from "path";
|
|
20506
|
+
import { createInterface as createInterface6 } from "readline";
|
|
20507
|
+
function getRetentionDays() {
|
|
20508
|
+
const env = process.env.SESSION_LOG_RETENTION_DAYS;
|
|
20509
|
+
if (env) {
|
|
20510
|
+
const n = parseInt(env, 10);
|
|
20511
|
+
if (!isNaN(n) && n > 0) return n;
|
|
20512
|
+
}
|
|
20513
|
+
return DEFAULT_RETENTION_DAYS;
|
|
20514
|
+
}
|
|
20515
|
+
function cleanupSessionLogs(retentionDays) {
|
|
20516
|
+
const days = retentionDays ?? getRetentionDays();
|
|
20517
|
+
if (!existsSync23(SESSION_LOGS_PATH)) return 0;
|
|
20518
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
20519
|
+
let cleaned = 0;
|
|
20520
|
+
try {
|
|
20521
|
+
for (const file of readdirSync12(SESSION_LOGS_PATH)) {
|
|
20522
|
+
if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
|
|
20523
|
+
const filePath = join24(SESSION_LOGS_PATH, file);
|
|
20524
|
+
try {
|
|
20525
|
+
const { mtimeMs } = statSync7(filePath);
|
|
20526
|
+
if (mtimeMs < cutoff) {
|
|
20527
|
+
unlinkSync6(filePath);
|
|
20528
|
+
cleaned++;
|
|
20529
|
+
}
|
|
20530
|
+
} catch {
|
|
20531
|
+
}
|
|
20532
|
+
}
|
|
20533
|
+
} catch (err) {
|
|
20534
|
+
log(`[session-log] Cleanup failed: ${err}`);
|
|
20535
|
+
}
|
|
20536
|
+
if (cleaned > 0) {
|
|
20537
|
+
log(`[session-log] Cleaned ${cleaned} session log(s) older than ${days} day(s)`);
|
|
20538
|
+
}
|
|
20539
|
+
return cleaned;
|
|
20540
|
+
}
|
|
20541
|
+
function startSessionLogCleanupTimer() {
|
|
20542
|
+
const timer = setInterval(() => {
|
|
20543
|
+
cleanupSessionLogs();
|
|
20544
|
+
}, 24 * 60 * 60 * 1e3);
|
|
20545
|
+
timer.unref();
|
|
20546
|
+
return timer;
|
|
20547
|
+
}
|
|
20548
|
+
function listSessionLogs() {
|
|
20549
|
+
if (!existsSync23(SESSION_LOGS_PATH)) return [];
|
|
20550
|
+
const logs = [];
|
|
20551
|
+
for (const file of readdirSync12(SESSION_LOGS_PATH)) {
|
|
20552
|
+
if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
|
|
20553
|
+
const filePath = join24(SESSION_LOGS_PATH, file);
|
|
20554
|
+
try {
|
|
20555
|
+
const stat4 = statSync7(filePath);
|
|
20556
|
+
const match = file.match(/^session-(.+?)-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})\.log$/);
|
|
20557
|
+
logs.push({
|
|
20558
|
+
filename: file,
|
|
20559
|
+
filePath,
|
|
20560
|
+
chatId: match?.[1] ?? "unknown",
|
|
20561
|
+
timestamp: match?.[2]?.replace(/-/g, (m, i) => i > 9 ? ":" : m) ?? "unknown",
|
|
20562
|
+
sizeBytes: stat4.size,
|
|
20563
|
+
modifiedAt: stat4.mtime
|
|
20564
|
+
});
|
|
20565
|
+
} catch {
|
|
20566
|
+
}
|
|
20567
|
+
}
|
|
20568
|
+
logs.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
|
|
20569
|
+
return logs;
|
|
20570
|
+
}
|
|
20571
|
+
async function* tailSessionLog(filePath, lines = 50) {
|
|
20572
|
+
if (!existsSync23(filePath)) {
|
|
20573
|
+
yield `File not found: ${filePath}`;
|
|
20574
|
+
return;
|
|
20575
|
+
}
|
|
20576
|
+
const allLines = [];
|
|
20577
|
+
const rl2 = createInterface6({
|
|
20578
|
+
input: createReadStream(filePath, { encoding: "utf-8" }),
|
|
20579
|
+
crlfDelay: Infinity
|
|
20580
|
+
});
|
|
20581
|
+
for await (const line of rl2) {
|
|
20582
|
+
allLines.push(line);
|
|
20583
|
+
}
|
|
20584
|
+
const start = Math.max(0, allLines.length - lines);
|
|
20585
|
+
for (let i = start; i < allLines.length; i++) {
|
|
20586
|
+
yield allLines[i];
|
|
20587
|
+
}
|
|
20588
|
+
}
|
|
20589
|
+
var DEFAULT_RETENTION_DAYS, SessionLogFile;
|
|
20590
|
+
var init_session_log2 = __esm({
|
|
20591
|
+
"src/router/session-log.ts"() {
|
|
20592
|
+
"use strict";
|
|
20593
|
+
init_paths();
|
|
20594
|
+
init_log();
|
|
20595
|
+
DEFAULT_RETENTION_DAYS = 7;
|
|
20596
|
+
SessionLogFile = class {
|
|
20597
|
+
constructor(chatId, backend2, model2) {
|
|
20598
|
+
this.backend = backend2;
|
|
20599
|
+
this.model = model2;
|
|
20600
|
+
if (!existsSync23(SESSION_LOGS_PATH)) {
|
|
20601
|
+
mkdirSync9(SESSION_LOGS_PATH, { recursive: true });
|
|
20602
|
+
}
|
|
20603
|
+
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
20604
|
+
const sanitizedChatId = chatId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
20605
|
+
this.filePath = join24(SESSION_LOGS_PATH, `session-${sanitizedChatId}-${ts2}.log`);
|
|
20606
|
+
const header2 = [
|
|
20607
|
+
"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
|
|
20608
|
+
`CC-Claw Agent Session \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
20609
|
+
`Chat: ${chatId} | Backend: ${backend2} | Model: ${model2}`,
|
|
20610
|
+
"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
|
|
20611
|
+
""
|
|
20612
|
+
].join("\n");
|
|
20613
|
+
appendFileSync(this.filePath, header2 + "\n", "utf-8");
|
|
20614
|
+
}
|
|
20615
|
+
filePath;
|
|
20616
|
+
startTime = Date.now();
|
|
20617
|
+
closed = false;
|
|
20618
|
+
/** Log a tool start with full, untruncated input. */
|
|
20619
|
+
logToolStart(toolName, input) {
|
|
20620
|
+
if (this.closed) return;
|
|
20621
|
+
const ts2 = this.timestamp();
|
|
20622
|
+
const inputStr = JSON.stringify(input, null, 2);
|
|
20623
|
+
const entry = `[${ts2}] TOOL_START ${toolName}
|
|
20624
|
+
${inputStr}
|
|
20625
|
+
|
|
20626
|
+
`;
|
|
20627
|
+
this.append(entry);
|
|
20628
|
+
}
|
|
20629
|
+
/** Log a tool end with full, untruncated result. */
|
|
20630
|
+
logToolEnd(toolName, result) {
|
|
20631
|
+
if (this.closed) return;
|
|
20632
|
+
const ts2 = this.timestamp();
|
|
20633
|
+
const preview = result.length > 5e3 ? `(${result.length} chars)
|
|
20634
|
+
${result.slice(0, 5e3)}\u2026[truncated]` : result;
|
|
20635
|
+
const entry = `[${ts2}] TOOL_END ${toolName}
|
|
20636
|
+
${preview}
|
|
20637
|
+
|
|
20638
|
+
`;
|
|
20639
|
+
this.append(entry);
|
|
20640
|
+
}
|
|
20641
|
+
/** Log thinking tokens with full text. */
|
|
20642
|
+
logThinking(text) {
|
|
20643
|
+
if (this.closed) return;
|
|
20644
|
+
const ts2 = this.timestamp();
|
|
20645
|
+
const entry = `[${ts2}] THINKING
|
|
20646
|
+
${text}
|
|
20647
|
+
|
|
20648
|
+
`;
|
|
20649
|
+
this.append(entry);
|
|
20650
|
+
}
|
|
20651
|
+
/** Log informational entry. */
|
|
20652
|
+
logInfo(text) {
|
|
20653
|
+
if (this.closed) return;
|
|
20654
|
+
const ts2 = this.timestamp();
|
|
20655
|
+
const entry = `[${ts2}] INFO ${text}
|
|
20656
|
+
|
|
20657
|
+
`;
|
|
20658
|
+
this.append(entry);
|
|
20659
|
+
}
|
|
20660
|
+
/** Finalize the session log with elapsed time and token counts. */
|
|
20661
|
+
finalize(elapsedMs, usage2) {
|
|
20662
|
+
if (this.closed) return;
|
|
20663
|
+
this.closed = true;
|
|
20664
|
+
const ts2 = this.timestamp();
|
|
20665
|
+
const elapsed = (elapsedMs / 1e3).toFixed(1);
|
|
20666
|
+
const usageStr = usage2 ? ` | input=${usage2.input} output=${usage2.output}${usage2.cacheRead ? ` cacheRead=${usage2.cacheRead}` : ""}` : "";
|
|
20667
|
+
const entry = `[${ts2}] FINALIZED \u2014 ${elapsed}s elapsed${usageStr}
|
|
20668
|
+
`;
|
|
20669
|
+
this.append(entry);
|
|
20670
|
+
}
|
|
20671
|
+
/** Get the file path for display/reference. */
|
|
20672
|
+
getFilePath() {
|
|
20673
|
+
return this.filePath;
|
|
20674
|
+
}
|
|
20675
|
+
/** Get just the filename (for compact display). */
|
|
20676
|
+
getFilename() {
|
|
20677
|
+
return basename3(this.filePath);
|
|
20678
|
+
}
|
|
20679
|
+
// ── Internal ──────────────────────────────────────────────────────
|
|
20680
|
+
timestamp() {
|
|
20681
|
+
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
|
|
20682
|
+
}
|
|
20683
|
+
append(text) {
|
|
20684
|
+
try {
|
|
20685
|
+
appendFileSync(this.filePath, text, "utf-8");
|
|
20686
|
+
} catch (err) {
|
|
20687
|
+
log(`[session-log] Write failed: ${err}`);
|
|
20688
|
+
}
|
|
20689
|
+
}
|
|
20690
|
+
};
|
|
20691
|
+
}
|
|
20692
|
+
});
|
|
20693
|
+
|
|
20694
|
+
// src/router/live-status.ts
|
|
20695
|
+
var live_status_exports = {};
|
|
20696
|
+
__export(live_status_exports, {
|
|
20697
|
+
LiveStatusMessage: () => LiveStatusMessage,
|
|
20698
|
+
makeLiveStatus: () => makeLiveStatus
|
|
20699
|
+
});
|
|
20700
|
+
function dedupThinking(entries) {
|
|
20701
|
+
const out = [];
|
|
20702
|
+
for (const e of entries) {
|
|
20703
|
+
const last = out[out.length - 1];
|
|
20704
|
+
if (e.kind === "thinking" && last?.kind === "thinking" && last.text === e.text) continue;
|
|
20705
|
+
out.push(e);
|
|
20706
|
+
}
|
|
20707
|
+
return out;
|
|
20708
|
+
}
|
|
20709
|
+
function renderEntry(e) {
|
|
20710
|
+
if (e.kind === "thinking") {
|
|
20711
|
+
const truncated = e.text.length > MAX_THINKING_CHARS ? e.text.slice(0, MAX_THINKING_CHARS) + "\u2026" : e.text;
|
|
20712
|
+
return `\u{1F4AD} ${truncated}`;
|
|
20713
|
+
}
|
|
20714
|
+
return e.text;
|
|
20715
|
+
}
|
|
20716
|
+
function renderEntries(entries, modelLabel, elapsedMs, trimmed) {
|
|
20717
|
+
const elapsedSec = (elapsedMs / 1e3).toFixed(1);
|
|
20718
|
+
const lines = [`\u23F3 ${modelLabel} \xB7 ${elapsedSec}s`];
|
|
20719
|
+
if (trimmed) lines[0] += " (\u2026)";
|
|
20720
|
+
lines.push("");
|
|
20721
|
+
for (const e of entries) lines.push(renderEntry(e));
|
|
20722
|
+
return lines.join("\n");
|
|
20723
|
+
}
|
|
20724
|
+
function renderFinal(entries, modelLabel, elapsedSec, trimmed) {
|
|
20725
|
+
const lines = [`\u2705 ${modelLabel} \xB7 ${elapsedSec}s`];
|
|
20726
|
+
if (trimmed) lines[0] += " (\u2026)";
|
|
20727
|
+
if (entries.length === 0) return lines[0];
|
|
20728
|
+
lines.push("");
|
|
20729
|
+
for (const e of entries) lines.push(renderEntry(e));
|
|
20730
|
+
return lines.join("\n");
|
|
20731
|
+
}
|
|
20732
|
+
function makeLiveStatus(chatId, channel, modelLabel, verboseLevel, showThinking) {
|
|
20733
|
+
const liveStatus = new LiveStatusMessage(chatId, channel, modelLabel, verboseLevel, showThinking);
|
|
20734
|
+
const toolCb = async (toolName, input, result) => {
|
|
20735
|
+
if (result === void 0) {
|
|
20736
|
+
liveStatus.addToolStart(toolName, input);
|
|
20737
|
+
} else {
|
|
20738
|
+
liveStatus.addToolEnd(toolName, result);
|
|
18915
20739
|
}
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
const tags = skill.sources.join(", ");
|
|
18919
|
-
await channel.sendText(chatId, `Loading skill: ${skillName} [${tags}]...`, { parseMode: "plain" });
|
|
18920
|
-
const skillModel = resolveModel(chatId);
|
|
18921
|
-
const sMode = getMode(chatId);
|
|
18922
|
-
const sVerbose = getVerboseLevel(chatId);
|
|
18923
|
-
const sToolCb = sVerbose !== "off" ? makeToolActionCallback(chatId, channel, sVerbose) : void 0;
|
|
18924
|
-
const response = await askAgent(chatId, skillContent, { cwd: getCwd(chatId), model: skillModel, permMode: sMode, onToolAction: sToolCb });
|
|
18925
|
-
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, skillModel, void 0, response.usage.contextSize);
|
|
18926
|
-
await sendResponse(chatId, channel, response.text);
|
|
18927
|
-
}
|
|
20740
|
+
};
|
|
20741
|
+
return { liveStatus, toolCb };
|
|
18928
20742
|
}
|
|
18929
|
-
var
|
|
18930
|
-
|
|
20743
|
+
var FLUSH_INTERVAL_MS, MAX_THINKING_CHARS, TRIM_THRESHOLD, MAX_ENTRIES, LiveStatusMessage;
|
|
20744
|
+
var init_live_status = __esm({
|
|
20745
|
+
"src/router/live-status.ts"() {
|
|
18931
20746
|
"use strict";
|
|
18932
|
-
init_format();
|
|
18933
20747
|
init_log();
|
|
18934
|
-
init_agent();
|
|
18935
|
-
init_discover();
|
|
18936
|
-
init_profile();
|
|
18937
|
-
init_profile();
|
|
18938
|
-
init_heartbeat2();
|
|
18939
|
-
init_store5();
|
|
18940
|
-
init_summarize();
|
|
18941
|
-
init_inject();
|
|
18942
|
-
init_session_log();
|
|
18943
|
-
init_backends();
|
|
18944
|
-
init_cron();
|
|
18945
|
-
init_wizard();
|
|
18946
|
-
init_store();
|
|
18947
|
-
init_orchestrator();
|
|
18948
|
-
init_store3();
|
|
18949
|
-
init_guard();
|
|
18950
|
-
init_pagination();
|
|
18951
|
-
init_stt();
|
|
18952
|
-
init_gate();
|
|
18953
20748
|
init_helpers();
|
|
18954
|
-
|
|
18955
|
-
|
|
18956
|
-
|
|
18957
|
-
|
|
18958
|
-
|
|
18959
|
-
|
|
18960
|
-
|
|
20749
|
+
FLUSH_INTERVAL_MS = 1e3;
|
|
20750
|
+
MAX_THINKING_CHARS = 800;
|
|
20751
|
+
TRIM_THRESHOLD = 3500;
|
|
20752
|
+
MAX_ENTRIES = 200;
|
|
20753
|
+
LiveStatusMessage = class {
|
|
20754
|
+
constructor(chatId, channel, modelLabel, verboseLevel, showThinking = false) {
|
|
20755
|
+
this.chatId = chatId;
|
|
20756
|
+
this.channel = channel;
|
|
20757
|
+
this.modelLabel = modelLabel;
|
|
20758
|
+
this.verboseLevel = verboseLevel;
|
|
20759
|
+
this.showThinking = showThinking;
|
|
20760
|
+
}
|
|
20761
|
+
messageId = null;
|
|
20762
|
+
entries = [];
|
|
20763
|
+
startTime = Date.now();
|
|
20764
|
+
flushTimer = null;
|
|
20765
|
+
lastRendered = "";
|
|
20766
|
+
finalized = false;
|
|
20767
|
+
/** Earliest time the next flush is allowed (set after 429 backoff) */
|
|
20768
|
+
nextFlushAllowedAt = 0;
|
|
20769
|
+
/** Tracks whether entries have been trimmed at least once (for display hint). */
|
|
20770
|
+
hasTrimmed = false;
|
|
20771
|
+
/** Send the initial status message. Must be called before adding entries. */
|
|
20772
|
+
async init() {
|
|
20773
|
+
if (!this.channel.sendTextReturningId) return;
|
|
20774
|
+
try {
|
|
20775
|
+
const initial = `\u23F3 ${this.modelLabel} \xB7 Processing\u2026`;
|
|
20776
|
+
this.messageId = await this.channel.sendTextReturningId(this.chatId, initial, "plain") ?? null;
|
|
20777
|
+
if (this.messageId) {
|
|
20778
|
+
this.flushTimer = setInterval(() => this.flush().catch(() => {
|
|
20779
|
+
}), FLUSH_INTERVAL_MS);
|
|
20780
|
+
}
|
|
20781
|
+
} catch (err) {
|
|
20782
|
+
log(`[live-status] init failed: ${err}`);
|
|
20783
|
+
}
|
|
20784
|
+
}
|
|
20785
|
+
/** Add a thinking token preview (from NdjsonEvent type "thinking"). */
|
|
20786
|
+
addThinking(text) {
|
|
20787
|
+
if (!this.showThinking) return;
|
|
20788
|
+
if (!this.messageId || this.finalized) return;
|
|
20789
|
+
const trimmed = text.trim();
|
|
20790
|
+
if (!trimmed) return;
|
|
20791
|
+
this.entries.push({ kind: "thinking", text: trimmed, ts: Date.now() });
|
|
20792
|
+
this.trimEntries();
|
|
20793
|
+
}
|
|
20794
|
+
/** Add a tool start event. */
|
|
20795
|
+
addToolStart(toolName, input, toolId) {
|
|
20796
|
+
if (!this.messageId || this.finalized) return;
|
|
20797
|
+
const formatted = formatToolStart(toolName, input, this.verboseLevel);
|
|
20798
|
+
this.entries.push({ kind: "tool_start", text: formatted, toolId, ts: Date.now() });
|
|
20799
|
+
this.trimEntries();
|
|
20800
|
+
}
|
|
20801
|
+
/** Add a tool result event. */
|
|
20802
|
+
addToolEnd(toolName, result, toolId) {
|
|
20803
|
+
if (!this.messageId || this.finalized) return;
|
|
20804
|
+
if (this.verboseLevel !== "verbose") return;
|
|
20805
|
+
const formatted = formatToolResult(toolName, result ?? "");
|
|
20806
|
+
if (formatted) {
|
|
20807
|
+
this.entries.push({ kind: "tool_end", text: formatted, toolId, ts: Date.now() });
|
|
20808
|
+
this.trimEntries();
|
|
20809
|
+
}
|
|
20810
|
+
}
|
|
20811
|
+
/** Add an informational entry (e.g. backend capability notes). */
|
|
20812
|
+
addInfo(text) {
|
|
20813
|
+
if (!this.messageId || this.finalized) return;
|
|
20814
|
+
this.entries.push({ kind: "info", text, ts: Date.now() });
|
|
20815
|
+
this.trimEntries();
|
|
20816
|
+
}
|
|
20817
|
+
/**
|
|
20818
|
+
* Finalize the status message: replace the spinner with ✅ and elapsed time.
|
|
20819
|
+
* Stops the flush loop. No-op if no message was created (channel doesn't support editing).
|
|
20820
|
+
*/
|
|
20821
|
+
async finalize(elapsedMs) {
|
|
20822
|
+
this.finalized = true;
|
|
20823
|
+
if (this.flushTimer) {
|
|
20824
|
+
clearInterval(this.flushTimer);
|
|
20825
|
+
this.flushTimer = null;
|
|
20826
|
+
}
|
|
20827
|
+
if (!this.messageId || !this.channel.editText) return;
|
|
20828
|
+
const elapsedSec = (elapsedMs / 1e3).toFixed(1);
|
|
20829
|
+
const deduped = dedupThinking(this.entries);
|
|
20830
|
+
const body = renderFinal(deduped, this.modelLabel, elapsedSec, this.hasTrimmed);
|
|
20831
|
+
try {
|
|
20832
|
+
await this.channel.editText(this.chatId, this.messageId, body, "plain");
|
|
20833
|
+
} catch (err) {
|
|
20834
|
+
log(`[live-status] finalize edit failed: ${err}`);
|
|
20835
|
+
}
|
|
20836
|
+
}
|
|
20837
|
+
/** Returns the messageId of the status message (if created). */
|
|
20838
|
+
getMessageId() {
|
|
20839
|
+
return this.messageId;
|
|
20840
|
+
}
|
|
20841
|
+
// ── Internal ──────────────────────────────────────────────────────────
|
|
20842
|
+
async flush() {
|
|
20843
|
+
if (this.finalized || !this.messageId || !this.channel.editText) return;
|
|
20844
|
+
if (Date.now() < this.nextFlushAllowedAt) return;
|
|
20845
|
+
const deduped = dedupThinking(this.entries);
|
|
20846
|
+
const body = renderEntries(deduped, this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
|
|
20847
|
+
if (body === this.lastRendered) return;
|
|
20848
|
+
this.lastRendered = body;
|
|
20849
|
+
try {
|
|
20850
|
+
await this.channel.editText(this.chatId, this.messageId, body, "plain");
|
|
20851
|
+
} catch (err) {
|
|
20852
|
+
this.handleRateLimit(err);
|
|
20853
|
+
}
|
|
20854
|
+
}
|
|
20855
|
+
/**
|
|
20856
|
+
* Trim entries from the BEGINNING when the rendered body exceeds the threshold.
|
|
20857
|
+
* This is the core of the single-message pattern: always show the most recent
|
|
20858
|
+
* activity, drop the oldest entries that scroll past the limit.
|
|
20859
|
+
*/
|
|
20860
|
+
trimEntries() {
|
|
20861
|
+
if (this.entries.length > MAX_ENTRIES) {
|
|
20862
|
+
this.entries = this.entries.slice(this.entries.length - MAX_ENTRIES);
|
|
20863
|
+
this.hasTrimmed = true;
|
|
20864
|
+
}
|
|
20865
|
+
let rendered = renderEntries(dedupThinking(this.entries), this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
|
|
20866
|
+
while (rendered.length > TRIM_THRESHOLD && this.entries.length > 3) {
|
|
20867
|
+
this.entries.shift();
|
|
20868
|
+
this.hasTrimmed = true;
|
|
20869
|
+
rendered = renderEntries(dedupThinking(this.entries), this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
|
|
20870
|
+
}
|
|
20871
|
+
}
|
|
20872
|
+
/**
|
|
20873
|
+
* Handle Telegram 429 rate-limit errors by backing off.
|
|
20874
|
+
* Parses the "retry after N" hint and sets a cooldown.
|
|
20875
|
+
*/
|
|
20876
|
+
handleRateLimit(err) {
|
|
20877
|
+
const msg = String(err);
|
|
20878
|
+
const match = msg.match(/retry after (\d+)/i);
|
|
20879
|
+
if (match) {
|
|
20880
|
+
const retrySec = parseInt(match[1], 10) || 3;
|
|
20881
|
+
this.nextFlushAllowedAt = Date.now() + retrySec * 1e3;
|
|
20882
|
+
log(`[live-status] 429 rate-limited, backing off ${retrySec}s`);
|
|
20883
|
+
} else {
|
|
20884
|
+
log(`[live-status] edit failed: ${msg}`);
|
|
20885
|
+
}
|
|
20886
|
+
}
|
|
20887
|
+
};
|
|
18961
20888
|
}
|
|
18962
20889
|
});
|
|
18963
20890
|
|
|
@@ -19078,7 +21005,7 @@ async function handleText(msg, channel) {
|
|
|
19078
21005
|
let intent = classifyIntent(text, chatId);
|
|
19079
21006
|
const cleanText = text.startsWith(">>") ? text.slice(2).trim() : text;
|
|
19080
21007
|
let bootstrapTier = intent === "chat" ? "chat" : void 0;
|
|
19081
|
-
let maxTurns =
|
|
21008
|
+
let maxTurns = void 0;
|
|
19082
21009
|
let effectiveAgentMode = msg.agentMode ?? getAgentMode(chatId);
|
|
19083
21010
|
const observedSubagents = /* @__PURE__ */ new Set();
|
|
19084
21011
|
if (effectiveAgentMode === "auto" && !text.startsWith(">>")) {
|
|
@@ -19245,6 +21172,10 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19245
21172
|
typingActive2 = false;
|
|
19246
21173
|
if (planResponse.text) {
|
|
19247
21174
|
let planText = planResponse.text.replace(/\[REACT:.+?\]/g, "").replace(/\[SEND_FILE:.+?\]/g, "").replace(/\[GENERATE_IMAGE:.+?\]/g, "").replace(/\[HISTORY_SEARCH:[^\]]+\]/g, "").trim();
|
|
21175
|
+
const PLAN_DISPLAY_LIMIT = 3500;
|
|
21176
|
+
if (planText.length > PLAN_DISPLAY_LIMIT) {
|
|
21177
|
+
planText = planText.slice(0, PLAN_DISPLAY_LIMIT) + "\n\u2026(truncated \u2014 tap Approve to proceed)";
|
|
21178
|
+
}
|
|
19248
21179
|
storePendingPlan(chatId, planText, cleanText || text);
|
|
19249
21180
|
if (typeof channel.sendKeyboard === "function") {
|
|
19250
21181
|
await channel.sendKeyboard(chatId, `\u{1F50D} ${planText}`, [
|
|
@@ -19253,7 +21184,7 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19253
21184
|
{ label: "\u274C Reject", data: "exec:reject", style: "danger" }
|
|
19254
21185
|
],
|
|
19255
21186
|
[
|
|
19256
|
-
{ label: "\u26A1
|
|
21187
|
+
{ label: "\u26A1 Approve & Switch to YOLO", data: "exec:yolo" }
|
|
19257
21188
|
]
|
|
19258
21189
|
]);
|
|
19259
21190
|
} else {
|
|
@@ -19283,7 +21214,48 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19283
21214
|
try {
|
|
19284
21215
|
const tMode = getMode(chatId);
|
|
19285
21216
|
const tVerbose = getVerboseLevel(chatId);
|
|
19286
|
-
const
|
|
21217
|
+
const adapter = getAdapterForChat(chatId);
|
|
21218
|
+
const modelLabel = formatModelShort(model2 ?? adapter.defaultModel);
|
|
21219
|
+
const { getShowThinkingUi: getShowThinkingUi3 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
21220
|
+
const showThinkingUi = getShowThinkingUi3(chatId);
|
|
21221
|
+
const needsLiveStatus = tVerbose !== "off" || showThinkingUi;
|
|
21222
|
+
let liveStatus = null;
|
|
21223
|
+
let tToolCb;
|
|
21224
|
+
const { getSessionLogEnabled: getSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
21225
|
+
const { SessionLogFile: SessionLogFile2 } = await Promise.resolve().then(() => (init_session_log2(), session_log_exports2));
|
|
21226
|
+
let sessionLog = null;
|
|
21227
|
+
if (getSessionLogEnabled2(chatId)) {
|
|
21228
|
+
sessionLog = new SessionLogFile2(chatId, adapter.id, model2 ?? adapter.defaultModel);
|
|
21229
|
+
}
|
|
21230
|
+
if (needsLiveStatus) {
|
|
21231
|
+
const { makeLiveStatus: makeLiveStatus2 } = await Promise.resolve().then(() => (init_live_status(), live_status_exports));
|
|
21232
|
+
const effectiveVerbose = tVerbose === "off" ? "normal" : tVerbose;
|
|
21233
|
+
const ls = makeLiveStatus2(chatId, channel, modelLabel, effectiveVerbose, showThinkingUi);
|
|
21234
|
+
liveStatus = ls.liveStatus;
|
|
21235
|
+
const baseCb = tVerbose !== "off" ? ls.toolCb : void 0;
|
|
21236
|
+
tToolCb = async (toolName, input, result) => {
|
|
21237
|
+
if (baseCb) await baseCb(toolName, input, result);
|
|
21238
|
+
if (sessionLog) {
|
|
21239
|
+
if (result === void 0) {
|
|
21240
|
+
sessionLog.logToolStart(toolName, input);
|
|
21241
|
+
} else {
|
|
21242
|
+
sessionLog.logToolEnd(toolName, result);
|
|
21243
|
+
}
|
|
21244
|
+
}
|
|
21245
|
+
};
|
|
21246
|
+
await liveStatus.init();
|
|
21247
|
+
if (showThinkingUi && adapter.id !== "claude") {
|
|
21248
|
+
liveStatus.addInfo(`\u{1F4AD} Thinking display not available for ${adapter.displayName}`);
|
|
21249
|
+
}
|
|
21250
|
+
} else if (sessionLog) {
|
|
21251
|
+
tToolCb = async (toolName, input, result) => {
|
|
21252
|
+
if (result === void 0) {
|
|
21253
|
+
sessionLog.logToolStart(toolName, input);
|
|
21254
|
+
} else {
|
|
21255
|
+
sessionLog.logToolEnd(toolName, result);
|
|
21256
|
+
}
|
|
21257
|
+
};
|
|
21258
|
+
}
|
|
19287
21259
|
const sigT0 = Date.now();
|
|
19288
21260
|
const response = await askAgent(chatId, cleanText || text, {
|
|
19289
21261
|
cwd: getCwd(chatId),
|
|
@@ -19293,6 +21265,10 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19293
21265
|
bootstrapTier,
|
|
19294
21266
|
maxTurns,
|
|
19295
21267
|
agentMode: effectiveAgentMode,
|
|
21268
|
+
onThinking: liveStatus || sessionLog ? (chunk) => {
|
|
21269
|
+
if (liveStatus) liveStatus.addThinking(chunk);
|
|
21270
|
+
if (sessionLog) sessionLog.logThinking(chunk);
|
|
21271
|
+
} : void 0,
|
|
19296
21272
|
onSubagentActivity: (backendId2, info) => {
|
|
19297
21273
|
observedSubagents.add(info.name);
|
|
19298
21274
|
try {
|
|
@@ -19326,26 +21302,32 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19326
21302
|
});
|
|
19327
21303
|
}
|
|
19328
21304
|
});
|
|
19329
|
-
const
|
|
21305
|
+
const elapsedMs = Date.now() - sigT0;
|
|
21306
|
+
const elapsedSec = (elapsedMs / 1e3).toFixed(1);
|
|
21307
|
+
if (liveStatus && response.thinkingText?.trim()) {
|
|
21308
|
+
liveStatus.addThinking(response.thinkingText.trim());
|
|
21309
|
+
}
|
|
21310
|
+
if (liveStatus) await liveStatus.finalize(elapsedMs);
|
|
21311
|
+
if (sessionLog) sessionLog.finalize(elapsedMs, response.usage);
|
|
19330
21312
|
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, model2, void 0, response.usage.contextSize);
|
|
19331
21313
|
let responseText = response.text;
|
|
19332
21314
|
const sigEnabled = getModelSignature(chatId);
|
|
19333
21315
|
if (sigEnabled === "on" && responseText && !responseText.startsWith("(No response")) {
|
|
19334
|
-
const
|
|
19335
|
-
const modelId = response.resolvedModel ?? model2 ??
|
|
21316
|
+
const adapter2 = getAdapterForChat(chatId);
|
|
21317
|
+
const modelId = response.resolvedModel ?? model2 ?? adapter2.defaultModel;
|
|
19336
21318
|
const thinking2 = getThinkingLevel(chatId) || "auto";
|
|
19337
21319
|
const shortModel = formatModelShort(modelId);
|
|
19338
21320
|
let slotTag = "";
|
|
19339
|
-
if (
|
|
21321
|
+
if (adapter2.id === "gemini") {
|
|
19340
21322
|
const slotId = getChatGeminiSlotId(chatId);
|
|
19341
21323
|
if (slotId) {
|
|
19342
21324
|
const slot = getGeminiSlots().find((s) => s.id === slotId);
|
|
19343
21325
|
if (slot) slotTag = ` \xB7 ${slot.label || `slot-${slot.id}`}`;
|
|
19344
21326
|
}
|
|
19345
|
-
} else if (
|
|
19346
|
-
const slotId = getChatBackendSlotId(chatId,
|
|
21327
|
+
} else if (adapter2.id === "claude" || adapter2.id === "codex") {
|
|
21328
|
+
const slotId = getChatBackendSlotId(chatId, adapter2.id);
|
|
19347
21329
|
if (slotId) {
|
|
19348
|
-
const slot = getBackendSlots(
|
|
21330
|
+
const slot = getBackendSlots(adapter2.id).find((s) => s.id === slotId);
|
|
19349
21331
|
if (slot) slotTag = ` \xB7 ${slot.label || `slot-${slot.id}`}`;
|
|
19350
21332
|
}
|
|
19351
21333
|
}
|
|
@@ -19379,10 +21361,10 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
|
|
|
19379
21361
|
await sendResponse(chatId, channel, responseText, msg.messageId);
|
|
19380
21362
|
try {
|
|
19381
21363
|
const { detectAndLogSignals: detectAndLogSignals2 } = await Promise.resolve().then(() => (init_detect(), detect_exports));
|
|
19382
|
-
const
|
|
21364
|
+
const adapter2 = getAdapterForChat(chatId);
|
|
19383
21365
|
detectAndLogSignals2(chatId, cleanText || text, responseText, {
|
|
19384
|
-
backendId:
|
|
19385
|
-
model: model2 ??
|
|
21366
|
+
backendId: adapter2.id,
|
|
21367
|
+
model: model2 ?? adapter2.defaultModel,
|
|
19386
21368
|
thinkingLevel: getThinkingLevel(chatId) || void 0
|
|
19387
21369
|
});
|
|
19388
21370
|
} catch (e) {
|
|
@@ -19835,7 +21817,7 @@ var init_cron = __esm({
|
|
|
19835
21817
|
});
|
|
19836
21818
|
|
|
19837
21819
|
// src/agents/runners/wrap-backend.ts
|
|
19838
|
-
import { join as
|
|
21820
|
+
import { join as join25 } from "path";
|
|
19839
21821
|
function buildMcpCommands(backendId) {
|
|
19840
21822
|
const exe = backendId === "cursor" ? "agent" : backendId;
|
|
19841
21823
|
return {
|
|
@@ -19929,7 +21911,7 @@ function wrapBackendAdapter(adapter) {
|
|
|
19929
21911
|
const configPath = writeMcpConfigFile(server);
|
|
19930
21912
|
return ["--mcp-config", configPath];
|
|
19931
21913
|
},
|
|
19932
|
-
getSkillPath: () =>
|
|
21914
|
+
getSkillPath: () => join25(SKILLS_PATH, `agent-${adapter.id}.md`)
|
|
19933
21915
|
};
|
|
19934
21916
|
}
|
|
19935
21917
|
var BACKEND_CAPABILITIES;
|
|
@@ -19980,18 +21962,18 @@ var init_wrap_backend = __esm({
|
|
|
19980
21962
|
});
|
|
19981
21963
|
|
|
19982
21964
|
// src/agents/runners/config-loader.ts
|
|
19983
|
-
import { readFileSync as
|
|
19984
|
-
import { join as
|
|
21965
|
+
import { readFileSync as readFileSync14, readdirSync as readdirSync13, existsSync as existsSync24, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
|
|
21966
|
+
import { join as join26 } from "path";
|
|
19985
21967
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
19986
21968
|
function resolveExecutable(config2) {
|
|
19987
|
-
if (
|
|
21969
|
+
if (existsSync24(config2.executable)) return config2.executable;
|
|
19988
21970
|
try {
|
|
19989
21971
|
return execFileSync2("which", [config2.executable], { encoding: "utf-8" }).trim();
|
|
19990
21972
|
} catch {
|
|
19991
21973
|
}
|
|
19992
21974
|
for (const fallback of config2.executableFallbacks ?? []) {
|
|
19993
21975
|
const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
|
|
19994
|
-
if (
|
|
21976
|
+
if (existsSync24(resolved)) return resolved;
|
|
19995
21977
|
}
|
|
19996
21978
|
return config2.executable;
|
|
19997
21979
|
}
|
|
@@ -20117,12 +22099,12 @@ function configToRunner(config2) {
|
|
|
20117
22099
|
prepareMcpInjection() {
|
|
20118
22100
|
return [];
|
|
20119
22101
|
},
|
|
20120
|
-
getSkillPath: () =>
|
|
22102
|
+
getSkillPath: () => join26(SKILLS_PATH, `agent-${config2.id}.md`)
|
|
20121
22103
|
};
|
|
20122
22104
|
}
|
|
20123
22105
|
function loadRunnerConfig(filePath) {
|
|
20124
22106
|
try {
|
|
20125
|
-
const content =
|
|
22107
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
20126
22108
|
return JSON.parse(content);
|
|
20127
22109
|
} catch (err) {
|
|
20128
22110
|
warn(`[runners] Failed to load config ${filePath}: ${err}`);
|
|
@@ -20130,14 +22112,14 @@ function loadRunnerConfig(filePath) {
|
|
|
20130
22112
|
}
|
|
20131
22113
|
}
|
|
20132
22114
|
function loadAllRunnerConfigs() {
|
|
20133
|
-
if (!
|
|
20134
|
-
|
|
22115
|
+
if (!existsSync24(RUNNERS_PATH)) {
|
|
22116
|
+
mkdirSync10(RUNNERS_PATH, { recursive: true });
|
|
20135
22117
|
return [];
|
|
20136
22118
|
}
|
|
20137
|
-
const files =
|
|
22119
|
+
const files = readdirSync13(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
20138
22120
|
const configs = [];
|
|
20139
22121
|
for (const file of files) {
|
|
20140
|
-
const config2 = loadRunnerConfig(
|
|
22122
|
+
const config2 = loadRunnerConfig(join26(RUNNERS_PATH, file));
|
|
20141
22123
|
if (config2) configs.push(config2);
|
|
20142
22124
|
}
|
|
20143
22125
|
return configs;
|
|
@@ -20158,16 +22140,16 @@ function registerConfigRunners() {
|
|
|
20158
22140
|
return count;
|
|
20159
22141
|
}
|
|
20160
22142
|
function watchRunnerConfigs(onChange) {
|
|
20161
|
-
if (!
|
|
22143
|
+
if (!existsSync24(RUNNERS_PATH)) return;
|
|
20162
22144
|
for (const prev of watchedFiles) {
|
|
20163
|
-
if (!
|
|
22145
|
+
if (!existsSync24(prev)) {
|
|
20164
22146
|
unwatchFile(prev);
|
|
20165
22147
|
watchedFiles.delete(prev);
|
|
20166
22148
|
}
|
|
20167
22149
|
}
|
|
20168
|
-
const files =
|
|
22150
|
+
const files = readdirSync13(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
20169
22151
|
for (const file of files) {
|
|
20170
|
-
const fullPath =
|
|
22152
|
+
const fullPath = join26(RUNNERS_PATH, file);
|
|
20171
22153
|
if (watchedFiles.has(fullPath)) continue;
|
|
20172
22154
|
watchedFiles.add(fullPath);
|
|
20173
22155
|
watchFile(fullPath, { interval: 5e3 }, () => {
|
|
@@ -20568,6 +22550,7 @@ var init_telegram2 = __esm({
|
|
|
20568
22550
|
{ command: "mode", description: "Execution gate (approved/yolo)" },
|
|
20569
22551
|
{ command: "tools", description: "Configure which tools the agent can use" },
|
|
20570
22552
|
{ command: "verbose", description: "Tool visibility (off/normal/verbose)" },
|
|
22553
|
+
{ command: "debug", description: "Toggle session debug logging (full tool I/O)" },
|
|
20571
22554
|
{ command: "cwd", description: "Set or show working directory" },
|
|
20572
22555
|
// Memory
|
|
20573
22556
|
{ command: "memory", description: "List stored memories" },
|
|
@@ -20608,7 +22591,8 @@ var init_telegram2 = __esm({
|
|
|
20608
22591
|
{ command: "chats", description: "Manage multi-chat aliases" },
|
|
20609
22592
|
{ command: "intent", description: "Test intent classifier on a message" },
|
|
20610
22593
|
{ command: "evolve", description: "Self-learning & evolution controls" },
|
|
20611
|
-
{ command: "reflect", description: "Trigger reflection analysis" }
|
|
22594
|
+
{ command: "reflect", description: "Trigger reflection analysis" },
|
|
22595
|
+
{ command: "optimize", description: "Audit identity files and skills" }
|
|
20612
22596
|
]);
|
|
20613
22597
|
this.bot.on("message", async (ctx) => {
|
|
20614
22598
|
const chatId = ctx.chat.id.toString();
|
|
@@ -21013,19 +22997,19 @@ var init_telegram2 = __esm({
|
|
|
21013
22997
|
});
|
|
21014
22998
|
|
|
21015
22999
|
// src/skills/bootstrap.ts
|
|
21016
|
-
import { existsSync as
|
|
23000
|
+
import { existsSync as existsSync25 } from "fs";
|
|
21017
23001
|
import { readdir as readdir6, readFile as readFile8, writeFile as writeFile5, copyFile } from "fs/promises";
|
|
21018
|
-
import { join as
|
|
23002
|
+
import { join as join27, dirname as dirname5 } from "path";
|
|
21019
23003
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21020
23004
|
async function copyAgentManifestSkills() {
|
|
21021
|
-
if (!
|
|
23005
|
+
if (!existsSync25(PKG_SKILLS)) return;
|
|
21022
23006
|
try {
|
|
21023
23007
|
const entries = await readdir6(PKG_SKILLS, { withFileTypes: true });
|
|
21024
23008
|
for (const entry of entries) {
|
|
21025
23009
|
if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
|
|
21026
|
-
const src =
|
|
21027
|
-
const dest =
|
|
21028
|
-
if (
|
|
23010
|
+
const src = join27(PKG_SKILLS, entry.name);
|
|
23011
|
+
const dest = join27(SKILLS_PATH, entry.name);
|
|
23012
|
+
if (existsSync25(dest)) continue;
|
|
21029
23013
|
await copyFile(src, dest);
|
|
21030
23014
|
log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
|
|
21031
23015
|
}
|
|
@@ -21035,8 +23019,8 @@ async function copyAgentManifestSkills() {
|
|
|
21035
23019
|
}
|
|
21036
23020
|
async function bootstrapSkills() {
|
|
21037
23021
|
await copyAgentManifestSkills();
|
|
21038
|
-
const usmDir =
|
|
21039
|
-
if (
|
|
23022
|
+
const usmDir = join27(SKILLS_PATH, USM_DIR_NAME);
|
|
23023
|
+
if (existsSync25(usmDir)) return;
|
|
21040
23024
|
try {
|
|
21041
23025
|
const entries = await readdir6(SKILLS_PATH);
|
|
21042
23026
|
const dirs = entries.filter((e) => !e.startsWith("."));
|
|
@@ -21058,8 +23042,8 @@ async function bootstrapSkills() {
|
|
|
21058
23042
|
}
|
|
21059
23043
|
}
|
|
21060
23044
|
async function patchUsmForCcClaw(usmDir) {
|
|
21061
|
-
const skillPath =
|
|
21062
|
-
if (!
|
|
23045
|
+
const skillPath = join27(usmDir, "SKILL.md");
|
|
23046
|
+
if (!existsSync25(skillPath)) return;
|
|
21063
23047
|
try {
|
|
21064
23048
|
let content = await readFile8(skillPath, "utf-8");
|
|
21065
23049
|
let patched = false;
|
|
@@ -21104,8 +23088,8 @@ var init_bootstrap = __esm({
|
|
|
21104
23088
|
USM_REPO = "jacob-bd/universal-skills-manager";
|
|
21105
23089
|
USM_DIR_NAME = "universal-skills-manager";
|
|
21106
23090
|
CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
|
|
21107
|
-
PKG_ROOT =
|
|
21108
|
-
PKG_SKILLS =
|
|
23091
|
+
PKG_ROOT = join27(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
|
|
23092
|
+
PKG_SKILLS = join27(PKG_ROOT, "skills");
|
|
21109
23093
|
}
|
|
21110
23094
|
});
|
|
21111
23095
|
|
|
@@ -21327,13 +23311,13 @@ __export(ai_skill_exports, {
|
|
|
21327
23311
|
generateAiSkill: () => generateAiSkill,
|
|
21328
23312
|
installAiSkill: () => installAiSkill
|
|
21329
23313
|
});
|
|
21330
|
-
import { existsSync as
|
|
21331
|
-
import { join as
|
|
21332
|
-
import { homedir as
|
|
23314
|
+
import { existsSync as existsSync26, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
|
|
23315
|
+
import { join as join28 } from "path";
|
|
23316
|
+
import { homedir as homedir9 } from "os";
|
|
21333
23317
|
function generateAiSkill() {
|
|
21334
23318
|
const version = VERSION;
|
|
21335
23319
|
let systemState = "";
|
|
21336
|
-
if (
|
|
23320
|
+
if (existsSync26(DB_PATH)) {
|
|
21337
23321
|
try {
|
|
21338
23322
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
|
|
21339
23323
|
const readDb = openDatabaseReadOnly2();
|
|
@@ -21421,6 +23405,7 @@ Use the CC-Claw CLI when you need to:
|
|
|
21421
23405
|
- \`/model_signature\` \u2014 Show/hide model name on responses
|
|
21422
23406
|
- \`/agents mode\` \u2014 Agent mode (auto/native/claw)
|
|
21423
23407
|
- \`/voice_config\` \u2014 Voice provider settings
|
|
23408
|
+
- \`/debug\` \u2014 Toggle per-chat session debug logging (full tool I/O to disk)
|
|
21424
23409
|
|
|
21425
23410
|
**Memory:**
|
|
21426
23411
|
- \`/remember <text>\` \u2014 Save a memory
|
|
@@ -21463,6 +23448,16 @@ cc-claw logs --error # Show error log
|
|
|
21463
23448
|
cc-claw logs --lines 50 # Show last N lines
|
|
21464
23449
|
\`\`\`
|
|
21465
23450
|
|
|
23451
|
+
### Session Debug Logs
|
|
23452
|
+
\`\`\`bash
|
|
23453
|
+
cc-claw session-logs list # List all session debug logs
|
|
23454
|
+
cc-claw session-logs tail # Tail latest session log
|
|
23455
|
+
cc-claw session-logs tail -f # Follow latest log (like tail -f)
|
|
23456
|
+
cc-claw session-logs tail --file <name> # Tail a specific log file
|
|
23457
|
+
cc-claw session-logs clean # Remove old session logs
|
|
23458
|
+
cc-claw session-logs clean --days 3 # Remove logs older than 3 days
|
|
23459
|
+
\`\`\`
|
|
23460
|
+
|
|
21466
23461
|
### Backend & Model
|
|
21467
23462
|
\`\`\`bash
|
|
21468
23463
|
cc-claw backend list --json # Available backends
|
|
@@ -21737,11 +23732,11 @@ function installAiSkill() {
|
|
|
21737
23732
|
const failed = [];
|
|
21738
23733
|
for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
|
|
21739
23734
|
for (const dir of dirs) {
|
|
21740
|
-
const skillDir =
|
|
21741
|
-
const skillPath =
|
|
23735
|
+
const skillDir = join28(dir, "cc-claw-cli");
|
|
23736
|
+
const skillPath = join28(skillDir, "SKILL.md");
|
|
21742
23737
|
try {
|
|
21743
|
-
|
|
21744
|
-
|
|
23738
|
+
mkdirSync11(skillDir, { recursive: true });
|
|
23739
|
+
writeFileSync8(skillPath, skill, "utf-8");
|
|
21745
23740
|
installed.push(skillPath);
|
|
21746
23741
|
} catch {
|
|
21747
23742
|
failed.push(skillPath);
|
|
@@ -21757,11 +23752,11 @@ var init_ai_skill = __esm({
|
|
|
21757
23752
|
init_paths();
|
|
21758
23753
|
init_version();
|
|
21759
23754
|
BACKEND_SKILL_DIRS2 = {
|
|
21760
|
-
"cc-claw": [
|
|
21761
|
-
claude: [
|
|
21762
|
-
gemini: [
|
|
21763
|
-
codex: [
|
|
21764
|
-
cursor: [
|
|
23755
|
+
"cc-claw": [join28(homedir9(), ".cc-claw", "workspace", "skills")],
|
|
23756
|
+
claude: [join28(homedir9(), ".claude", "skills")],
|
|
23757
|
+
gemini: [join28(homedir9(), ".gemini", "skills")],
|
|
23758
|
+
codex: [join28(homedir9(), ".agents", "skills")],
|
|
23759
|
+
cursor: [join28(homedir9(), ".cursor", "skills"), join28(homedir9(), ".cursor", "skills-cursor")]
|
|
21765
23760
|
};
|
|
21766
23761
|
}
|
|
21767
23762
|
});
|
|
@@ -21771,21 +23766,21 @@ var index_exports = {};
|
|
|
21771
23766
|
__export(index_exports, {
|
|
21772
23767
|
main: () => main
|
|
21773
23768
|
});
|
|
21774
|
-
import { mkdirSync as
|
|
21775
|
-
import { join as
|
|
23769
|
+
import { mkdirSync as mkdirSync12, existsSync as existsSync27, renameSync as renameSync2, statSync as statSync8, readFileSync as readFileSync16 } from "fs";
|
|
23770
|
+
import { join as join29 } from "path";
|
|
21776
23771
|
import dotenv from "dotenv";
|
|
21777
23772
|
function migrateLayout() {
|
|
21778
23773
|
const moves = [
|
|
21779
|
-
[
|
|
21780
|
-
[
|
|
21781
|
-
[
|
|
21782
|
-
[
|
|
21783
|
-
[
|
|
21784
|
-
[
|
|
21785
|
-
[
|
|
23774
|
+
[join29(CC_CLAW_HOME, "cc-claw.db"), join29(DATA_PATH, "cc-claw.db")],
|
|
23775
|
+
[join29(CC_CLAW_HOME, "cc-claw.db-shm"), join29(DATA_PATH, "cc-claw.db-shm")],
|
|
23776
|
+
[join29(CC_CLAW_HOME, "cc-claw.db-wal"), join29(DATA_PATH, "cc-claw.db-wal")],
|
|
23777
|
+
[join29(CC_CLAW_HOME, "cc-claw.log"), join29(LOGS_PATH, "cc-claw.log")],
|
|
23778
|
+
[join29(CC_CLAW_HOME, "cc-claw.log.1"), join29(LOGS_PATH, "cc-claw.log.1")],
|
|
23779
|
+
[join29(CC_CLAW_HOME, "cc-claw.error.log"), join29(LOGS_PATH, "cc-claw.error.log")],
|
|
23780
|
+
[join29(CC_CLAW_HOME, "cc-claw.error.log.1"), join29(LOGS_PATH, "cc-claw.error.log.1")]
|
|
21786
23781
|
];
|
|
21787
23782
|
for (const [from, to] of moves) {
|
|
21788
|
-
if (
|
|
23783
|
+
if (existsSync27(from) && !existsSync27(to)) {
|
|
21789
23784
|
try {
|
|
21790
23785
|
renameSync2(from, to);
|
|
21791
23786
|
} catch {
|
|
@@ -21796,7 +23791,7 @@ function migrateLayout() {
|
|
|
21796
23791
|
function rotateLogs() {
|
|
21797
23792
|
for (const file of [LOG_PATH, ERROR_LOG_PATH]) {
|
|
21798
23793
|
try {
|
|
21799
|
-
const { size } =
|
|
23794
|
+
const { size } = statSync8(file);
|
|
21800
23795
|
if (size > LOG_MAX_BYTES) {
|
|
21801
23796
|
const archivePath = `${file}.1`;
|
|
21802
23797
|
try {
|
|
@@ -21814,7 +23809,7 @@ async function main() {
|
|
|
21814
23809
|
let version = "unknown";
|
|
21815
23810
|
try {
|
|
21816
23811
|
const pkgPath = new URL("../package.json", import.meta.url);
|
|
21817
|
-
version = JSON.parse(
|
|
23812
|
+
version = JSON.parse(readFileSync16(pkgPath, "utf-8")).version;
|
|
21818
23813
|
} catch {
|
|
21819
23814
|
}
|
|
21820
23815
|
log(`[cc-claw] Starting v${version}`);
|
|
@@ -21930,11 +23925,11 @@ async function main() {
|
|
|
21930
23925
|
bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
|
|
21931
23926
|
try {
|
|
21932
23927
|
const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
|
|
21933
|
-
const { writeFileSync:
|
|
21934
|
-
const { join:
|
|
21935
|
-
const skillDir =
|
|
21936
|
-
|
|
21937
|
-
|
|
23928
|
+
const { writeFileSync: writeFileSync13, mkdirSync: mkdirSync19 } = await import("fs");
|
|
23929
|
+
const { join: join35 } = await import("path");
|
|
23930
|
+
const skillDir = join35(SKILLS_PATH, "cc-claw-cli");
|
|
23931
|
+
mkdirSync19(skillDir, { recursive: true });
|
|
23932
|
+
writeFileSync13(join35(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
|
|
21938
23933
|
log("[cc-claw] AI skill updated");
|
|
21939
23934
|
} catch {
|
|
21940
23935
|
}
|
|
@@ -21954,6 +23949,12 @@ async function main() {
|
|
|
21954
23949
|
cleanupOldMedia().catch(() => {
|
|
21955
23950
|
});
|
|
21956
23951
|
pruneImageCache();
|
|
23952
|
+
try {
|
|
23953
|
+
const { cleanupSessionLogs: cleanupSessionLogs2, startSessionLogCleanupTimer: startSessionLogCleanupTimer2 } = await Promise.resolve().then(() => (init_session_log2(), session_log_exports2));
|
|
23954
|
+
cleanupSessionLogs2();
|
|
23955
|
+
startSessionLogCleanupTimer2();
|
|
23956
|
+
} catch {
|
|
23957
|
+
}
|
|
21957
23958
|
log("[cc-claw] Ready!");
|
|
21958
23959
|
const shutdown = async (signal) => {
|
|
21959
23960
|
log(`[cc-claw] Received ${signal}, shutting down...`);
|
|
@@ -22006,11 +24007,11 @@ var init_index = __esm({
|
|
|
22006
24007
|
init_bootstrap2();
|
|
22007
24008
|
init_health3();
|
|
22008
24009
|
init_image_gen();
|
|
22009
|
-
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
22010
|
-
if (!
|
|
24010
|
+
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SESSION_LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
24011
|
+
if (!existsSync27(dir)) mkdirSync12(dir, { recursive: true });
|
|
22011
24012
|
}
|
|
22012
24013
|
migrateLayout();
|
|
22013
|
-
if (
|
|
24014
|
+
if (existsSync27(ENV_PATH)) {
|
|
22014
24015
|
dotenv.config({ path: ENV_PATH });
|
|
22015
24016
|
} else {
|
|
22016
24017
|
console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
|
|
@@ -22031,12 +24032,12 @@ __export(api_client_exports, {
|
|
|
22031
24032
|
apiPost: () => apiPost,
|
|
22032
24033
|
isDaemonRunning: () => isDaemonRunning
|
|
22033
24034
|
});
|
|
22034
|
-
import { readFileSync as
|
|
24035
|
+
import { readFileSync as readFileSync17, existsSync as existsSync28 } from "fs";
|
|
22035
24036
|
import { request as httpRequest, Agent } from "http";
|
|
22036
24037
|
function getToken() {
|
|
22037
24038
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
22038
24039
|
try {
|
|
22039
|
-
if (
|
|
24040
|
+
if (existsSync28(TOKEN_PATH)) return readFileSync17(TOKEN_PATH, "utf-8").trim();
|
|
22040
24041
|
} catch {
|
|
22041
24042
|
}
|
|
22042
24043
|
return null;
|
|
@@ -22135,10 +24136,10 @@ __export(service_exports, {
|
|
|
22135
24136
|
serviceStatus: () => serviceStatus,
|
|
22136
24137
|
uninstallService: () => uninstallService
|
|
22137
24138
|
});
|
|
22138
|
-
import { existsSync as
|
|
24139
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, unlinkSync as unlinkSync7 } from "fs";
|
|
22139
24140
|
import { execFileSync as execFileSync3, execSync as execSync6 } from "child_process";
|
|
22140
|
-
import { homedir as
|
|
22141
|
-
import { join as
|
|
24141
|
+
import { homedir as homedir10, platform } from "os";
|
|
24142
|
+
import { join as join30, dirname as dirname6 } from "path";
|
|
22142
24143
|
function xmlEscape(s) {
|
|
22143
24144
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
22144
24145
|
}
|
|
@@ -22147,23 +24148,23 @@ function resolveExecutable2(name) {
|
|
|
22147
24148
|
return execFileSync3("which", [name], { encoding: "utf-8" }).trim();
|
|
22148
24149
|
} catch {
|
|
22149
24150
|
const fallback = process.argv[1];
|
|
22150
|
-
if (fallback &&
|
|
24151
|
+
if (fallback && existsSync29(fallback)) return fallback;
|
|
22151
24152
|
throw new Error(`Cannot find '${name}' executable. Install globally: npm install -g cc-claw`);
|
|
22152
24153
|
}
|
|
22153
24154
|
}
|
|
22154
24155
|
function getPathDirs() {
|
|
22155
|
-
const nodeBin =
|
|
22156
|
-
const home =
|
|
24156
|
+
const nodeBin = dirname6(process.execPath);
|
|
24157
|
+
const home = homedir10();
|
|
22157
24158
|
const dirs = /* @__PURE__ */ new Set([
|
|
22158
24159
|
nodeBin,
|
|
22159
|
-
|
|
24160
|
+
join30(home, ".local", "bin"),
|
|
22160
24161
|
"/usr/local/bin",
|
|
22161
24162
|
"/usr/bin",
|
|
22162
24163
|
"/bin"
|
|
22163
24164
|
]);
|
|
22164
24165
|
try {
|
|
22165
24166
|
const prefix = execSync6("npm config get prefix", { encoding: "utf-8" }).trim();
|
|
22166
|
-
if (prefix) dirs.add(
|
|
24167
|
+
if (prefix) dirs.add(join30(prefix, "bin"));
|
|
22167
24168
|
} catch {
|
|
22168
24169
|
}
|
|
22169
24170
|
return [...dirs].join(":");
|
|
@@ -22171,7 +24172,7 @@ function getPathDirs() {
|
|
|
22171
24172
|
function generatePlist() {
|
|
22172
24173
|
const ccClawBin = resolveExecutable2("cc-claw");
|
|
22173
24174
|
const pathDirs = getPathDirs();
|
|
22174
|
-
const home =
|
|
24175
|
+
const home = homedir10();
|
|
22175
24176
|
const safeBin = xmlEscape(ccClawBin);
|
|
22176
24177
|
const safePaths = xmlEscape(pathDirs);
|
|
22177
24178
|
const safeHome = xmlEscape(home);
|
|
@@ -22221,22 +24222,22 @@ function generatePlist() {
|
|
|
22221
24222
|
</plist>`;
|
|
22222
24223
|
}
|
|
22223
24224
|
function installMacOS() {
|
|
22224
|
-
const agentsDir =
|
|
22225
|
-
if (!
|
|
22226
|
-
if (!
|
|
22227
|
-
if (
|
|
24225
|
+
const agentsDir = dirname6(PLIST_PATH);
|
|
24226
|
+
if (!existsSync29(agentsDir)) mkdirSync13(agentsDir, { recursive: true });
|
|
24227
|
+
if (!existsSync29(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
|
|
24228
|
+
if (existsSync29(PLIST_PATH)) {
|
|
22228
24229
|
try {
|
|
22229
24230
|
execFileSync3("launchctl", ["unload", PLIST_PATH]);
|
|
22230
24231
|
} catch {
|
|
22231
24232
|
}
|
|
22232
24233
|
}
|
|
22233
|
-
|
|
24234
|
+
writeFileSync9(PLIST_PATH, generatePlist());
|
|
22234
24235
|
console.log(` Installed: ${PLIST_PATH}`);
|
|
22235
24236
|
execFileSync3("launchctl", ["load", PLIST_PATH]);
|
|
22236
24237
|
console.log(" Service loaded and starting.");
|
|
22237
24238
|
}
|
|
22238
24239
|
function uninstallMacOS() {
|
|
22239
|
-
if (!
|
|
24240
|
+
if (!existsSync29(PLIST_PATH)) {
|
|
22240
24241
|
console.log(" No service found to uninstall.");
|
|
22241
24242
|
return;
|
|
22242
24243
|
}
|
|
@@ -22244,7 +24245,7 @@ function uninstallMacOS() {
|
|
|
22244
24245
|
execFileSync3("launchctl", ["unload", PLIST_PATH]);
|
|
22245
24246
|
} catch {
|
|
22246
24247
|
}
|
|
22247
|
-
|
|
24248
|
+
unlinkSync7(PLIST_PATH);
|
|
22248
24249
|
console.log(" Service uninstalled.");
|
|
22249
24250
|
}
|
|
22250
24251
|
function formatUptime(seconds) {
|
|
@@ -22304,16 +24305,16 @@ Restart=on-failure
|
|
|
22304
24305
|
RestartSec=10
|
|
22305
24306
|
WorkingDirectory=${CC_CLAW_HOME}
|
|
22306
24307
|
Environment=PATH=${pathDirs}
|
|
22307
|
-
Environment=HOME=${
|
|
24308
|
+
Environment=HOME=${homedir10()}
|
|
22308
24309
|
|
|
22309
24310
|
[Install]
|
|
22310
24311
|
WantedBy=default.target
|
|
22311
24312
|
`;
|
|
22312
24313
|
}
|
|
22313
24314
|
function installLinux() {
|
|
22314
|
-
if (!
|
|
22315
|
-
if (!
|
|
22316
|
-
|
|
24315
|
+
if (!existsSync29(SYSTEMD_DIR)) mkdirSync13(SYSTEMD_DIR, { recursive: true });
|
|
24316
|
+
if (!existsSync29(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
|
|
24317
|
+
writeFileSync9(UNIT_PATH, generateUnit());
|
|
22317
24318
|
console.log(` Installed: ${UNIT_PATH}`);
|
|
22318
24319
|
execFileSync3("systemctl", ["--user", "daemon-reload"]);
|
|
22319
24320
|
execFileSync3("systemctl", ["--user", "enable", "cc-claw"]);
|
|
@@ -22321,7 +24322,7 @@ function installLinux() {
|
|
|
22321
24322
|
console.log(" Service enabled and started.");
|
|
22322
24323
|
}
|
|
22323
24324
|
function uninstallLinux() {
|
|
22324
|
-
if (!
|
|
24325
|
+
if (!existsSync29(UNIT_PATH)) {
|
|
22325
24326
|
console.log(" No service found to uninstall.");
|
|
22326
24327
|
return;
|
|
22327
24328
|
}
|
|
@@ -22333,7 +24334,7 @@ function uninstallLinux() {
|
|
|
22333
24334
|
execFileSync3("systemctl", ["--user", "disable", "cc-claw"]);
|
|
22334
24335
|
} catch {
|
|
22335
24336
|
}
|
|
22336
|
-
|
|
24337
|
+
unlinkSync7(UNIT_PATH);
|
|
22337
24338
|
execFileSync3("systemctl", ["--user", "daemon-reload"]);
|
|
22338
24339
|
console.log(" Service uninstalled.");
|
|
22339
24340
|
}
|
|
@@ -22346,7 +24347,7 @@ function statusLinux() {
|
|
|
22346
24347
|
}
|
|
22347
24348
|
}
|
|
22348
24349
|
function installService() {
|
|
22349
|
-
if (!
|
|
24350
|
+
if (!existsSync29(join30(CC_CLAW_HOME, ".env"))) {
|
|
22350
24351
|
console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
|
|
22351
24352
|
console.error(" Run 'cc-claw setup' before installing the service.");
|
|
22352
24353
|
process.exitCode = 1;
|
|
@@ -22375,9 +24376,9 @@ var init_service = __esm({
|
|
|
22375
24376
|
"use strict";
|
|
22376
24377
|
init_paths();
|
|
22377
24378
|
PLIST_LABEL = "com.cc-claw";
|
|
22378
|
-
PLIST_PATH =
|
|
22379
|
-
SYSTEMD_DIR =
|
|
22380
|
-
UNIT_PATH =
|
|
24379
|
+
PLIST_PATH = join30(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
24380
|
+
SYSTEMD_DIR = join30(homedir10(), ".config", "systemd", "user");
|
|
24381
|
+
UNIT_PATH = join30(SYSTEMD_DIR, "cc-claw.service");
|
|
22381
24382
|
}
|
|
22382
24383
|
});
|
|
22383
24384
|
|
|
@@ -22544,13 +24545,13 @@ var init_daemon = __esm({
|
|
|
22544
24545
|
});
|
|
22545
24546
|
|
|
22546
24547
|
// src/cli/resolve-chat.ts
|
|
22547
|
-
import { readFileSync as
|
|
24548
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
22548
24549
|
function resolveChatId(globalOpts) {
|
|
22549
24550
|
const explicit = globalOpts.chat;
|
|
22550
24551
|
if (explicit) return explicit;
|
|
22551
24552
|
if (_cachedDefault) return _cachedDefault;
|
|
22552
24553
|
try {
|
|
22553
|
-
const content =
|
|
24554
|
+
const content = readFileSync19(ENV_PATH, "utf-8");
|
|
22554
24555
|
const match = content.match(/^ALLOWED_CHAT_ID=(.+)$/m);
|
|
22555
24556
|
if (match) {
|
|
22556
24557
|
_cachedDefault = match[1].split(",")[0].trim();
|
|
@@ -22574,7 +24575,7 @@ var status_exports = {};
|
|
|
22574
24575
|
__export(status_exports, {
|
|
22575
24576
|
statusCommand: () => statusCommand
|
|
22576
24577
|
});
|
|
22577
|
-
import { existsSync as
|
|
24578
|
+
import { existsSync as existsSync30, statSync as statSync9 } from "fs";
|
|
22578
24579
|
async function statusCommand(globalOpts, localOpts) {
|
|
22579
24580
|
try {
|
|
22580
24581
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
@@ -22614,7 +24615,7 @@ async function statusCommand(globalOpts, localOpts) {
|
|
|
22614
24615
|
const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
|
|
22615
24616
|
const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
|
|
22616
24617
|
const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
|
|
22617
|
-
const dbStat =
|
|
24618
|
+
const dbStat = existsSync30(DB_PATH) ? statSync9(DB_PATH) : null;
|
|
22618
24619
|
let daemonRunning = false;
|
|
22619
24620
|
let daemonInfo = {};
|
|
22620
24621
|
try {
|
|
@@ -22703,12 +24704,12 @@ var doctor_exports = {};
|
|
|
22703
24704
|
__export(doctor_exports, {
|
|
22704
24705
|
doctorCommand: () => doctorCommand
|
|
22705
24706
|
});
|
|
22706
|
-
import { existsSync as
|
|
24707
|
+
import { existsSync as existsSync31, statSync as statSync10, accessSync, constants } from "fs";
|
|
22707
24708
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
22708
24709
|
async function doctorCommand(globalOpts, localOpts) {
|
|
22709
24710
|
const checks = [];
|
|
22710
|
-
if (
|
|
22711
|
-
const size =
|
|
24711
|
+
if (existsSync31(DB_PATH)) {
|
|
24712
|
+
const size = statSync10(DB_PATH).size;
|
|
22712
24713
|
checks.push({ name: "Database", status: "ok", message: `${DB_PATH} (${(size / 1024).toFixed(0)}KB)` });
|
|
22713
24714
|
try {
|
|
22714
24715
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
@@ -22737,7 +24738,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
22737
24738
|
} else {
|
|
22738
24739
|
checks.push({ name: "Database", status: "error", message: `Not found at ${DB_PATH}`, fix: "cc-claw setup" });
|
|
22739
24740
|
}
|
|
22740
|
-
if (
|
|
24741
|
+
if (existsSync31(ENV_PATH)) {
|
|
22741
24742
|
checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
|
|
22742
24743
|
} else {
|
|
22743
24744
|
checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
|
|
@@ -22792,7 +24793,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
22792
24793
|
} catch {
|
|
22793
24794
|
}
|
|
22794
24795
|
const tokenPath = `${DATA_PATH}/api-token`;
|
|
22795
|
-
if (
|
|
24796
|
+
if (existsSync31(tokenPath)) {
|
|
22796
24797
|
try {
|
|
22797
24798
|
accessSync(tokenPath, constants.R_OK);
|
|
22798
24799
|
checks.push({ name: "API token", status: "ok", message: "token file readable" });
|
|
@@ -22817,10 +24818,10 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
22817
24818
|
}
|
|
22818
24819
|
} catch {
|
|
22819
24820
|
}
|
|
22820
|
-
if (
|
|
24821
|
+
if (existsSync31(ERROR_LOG_PATH)) {
|
|
22821
24822
|
try {
|
|
22822
|
-
const { readFileSync:
|
|
22823
|
-
const logContent =
|
|
24823
|
+
const { readFileSync: readFileSync27 } = await import("fs");
|
|
24824
|
+
const logContent = readFileSync27(ERROR_LOG_PATH, "utf-8");
|
|
22824
24825
|
const recentLines = logContent.split("\n").filter(Boolean).slice(-100);
|
|
22825
24826
|
const last24h = Date.now() - 864e5;
|
|
22826
24827
|
const recentErrors = recentLines.filter((line) => {
|
|
@@ -22943,15 +24944,15 @@ var logs_exports = {};
|
|
|
22943
24944
|
__export(logs_exports, {
|
|
22944
24945
|
logsCommand: () => logsCommand
|
|
22945
24946
|
});
|
|
22946
|
-
import { existsSync as
|
|
24947
|
+
import { existsSync as existsSync32, readFileSync as readFileSync20, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
|
|
22947
24948
|
async function logsCommand(opts) {
|
|
22948
24949
|
const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
|
|
22949
|
-
if (!
|
|
24950
|
+
if (!existsSync32(logFile)) {
|
|
22950
24951
|
outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
|
|
22951
24952
|
process.exit(1);
|
|
22952
24953
|
}
|
|
22953
24954
|
const maxLines = parseInt(opts.lines ?? "100", 10);
|
|
22954
|
-
const content =
|
|
24955
|
+
const content = readFileSync20(logFile, "utf-8");
|
|
22955
24956
|
const allLines = content.split("\n");
|
|
22956
24957
|
const tailLines = allLines.slice(-maxLines);
|
|
22957
24958
|
console.log(muted(` \u2500\u2500 ${logFile} (last ${tailLines.length} lines) \u2500\u2500`));
|
|
@@ -22961,7 +24962,7 @@ async function logsCommand(opts) {
|
|
|
22961
24962
|
let lastLength = content.length;
|
|
22962
24963
|
watchFile2(logFile, { interval: 500 }, () => {
|
|
22963
24964
|
try {
|
|
22964
|
-
const newContent =
|
|
24965
|
+
const newContent = readFileSync20(logFile, "utf-8");
|
|
22965
24966
|
if (newContent.length > lastLength) {
|
|
22966
24967
|
const newPart = newContent.slice(lastLength);
|
|
22967
24968
|
process.stdout.write(newPart);
|
|
@@ -22986,6 +24987,105 @@ var init_logs = __esm({
|
|
|
22986
24987
|
}
|
|
22987
24988
|
});
|
|
22988
24989
|
|
|
24990
|
+
// src/cli/commands/session-logs.ts
|
|
24991
|
+
var session_logs_exports = {};
|
|
24992
|
+
__export(session_logs_exports, {
|
|
24993
|
+
sessionLogsClean: () => sessionLogsClean,
|
|
24994
|
+
sessionLogsList: () => sessionLogsList,
|
|
24995
|
+
sessionLogsTail: () => sessionLogsTail
|
|
24996
|
+
});
|
|
24997
|
+
import { readFileSync as readFileSync21, watchFile as watchFile3, unwatchFile as unwatchFile3 } from "fs";
|
|
24998
|
+
async function sessionLogsList(opts) {
|
|
24999
|
+
const logs = listSessionLogs();
|
|
25000
|
+
if (logs.length === 0) {
|
|
25001
|
+
console.log(muted(" No session debug logs found."));
|
|
25002
|
+
console.log(muted(` Enable via /debug in Telegram, then logs will appear in ${SESSION_LOGS_PATH}`));
|
|
25003
|
+
return;
|
|
25004
|
+
}
|
|
25005
|
+
if (opts.json) {
|
|
25006
|
+
console.log(JSON.stringify(logs.map((l) => ({
|
|
25007
|
+
filename: l.filename,
|
|
25008
|
+
chatId: l.chatId,
|
|
25009
|
+
timestamp: l.timestamp,
|
|
25010
|
+
sizeBytes: l.sizeBytes,
|
|
25011
|
+
modifiedAt: l.modifiedAt.toISOString()
|
|
25012
|
+
})), null, 2));
|
|
25013
|
+
return;
|
|
25014
|
+
}
|
|
25015
|
+
console.log(muted(` \u2500\u2500 Session Debug Logs (${logs.length}) \u2500\u2500
|
|
25016
|
+
`));
|
|
25017
|
+
console.log(` ${"Filename".padEnd(55)} ${"Size".padStart(8)} Chat ID`);
|
|
25018
|
+
console.log(` ${"\u2500".repeat(55)} ${"\u2500".repeat(8)} ${"\u2500".repeat(15)}`);
|
|
25019
|
+
for (const log5 of logs) {
|
|
25020
|
+
const size = log5.sizeBytes < 1024 ? `${log5.sizeBytes}B` : log5.sizeBytes < 1024 * 1024 ? `${(log5.sizeBytes / 1024).toFixed(1)}K` : `${(log5.sizeBytes / 1024 / 1024).toFixed(1)}M`;
|
|
25021
|
+
console.log(` ${log5.filename.padEnd(55)} ${size.padStart(8)} ${log5.chatId}`);
|
|
25022
|
+
}
|
|
25023
|
+
console.log(muted(`
|
|
25024
|
+
Path: ${SESSION_LOGS_PATH}`));
|
|
25025
|
+
console.log(muted(` Retention: ${getRetentionDays()} day(s) (set SESSION_LOG_RETENTION_DAYS to change)`));
|
|
25026
|
+
}
|
|
25027
|
+
async function sessionLogsTail(opts) {
|
|
25028
|
+
const logs = listSessionLogs();
|
|
25029
|
+
if (logs.length === 0) {
|
|
25030
|
+
outputError("NO_LOGS", "No session debug logs found. Enable via /debug in Telegram.");
|
|
25031
|
+
return;
|
|
25032
|
+
}
|
|
25033
|
+
let targetPath;
|
|
25034
|
+
if (opts.file) {
|
|
25035
|
+
const match = logs.find((l) => l.filename.includes(opts.file));
|
|
25036
|
+
if (!match) {
|
|
25037
|
+
outputError("NOT_FOUND", `No session log matching "${opts.file}". Use 'cc-claw logs session list' to see available logs.`);
|
|
25038
|
+
return;
|
|
25039
|
+
}
|
|
25040
|
+
targetPath = match.filePath;
|
|
25041
|
+
} else {
|
|
25042
|
+
targetPath = logs[0].filePath;
|
|
25043
|
+
}
|
|
25044
|
+
const lineCount = parseInt(opts.lines ?? "50", 10);
|
|
25045
|
+
console.log(muted(` \u2500\u2500 ${targetPath} (last ${lineCount} lines) \u2500\u2500
|
|
25046
|
+
`));
|
|
25047
|
+
for await (const line of tailSessionLog(targetPath, lineCount)) {
|
|
25048
|
+
console.log(line);
|
|
25049
|
+
}
|
|
25050
|
+
if (opts.follow) {
|
|
25051
|
+
console.log(muted("\n Following... (Ctrl+C to stop)\n"));
|
|
25052
|
+
let lastLength = 0;
|
|
25053
|
+
try {
|
|
25054
|
+
lastLength = readFileSync21(targetPath, "utf-8").length;
|
|
25055
|
+
} catch {
|
|
25056
|
+
}
|
|
25057
|
+
watchFile3(targetPath, { interval: 500 }, () => {
|
|
25058
|
+
try {
|
|
25059
|
+
const content = readFileSync21(targetPath, "utf-8");
|
|
25060
|
+
if (content.length > lastLength) {
|
|
25061
|
+
process.stdout.write(content.slice(lastLength));
|
|
25062
|
+
lastLength = content.length;
|
|
25063
|
+
}
|
|
25064
|
+
} catch {
|
|
25065
|
+
}
|
|
25066
|
+
});
|
|
25067
|
+
process.on("SIGINT", () => {
|
|
25068
|
+
unwatchFile3(targetPath);
|
|
25069
|
+
process.exit(0);
|
|
25070
|
+
});
|
|
25071
|
+
await new Promise(() => {
|
|
25072
|
+
});
|
|
25073
|
+
}
|
|
25074
|
+
}
|
|
25075
|
+
async function sessionLogsClean(opts) {
|
|
25076
|
+
const days = opts.days ? parseInt(opts.days, 10) : void 0;
|
|
25077
|
+
const cleaned = cleanupSessionLogs(days);
|
|
25078
|
+
console.log(success(`Cleaned ${cleaned} session log(s) older than ${days ?? getRetentionDays()} day(s).`));
|
|
25079
|
+
}
|
|
25080
|
+
var init_session_logs = __esm({
|
|
25081
|
+
"src/cli/commands/session-logs.ts"() {
|
|
25082
|
+
"use strict";
|
|
25083
|
+
init_session_log2();
|
|
25084
|
+
init_paths();
|
|
25085
|
+
init_format2();
|
|
25086
|
+
}
|
|
25087
|
+
});
|
|
25088
|
+
|
|
22989
25089
|
// src/cli/commands/gemini.ts
|
|
22990
25090
|
var gemini_exports = {};
|
|
22991
25091
|
__export(gemini_exports, {
|
|
@@ -22998,11 +25098,11 @@ __export(gemini_exports, {
|
|
|
22998
25098
|
geminiReorder: () => geminiReorder,
|
|
22999
25099
|
geminiRotation: () => geminiRotation
|
|
23000
25100
|
});
|
|
23001
|
-
import { existsSync as
|
|
23002
|
-
import { join as
|
|
23003
|
-
import { createInterface as
|
|
25101
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync14, writeFileSync as writeFileSync10, readFileSync as readFileSync22, chmodSync } from "fs";
|
|
25102
|
+
import { join as join31 } from "path";
|
|
25103
|
+
import { createInterface as createInterface7 } from "readline";
|
|
23004
25104
|
function requireDb() {
|
|
23005
|
-
if (!
|
|
25105
|
+
if (!existsSync34(DB_PATH)) {
|
|
23006
25106
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
23007
25107
|
process.exit(1);
|
|
23008
25108
|
}
|
|
@@ -23027,9 +25127,9 @@ async function resolveSlotId(idOrLabel) {
|
|
|
23027
25127
|
function resolveOAuthEmail(configHome) {
|
|
23028
25128
|
if (!configHome) return null;
|
|
23029
25129
|
try {
|
|
23030
|
-
const accountsPath =
|
|
23031
|
-
if (!
|
|
23032
|
-
const accounts = JSON.parse(
|
|
25130
|
+
const accountsPath = join31(configHome, ".gemini", "google_accounts.json");
|
|
25131
|
+
if (!existsSync34(accountsPath)) return null;
|
|
25132
|
+
const accounts = JSON.parse(readFileSync22(accountsPath, "utf-8"));
|
|
23033
25133
|
return accounts.active || null;
|
|
23034
25134
|
} catch {
|
|
23035
25135
|
return null;
|
|
@@ -23073,7 +25173,7 @@ async function geminiList(globalOpts) {
|
|
|
23073
25173
|
}
|
|
23074
25174
|
async function geminiAddKey(globalOpts, opts) {
|
|
23075
25175
|
await requireWriteDb();
|
|
23076
|
-
const rl2 =
|
|
25176
|
+
const rl2 = createInterface7({ input: process.stdin, output: process.stdout });
|
|
23077
25177
|
const ask2 = (q) => new Promise((r) => rl2.question(q, r));
|
|
23078
25178
|
const key = await ask2("Paste your Gemini API key: ");
|
|
23079
25179
|
rl2.close();
|
|
@@ -23111,14 +25211,14 @@ async function geminiAddKey(globalOpts, opts) {
|
|
|
23111
25211
|
}
|
|
23112
25212
|
async function geminiAddAccount(globalOpts, opts) {
|
|
23113
25213
|
await requireWriteDb();
|
|
23114
|
-
const slotsDir =
|
|
23115
|
-
if (!
|
|
25214
|
+
const slotsDir = join31(CC_CLAW_HOME, "gemini-slots");
|
|
25215
|
+
if (!existsSync34(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
|
|
23116
25216
|
const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
23117
25217
|
const tempId = Date.now();
|
|
23118
|
-
const slotDir =
|
|
23119
|
-
|
|
23120
|
-
|
|
23121
|
-
|
|
25218
|
+
const slotDir = join31(slotsDir, `slot-${tempId}`);
|
|
25219
|
+
mkdirSync14(slotDir, { recursive: true, mode: 448 });
|
|
25220
|
+
mkdirSync14(join31(slotDir, ".gemini"), { recursive: true });
|
|
25221
|
+
writeFileSync10(join31(slotDir, ".gemini", "settings.json"), JSON.stringify({
|
|
23122
25222
|
security: { auth: { selectedType: "oauth-personal" } }
|
|
23123
25223
|
}, null, 2));
|
|
23124
25224
|
console.log("");
|
|
@@ -23135,8 +25235,8 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
23135
25235
|
});
|
|
23136
25236
|
} catch {
|
|
23137
25237
|
}
|
|
23138
|
-
const oauthPath =
|
|
23139
|
-
if (!
|
|
25238
|
+
const oauthPath = join31(slotDir, ".gemini", "oauth_creds.json");
|
|
25239
|
+
if (!existsSync34(oauthPath)) {
|
|
23140
25240
|
console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
|
|
23141
25241
|
console.log(" The slot directory is preserved at: " + slotDir);
|
|
23142
25242
|
console.log(" Re-run: cc-claw gemini add-account\n");
|
|
@@ -23144,7 +25244,7 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
23144
25244
|
}
|
|
23145
25245
|
let accountEmail = "unknown";
|
|
23146
25246
|
try {
|
|
23147
|
-
const accounts = JSON.parse(__require("fs").readFileSync(
|
|
25247
|
+
const accounts = JSON.parse(__require("fs").readFileSync(join31(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
|
|
23148
25248
|
accountEmail = accounts.active || accountEmail;
|
|
23149
25249
|
} catch {
|
|
23150
25250
|
}
|
|
@@ -23263,11 +25363,11 @@ __export(backend_cmd_factory_exports, {
|
|
|
23263
25363
|
makeReorder: () => makeReorder,
|
|
23264
25364
|
registerBackendSlotCommands: () => registerBackendSlotCommands
|
|
23265
25365
|
});
|
|
23266
|
-
import { existsSync as
|
|
23267
|
-
import { join as
|
|
23268
|
-
import { createInterface as
|
|
25366
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync15, readFileSync as readFileSync23 } from "fs";
|
|
25367
|
+
import { join as join32 } from "path";
|
|
25368
|
+
import { createInterface as createInterface8 } from "readline";
|
|
23269
25369
|
function requireDb2() {
|
|
23270
|
-
if (!
|
|
25370
|
+
if (!existsSync35(DB_PATH)) {
|
|
23271
25371
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
23272
25372
|
process.exit(1);
|
|
23273
25373
|
}
|
|
@@ -23326,7 +25426,7 @@ Add one with: cc-claw ${backend2} add-account or cc-claw ${backend2} add-key`)
|
|
|
23326
25426
|
function makeAddKey(backend2, displayName) {
|
|
23327
25427
|
return async function addKey(_globalOpts, opts) {
|
|
23328
25428
|
await requireWriteDb2();
|
|
23329
|
-
const rl2 =
|
|
25429
|
+
const rl2 = createInterface8({ input: process.stdin, output: process.stdout });
|
|
23330
25430
|
const ask2 = (q) => new Promise((r) => rl2.question(q, r));
|
|
23331
25431
|
const key = await ask2(`Paste your ${displayName} API key: `);
|
|
23332
25432
|
rl2.close();
|
|
@@ -23356,11 +25456,11 @@ function makeAddAccount(backend2, displayName) {
|
|
|
23356
25456
|
process.exit(1);
|
|
23357
25457
|
}
|
|
23358
25458
|
await requireWriteDb2();
|
|
23359
|
-
const slotsDir =
|
|
23360
|
-
if (!
|
|
25459
|
+
const slotsDir = join32(CC_CLAW_HOME, config2.slotsSubdir);
|
|
25460
|
+
if (!existsSync35(slotsDir)) mkdirSync15(slotsDir, { recursive: true });
|
|
23361
25461
|
const tempId = Date.now();
|
|
23362
|
-
const slotDir =
|
|
23363
|
-
|
|
25462
|
+
const slotDir = join32(slotsDir, `slot-${tempId}`);
|
|
25463
|
+
mkdirSync15(slotDir, { recursive: true, mode: 448 });
|
|
23364
25464
|
if (config2.preSetup) config2.preSetup(slotDir);
|
|
23365
25465
|
console.log("");
|
|
23366
25466
|
console.log(` Opening ${displayName} CLI for sign-in...`);
|
|
@@ -23528,22 +25628,22 @@ var init_backend_cmd_factory = __esm({
|
|
|
23528
25628
|
envValue: (slotDir) => slotDir,
|
|
23529
25629
|
envOverrides: { ANTHROPIC_API_KEY: void 0 },
|
|
23530
25630
|
preSetup: (slotDir) => {
|
|
23531
|
-
|
|
25631
|
+
mkdirSync15(join32(slotDir, ".claude"), { recursive: true });
|
|
23532
25632
|
},
|
|
23533
25633
|
verifyCredentials: (slotDir) => {
|
|
23534
|
-
const claudeJson =
|
|
23535
|
-
const claudeJsonNested =
|
|
23536
|
-
if (
|
|
25634
|
+
const claudeJson = join32(slotDir, ".claude.json");
|
|
25635
|
+
const claudeJsonNested = join32(slotDir, ".claude", ".claude.json");
|
|
25636
|
+
if (existsSync35(claudeJson)) {
|
|
23537
25637
|
try {
|
|
23538
|
-
const data = JSON.parse(
|
|
25638
|
+
const data = JSON.parse(readFileSync23(claudeJson, "utf-8"));
|
|
23539
25639
|
return Boolean(data.oauthAccount);
|
|
23540
25640
|
} catch {
|
|
23541
25641
|
return false;
|
|
23542
25642
|
}
|
|
23543
25643
|
}
|
|
23544
|
-
if (
|
|
25644
|
+
if (existsSync35(claudeJsonNested)) {
|
|
23545
25645
|
try {
|
|
23546
|
-
const data = JSON.parse(
|
|
25646
|
+
const data = JSON.parse(readFileSync23(claudeJsonNested, "utf-8"));
|
|
23547
25647
|
return Boolean(data.oauthAccount);
|
|
23548
25648
|
} catch {
|
|
23549
25649
|
return false;
|
|
@@ -23564,9 +25664,9 @@ var init_backend_cmd_factory = __esm({
|
|
|
23564
25664
|
} catch {
|
|
23565
25665
|
}
|
|
23566
25666
|
try {
|
|
23567
|
-
const claudeJson =
|
|
23568
|
-
if (
|
|
23569
|
-
const data = JSON.parse(
|
|
25667
|
+
const claudeJson = join32(slotDir, ".claude.json");
|
|
25668
|
+
if (existsSync35(claudeJson)) {
|
|
25669
|
+
const data = JSON.parse(readFileSync23(claudeJson, "utf-8"));
|
|
23570
25670
|
if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
|
|
23571
25671
|
}
|
|
23572
25672
|
} catch {
|
|
@@ -23581,11 +25681,11 @@ var init_backend_cmd_factory = __esm({
|
|
|
23581
25681
|
envValue: (slotDir) => slotDir,
|
|
23582
25682
|
envOverrides: { OPENAI_API_KEY: void 0 },
|
|
23583
25683
|
verifyCredentials: (slotDir) => {
|
|
23584
|
-
return
|
|
25684
|
+
return existsSync35(join32(slotDir, "auth.json"));
|
|
23585
25685
|
},
|
|
23586
25686
|
extractLabel: (slotDir) => {
|
|
23587
25687
|
try {
|
|
23588
|
-
const authData = JSON.parse(
|
|
25688
|
+
const authData = JSON.parse(readFileSync23(join32(slotDir, "auth.json"), "utf-8"));
|
|
23589
25689
|
if (authData.email) return authData.email;
|
|
23590
25690
|
if (authData.account_name) return authData.account_name;
|
|
23591
25691
|
if (authData.user?.email) return authData.user.email;
|
|
@@ -23605,12 +25705,12 @@ __export(backend_exports, {
|
|
|
23605
25705
|
backendList: () => backendList,
|
|
23606
25706
|
backendSet: () => backendSet
|
|
23607
25707
|
});
|
|
23608
|
-
import { existsSync as
|
|
25708
|
+
import { existsSync as existsSync36 } from "fs";
|
|
23609
25709
|
async function backendList(globalOpts) {
|
|
23610
25710
|
const { getAvailableAdapters: getAvailableAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
23611
25711
|
const chatId = resolveChatId(globalOpts);
|
|
23612
25712
|
let activeBackend = null;
|
|
23613
|
-
if (
|
|
25713
|
+
if (existsSync36(DB_PATH)) {
|
|
23614
25714
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
23615
25715
|
const readDb = openDatabaseReadOnly2();
|
|
23616
25716
|
try {
|
|
@@ -23641,7 +25741,7 @@ async function backendList(globalOpts) {
|
|
|
23641
25741
|
}
|
|
23642
25742
|
async function backendGet(globalOpts) {
|
|
23643
25743
|
const chatId = resolveChatId(globalOpts);
|
|
23644
|
-
if (!
|
|
25744
|
+
if (!existsSync36(DB_PATH)) {
|
|
23645
25745
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
23646
25746
|
process.exit(1);
|
|
23647
25747
|
}
|
|
@@ -23685,13 +25785,13 @@ __export(model_exports, {
|
|
|
23685
25785
|
modelList: () => modelList,
|
|
23686
25786
|
modelSet: () => modelSet
|
|
23687
25787
|
});
|
|
23688
|
-
import { existsSync as
|
|
25788
|
+
import { existsSync as existsSync37 } from "fs";
|
|
23689
25789
|
async function modelList(globalOpts) {
|
|
23690
25790
|
const chatId = resolveChatId(globalOpts);
|
|
23691
25791
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
23692
25792
|
const { getAdapter: getAdapter4, getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
23693
25793
|
let backendId = "claude";
|
|
23694
|
-
if (
|
|
25794
|
+
if (existsSync37(DB_PATH)) {
|
|
23695
25795
|
const readDb = openDatabaseReadOnly2();
|
|
23696
25796
|
try {
|
|
23697
25797
|
const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
|
|
@@ -23724,7 +25824,7 @@ async function modelList(globalOpts) {
|
|
|
23724
25824
|
}
|
|
23725
25825
|
async function modelGet(globalOpts) {
|
|
23726
25826
|
const chatId = resolveChatId(globalOpts);
|
|
23727
|
-
if (!
|
|
25827
|
+
if (!existsSync37(DB_PATH)) {
|
|
23728
25828
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23729
25829
|
process.exit(1);
|
|
23730
25830
|
}
|
|
@@ -23768,9 +25868,9 @@ __export(memory_exports2, {
|
|
|
23768
25868
|
memoryList: () => memoryList,
|
|
23769
25869
|
memorySearch: () => memorySearch
|
|
23770
25870
|
});
|
|
23771
|
-
import { existsSync as
|
|
25871
|
+
import { existsSync as existsSync38 } from "fs";
|
|
23772
25872
|
async function memoryList(globalOpts) {
|
|
23773
|
-
if (!
|
|
25873
|
+
if (!existsSync38(DB_PATH)) {
|
|
23774
25874
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
23775
25875
|
process.exit(1);
|
|
23776
25876
|
}
|
|
@@ -23794,7 +25894,7 @@ async function memoryList(globalOpts) {
|
|
|
23794
25894
|
});
|
|
23795
25895
|
}
|
|
23796
25896
|
async function memorySearch(globalOpts, query) {
|
|
23797
|
-
if (!
|
|
25897
|
+
if (!existsSync38(DB_PATH)) {
|
|
23798
25898
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23799
25899
|
process.exit(1);
|
|
23800
25900
|
}
|
|
@@ -23816,7 +25916,7 @@ async function memorySearch(globalOpts, query) {
|
|
|
23816
25916
|
});
|
|
23817
25917
|
}
|
|
23818
25918
|
async function memoryHistory(globalOpts, opts) {
|
|
23819
|
-
if (!
|
|
25919
|
+
if (!existsSync38(DB_PATH)) {
|
|
23820
25920
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23821
25921
|
process.exit(1);
|
|
23822
25922
|
}
|
|
@@ -23864,7 +25964,7 @@ __export(cron_exports2, {
|
|
|
23864
25964
|
cronList: () => cronList,
|
|
23865
25965
|
cronRuns: () => cronRuns
|
|
23866
25966
|
});
|
|
23867
|
-
import { existsSync as
|
|
25967
|
+
import { existsSync as existsSync39 } from "fs";
|
|
23868
25968
|
function parseFallbacks(raw) {
|
|
23869
25969
|
return raw.slice(0, 3).map((f) => {
|
|
23870
25970
|
const [backend2, ...rest] = f.split(":");
|
|
@@ -23885,7 +25985,7 @@ function parseAndValidateTimeout(raw) {
|
|
|
23885
25985
|
return val;
|
|
23886
25986
|
}
|
|
23887
25987
|
async function cronList(globalOpts) {
|
|
23888
|
-
if (!
|
|
25988
|
+
if (!existsSync39(DB_PATH)) {
|
|
23889
25989
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23890
25990
|
process.exit(1);
|
|
23891
25991
|
}
|
|
@@ -23923,7 +26023,7 @@ async function cronList(globalOpts) {
|
|
|
23923
26023
|
});
|
|
23924
26024
|
}
|
|
23925
26025
|
async function cronHealth(globalOpts) {
|
|
23926
|
-
if (!
|
|
26026
|
+
if (!existsSync39(DB_PATH)) {
|
|
23927
26027
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
23928
26028
|
process.exit(1);
|
|
23929
26029
|
}
|
|
@@ -24082,7 +26182,7 @@ async function cronEdit(globalOpts, id, opts) {
|
|
|
24082
26182
|
}
|
|
24083
26183
|
}
|
|
24084
26184
|
async function cronRuns(globalOpts, jobId, opts) {
|
|
24085
|
-
if (!
|
|
26185
|
+
if (!existsSync39(DB_PATH)) {
|
|
24086
26186
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24087
26187
|
process.exit(1);
|
|
24088
26188
|
}
|
|
@@ -24129,9 +26229,9 @@ __export(agents_exports, {
|
|
|
24129
26229
|
runnersList: () => runnersList,
|
|
24130
26230
|
tasksList: () => tasksList
|
|
24131
26231
|
});
|
|
24132
|
-
import { existsSync as
|
|
26232
|
+
import { existsSync as existsSync40 } from "fs";
|
|
24133
26233
|
async function agentsList(globalOpts) {
|
|
24134
|
-
if (!
|
|
26234
|
+
if (!existsSync40(DB_PATH)) {
|
|
24135
26235
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24136
26236
|
process.exit(1);
|
|
24137
26237
|
}
|
|
@@ -24162,7 +26262,7 @@ async function agentsList(globalOpts) {
|
|
|
24162
26262
|
});
|
|
24163
26263
|
}
|
|
24164
26264
|
async function tasksList(globalOpts) {
|
|
24165
|
-
if (!
|
|
26265
|
+
if (!existsSync40(DB_PATH)) {
|
|
24166
26266
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24167
26267
|
process.exit(1);
|
|
24168
26268
|
}
|
|
@@ -24290,18 +26390,18 @@ __export(db_exports, {
|
|
|
24290
26390
|
dbPath: () => dbPath,
|
|
24291
26391
|
dbStats: () => dbStats
|
|
24292
26392
|
});
|
|
24293
|
-
import { existsSync as
|
|
24294
|
-
import { dirname as
|
|
26393
|
+
import { existsSync as existsSync41, statSync as statSync11, copyFileSync as copyFileSync3, mkdirSync as mkdirSync16 } from "fs";
|
|
26394
|
+
import { dirname as dirname7 } from "path";
|
|
24295
26395
|
async function dbStats(globalOpts) {
|
|
24296
|
-
if (!
|
|
26396
|
+
if (!existsSync41(DB_PATH)) {
|
|
24297
26397
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
24298
26398
|
process.exit(1);
|
|
24299
26399
|
}
|
|
24300
26400
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
24301
26401
|
const readDb = openDatabaseReadOnly2();
|
|
24302
|
-
const mainSize =
|
|
26402
|
+
const mainSize = statSync11(DB_PATH).size;
|
|
24303
26403
|
const walPath = DB_PATH + "-wal";
|
|
24304
|
-
const walSize =
|
|
26404
|
+
const walSize = existsSync41(walPath) ? statSync11(walPath).size : 0;
|
|
24305
26405
|
const tableNames = readDb.prepare(
|
|
24306
26406
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
|
|
24307
26407
|
).all();
|
|
@@ -24335,17 +26435,17 @@ async function dbPath(globalOpts) {
|
|
|
24335
26435
|
output({ path: DB_PATH }, (d) => d.path);
|
|
24336
26436
|
}
|
|
24337
26437
|
async function dbBackup(globalOpts, destPath) {
|
|
24338
|
-
if (!
|
|
26438
|
+
if (!existsSync41(DB_PATH)) {
|
|
24339
26439
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
24340
26440
|
process.exit(1);
|
|
24341
26441
|
}
|
|
24342
26442
|
const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
24343
26443
|
try {
|
|
24344
|
-
|
|
26444
|
+
mkdirSync16(dirname7(dest), { recursive: true });
|
|
24345
26445
|
copyFileSync3(DB_PATH, dest);
|
|
24346
26446
|
const walPath = DB_PATH + "-wal";
|
|
24347
|
-
if (
|
|
24348
|
-
output({ path: dest, sizeBytes:
|
|
26447
|
+
if (existsSync41(walPath)) copyFileSync3(walPath, dest + "-wal");
|
|
26448
|
+
output({ path: dest, sizeBytes: statSync11(dest).size }, (d) => {
|
|
24349
26449
|
const b = d;
|
|
24350
26450
|
return `
|
|
24351
26451
|
${success("Backup created:")} ${b.path} (${(b.sizeBytes / 1024).toFixed(0)}KB)
|
|
@@ -24373,9 +26473,9 @@ __export(usage_exports, {
|
|
|
24373
26473
|
usageCost: () => usageCost,
|
|
24374
26474
|
usageTokens: () => usageTokens
|
|
24375
26475
|
});
|
|
24376
|
-
import { existsSync as
|
|
26476
|
+
import { existsSync as existsSync42 } from "fs";
|
|
24377
26477
|
function ensureDb() {
|
|
24378
|
-
if (!
|
|
26478
|
+
if (!existsSync42(DB_PATH)) {
|
|
24379
26479
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
24380
26480
|
process.exit(1);
|
|
24381
26481
|
}
|
|
@@ -24565,9 +26665,9 @@ __export(config_exports2, {
|
|
|
24565
26665
|
configList: () => configList,
|
|
24566
26666
|
configSet: () => configSet
|
|
24567
26667
|
});
|
|
24568
|
-
import { existsSync as
|
|
26668
|
+
import { existsSync as existsSync43, readFileSync as readFileSync24 } from "fs";
|
|
24569
26669
|
async function configList(globalOpts) {
|
|
24570
|
-
if (!
|
|
26670
|
+
if (!existsSync43(DB_PATH)) {
|
|
24571
26671
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24572
26672
|
process.exit(1);
|
|
24573
26673
|
}
|
|
@@ -24601,7 +26701,7 @@ async function configGet(globalOpts, key) {
|
|
|
24601
26701
|
outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
|
|
24602
26702
|
process.exit(1);
|
|
24603
26703
|
}
|
|
24604
|
-
if (!
|
|
26704
|
+
if (!existsSync43(DB_PATH)) {
|
|
24605
26705
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24606
26706
|
process.exit(1);
|
|
24607
26707
|
}
|
|
@@ -24647,11 +26747,11 @@ async function configSet(globalOpts, key, value) {
|
|
|
24647
26747
|
}
|
|
24648
26748
|
}
|
|
24649
26749
|
async function configEnv(_globalOpts) {
|
|
24650
|
-
if (!
|
|
26750
|
+
if (!existsSync43(ENV_PATH)) {
|
|
24651
26751
|
outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
|
|
24652
26752
|
process.exit(1);
|
|
24653
26753
|
}
|
|
24654
|
-
const content =
|
|
26754
|
+
const content = readFileSync24(ENV_PATH, "utf-8");
|
|
24655
26755
|
const entries = {};
|
|
24656
26756
|
const secretPatterns = /TOKEN|KEY|SECRET|PASSWORD|CREDENTIALS/i;
|
|
24657
26757
|
for (const line of content.split("\n")) {
|
|
@@ -24701,9 +26801,9 @@ __export(session_exports, {
|
|
|
24701
26801
|
sessionGet: () => sessionGet,
|
|
24702
26802
|
sessionNew: () => sessionNew
|
|
24703
26803
|
});
|
|
24704
|
-
import { existsSync as
|
|
26804
|
+
import { existsSync as existsSync44 } from "fs";
|
|
24705
26805
|
async function sessionGet(globalOpts) {
|
|
24706
|
-
if (!
|
|
26806
|
+
if (!existsSync44(DB_PATH)) {
|
|
24707
26807
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24708
26808
|
process.exit(1);
|
|
24709
26809
|
}
|
|
@@ -24764,9 +26864,9 @@ __export(permissions_exports, {
|
|
|
24764
26864
|
verboseGet: () => verboseGet,
|
|
24765
26865
|
verboseSet: () => verboseSet
|
|
24766
26866
|
});
|
|
24767
|
-
import { existsSync as
|
|
26867
|
+
import { existsSync as existsSync45 } from "fs";
|
|
24768
26868
|
function ensureDb2() {
|
|
24769
|
-
if (!
|
|
26869
|
+
if (!existsSync45(DB_PATH)) {
|
|
24770
26870
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24771
26871
|
process.exit(1);
|
|
24772
26872
|
}
|
|
@@ -24913,9 +27013,9 @@ __export(cwd_exports, {
|
|
|
24913
27013
|
cwdGet: () => cwdGet,
|
|
24914
27014
|
cwdSet: () => cwdSet
|
|
24915
27015
|
});
|
|
24916
|
-
import { existsSync as
|
|
27016
|
+
import { existsSync as existsSync46 } from "fs";
|
|
24917
27017
|
async function cwdGet(globalOpts) {
|
|
24918
|
-
if (!
|
|
27018
|
+
if (!existsSync46(DB_PATH)) {
|
|
24919
27019
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24920
27020
|
process.exit(1);
|
|
24921
27021
|
}
|
|
@@ -24977,9 +27077,9 @@ __export(voice_exports, {
|
|
|
24977
27077
|
voiceGet: () => voiceGet,
|
|
24978
27078
|
voiceSet: () => voiceSet
|
|
24979
27079
|
});
|
|
24980
|
-
import { existsSync as
|
|
27080
|
+
import { existsSync as existsSync47 } from "fs";
|
|
24981
27081
|
async function voiceGet(globalOpts) {
|
|
24982
|
-
if (!
|
|
27082
|
+
if (!existsSync47(DB_PATH)) {
|
|
24983
27083
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
24984
27084
|
process.exit(1);
|
|
24985
27085
|
}
|
|
@@ -25028,9 +27128,9 @@ __export(heartbeat_exports, {
|
|
|
25028
27128
|
heartbeatGet: () => heartbeatGet,
|
|
25029
27129
|
heartbeatSet: () => heartbeatSet
|
|
25030
27130
|
});
|
|
25031
|
-
import { existsSync as
|
|
27131
|
+
import { existsSync as existsSync48 } from "fs";
|
|
25032
27132
|
async function heartbeatGet(globalOpts) {
|
|
25033
|
-
if (!
|
|
27133
|
+
if (!existsSync48(DB_PATH)) {
|
|
25034
27134
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25035
27135
|
process.exit(1);
|
|
25036
27136
|
}
|
|
@@ -25139,9 +27239,9 @@ __export(summarizer_exports, {
|
|
|
25139
27239
|
summarizerGet: () => summarizerGet,
|
|
25140
27240
|
summarizerSet: () => summarizerSet
|
|
25141
27241
|
});
|
|
25142
|
-
import { existsSync as
|
|
27242
|
+
import { existsSync as existsSync49 } from "fs";
|
|
25143
27243
|
async function summarizerGet(globalOpts) {
|
|
25144
|
-
if (!
|
|
27244
|
+
if (!existsSync49(DB_PATH)) {
|
|
25145
27245
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25146
27246
|
process.exit(1);
|
|
25147
27247
|
}
|
|
@@ -25185,9 +27285,9 @@ __export(thinking_exports, {
|
|
|
25185
27285
|
thinkingGet: () => thinkingGet,
|
|
25186
27286
|
thinkingSet: () => thinkingSet
|
|
25187
27287
|
});
|
|
25188
|
-
import { existsSync as
|
|
27288
|
+
import { existsSync as existsSync50 } from "fs";
|
|
25189
27289
|
async function thinkingGet(globalOpts) {
|
|
25190
|
-
if (!
|
|
27290
|
+
if (!existsSync50(DB_PATH)) {
|
|
25191
27291
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25192
27292
|
process.exit(1);
|
|
25193
27293
|
}
|
|
@@ -25231,9 +27331,9 @@ __export(chats_exports, {
|
|
|
25231
27331
|
chatsList: () => chatsList,
|
|
25232
27332
|
chatsRemoveAlias: () => chatsRemoveAlias
|
|
25233
27333
|
});
|
|
25234
|
-
import { existsSync as
|
|
27334
|
+
import { existsSync as existsSync51 } from "fs";
|
|
25235
27335
|
async function chatsList(_globalOpts) {
|
|
25236
|
-
if (!
|
|
27336
|
+
if (!existsSync51(DB_PATH)) {
|
|
25237
27337
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25238
27338
|
process.exit(1);
|
|
25239
27339
|
}
|
|
@@ -25361,9 +27461,9 @@ var mcps_exports2 = {};
|
|
|
25361
27461
|
__export(mcps_exports2, {
|
|
25362
27462
|
mcpsList: () => mcpsList
|
|
25363
27463
|
});
|
|
25364
|
-
import { existsSync as
|
|
27464
|
+
import { existsSync as existsSync52 } from "fs";
|
|
25365
27465
|
async function mcpsList(_globalOpts) {
|
|
25366
|
-
if (!
|
|
27466
|
+
if (!existsSync52(DB_PATH)) {
|
|
25367
27467
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
25368
27468
|
process.exit(1);
|
|
25369
27469
|
}
|
|
@@ -25400,11 +27500,11 @@ __export(chat_exports2, {
|
|
|
25400
27500
|
chatSend: () => chatSend
|
|
25401
27501
|
});
|
|
25402
27502
|
import { request as httpRequest2 } from "http";
|
|
25403
|
-
import { readFileSync as
|
|
27503
|
+
import { readFileSync as readFileSync25, existsSync as existsSync53 } from "fs";
|
|
25404
27504
|
function getToken2() {
|
|
25405
27505
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
25406
27506
|
try {
|
|
25407
|
-
if (
|
|
27507
|
+
if (existsSync53(TOKEN_PATH2)) return readFileSync25(TOKEN_PATH2, "utf-8").trim();
|
|
25408
27508
|
} catch {
|
|
25409
27509
|
}
|
|
25410
27510
|
return null;
|
|
@@ -25541,7 +27641,7 @@ var tui_exports = {};
|
|
|
25541
27641
|
__export(tui_exports, {
|
|
25542
27642
|
tuiCommand: () => tuiCommand
|
|
25543
27643
|
});
|
|
25544
|
-
import { createInterface as
|
|
27644
|
+
import { createInterface as createInterface9 } from "readline";
|
|
25545
27645
|
import pc2 from "picocolors";
|
|
25546
27646
|
async function tuiCommand(globalOpts, cmdOpts) {
|
|
25547
27647
|
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
@@ -25551,7 +27651,7 @@ async function tuiCommand(globalOpts, cmdOpts) {
|
|
|
25551
27651
|
}
|
|
25552
27652
|
const chatId = resolveChatId(globalOpts);
|
|
25553
27653
|
const { chatSend: chatSend2 } = await Promise.resolve().then(() => (init_chat2(), chat_exports2));
|
|
25554
|
-
const rl2 =
|
|
27654
|
+
const rl2 = createInterface9({
|
|
25555
27655
|
input: process.stdin,
|
|
25556
27656
|
output: process.stdout,
|
|
25557
27657
|
prompt: pc2.cyan("you > "),
|
|
@@ -25683,9 +27783,9 @@ var completion_exports = {};
|
|
|
25683
27783
|
__export(completion_exports, {
|
|
25684
27784
|
completionCommand: () => completionCommand
|
|
25685
27785
|
});
|
|
25686
|
-
import { writeFileSync as
|
|
25687
|
-
import { join as
|
|
25688
|
-
import { homedir as
|
|
27786
|
+
import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync17 } from "fs";
|
|
27787
|
+
import { join as join33 } from "path";
|
|
27788
|
+
import { homedir as homedir11 } from "os";
|
|
25689
27789
|
async function completionCommand(opts) {
|
|
25690
27790
|
const shell = opts.shell ?? detectShell();
|
|
25691
27791
|
let script;
|
|
@@ -25700,11 +27800,11 @@ async function completionCommand(opts) {
|
|
|
25700
27800
|
process.exit(1);
|
|
25701
27801
|
}
|
|
25702
27802
|
if (opts.install) {
|
|
25703
|
-
const dir =
|
|
25704
|
-
|
|
27803
|
+
const dir = join33(homedir11(), ".config", "cc-claw", "completions");
|
|
27804
|
+
mkdirSync17(dir, { recursive: true });
|
|
25705
27805
|
const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
|
|
25706
|
-
const filepath =
|
|
25707
|
-
|
|
27806
|
+
const filepath = join33(dir, filename);
|
|
27807
|
+
writeFileSync11(filepath, script, "utf-8");
|
|
25708
27808
|
console.log(`\u2713 Completion script written to ${filepath}
|
|
25709
27809
|
`);
|
|
25710
27810
|
if (shell === "zsh") {
|
|
@@ -25874,9 +27974,9 @@ __export(evolve_exports2, {
|
|
|
25874
27974
|
evolveStatus: () => evolveStatus,
|
|
25875
27975
|
evolveUndo: () => evolveUndo
|
|
25876
27976
|
});
|
|
25877
|
-
import { existsSync as
|
|
27977
|
+
import { existsSync as existsSync54 } from "fs";
|
|
25878
27978
|
function ensureDb3() {
|
|
25879
|
-
if (!
|
|
27979
|
+
if (!existsSync54(DB_PATH)) {
|
|
25880
27980
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
25881
27981
|
process.exit(1);
|
|
25882
27982
|
}
|
|
@@ -26290,12 +28390,70 @@ var init_evolve3 = __esm({
|
|
|
26290
28390
|
}
|
|
26291
28391
|
});
|
|
26292
28392
|
|
|
28393
|
+
// src/cli/commands/optimize.ts
|
|
28394
|
+
var optimize_exports = {};
|
|
28395
|
+
__export(optimize_exports, {
|
|
28396
|
+
optimizeSkills: () => optimizeSkills,
|
|
28397
|
+
optimizeStatus: () => optimizeStatus
|
|
28398
|
+
});
|
|
28399
|
+
async function optimizeStatus() {
|
|
28400
|
+
const { listCcClawSkills: listCcClawSkills2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
28401
|
+
const skills2 = listCcClawSkills2();
|
|
28402
|
+
output({
|
|
28403
|
+
status: "ok",
|
|
28404
|
+
description: "Run identity and skill audits via Telegram with /optimize",
|
|
28405
|
+
availableSkills: skills2.length,
|
|
28406
|
+
skillNames: skills2.map((s) => s.name)
|
|
28407
|
+
}, () => {
|
|
28408
|
+
const lines = [
|
|
28409
|
+
box("\u{1F527} CC-Claw Optimizer"),
|
|
28410
|
+
"",
|
|
28411
|
+
" Use /optimize in Telegram for the interactive audit experience.",
|
|
28412
|
+
"",
|
|
28413
|
+
divider("CLI subcommands"),
|
|
28414
|
+
kvLine("skills", "List available CC-Claw skills"),
|
|
28415
|
+
"",
|
|
28416
|
+
muted(` \u{1F4CA} ${skills2.length} skill(s) available for audit`),
|
|
28417
|
+
""
|
|
28418
|
+
];
|
|
28419
|
+
return lines.join("\n");
|
|
28420
|
+
});
|
|
28421
|
+
}
|
|
28422
|
+
async function optimizeSkills() {
|
|
28423
|
+
const { listCcClawSkills: listCcClawSkills2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
|
|
28424
|
+
const skills2 = listCcClawSkills2();
|
|
28425
|
+
output({
|
|
28426
|
+
status: "ok",
|
|
28427
|
+
skills: skills2.map((s) => ({ name: s.name, path: s.path, description: s.description })),
|
|
28428
|
+
count: skills2.length
|
|
28429
|
+
}, () => {
|
|
28430
|
+
if (skills2.length === 0) {
|
|
28431
|
+
return " No CC-Claw skills found in ~/.cc-claw/workspace/skills/";
|
|
28432
|
+
}
|
|
28433
|
+
const lines = [
|
|
28434
|
+
box("\u{1F9E9} CC-Claw Skills"),
|
|
28435
|
+
"",
|
|
28436
|
+
...skills2.map((s) => kvLine(s.name, s.description)),
|
|
28437
|
+
"",
|
|
28438
|
+
muted(` ${skills2.length} skill(s) \u2014 use /optimize in Telegram to audit`),
|
|
28439
|
+
""
|
|
28440
|
+
];
|
|
28441
|
+
return lines.join("\n");
|
|
28442
|
+
});
|
|
28443
|
+
}
|
|
28444
|
+
var init_optimize2 = __esm({
|
|
28445
|
+
"src/cli/commands/optimize.ts"() {
|
|
28446
|
+
"use strict";
|
|
28447
|
+
init_format2();
|
|
28448
|
+
}
|
|
28449
|
+
});
|
|
28450
|
+
|
|
26293
28451
|
// src/setup.ts
|
|
26294
28452
|
var setup_exports = {};
|
|
26295
|
-
import { existsSync as
|
|
28453
|
+
import { existsSync as existsSync55, writeFileSync as writeFileSync12, readFileSync as readFileSync26, copyFileSync as copyFileSync4, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
|
|
26296
28454
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
26297
|
-
import { createInterface as
|
|
26298
|
-
import { join as
|
|
28455
|
+
import { createInterface as createInterface10 } from "readline";
|
|
28456
|
+
import { join as join34 } from "path";
|
|
26299
28457
|
function divider2() {
|
|
26300
28458
|
console.log(dim("\u2500".repeat(55)));
|
|
26301
28459
|
}
|
|
@@ -26370,22 +28528,22 @@ async function setup() {
|
|
|
26370
28528
|
}
|
|
26371
28529
|
console.log("");
|
|
26372
28530
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
26373
|
-
if (!
|
|
28531
|
+
if (!existsSync55(dir)) mkdirSync18(dir, { recursive: true });
|
|
26374
28532
|
}
|
|
26375
28533
|
const env = {};
|
|
26376
|
-
const envSource =
|
|
28534
|
+
const envSource = existsSync55(ENV_PATH) ? ENV_PATH : existsSync55(".env") ? ".env" : null;
|
|
26377
28535
|
if (envSource) {
|
|
26378
28536
|
console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
|
|
26379
28537
|
console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
|
|
26380
|
-
const existing =
|
|
28538
|
+
const existing = readFileSync26(envSource, "utf-8");
|
|
26381
28539
|
for (const line of existing.split("\n")) {
|
|
26382
28540
|
const match = line.match(/^([^#=]+)=(.*)$/);
|
|
26383
28541
|
if (match) env[match[1].trim()] = match[2].trim();
|
|
26384
28542
|
}
|
|
26385
28543
|
}
|
|
26386
|
-
const cwdDb =
|
|
26387
|
-
if (
|
|
26388
|
-
const { size } =
|
|
28544
|
+
const cwdDb = join34(process.cwd(), "cc-claw.db");
|
|
28545
|
+
if (existsSync55(cwdDb) && !existsSync55(DB_PATH)) {
|
|
28546
|
+
const { size } = statSync12(cwdDb);
|
|
26389
28547
|
console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
|
|
26390
28548
|
const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
|
|
26391
28549
|
if (migrate) {
|
|
@@ -26601,7 +28759,7 @@ async function setup() {
|
|
|
26601
28759
|
envLines.push("", "# Video Analysis", `GEMINI_API_KEY=${env.GEMINI_API_KEY}`);
|
|
26602
28760
|
}
|
|
26603
28761
|
const envContent = envLines.join("\n") + "\n";
|
|
26604
|
-
|
|
28762
|
+
writeFileSync12(ENV_PATH, envContent, { mode: 384 });
|
|
26605
28763
|
console.log(green(` Config saved to ${ENV_PATH} (permissions: owner-only)`));
|
|
26606
28764
|
header(6, TOTAL_STEPS, "Run on Startup (Daemon)");
|
|
26607
28765
|
console.log(" CC-Claw can run automatically in the background, starting");
|
|
@@ -26657,7 +28815,7 @@ var init_setup = __esm({
|
|
|
26657
28815
|
"src/setup.ts"() {
|
|
26658
28816
|
"use strict";
|
|
26659
28817
|
init_paths();
|
|
26660
|
-
rl =
|
|
28818
|
+
rl = createInterface10({ input: process.stdin, output: process.stdout });
|
|
26661
28819
|
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
26662
28820
|
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
26663
28821
|
green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
@@ -26726,6 +28884,19 @@ program.command("logs").description("Tail daemon logs").option("-f, --follow", "
|
|
|
26726
28884
|
const { logsCommand: logsCommand2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
|
|
26727
28885
|
await logsCommand2(opts);
|
|
26728
28886
|
});
|
|
28887
|
+
var sessionLogs = program.command("session-logs").description("Manage session debug logs (enable via /debug in Telegram)");
|
|
28888
|
+
sessionLogs.command("list").description("List all session debug logs").action(async () => {
|
|
28889
|
+
const { sessionLogsList: sessionLogsList2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
|
|
28890
|
+
await sessionLogsList2(program.opts());
|
|
28891
|
+
});
|
|
28892
|
+
sessionLogs.command("tail").description("Tail latest (or specific) session log").option("-f, --follow", "Follow mode (like tail -f)").option("--file <name>", "Specific log file (partial match)").option("--lines <n>", "Number of lines", "50").action(async (opts) => {
|
|
28893
|
+
const { sessionLogsTail: sessionLogsTail2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
|
|
28894
|
+
await sessionLogsTail2(opts);
|
|
28895
|
+
});
|
|
28896
|
+
sessionLogs.command("clean").description("Remove old session logs").option("--days <n>", "Remove logs older than N days").action(async (opts) => {
|
|
28897
|
+
const { sessionLogsClean: sessionLogsClean2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
|
|
28898
|
+
await sessionLogsClean2(opts);
|
|
28899
|
+
});
|
|
26729
28900
|
var gemini = program.command("gemini").description("Manage Gemini credential slots for rotation");
|
|
26730
28901
|
gemini.command("list").description("Show all configured Gemini credential slots").action(async () => {
|
|
26731
28902
|
const { geminiList: geminiList2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
|
|
@@ -27182,6 +29353,15 @@ evolve.command("settings").description("View or update reflection settings").opt
|
|
|
27182
29353
|
const { evolveSettings: evolveSettings2 } = await Promise.resolve().then(() => (init_evolve3(), evolve_exports2));
|
|
27183
29354
|
await evolveSettings2(program.opts(), opts);
|
|
27184
29355
|
});
|
|
29356
|
+
var optimize = program.command("optimize").description("Audit identity files and skills");
|
|
29357
|
+
optimize.action(async () => {
|
|
29358
|
+
const { optimizeStatus: optimizeStatus2 } = await Promise.resolve().then(() => (init_optimize2(), optimize_exports));
|
|
29359
|
+
await optimizeStatus2();
|
|
29360
|
+
});
|
|
29361
|
+
optimize.command("skills").description("List available CC-Claw skills").action(async () => {
|
|
29362
|
+
const { optimizeSkills: optimizeSkills2 } = await Promise.resolve().then(() => (init_optimize2(), optimize_exports));
|
|
29363
|
+
await optimizeSkills2();
|
|
29364
|
+
});
|
|
27185
29365
|
program.command("start", { hidden: true }).description("Run the bot in the foreground (use 'service start' for background daemon)").action(async () => {
|
|
27186
29366
|
await Promise.resolve().then(() => (init_index(), index_exports));
|
|
27187
29367
|
});
|