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