cc-claw 0.12.1 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +685 -220
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -72,7 +72,7 @@ var VERSION;
|
|
|
72
72
|
var init_version = __esm({
|
|
73
73
|
"src/version.ts"() {
|
|
74
74
|
"use strict";
|
|
75
|
-
VERSION = true ? "0.12.
|
|
75
|
+
VERSION = true ? "0.12.3" : (() => {
|
|
76
76
|
try {
|
|
77
77
|
return JSON.parse(readFileSync(join2(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
78
78
|
} catch {
|
|
@@ -153,6 +153,9 @@ function migrateAgentColumns(db3) {
|
|
|
153
153
|
if (!colNames.has("name")) db3.exec("ALTER TABLE agents ADD COLUMN name TEXT");
|
|
154
154
|
if (!colNames.has("description")) db3.exec("ALTER TABLE agents ADD COLUMN description TEXT");
|
|
155
155
|
if (!colNames.has("persona")) db3.exec("ALTER TABLE agents ADD COLUMN persona TEXT");
|
|
156
|
+
if (!colNames.has("stderr")) db3.exec("ALTER TABLE agents ADD COLUMN stderr TEXT");
|
|
157
|
+
if (!colNames.has("durationMs")) db3.exec("ALTER TABLE agents ADD COLUMN durationMs INTEGER");
|
|
158
|
+
if (!colNames.has("signal")) db3.exec("ALTER TABLE agents ADD COLUMN signal TEXT");
|
|
156
159
|
}
|
|
157
160
|
function initAgentTables(db3) {
|
|
158
161
|
db3.exec(`
|
|
@@ -329,10 +332,21 @@ function updateAgentOutput(db3, id) {
|
|
|
329
332
|
function updateAgentResult(db3, id, opts) {
|
|
330
333
|
db3.prepare(`
|
|
331
334
|
UPDATE agents SET exitCode = ?, resultSummary = ?, tokenInput = ?, tokenOutput = ?,
|
|
335
|
+
stderr = ?, durationMs = ?, signal = ?,
|
|
332
336
|
status = CASE WHEN ? = 0 THEN 'completed' ELSE 'failed' END,
|
|
333
337
|
completedAt = datetime('now')
|
|
334
338
|
WHERE id = ?
|
|
335
|
-
`).run(
|
|
339
|
+
`).run(
|
|
340
|
+
opts.exitCode,
|
|
341
|
+
opts.resultSummary ?? null,
|
|
342
|
+
opts.tokenInput ?? 0,
|
|
343
|
+
opts.tokenOutput ?? 0,
|
|
344
|
+
opts.stderr ?? null,
|
|
345
|
+
opts.durationMs ?? null,
|
|
346
|
+
opts.signal ?? null,
|
|
347
|
+
opts.exitCode,
|
|
348
|
+
id
|
|
349
|
+
);
|
|
336
350
|
}
|
|
337
351
|
function updateAgentMcpsAdded(db3, id, mcps2) {
|
|
338
352
|
db3.prepare("UPDATE agents SET mcpsAdded = ? WHERE id = ?").run(JSON.stringify(mcps2), id);
|
|
@@ -678,8 +692,12 @@ var init_identity = __esm({
|
|
|
678
692
|
// src/reflection/store.ts
|
|
679
693
|
var store_exports4 = {};
|
|
680
694
|
__export(store_exports4, {
|
|
695
|
+
advanceReviewSession: () => advanceReviewSession,
|
|
681
696
|
cleanupBackupFiles: () => cleanupBackupFiles,
|
|
682
697
|
cleanupReflectionData: () => cleanupReflectionData,
|
|
698
|
+
createReviewSession: () => createReviewSession,
|
|
699
|
+
deleteReviewSession: () => deleteReviewSession,
|
|
700
|
+
getAppliedCountTodayForFile: () => getAppliedCountTodayForFile,
|
|
683
701
|
getAppliedInsightCountToday: () => getAppliedInsightCountToday,
|
|
684
702
|
getAppliedInsights: () => getAppliedInsights,
|
|
685
703
|
getGrowthMetrics: () => getGrowthMetrics,
|
|
@@ -688,8 +706,10 @@ __export(store_exports4, {
|
|
|
688
706
|
getPendingInsightCount: () => getPendingInsightCount,
|
|
689
707
|
getPendingInsights: () => getPendingInsights,
|
|
690
708
|
getReflectionModelConfig: () => getReflectionModelConfig,
|
|
709
|
+
getReflectionSettings: () => getReflectionSettings,
|
|
691
710
|
getReflectionStatus: () => getReflectionStatus,
|
|
692
711
|
getRejectedInsights: () => getRejectedInsights,
|
|
712
|
+
getReviewSession: () => getReviewSession,
|
|
693
713
|
getSignalCountForChat: () => getSignalCountForChat,
|
|
694
714
|
getUnprocessedSignalCount: () => getUnprocessedSignalCount,
|
|
695
715
|
getUnprocessedSignals: () => getUnprocessedSignals,
|
|
@@ -698,6 +718,7 @@ __export(store_exports4, {
|
|
|
698
718
|
logSignal: () => logSignal,
|
|
699
719
|
markSignalsProcessed: () => markSignalsProcessed,
|
|
700
720
|
setReflectionModelConfig: () => setReflectionModelConfig,
|
|
721
|
+
setReflectionSettings: () => setReflectionSettings,
|
|
701
722
|
setReflectionStatus: () => setReflectionStatus,
|
|
702
723
|
updateInsightEffectiveness: () => updateInsightEffectiveness,
|
|
703
724
|
updateInsightProposal: () => updateInsightProposal,
|
|
@@ -707,16 +728,37 @@ __export(store_exports4, {
|
|
|
707
728
|
});
|
|
708
729
|
import { existsSync, readdirSync, statSync, unlinkSync } from "fs";
|
|
709
730
|
import { join as join3 } from "path";
|
|
710
|
-
function cleanupBackupFiles(ccClawHome) {
|
|
711
|
-
const
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
731
|
+
function cleanupBackupFiles(ccClawHome, retentionDays = 7) {
|
|
732
|
+
const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
733
|
+
const dirs = [
|
|
734
|
+
join3(ccClawHome, "identity"),
|
|
735
|
+
join3(ccClawHome, "workspace", "context")
|
|
736
|
+
];
|
|
737
|
+
const skillsRoot = join3(ccClawHome, "workspace", "skills");
|
|
738
|
+
try {
|
|
739
|
+
if (existsSync(skillsRoot)) {
|
|
740
|
+
for (const entry of readdirSync(skillsRoot)) {
|
|
741
|
+
const p = join3(skillsRoot, entry);
|
|
742
|
+
try {
|
|
743
|
+
if (statSync(p).isDirectory()) dirs.push(p);
|
|
744
|
+
} catch {
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
} catch {
|
|
749
|
+
}
|
|
750
|
+
for (const dir of dirs) {
|
|
751
|
+
if (!existsSync(dir)) continue;
|
|
717
752
|
try {
|
|
718
|
-
const
|
|
719
|
-
|
|
753
|
+
for (const file of readdirSync(dir)) {
|
|
754
|
+
if (!file.includes(".bak.")) continue;
|
|
755
|
+
const fullPath = join3(dir, file);
|
|
756
|
+
try {
|
|
757
|
+
const stat2 = statSync(fullPath);
|
|
758
|
+
if (stat2.mtimeMs < cutoffMs) unlinkSync(fullPath);
|
|
759
|
+
} catch {
|
|
760
|
+
}
|
|
761
|
+
}
|
|
720
762
|
} catch {
|
|
721
763
|
}
|
|
722
764
|
}
|
|
@@ -792,9 +834,25 @@ function initReflectionTables(db3) {
|
|
|
792
834
|
model TEXT,
|
|
793
835
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
794
836
|
);
|
|
837
|
+
|
|
838
|
+
CREATE TABLE IF NOT EXISTS review_sessions (
|
|
839
|
+
chatId TEXT PRIMARY KEY,
|
|
840
|
+
insightIds TEXT NOT NULL,
|
|
841
|
+
currentIndex INTEGER NOT NULL DEFAULT 0,
|
|
842
|
+
results TEXT NOT NULL DEFAULT '{}',
|
|
843
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
844
|
+
);
|
|
845
|
+
|
|
846
|
+
CREATE TABLE IF NOT EXISTS reflection_settings (
|
|
847
|
+
chatId TEXT PRIMARY KEY,
|
|
848
|
+
perFileCap INTEGER NOT NULL DEFAULT 3,
|
|
849
|
+
backupRetentionDays INTEGER NOT NULL DEFAULT 7,
|
|
850
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
851
|
+
);
|
|
795
852
|
`);
|
|
796
853
|
cleanupReflectionData(db3);
|
|
797
|
-
|
|
854
|
+
const settings = getReflectionSettings(db3, "global");
|
|
855
|
+
cleanupBackupFiles(CC_CLAW_HOME, settings.backupRetentionDays);
|
|
798
856
|
}
|
|
799
857
|
function logSignal(db3, params) {
|
|
800
858
|
const result = db3.prepare(`
|
|
@@ -939,6 +997,13 @@ function getAppliedInsightCountToday(db3, chatId) {
|
|
|
939
997
|
`).get(chatId);
|
|
940
998
|
return row.count;
|
|
941
999
|
}
|
|
1000
|
+
function getAppliedCountTodayForFile(db3, chatId, targetFile) {
|
|
1001
|
+
const row = db3.prepare(`
|
|
1002
|
+
SELECT COUNT(*) as count FROM insights
|
|
1003
|
+
WHERE chatId = ? AND status = 'applied' AND targetFile = ? AND appliedAt >= date('now') AND appliedAt < date('now', '+1 day')
|
|
1004
|
+
`).get(chatId, targetFile);
|
|
1005
|
+
return row.count;
|
|
1006
|
+
}
|
|
942
1007
|
function upsertGrowthMetric(db3, chatId, period, data) {
|
|
943
1008
|
db3.prepare(`
|
|
944
1009
|
INSERT OR REPLACE INTO growth_metrics (chatId, period, corrections, praises, errors, insightsApplied)
|
|
@@ -966,6 +1031,58 @@ function setReflectionModelConfig(db3, chatId, mode, backend2, model2) {
|
|
|
966
1031
|
VALUES (?, ?, ?, ?)
|
|
967
1032
|
`).run(chatId, mode, backend2 ?? null, model2 ?? null);
|
|
968
1033
|
}
|
|
1034
|
+
function createReviewSession(db3, chatId, insightIds) {
|
|
1035
|
+
db3.prepare(`
|
|
1036
|
+
INSERT OR REPLACE INTO review_sessions (chatId, insightIds, currentIndex, results)
|
|
1037
|
+
VALUES (?, ?, 0, '{}')
|
|
1038
|
+
`).run(chatId, JSON.stringify(insightIds));
|
|
1039
|
+
}
|
|
1040
|
+
function getReviewSession(db3, chatId) {
|
|
1041
|
+
const row = db3.prepare(
|
|
1042
|
+
"SELECT * FROM review_sessions WHERE chatId = ?"
|
|
1043
|
+
).get(chatId);
|
|
1044
|
+
if (!row) return null;
|
|
1045
|
+
return {
|
|
1046
|
+
chatId: row.chatId,
|
|
1047
|
+
insightIds: JSON.parse(row.insightIds),
|
|
1048
|
+
currentIndex: row.currentIndex,
|
|
1049
|
+
results: JSON.parse(row.results),
|
|
1050
|
+
created_at: row.created_at
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
function advanceReviewSession(db3, chatId, insightId, action) {
|
|
1054
|
+
const session2 = getReviewSession(db3, chatId);
|
|
1055
|
+
if (!session2) return null;
|
|
1056
|
+
session2.results[insightId] = action;
|
|
1057
|
+
session2.currentIndex = session2.currentIndex + 1;
|
|
1058
|
+
db3.prepare(`
|
|
1059
|
+
UPDATE review_sessions SET currentIndex = ?, results = ? WHERE chatId = ?
|
|
1060
|
+
`).run(session2.currentIndex, JSON.stringify(session2.results), chatId);
|
|
1061
|
+
return session2;
|
|
1062
|
+
}
|
|
1063
|
+
function deleteReviewSession(db3, chatId) {
|
|
1064
|
+
db3.prepare("DELETE FROM review_sessions WHERE chatId = ?").run(chatId);
|
|
1065
|
+
}
|
|
1066
|
+
function getReflectionSettings(db3, chatId) {
|
|
1067
|
+
const row = db3.prepare(
|
|
1068
|
+
"SELECT perFileCap, backupRetentionDays FROM reflection_settings WHERE chatId = ?"
|
|
1069
|
+
).get(chatId);
|
|
1070
|
+
return {
|
|
1071
|
+
perFileCap: row?.perFileCap ?? 3,
|
|
1072
|
+
backupRetentionDays: row?.backupRetentionDays ?? 7
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
function setReflectionSettings(db3, chatId, settings) {
|
|
1076
|
+
const current = getReflectionSettings(db3, chatId);
|
|
1077
|
+
db3.prepare(`
|
|
1078
|
+
INSERT OR REPLACE INTO reflection_settings (chatId, perFileCap, backupRetentionDays)
|
|
1079
|
+
VALUES (?, ?, ?)
|
|
1080
|
+
`).run(
|
|
1081
|
+
chatId,
|
|
1082
|
+
settings.perFileCap ?? current.perFileCap,
|
|
1083
|
+
settings.backupRetentionDays ?? current.backupRetentionDays
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
969
1086
|
function cleanupReflectionData(db3) {
|
|
970
1087
|
db3.prepare(`
|
|
971
1088
|
DELETE FROM feedback_signals WHERE created_at < datetime('now', '-90 days')
|
|
@@ -976,6 +1093,9 @@ function cleanupReflectionData(db3) {
|
|
|
976
1093
|
db3.prepare(`
|
|
977
1094
|
DELETE FROM growth_metrics WHERE created_at < datetime('now', '-365 days')
|
|
978
1095
|
`).run();
|
|
1096
|
+
db3.prepare(`
|
|
1097
|
+
DELETE FROM review_sessions WHERE created_at < datetime('now', '-1 day')
|
|
1098
|
+
`).run();
|
|
979
1099
|
}
|
|
980
1100
|
var init_store4 = __esm({
|
|
981
1101
|
"src/reflection/store.ts"() {
|
|
@@ -3357,13 +3477,25 @@ var init_claude = __esm({
|
|
|
3357
3477
|
import { existsSync as existsSync3 } from "fs";
|
|
3358
3478
|
import { execSync as execSync2 } from "child_process";
|
|
3359
3479
|
import { join as join5 } from "path";
|
|
3360
|
-
|
|
3480
|
+
function stripThinkingContent(text) {
|
|
3481
|
+
let result = text;
|
|
3482
|
+
for (const pattern of THINKING_PATTERNS) {
|
|
3483
|
+
result = result.replace(pattern, "");
|
|
3484
|
+
}
|
|
3485
|
+
return result.trim();
|
|
3486
|
+
}
|
|
3487
|
+
var THINKING_PATTERNS, GeminiAdapter;
|
|
3361
3488
|
var init_gemini = __esm({
|
|
3362
3489
|
"src/backends/gemini.ts"() {
|
|
3363
3490
|
"use strict";
|
|
3364
3491
|
init_store5();
|
|
3365
3492
|
init_env();
|
|
3366
3493
|
init_paths();
|
|
3494
|
+
THINKING_PATTERNS = [
|
|
3495
|
+
/<think>[\s\S]*?<\/think>/gi,
|
|
3496
|
+
/<thinking>[\s\S]*?<\/thinking>/gi,
|
|
3497
|
+
/\[Thought:\s*true\][\s\S]*?(?:\[\/Thought\]|\[Thought:\s*false\])/gi
|
|
3498
|
+
];
|
|
3367
3499
|
GeminiAdapter = class {
|
|
3368
3500
|
id = "gemini";
|
|
3369
3501
|
displayName = "Gemini";
|
|
@@ -3473,8 +3605,12 @@ var init_gemini = __esm({
|
|
|
3473
3605
|
if (line.type === "init") {
|
|
3474
3606
|
events.push({ type: "init", sessionId: line.session_id });
|
|
3475
3607
|
} else if (line.type === "message" && line.role === "assistant") {
|
|
3476
|
-
if (line.
|
|
3477
|
-
|
|
3608
|
+
if (line.thought === true) {
|
|
3609
|
+
} else if (line.content) {
|
|
3610
|
+
const cleaned = stripThinkingContent(line.content);
|
|
3611
|
+
if (cleaned) {
|
|
3612
|
+
events.push({ type: "text", text: cleaned });
|
|
3613
|
+
}
|
|
3478
3614
|
}
|
|
3479
3615
|
} else if (line.type === "tool_use") {
|
|
3480
3616
|
events.push({
|
|
@@ -5328,6 +5464,7 @@ function spawnAgentProcess(runner, opts, callbacks) {
|
|
|
5328
5464
|
const rl2 = createInterface2({ input: child.stdout });
|
|
5329
5465
|
rl2.on("line", (line) => {
|
|
5330
5466
|
try {
|
|
5467
|
+
callbacks.onRawLine?.(line);
|
|
5331
5468
|
const raw = JSON.parse(line);
|
|
5332
5469
|
const events = runner.parseLine(raw);
|
|
5333
5470
|
for (const event of events) {
|
|
@@ -5682,6 +5819,103 @@ var init_loader2 = __esm({
|
|
|
5682
5819
|
}
|
|
5683
5820
|
});
|
|
5684
5821
|
|
|
5822
|
+
// src/agents/agent-log.ts
|
|
5823
|
+
import { writeFileSync as writeFileSync3, readdirSync as readdirSync5, statSync as statSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
5824
|
+
import { join as join10 } from "path";
|
|
5825
|
+
function truncate(text, maxBytes) {
|
|
5826
|
+
if (Buffer.byteLength(text, "utf-8") <= maxBytes) return text;
|
|
5827
|
+
let lo = 0, hi = text.length;
|
|
5828
|
+
while (lo < hi) {
|
|
5829
|
+
const mid = lo + hi + 1 >>> 1;
|
|
5830
|
+
if (Buffer.byteLength(text.slice(0, mid), "utf-8") <= maxBytes) lo = mid;
|
|
5831
|
+
else hi = mid - 1;
|
|
5832
|
+
}
|
|
5833
|
+
const truncated = text.slice(0, lo);
|
|
5834
|
+
const droppedBytes = Buffer.byteLength(text, "utf-8") - Buffer.byteLength(truncated, "utf-8");
|
|
5835
|
+
return truncated + `
|
|
5836
|
+
[...truncated ${droppedBytes} bytes...]`;
|
|
5837
|
+
}
|
|
5838
|
+
function writeAgentLog(data) {
|
|
5839
|
+
const logPath = join10(AGENTS_PATH, `${data.agentId}.log`);
|
|
5840
|
+
const exitDisplay = data.exitCodeForced ? `${data.exitCode} (forced \u2014 no output from original exit code 0)` : String(data.exitCode ?? "null");
|
|
5841
|
+
const stderrContent = truncate(data.stderr || "(empty)", MAX_STDERR_BYTES);
|
|
5842
|
+
const stdoutContent = truncate(data.rawStdoutLines.join("\n") || "(empty)", MAX_STDOUT_BYTES);
|
|
5843
|
+
const lines = [
|
|
5844
|
+
"=== Agent Execution Log ===",
|
|
5845
|
+
`Agent ID: ${data.agentId}`,
|
|
5846
|
+
`Runner: ${data.runner}`,
|
|
5847
|
+
`Model: ${data.model}`,
|
|
5848
|
+
`Task: ${data.task.slice(0, 200)}${data.task.length > 200 ? "..." : ""}`,
|
|
5849
|
+
`Started: ${data.startedAt.toISOString()}`,
|
|
5850
|
+
`Duration: ${data.durationMs}ms`,
|
|
5851
|
+
`Exit Code: ${exitDisplay}`,
|
|
5852
|
+
`Signal: ${data.signal ?? "null"}`,
|
|
5853
|
+
`Tokens: ${data.tokenInput} in / ${data.tokenOutput} out`,
|
|
5854
|
+
"",
|
|
5855
|
+
"--- STDERR ---",
|
|
5856
|
+
stderrContent,
|
|
5857
|
+
"",
|
|
5858
|
+
"--- STDOUT (raw NDJSON lines) ---",
|
|
5859
|
+
stdoutContent,
|
|
5860
|
+
""
|
|
5861
|
+
];
|
|
5862
|
+
try {
|
|
5863
|
+
mkdirSync3(AGENTS_PATH, { recursive: true });
|
|
5864
|
+
writeFileSync3(logPath, lines.join("\n"), "utf-8");
|
|
5865
|
+
} catch (err) {
|
|
5866
|
+
log(`[agent-log] Failed to write log for ${data.agentId}: ${err}`);
|
|
5867
|
+
}
|
|
5868
|
+
return logPath;
|
|
5869
|
+
}
|
|
5870
|
+
function pruneAgentLogs() {
|
|
5871
|
+
try {
|
|
5872
|
+
mkdirSync3(AGENTS_PATH, { recursive: true });
|
|
5873
|
+
const files = readdirSync5(AGENTS_PATH).filter((f) => f.endsWith(".log")).map((f) => {
|
|
5874
|
+
const fullPath = join10(AGENTS_PATH, f);
|
|
5875
|
+
const stat2 = statSync3(fullPath);
|
|
5876
|
+
return { path: fullPath, mtime: stat2.mtimeMs, size: stat2.size };
|
|
5877
|
+
});
|
|
5878
|
+
const now = Date.now();
|
|
5879
|
+
const remaining = files.filter((f) => {
|
|
5880
|
+
if (now - f.mtime > MAX_AGE_MS) {
|
|
5881
|
+
try {
|
|
5882
|
+
unlinkSync4(f.path);
|
|
5883
|
+
} catch {
|
|
5884
|
+
}
|
|
5885
|
+
return false;
|
|
5886
|
+
}
|
|
5887
|
+
return true;
|
|
5888
|
+
});
|
|
5889
|
+
remaining.sort((a, b) => a.mtime - b.mtime);
|
|
5890
|
+
let totalSize = remaining.reduce((sum, f) => sum + f.size, 0);
|
|
5891
|
+
for (const f of remaining) {
|
|
5892
|
+
if (totalSize <= MAX_DIR_BYTES) break;
|
|
5893
|
+
try {
|
|
5894
|
+
unlinkSync4(f.path);
|
|
5895
|
+
totalSize -= f.size;
|
|
5896
|
+
} catch {
|
|
5897
|
+
}
|
|
5898
|
+
}
|
|
5899
|
+
if (files.length > remaining.length) {
|
|
5900
|
+
log(`[agent-log] Pruned ${files.length - remaining.length} old log file(s)`);
|
|
5901
|
+
}
|
|
5902
|
+
} catch (err) {
|
|
5903
|
+
log(`[agent-log] Prune error: ${err}`);
|
|
5904
|
+
}
|
|
5905
|
+
}
|
|
5906
|
+
var MAX_STDERR_BYTES, MAX_STDOUT_BYTES, MAX_AGE_MS, MAX_DIR_BYTES;
|
|
5907
|
+
var init_agent_log = __esm({
|
|
5908
|
+
"src/agents/agent-log.ts"() {
|
|
5909
|
+
"use strict";
|
|
5910
|
+
init_paths();
|
|
5911
|
+
init_log();
|
|
5912
|
+
MAX_STDERR_BYTES = 50 * 1024;
|
|
5913
|
+
MAX_STDOUT_BYTES = 100 * 1024;
|
|
5914
|
+
MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
5915
|
+
MAX_DIR_BYTES = 50 * 1024 * 1024;
|
|
5916
|
+
}
|
|
5917
|
+
});
|
|
5918
|
+
|
|
5685
5919
|
// src/agents/orchestrator.ts
|
|
5686
5920
|
import { existsSync as existsSync10 } from "fs";
|
|
5687
5921
|
async function withRunnerLock(runnerId, fn) {
|
|
@@ -5751,6 +5985,19 @@ async function spawnSubAgent(chatId, opts) {
|
|
|
5751
5985
|
const orchestrationId = getOrCreateOrchestration(chatId);
|
|
5752
5986
|
const runner = getRunner(opts.runner);
|
|
5753
5987
|
if (!runner) throw new Error(`Unknown runner: ${opts.runner}`);
|
|
5988
|
+
if (opts.model) {
|
|
5989
|
+
try {
|
|
5990
|
+
const { getAdapter: getAdapter2 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
5991
|
+
const adapter = getAdapter2(opts.runner);
|
|
5992
|
+
if (adapter.availableModels && !adapter.availableModels[opts.model]) {
|
|
5993
|
+
const validModels = Object.keys(adapter.availableModels).join(", ");
|
|
5994
|
+
throw new Error(`Unknown model "${opts.model}" for ${opts.runner}. Available: ${validModels}`);
|
|
5995
|
+
}
|
|
5996
|
+
} catch (err) {
|
|
5997
|
+
if (err instanceof Error && err.message.startsWith("Unknown model")) throw err;
|
|
5998
|
+
warn(`[orchestrator] Could not validate model "${opts.model}" for ${opts.runner}: ${err}`);
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
5754
6001
|
const agentId = createAgent(db3, {
|
|
5755
6002
|
orchestrationId,
|
|
5756
6003
|
runnerId: opts.runner,
|
|
@@ -5873,7 +6120,9 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
5873
6120
|
}
|
|
5874
6121
|
updateAgentStatus(db3, agentId, "starting");
|
|
5875
6122
|
const stderrChunks = [];
|
|
6123
|
+
const rawStdoutLines = [];
|
|
5876
6124
|
let gotResult = false;
|
|
6125
|
+
const startedAt = Date.now();
|
|
5877
6126
|
const child = spawnAgentProcess(runner, {
|
|
5878
6127
|
task: opts.task,
|
|
5879
6128
|
cwd: opts.cwd,
|
|
@@ -5890,9 +6139,20 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
5890
6139
|
onText: () => {
|
|
5891
6140
|
updateAgentOutput(db3, agentId);
|
|
5892
6141
|
},
|
|
6142
|
+
onRawLine: (line) => rawStdoutLines.push(line),
|
|
5893
6143
|
onResult: (text, usage2) => {
|
|
5894
6144
|
gotResult = true;
|
|
5895
|
-
|
|
6145
|
+
const durationMs = Date.now() - startedAt;
|
|
6146
|
+
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
6147
|
+
handleAgentComplete(agentId, chatId, text, usage2, mcpsAdded, {
|
|
6148
|
+
stderr,
|
|
6149
|
+
durationMs,
|
|
6150
|
+
rawStdoutLines,
|
|
6151
|
+
startedAt: new Date(startedAt),
|
|
6152
|
+
runner: opts.runner,
|
|
6153
|
+
model: opts.model ?? "default",
|
|
6154
|
+
task: opts.task
|
|
6155
|
+
});
|
|
5896
6156
|
},
|
|
5897
6157
|
onError: (err) => {
|
|
5898
6158
|
const detail = diagnoseSpawnError(err, exePath, opts.cwd);
|
|
@@ -5943,18 +6203,46 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
5943
6203
|
{ runner: opts.runner, task: opts.task, model: opts.model },
|
|
5944
6204
|
agentId
|
|
5945
6205
|
);
|
|
5946
|
-
child.on("close", (code) => {
|
|
6206
|
+
child.on("close", (code, signal) => {
|
|
5947
6207
|
if (gotResult) return;
|
|
5948
6208
|
const agent = getAgent(db3, agentId);
|
|
5949
6209
|
if (!agent || agent.status === "completed" || agent.status === "failed" || agent.status === "cancelled") return;
|
|
5950
6210
|
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
5951
6211
|
if (stderr) warn(`[orchestrator] Agent ${agentId.slice(0, 8)} stderr: ${stderr.slice(0, 500)}`);
|
|
5952
|
-
const
|
|
5953
|
-
const
|
|
5954
|
-
|
|
6212
|
+
const durationMs = Date.now() - startedAt;
|
|
6213
|
+
const signalStr = signal ?? null;
|
|
6214
|
+
let exitCode = code ?? 1;
|
|
6215
|
+
let exitCodeForced = false;
|
|
6216
|
+
if (exitCode === 0) {
|
|
6217
|
+
exitCode = 1;
|
|
6218
|
+
exitCodeForced = true;
|
|
6219
|
+
warn(`[orchestrator] Agent ${agentId.slice(0, 8)}: exit code 0 with no output \u2014 forced to 1 (likely auth/model issue)`);
|
|
6220
|
+
}
|
|
6221
|
+
const errMsg = exitCodeForced ? `CLI exited cleanly but produced no output (${durationMs}ms) \u2014 likely auth failure or invalid model${stderr ? `: ${stderr.slice(0, 200)}` : ""}` : `CLI exited with code ${exitCode}${stderr ? `: ${stderr.slice(0, 200)}` : ""}`;
|
|
6222
|
+
updateAgentResult(db3, agentId, {
|
|
6223
|
+
exitCode,
|
|
6224
|
+
stderr: stderr || void 0,
|
|
6225
|
+
durationMs,
|
|
6226
|
+
signal: signalStr ?? void 0
|
|
6227
|
+
});
|
|
5955
6228
|
clearTimeout(timeoutTimers.get(agentId));
|
|
5956
6229
|
timeoutTimers.delete(agentId);
|
|
5957
6230
|
activeProcesses.delete(agentId);
|
|
6231
|
+
writeAgentLog({
|
|
6232
|
+
agentId,
|
|
6233
|
+
runner: opts.runner,
|
|
6234
|
+
model: opts.model ?? "default",
|
|
6235
|
+
task: opts.task,
|
|
6236
|
+
startedAt: new Date(startedAt),
|
|
6237
|
+
durationMs,
|
|
6238
|
+
exitCode,
|
|
6239
|
+
exitCodeForced,
|
|
6240
|
+
signal: signalStr,
|
|
6241
|
+
tokenInput: 0,
|
|
6242
|
+
tokenOutput: 0,
|
|
6243
|
+
stderr,
|
|
6244
|
+
rawStdoutLines
|
|
6245
|
+
});
|
|
5958
6246
|
const crashedAgent = getAgent(db3, agentId);
|
|
5959
6247
|
if (crashedAgent) {
|
|
5960
6248
|
const mcpsCrashed = crashedAgent.mcpsAdded ? JSON.parse(crashedAgent.mcpsAdded) : [];
|
|
@@ -5980,13 +6268,13 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
5980
6268
|
toAgentId: "main",
|
|
5981
6269
|
fromAgentId: agentId,
|
|
5982
6270
|
messageType: "task_result",
|
|
5983
|
-
content:
|
|
6271
|
+
content: `Failed: ${errMsg}`
|
|
5984
6272
|
});
|
|
5985
6273
|
notifyWithActivity(
|
|
5986
6274
|
chatId,
|
|
5987
|
-
`Agent ${agentId.slice(0, 8)}
|
|
5988
|
-
|
|
5989
|
-
{ exitCode, stderr: stderr?.slice(0,
|
|
6275
|
+
`Agent ${agentId.slice(0, 8)} failed (code ${exitCode}, ${durationMs}ms)${stderr ? ` \u2014 ${stderr.slice(0, 100)}` : ""}`,
|
|
6276
|
+
"agent_failed",
|
|
6277
|
+
{ exitCode, exitCodeForced, durationMs, signal: signalStr, stderr: stderr?.slice(0, 500) },
|
|
5990
6278
|
agentId
|
|
5991
6279
|
);
|
|
5992
6280
|
const activeAgents = listActiveAgents(db3);
|
|
@@ -6019,7 +6307,7 @@ function diagnoseSpawnError(err, exePath, cwd) {
|
|
|
6019
6307
|
}
|
|
6020
6308
|
return err.message;
|
|
6021
6309
|
}
|
|
6022
|
-
async function handleAgentComplete(agentId, chatId, resultText, usage2, mcpsAdded) {
|
|
6310
|
+
async function handleAgentComplete(agentId, chatId, resultText, usage2, mcpsAdded, diagnostics) {
|
|
6023
6311
|
const db3 = getDb();
|
|
6024
6312
|
const agent = getAgent(db3, agentId);
|
|
6025
6313
|
if (!agent) return;
|
|
@@ -6030,8 +6318,26 @@ async function handleAgentComplete(agentId, chatId, resultText, usage2, mcpsAdde
|
|
|
6030
6318
|
exitCode: 0,
|
|
6031
6319
|
resultSummary: resultText.slice(0, 1e4),
|
|
6032
6320
|
tokenInput: usage2?.input ?? 0,
|
|
6033
|
-
tokenOutput: usage2?.output ?? 0
|
|
6321
|
+
tokenOutput: usage2?.output ?? 0,
|
|
6322
|
+
stderr: diagnostics?.stderr || void 0,
|
|
6323
|
+
durationMs: diagnostics?.durationMs
|
|
6034
6324
|
});
|
|
6325
|
+
if (diagnostics) {
|
|
6326
|
+
writeAgentLog({
|
|
6327
|
+
agentId,
|
|
6328
|
+
runner: diagnostics.runner,
|
|
6329
|
+
model: diagnostics.model,
|
|
6330
|
+
task: diagnostics.task,
|
|
6331
|
+
startedAt: diagnostics.startedAt,
|
|
6332
|
+
durationMs: diagnostics.durationMs,
|
|
6333
|
+
exitCode: 0,
|
|
6334
|
+
signal: null,
|
|
6335
|
+
tokenInput: usage2?.input ?? 0,
|
|
6336
|
+
tokenOutput: usage2?.output ?? 0,
|
|
6337
|
+
stderr: diagnostics.stderr,
|
|
6338
|
+
rawStdoutLines: diagnostics.rawStdoutLines
|
|
6339
|
+
});
|
|
6340
|
+
}
|
|
6035
6341
|
if (usage2) {
|
|
6036
6342
|
const runner = getRunner(agent.runnerId);
|
|
6037
6343
|
if (runner) {
|
|
@@ -6087,7 +6393,15 @@ async function handleAgentComplete(agentId, chatId, resultText, usage2, mcpsAdde
|
|
|
6087
6393
|
chatId,
|
|
6088
6394
|
`Agent ${agentId.slice(0, 8)} completed \u2192 ${usage2?.input ?? 0} in / ${usage2?.output ?? 0} out tokens`,
|
|
6089
6395
|
"agent_completed",
|
|
6090
|
-
{
|
|
6396
|
+
{
|
|
6397
|
+
runner: agent.runnerId,
|
|
6398
|
+
task: agent.task,
|
|
6399
|
+
tokenInput: usage2?.input,
|
|
6400
|
+
tokenOutput: usage2?.output,
|
|
6401
|
+
resultPreview: resultText.slice(0, 200),
|
|
6402
|
+
durationMs: diagnostics?.durationMs,
|
|
6403
|
+
stderr: diagnostics?.stderr?.slice(0, 500) || void 0
|
|
6404
|
+
},
|
|
6091
6405
|
agentId
|
|
6092
6406
|
);
|
|
6093
6407
|
const activeAgents = listActiveAgents(db3);
|
|
@@ -6213,6 +6527,7 @@ function shutdownOrchestrator() {
|
|
|
6213
6527
|
}
|
|
6214
6528
|
function initOrchestrator() {
|
|
6215
6529
|
cleanupOrphanedMcpConfigs();
|
|
6530
|
+
pruneAgentLogs();
|
|
6216
6531
|
const db3 = getDb();
|
|
6217
6532
|
const staleCount = cleanupStaleAgents(db3);
|
|
6218
6533
|
if (staleCount > 0) {
|
|
@@ -6235,6 +6550,7 @@ var init_orchestrator = __esm({
|
|
|
6235
6550
|
init_log();
|
|
6236
6551
|
init_store3();
|
|
6237
6552
|
init_loader2();
|
|
6553
|
+
init_agent_log();
|
|
6238
6554
|
activeProcesses = /* @__PURE__ */ new Map();
|
|
6239
6555
|
timeoutTimers = /* @__PURE__ */ new Map();
|
|
6240
6556
|
runnerLocks = /* @__PURE__ */ new Map();
|
|
@@ -6628,19 +6944,19 @@ __export(analyze_exports, {
|
|
|
6628
6944
|
});
|
|
6629
6945
|
import { spawn as spawn4 } from "child_process";
|
|
6630
6946
|
import { createInterface as createInterface3 } from "readline";
|
|
6631
|
-
import { readFileSync as readFileSync6, existsSync as existsSync11, readdirSync as
|
|
6632
|
-
import { join as
|
|
6947
|
+
import { readFileSync as readFileSync6, existsSync as existsSync11, readdirSync as readdirSync6, statSync as statSync4 } from "fs";
|
|
6948
|
+
import { join as join11 } from "path";
|
|
6633
6949
|
import { homedir as homedir4 } from "os";
|
|
6634
6950
|
function discoverReflectionTargets() {
|
|
6635
|
-
const ccClawHome =
|
|
6951
|
+
const ccClawHome = join11(homedir4(), ".cc-claw");
|
|
6636
6952
|
const targets = [];
|
|
6637
6953
|
try {
|
|
6638
|
-
const skillsDir =
|
|
6954
|
+
const skillsDir = join11(ccClawHome, "workspace", "skills");
|
|
6639
6955
|
if (existsSync11(skillsDir)) {
|
|
6640
|
-
for (const entry of
|
|
6641
|
-
const entryPath =
|
|
6642
|
-
if (!
|
|
6643
|
-
const skillFile =
|
|
6956
|
+
for (const entry of readdirSync6(skillsDir)) {
|
|
6957
|
+
const entryPath = join11(skillsDir, entry);
|
|
6958
|
+
if (!statSync4(entryPath).isDirectory()) continue;
|
|
6959
|
+
const skillFile = join11(entryPath, "SKILL.md");
|
|
6644
6960
|
if (!existsSync11(skillFile)) continue;
|
|
6645
6961
|
let desc = "skill";
|
|
6646
6962
|
try {
|
|
@@ -6655,9 +6971,9 @@ function discoverReflectionTargets() {
|
|
|
6655
6971
|
} catch {
|
|
6656
6972
|
}
|
|
6657
6973
|
try {
|
|
6658
|
-
const contextDir =
|
|
6974
|
+
const contextDir = join11(ccClawHome, "workspace", "context");
|
|
6659
6975
|
if (existsSync11(contextDir)) {
|
|
6660
|
-
for (const entry of
|
|
6976
|
+
for (const entry of readdirSync6(contextDir)) {
|
|
6661
6977
|
if (!entry.endsWith(".md")) continue;
|
|
6662
6978
|
const name = entry.replace(/\.md$/, "");
|
|
6663
6979
|
targets.push({ path: `workspace/context/${entry}`, description: `context file: ${name}` });
|
|
@@ -6689,6 +7005,7 @@ Rules:
|
|
|
6689
7005
|
- WHY field max 2 sentences
|
|
6690
7006
|
- Only propose changes you are confident about (confidence >= 0.6)
|
|
6691
7007
|
- Never re-propose previously rejected insights
|
|
7008
|
+
- Do not propose more than 3 changes to the same target file in a single analysis (spread across files to avoid drift)
|
|
6692
7009
|
|
|
6693
7010
|
Valid categories:
|
|
6694
7011
|
${categoryList}`);
|
|
@@ -6837,7 +7154,7 @@ function resolveReflectionAdapter(chatId) {
|
|
|
6837
7154
|
}
|
|
6838
7155
|
function readIdentityFile(filename) {
|
|
6839
7156
|
try {
|
|
6840
|
-
return readFileSync6(
|
|
7157
|
+
return readFileSync6(join11(IDENTITY_PATH, filename), "utf-8");
|
|
6841
7158
|
} catch {
|
|
6842
7159
|
return "";
|
|
6843
7160
|
}
|
|
@@ -7073,8 +7390,8 @@ __export(apply_exports, {
|
|
|
7073
7390
|
isTargetAllowed: () => isTargetAllowed,
|
|
7074
7391
|
rollbackInsight: () => rollbackInsight
|
|
7075
7392
|
});
|
|
7076
|
-
import { readFileSync as readFileSync7, writeFileSync as
|
|
7077
|
-
import { join as
|
|
7393
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync12, mkdirSync as mkdirSync4, readdirSync as readdirSync7, unlinkSync as unlinkSync5 } from "fs";
|
|
7394
|
+
import { join as join12, dirname as dirname2 } from "path";
|
|
7078
7395
|
function isTargetAllowed(relativePath) {
|
|
7079
7396
|
if (relativePath.includes("..")) return false;
|
|
7080
7397
|
if (!relativePath.endsWith(".md")) return false;
|
|
@@ -7124,6 +7441,21 @@ function applyDiff(original, diff, action) {
|
|
|
7124
7441
|
warn(`[reflection/apply] Unknown diff action "${action}", returning original`);
|
|
7125
7442
|
return original;
|
|
7126
7443
|
}
|
|
7444
|
+
function pruneBackups(absolutePath) {
|
|
7445
|
+
const dir = dirname2(absolutePath);
|
|
7446
|
+
const baseName = absolutePath.split("/").pop() ?? "";
|
|
7447
|
+
try {
|
|
7448
|
+
const backups = readdirSync7(dir).filter((f) => f.startsWith(baseName + ".bak.")).sort().map((f) => join12(dir, f));
|
|
7449
|
+
while (backups.length > MAX_BACKUPS_PER_FILE) {
|
|
7450
|
+
const oldest = backups.shift();
|
|
7451
|
+
try {
|
|
7452
|
+
unlinkSync5(oldest);
|
|
7453
|
+
} catch {
|
|
7454
|
+
}
|
|
7455
|
+
}
|
|
7456
|
+
} catch {
|
|
7457
|
+
}
|
|
7458
|
+
}
|
|
7127
7459
|
async function applyInsight(insightId) {
|
|
7128
7460
|
const db3 = getDb();
|
|
7129
7461
|
const insight = getInsightById(db3, insightId);
|
|
@@ -7139,7 +7471,7 @@ async function applyInsight(insightId) {
|
|
|
7139
7471
|
if (!isTargetAllowed(insight.targetFile)) {
|
|
7140
7472
|
return { success: false, message: `Target file "${insight.targetFile}" is not in the allowed list` };
|
|
7141
7473
|
}
|
|
7142
|
-
const absolutePath =
|
|
7474
|
+
const absolutePath = join12(CC_CLAW_HOME, insight.targetFile);
|
|
7143
7475
|
if (insight.proposedAction === "append" && insight.targetFile === "identity/SOUL.md") {
|
|
7144
7476
|
if (existsSync12(absolutePath)) {
|
|
7145
7477
|
const currentContent = readFileSync7(absolutePath, "utf-8");
|
|
@@ -7153,11 +7485,13 @@ async function applyInsight(insightId) {
|
|
|
7153
7485
|
}
|
|
7154
7486
|
}
|
|
7155
7487
|
const chatId = insight.chatId ?? "global";
|
|
7156
|
-
const
|
|
7157
|
-
|
|
7488
|
+
const settings = getReflectionSettings(db3, chatId);
|
|
7489
|
+
const perFileCap = settings.perFileCap;
|
|
7490
|
+
const appliedTodayForFile = getAppliedCountTodayForFile(db3, chatId, insight.targetFile);
|
|
7491
|
+
if (appliedTodayForFile >= perFileCap) {
|
|
7158
7492
|
return {
|
|
7159
7493
|
success: false,
|
|
7160
|
-
message: `
|
|
7494
|
+
message: `Reflection cap reached for ${insight.targetFile} (${appliedTodayForFile}/${perFileCap} today). Try again tomorrow.`
|
|
7161
7495
|
};
|
|
7162
7496
|
}
|
|
7163
7497
|
let original = "";
|
|
@@ -7171,13 +7505,14 @@ async function applyInsight(insightId) {
|
|
|
7171
7505
|
try {
|
|
7172
7506
|
const parentDir = dirname2(absolutePath);
|
|
7173
7507
|
if (!existsSync12(parentDir)) {
|
|
7174
|
-
|
|
7508
|
+
mkdirSync4(parentDir, { recursive: true });
|
|
7175
7509
|
}
|
|
7176
7510
|
if (original) {
|
|
7177
|
-
|
|
7511
|
+
writeFileSync4(backupPath, original, "utf-8");
|
|
7512
|
+
pruneBackups(absolutePath);
|
|
7178
7513
|
}
|
|
7179
7514
|
const newContent = applyDiff(original, insight.proposedDiff, insight.proposedAction);
|
|
7180
|
-
|
|
7515
|
+
writeFileSync4(absolutePath, newContent, "utf-8");
|
|
7181
7516
|
const rollbackData = JSON.stringify({ original, backupPath, appliedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
7182
7517
|
updateInsightRollback(db3, insightId, rollbackData);
|
|
7183
7518
|
updateInsightStatus(db3, insightId, "applied");
|
|
@@ -7205,7 +7540,7 @@ async function applyInsight(insightId) {
|
|
|
7205
7540
|
warn(`[reflection/apply] Failed to apply insight #${insightId}: ${msg}`);
|
|
7206
7541
|
try {
|
|
7207
7542
|
if (original) {
|
|
7208
|
-
|
|
7543
|
+
writeFileSync4(absolutePath, original, "utf-8");
|
|
7209
7544
|
}
|
|
7210
7545
|
} catch {
|
|
7211
7546
|
}
|
|
@@ -7233,9 +7568,9 @@ async function rollbackInsight(insightId) {
|
|
|
7233
7568
|
} catch {
|
|
7234
7569
|
return { success: false, message: `Insight #${insightId} has malformed rollback data` };
|
|
7235
7570
|
}
|
|
7236
|
-
const absolutePath =
|
|
7571
|
+
const absolutePath = join12(CC_CLAW_HOME, insight.targetFile);
|
|
7237
7572
|
try {
|
|
7238
|
-
|
|
7573
|
+
writeFileSync4(absolutePath, rollback.original, "utf-8");
|
|
7239
7574
|
updateInsightStatus(db3, insightId, "rolled_back");
|
|
7240
7575
|
syncNativeCliFiles();
|
|
7241
7576
|
const chatId = insight.chatId ?? "global";
|
|
@@ -7266,8 +7601,8 @@ function calculateDrift(chatId) {
|
|
|
7266
7601
|
if (!row || !row.baselineSoulMd && !row.baselineUserMd) {
|
|
7267
7602
|
return null;
|
|
7268
7603
|
}
|
|
7269
|
-
const soulPath =
|
|
7270
|
-
const userPath =
|
|
7604
|
+
const soulPath = join12(CC_CLAW_HOME, "identity/SOUL.md");
|
|
7605
|
+
const userPath = join12(CC_CLAW_HOME, "identity/USER.md");
|
|
7271
7606
|
const soulDrift = computeLineDrift(row.baselineSoulMd, soulPath);
|
|
7272
7607
|
const userDrift = computeLineDrift(row.baselineUserMd, userPath);
|
|
7273
7608
|
return { soulDrift, userDrift };
|
|
@@ -7295,7 +7630,7 @@ function computeLineDrift(baseline, absolutePath) {
|
|
|
7295
7630
|
const changed = totalBaseline - unchanged;
|
|
7296
7631
|
return changed / totalBaseline;
|
|
7297
7632
|
}
|
|
7298
|
-
var ALLOWED_TARGETS, ALLOWED_PREFIXES, SOUL_LINE_CAP,
|
|
7633
|
+
var ALLOWED_TARGETS, ALLOWED_PREFIXES, SOUL_LINE_CAP, MAX_BACKUPS_PER_FILE;
|
|
7299
7634
|
var init_apply = __esm({
|
|
7300
7635
|
"src/reflection/apply.ts"() {
|
|
7301
7636
|
"use strict";
|
|
@@ -7314,7 +7649,7 @@ var init_apply = __esm({
|
|
|
7314
7649
|
"workspace/skills/"
|
|
7315
7650
|
];
|
|
7316
7651
|
SOUL_LINE_CAP = 100;
|
|
7317
|
-
|
|
7652
|
+
MAX_BACKUPS_PER_FILE = 3;
|
|
7318
7653
|
}
|
|
7319
7654
|
});
|
|
7320
7655
|
|
|
@@ -7328,7 +7663,7 @@ __export(server_exports, {
|
|
|
7328
7663
|
});
|
|
7329
7664
|
import { createServer } from "http";
|
|
7330
7665
|
import { randomBytes } from "crypto";
|
|
7331
|
-
import { writeFileSync as
|
|
7666
|
+
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync13 } from "fs";
|
|
7332
7667
|
function createSubAgentToken(agentId) {
|
|
7333
7668
|
const token = `sub:${agentId.slice(0, 8)}:${randomBytes(16).toString("hex")}`;
|
|
7334
7669
|
subAgentTokens.set(token, agentId);
|
|
@@ -8097,11 +8432,11 @@ data: ${JSON.stringify(data)}
|
|
|
8097
8432
|
const body = JSON.parse(await readBody(req));
|
|
8098
8433
|
const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
8099
8434
|
const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
|
|
8100
|
-
const { join:
|
|
8435
|
+
const { join: join27 } = await import("path");
|
|
8101
8436
|
const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
8102
8437
|
const chatId = body.chatId || (process.env.ALLOWED_CHAT_ID ?? "").split(",")[0]?.trim() || "default";
|
|
8103
|
-
const soulPath =
|
|
8104
|
-
const userPath =
|
|
8438
|
+
const soulPath = join27(home, "identity/SOUL.md");
|
|
8439
|
+
const userPath = join27(home, "identity/USER.md");
|
|
8105
8440
|
const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
|
|
8106
8441
|
const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
|
|
8107
8442
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
@@ -8132,6 +8467,21 @@ data: ${JSON.stringify(data)}
|
|
|
8132
8467
|
return jsonResponse(res, { error: errorMessage(err) }, 400);
|
|
8133
8468
|
}
|
|
8134
8469
|
}
|
|
8470
|
+
if (url.pathname === "/api/evolve/settings" && req.method === "POST") {
|
|
8471
|
+
try {
|
|
8472
|
+
const body = JSON.parse(await readBody(req));
|
|
8473
|
+
const { setReflectionSettings: setReflectionSettings2, getReflectionSettings: getReflectionSettings2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
8474
|
+
const chatId = body.chatId || (process.env.ALLOWED_CHAT_ID ?? "").split(",")[0]?.trim() || "default";
|
|
8475
|
+
const updates = {};
|
|
8476
|
+
if (body.perFileCap !== void 0) updates.perFileCap = body.perFileCap;
|
|
8477
|
+
if (body.backupRetentionDays !== void 0) updates.backupRetentionDays = body.backupRetentionDays;
|
|
8478
|
+
setReflectionSettings2(getDb(), chatId, updates);
|
|
8479
|
+
const current = getReflectionSettings2(getDb(), chatId);
|
|
8480
|
+
return jsonResponse(res, { success: true, ...current });
|
|
8481
|
+
} catch (err) {
|
|
8482
|
+
return jsonResponse(res, { error: errorMessage(err) }, 400);
|
|
8483
|
+
}
|
|
8484
|
+
}
|
|
8135
8485
|
if (url.pathname === "/" || url.pathname === "/index.html") {
|
|
8136
8486
|
return htmlResponse(res, DASHBOARD_HTML.replace("__TOKEN__", DASHBOARD_TOKEN));
|
|
8137
8487
|
}
|
|
@@ -8149,9 +8499,9 @@ data: ${JSON.stringify(data)}
|
|
|
8149
8499
|
});
|
|
8150
8500
|
server.listen(PORT, "127.0.0.1");
|
|
8151
8501
|
try {
|
|
8152
|
-
|
|
8502
|
+
mkdirSync5(DATA_PATH, { recursive: true });
|
|
8153
8503
|
const tokenPath = `${DATA_PATH}/api-token`;
|
|
8154
|
-
|
|
8504
|
+
writeFileSync5(tokenPath, DASHBOARD_TOKEN, { mode: 384 });
|
|
8155
8505
|
} catch (err) {
|
|
8156
8506
|
log(`[api] Warning: could not write api-token file: ${errorMessage(err)}`);
|
|
8157
8507
|
}
|
|
@@ -9362,11 +9712,13 @@ __export(propose_exports, {
|
|
|
9362
9712
|
buildEvolveOnboardingKeyboard: () => buildEvolveOnboardingKeyboard,
|
|
9363
9713
|
buildModelKeyboard: () => buildModelKeyboard,
|
|
9364
9714
|
buildProposalKeyboard: () => buildProposalKeyboard,
|
|
9715
|
+
buildReviewCompleteMessage: () => buildReviewCompleteMessage,
|
|
9365
9716
|
buildUndoKeyboard: () => buildUndoKeyboard,
|
|
9366
9717
|
formatDiffCodeBlock: () => formatDiffCodeBlock,
|
|
9367
9718
|
formatGrowthReport: () => formatGrowthReport,
|
|
9368
9719
|
formatNightlySummary: () => formatNightlySummary,
|
|
9369
|
-
formatProposalCard: () => formatProposalCard
|
|
9720
|
+
formatProposalCard: () => formatProposalCard,
|
|
9721
|
+
formatProposalCardWithProgress: () => formatProposalCardWithProgress
|
|
9370
9722
|
});
|
|
9371
9723
|
function pct(ratio) {
|
|
9372
9724
|
return `${Math.round(ratio * 100)}%`;
|
|
@@ -9387,6 +9739,28 @@ function formatProposalCard(params) {
|
|
|
9387
9739
|
}
|
|
9388
9740
|
return lines.join("\n");
|
|
9389
9741
|
}
|
|
9742
|
+
function formatProposalCardWithProgress(params, index, total) {
|
|
9743
|
+
const progress = `\u{1F4CB} Proposal ${index + 1} of ${total}`;
|
|
9744
|
+
const separator = "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
|
|
9745
|
+
const card = formatProposalCard(params);
|
|
9746
|
+
return `${progress}
|
|
9747
|
+
${separator}
|
|
9748
|
+
${card}`;
|
|
9749
|
+
}
|
|
9750
|
+
function buildReviewCompleteMessage(results) {
|
|
9751
|
+
const values = Object.values(results);
|
|
9752
|
+
const applied = values.filter((v) => v === "applied").length;
|
|
9753
|
+
const rejected = values.filter((v) => v === "rejected").length;
|
|
9754
|
+
const skipped = values.filter((v) => v === "skipped").length;
|
|
9755
|
+
const total = values.length;
|
|
9756
|
+
const parts = [];
|
|
9757
|
+
if (applied > 0) parts.push(`${applied} applied`);
|
|
9758
|
+
if (rejected > 0) parts.push(`${rejected} rejected`);
|
|
9759
|
+
if (skipped > 0) parts.push(`${skipped} skipped`);
|
|
9760
|
+
return `\u2705 Review complete \u2014 ${total} proposal${total === 1 ? "" : "s"}: ${parts.join(", ")}
|
|
9761
|
+
|
|
9762
|
+
Skipped proposals will appear in your next review.`;
|
|
9763
|
+
}
|
|
9390
9764
|
function formatNightlySummary(insights) {
|
|
9391
9765
|
const count = insights.length;
|
|
9392
9766
|
const header2 = `Nightly Reflection \u2014 ${count} proposal${count === 1 ? "" : "s"} ready`;
|
|
@@ -9430,7 +9804,10 @@ function buildProposalKeyboard(insightId, category) {
|
|
|
9430
9804
|
return [
|
|
9431
9805
|
[
|
|
9432
9806
|
{ label: "Show Diff", data: `evolve:diff:${insightId}`, style: "primary" },
|
|
9433
|
-
{ label: "Discuss", data: `evolve:discuss:${insightId}` }
|
|
9807
|
+
{ label: "Discuss", data: `evolve:discuss:${insightId}` }
|
|
9808
|
+
],
|
|
9809
|
+
[
|
|
9810
|
+
{ label: "Skip \u23ED", data: `evolve:skip:${insightId}` },
|
|
9434
9811
|
{ label: "Reject", data: `evolve:reject:${insightId}`, style: "danger" }
|
|
9435
9812
|
]
|
|
9436
9813
|
];
|
|
@@ -9438,7 +9815,10 @@ function buildProposalKeyboard(insightId, category) {
|
|
|
9438
9815
|
return [
|
|
9439
9816
|
[
|
|
9440
9817
|
{ label: "Apply", data: `evolve:apply:${insightId}`, style: "success" },
|
|
9441
|
-
{ label: "Discuss", data: `evolve:discuss:${insightId}` }
|
|
9818
|
+
{ label: "Discuss", data: `evolve:discuss:${insightId}` }
|
|
9819
|
+
],
|
|
9820
|
+
[
|
|
9821
|
+
{ label: "Skip \u23ED", data: `evolve:skip:${insightId}` },
|
|
9442
9822
|
{ label: "Reject", data: `evolve:reject:${insightId}`, style: "danger" }
|
|
9443
9823
|
]
|
|
9444
9824
|
];
|
|
@@ -9814,7 +10194,7 @@ var init_cron = __esm({
|
|
|
9814
10194
|
});
|
|
9815
10195
|
|
|
9816
10196
|
// src/agents/runners/wrap-backend.ts
|
|
9817
|
-
import { join as
|
|
10197
|
+
import { join as join13 } from "path";
|
|
9818
10198
|
function buildMcpCommands(backendId) {
|
|
9819
10199
|
const exe = backendId === "cursor" ? "agent" : backendId;
|
|
9820
10200
|
return {
|
|
@@ -9908,7 +10288,7 @@ function wrapBackendAdapter(adapter) {
|
|
|
9908
10288
|
const configPath = writeMcpConfigFile(server);
|
|
9909
10289
|
return ["--mcp-config", configPath];
|
|
9910
10290
|
},
|
|
9911
|
-
getSkillPath: () =>
|
|
10291
|
+
getSkillPath: () => join13(SKILLS_PATH, `agent-${adapter.id}.md`)
|
|
9912
10292
|
};
|
|
9913
10293
|
}
|
|
9914
10294
|
var BACKEND_CAPABILITIES;
|
|
@@ -9959,8 +10339,8 @@ var init_wrap_backend = __esm({
|
|
|
9959
10339
|
});
|
|
9960
10340
|
|
|
9961
10341
|
// src/agents/runners/config-loader.ts
|
|
9962
|
-
import { readFileSync as readFileSync8, readdirSync as
|
|
9963
|
-
import { join as
|
|
10342
|
+
import { readFileSync as readFileSync8, readdirSync as readdirSync8, existsSync as existsSync14, mkdirSync as mkdirSync6, watchFile, unwatchFile } from "fs";
|
|
10343
|
+
import { join as join14 } from "path";
|
|
9964
10344
|
import { execFileSync } from "child_process";
|
|
9965
10345
|
function resolveExecutable(config2) {
|
|
9966
10346
|
if (existsSync14(config2.executable)) return config2.executable;
|
|
@@ -10096,7 +10476,7 @@ function configToRunner(config2) {
|
|
|
10096
10476
|
prepareMcpInjection() {
|
|
10097
10477
|
return [];
|
|
10098
10478
|
},
|
|
10099
|
-
getSkillPath: () =>
|
|
10479
|
+
getSkillPath: () => join14(SKILLS_PATH, `agent-${config2.id}.md`)
|
|
10100
10480
|
};
|
|
10101
10481
|
}
|
|
10102
10482
|
function loadRunnerConfig(filePath) {
|
|
@@ -10110,13 +10490,13 @@ function loadRunnerConfig(filePath) {
|
|
|
10110
10490
|
}
|
|
10111
10491
|
function loadAllRunnerConfigs() {
|
|
10112
10492
|
if (!existsSync14(RUNNERS_PATH)) {
|
|
10113
|
-
|
|
10493
|
+
mkdirSync6(RUNNERS_PATH, { recursive: true });
|
|
10114
10494
|
return [];
|
|
10115
10495
|
}
|
|
10116
|
-
const files =
|
|
10496
|
+
const files = readdirSync8(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
10117
10497
|
const configs = [];
|
|
10118
10498
|
for (const file of files) {
|
|
10119
|
-
const config2 = loadRunnerConfig(
|
|
10499
|
+
const config2 = loadRunnerConfig(join14(RUNNERS_PATH, file));
|
|
10120
10500
|
if (config2) configs.push(config2);
|
|
10121
10501
|
}
|
|
10122
10502
|
return configs;
|
|
@@ -10144,9 +10524,9 @@ function watchRunnerConfigs(onChange) {
|
|
|
10144
10524
|
watchedFiles.delete(prev);
|
|
10145
10525
|
}
|
|
10146
10526
|
}
|
|
10147
|
-
const files =
|
|
10527
|
+
const files = readdirSync8(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
10148
10528
|
for (const file of files) {
|
|
10149
|
-
const fullPath =
|
|
10529
|
+
const fullPath = join14(RUNNERS_PATH, file);
|
|
10150
10530
|
if (watchedFiles.has(fullPath)) continue;
|
|
10151
10531
|
watchedFiles.add(fullPath);
|
|
10152
10532
|
watchFile(fullPath, { interval: 5e3 }, () => {
|
|
@@ -10854,7 +11234,7 @@ __export(discover_exports, {
|
|
|
10854
11234
|
import { readdir, readFile as readFile2 } from "fs/promises";
|
|
10855
11235
|
import { createHash } from "crypto";
|
|
10856
11236
|
import { homedir as homedir5 } from "os";
|
|
10857
|
-
import { join as
|
|
11237
|
+
import { join as join15 } from "path";
|
|
10858
11238
|
function invalidateSkillCache() {
|
|
10859
11239
|
cachedSkills = null;
|
|
10860
11240
|
cacheTimestamp = 0;
|
|
@@ -10872,7 +11252,7 @@ async function discoverAllSkills() {
|
|
|
10872
11252
|
const rawSkills = [];
|
|
10873
11253
|
rawSkills.push(...await scanSkillDir(SKILLS_PATH, "cc-claw"));
|
|
10874
11254
|
for (const backendId of getAllBackendIds()) {
|
|
10875
|
-
const dirs = BACKEND_SKILL_DIRS[backendId] ?? [
|
|
11255
|
+
const dirs = BACKEND_SKILL_DIRS[backendId] ?? [join15(homedir5(), `.${backendId}`, "skills")];
|
|
10876
11256
|
for (const dir of dirs) {
|
|
10877
11257
|
rawSkills.push(...await scanSkillDir(dir, backendId));
|
|
10878
11258
|
}
|
|
@@ -10900,7 +11280,7 @@ async function scanSkillDir(skillsDir, source) {
|
|
|
10900
11280
|
let content;
|
|
10901
11281
|
let resolvedPath;
|
|
10902
11282
|
for (const candidate of SKILL_FILE_CANDIDATES) {
|
|
10903
|
-
const p =
|
|
11283
|
+
const p = join15(skillsDir, entry.name, candidate);
|
|
10904
11284
|
try {
|
|
10905
11285
|
content = await readFile2(p, "utf-8");
|
|
10906
11286
|
resolvedPath = p;
|
|
@@ -11003,15 +11383,15 @@ var init_discover = __esm({
|
|
|
11003
11383
|
init_backends();
|
|
11004
11384
|
SKILL_FILE_CANDIDATES = ["SKILL.md", "skill.md"];
|
|
11005
11385
|
BACKEND_SKILL_DIRS = {
|
|
11006
|
-
claude: [
|
|
11007
|
-
gemini: [
|
|
11386
|
+
claude: [join15(homedir5(), ".claude", "skills")],
|
|
11387
|
+
gemini: [join15(homedir5(), ".gemini", "skills")],
|
|
11008
11388
|
codex: [
|
|
11009
|
-
|
|
11010
|
-
|
|
11389
|
+
join15(homedir5(), ".agents", "skills"),
|
|
11390
|
+
join15(homedir5(), ".codex", "skills")
|
|
11011
11391
|
],
|
|
11012
11392
|
cursor: [
|
|
11013
|
-
|
|
11014
|
-
|
|
11393
|
+
join15(homedir5(), ".cursor", "skills"),
|
|
11394
|
+
join15(homedir5(), ".cursor", "skills-cursor")
|
|
11015
11395
|
]
|
|
11016
11396
|
};
|
|
11017
11397
|
CACHE_TTL_MS2 = 3e5;
|
|
@@ -11028,7 +11408,7 @@ __export(install_exports, {
|
|
|
11028
11408
|
});
|
|
11029
11409
|
import { mkdir, readdir as readdir2, readFile as readFile3, cp } from "fs/promises";
|
|
11030
11410
|
import { existsSync as existsSync15 } from "fs";
|
|
11031
|
-
import { join as
|
|
11411
|
+
import { join as join16, basename } from "path";
|
|
11032
11412
|
import { execSync as execSync6 } from "child_process";
|
|
11033
11413
|
async function installSkillFromGitHub(urlOrShorthand) {
|
|
11034
11414
|
let repoUrl;
|
|
@@ -11039,23 +11419,23 @@ async function installSkillFromGitHub(urlOrShorthand) {
|
|
|
11039
11419
|
}
|
|
11040
11420
|
repoUrl = parsed.cloneUrl;
|
|
11041
11421
|
subPath = parsed.subPath;
|
|
11042
|
-
const tmpDir =
|
|
11422
|
+
const tmpDir = join16("/tmp", `cc-claw-skill-${Date.now()}`);
|
|
11043
11423
|
try {
|
|
11044
11424
|
log(`[skill-install] Cloning ${repoUrl} to ${tmpDir}`);
|
|
11045
11425
|
execSync6(`git clone --depth 1 ${repoUrl} ${tmpDir}`, {
|
|
11046
11426
|
stdio: "pipe",
|
|
11047
11427
|
timeout: 3e4
|
|
11048
11428
|
});
|
|
11049
|
-
if (!existsSync15(
|
|
11429
|
+
if (!existsSync15(join16(tmpDir, ".git"))) {
|
|
11050
11430
|
return { success: false, error: "Git clone failed: no .git directory produced" };
|
|
11051
11431
|
}
|
|
11052
|
-
const searchRoot = subPath ?
|
|
11432
|
+
const searchRoot = subPath ? join16(tmpDir, subPath) : tmpDir;
|
|
11053
11433
|
const skillDir = await findSkillDir(searchRoot);
|
|
11054
11434
|
if (!skillDir) {
|
|
11055
11435
|
return { success: false, error: "No SKILL.md found in the repository." };
|
|
11056
11436
|
}
|
|
11057
11437
|
const skillFolderName = basename(skillDir);
|
|
11058
|
-
const destDir =
|
|
11438
|
+
const destDir = join16(SKILLS_PATH, skillFolderName);
|
|
11059
11439
|
if (existsSync15(destDir)) {
|
|
11060
11440
|
log(`[skill-install] Overwriting existing skill at ${destDir}`);
|
|
11061
11441
|
}
|
|
@@ -11063,12 +11443,12 @@ async function installSkillFromGitHub(urlOrShorthand) {
|
|
|
11063
11443
|
await cp(skillDir, destDir, { recursive: true });
|
|
11064
11444
|
let skillName = skillFolderName;
|
|
11065
11445
|
try {
|
|
11066
|
-
const content = await readFile3(
|
|
11446
|
+
const content = await readFile3(join16(destDir, "SKILL.md"), "utf-8");
|
|
11067
11447
|
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
11068
11448
|
if (nameMatch) skillName = nameMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
11069
11449
|
} catch {
|
|
11070
11450
|
try {
|
|
11071
|
-
const content = await readFile3(
|
|
11451
|
+
const content = await readFile3(join16(destDir, "skill.md"), "utf-8");
|
|
11072
11452
|
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
11073
11453
|
if (nameMatch) skillName = nameMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
11074
11454
|
} catch {
|
|
@@ -11103,15 +11483,15 @@ function parseGitHubUrl(input) {
|
|
|
11103
11483
|
async function findSkillDir(root) {
|
|
11104
11484
|
const candidates = ["SKILL.md", "skill.md"];
|
|
11105
11485
|
for (const c of candidates) {
|
|
11106
|
-
if (existsSync15(
|
|
11486
|
+
if (existsSync15(join16(root, c))) return root;
|
|
11107
11487
|
}
|
|
11108
11488
|
try {
|
|
11109
11489
|
const entries = await readdir2(root, { withFileTypes: true });
|
|
11110
11490
|
for (const entry of entries) {
|
|
11111
11491
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
11112
11492
|
for (const c of candidates) {
|
|
11113
|
-
if (existsSync15(
|
|
11114
|
-
return
|
|
11493
|
+
if (existsSync15(join16(root, entry.name, c))) {
|
|
11494
|
+
return join16(root, entry.name);
|
|
11115
11495
|
}
|
|
11116
11496
|
}
|
|
11117
11497
|
}
|
|
@@ -11123,15 +11503,15 @@ async function findSkillDir(root) {
|
|
|
11123
11503
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
11124
11504
|
let subEntries;
|
|
11125
11505
|
try {
|
|
11126
|
-
subEntries = await readdir2(
|
|
11506
|
+
subEntries = await readdir2(join16(root, entry.name), { withFileTypes: true });
|
|
11127
11507
|
} catch {
|
|
11128
11508
|
continue;
|
|
11129
11509
|
}
|
|
11130
11510
|
for (const sub of subEntries) {
|
|
11131
11511
|
if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
|
|
11132
11512
|
for (const c of candidates) {
|
|
11133
|
-
if (existsSync15(
|
|
11134
|
-
return
|
|
11513
|
+
if (existsSync15(join16(root, entry.name, sub.name, c))) {
|
|
11514
|
+
return join16(root, entry.name, sub.name);
|
|
11135
11515
|
}
|
|
11136
11516
|
}
|
|
11137
11517
|
}
|
|
@@ -11149,8 +11529,8 @@ var init_install = __esm({
|
|
|
11149
11529
|
});
|
|
11150
11530
|
|
|
11151
11531
|
// src/bootstrap/profile.ts
|
|
11152
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
11153
|
-
import { join as
|
|
11532
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync16 } from "fs";
|
|
11533
|
+
import { join as join17 } from "path";
|
|
11154
11534
|
function hasActiveProfile(chatId) {
|
|
11155
11535
|
return activeProfiles.has(chatId);
|
|
11156
11536
|
}
|
|
@@ -11253,7 +11633,7 @@ async function finalizeProfile(chatId, state, channel) {
|
|
|
11253
11633
|
"<!-- Add any additional preferences below this line -->",
|
|
11254
11634
|
""
|
|
11255
11635
|
].join("\n");
|
|
11256
|
-
|
|
11636
|
+
writeFileSync6(USER_PATH2, content, "utf-8");
|
|
11257
11637
|
activeProfiles.delete(chatId);
|
|
11258
11638
|
log(`[profile] User profile saved for chat ${chatId}`);
|
|
11259
11639
|
await channel.sendText(
|
|
@@ -11286,7 +11666,7 @@ function appendToUserProfile(key, value) {
|
|
|
11286
11666
|
const updated = content.trimEnd() + `
|
|
11287
11667
|
${line}
|
|
11288
11668
|
`;
|
|
11289
|
-
|
|
11669
|
+
writeFileSync6(USER_PATH2, updated, "utf-8");
|
|
11290
11670
|
log(`[profile] Appended preference: ${key}=${value}`);
|
|
11291
11671
|
}
|
|
11292
11672
|
var USER_PATH2, activeProfiles;
|
|
@@ -11295,14 +11675,14 @@ var init_profile = __esm({
|
|
|
11295
11675
|
"use strict";
|
|
11296
11676
|
init_paths();
|
|
11297
11677
|
init_log();
|
|
11298
|
-
USER_PATH2 =
|
|
11678
|
+
USER_PATH2 = join17(IDENTITY_PATH, "USER.md");
|
|
11299
11679
|
activeProfiles = /* @__PURE__ */ new Map();
|
|
11300
11680
|
}
|
|
11301
11681
|
});
|
|
11302
11682
|
|
|
11303
11683
|
// src/bootstrap/heartbeat.ts
|
|
11304
11684
|
import { readFileSync as readFileSync10, existsSync as existsSync17 } from "fs";
|
|
11305
|
-
import { join as
|
|
11685
|
+
import { join as join18 } from "path";
|
|
11306
11686
|
function initHeartbeat(channelReg) {
|
|
11307
11687
|
registry2 = channelReg;
|
|
11308
11688
|
}
|
|
@@ -11488,7 +11868,7 @@ var init_heartbeat = __esm({
|
|
|
11488
11868
|
init_backends();
|
|
11489
11869
|
init_health2();
|
|
11490
11870
|
init_log();
|
|
11491
|
-
HEARTBEAT_MD_PATH =
|
|
11871
|
+
HEARTBEAT_MD_PATH = join18(WORKSPACE_PATH, "HEARTBEAT.md");
|
|
11492
11872
|
HEARTBEAT_OK = "HEARTBEAT_OK";
|
|
11493
11873
|
registry2 = null;
|
|
11494
11874
|
activeTimers2 = /* @__PURE__ */ new Map();
|
|
@@ -11671,9 +12051,9 @@ var init_classify = __esm({
|
|
|
11671
12051
|
});
|
|
11672
12052
|
|
|
11673
12053
|
// src/media/image-gen.ts
|
|
11674
|
-
import { mkdirSync as
|
|
12054
|
+
import { mkdirSync as mkdirSync7, existsSync as existsSync18 } from "fs";
|
|
11675
12055
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
11676
|
-
import { join as
|
|
12056
|
+
import { join as join19 } from "path";
|
|
11677
12057
|
async function generateImage(prompt) {
|
|
11678
12058
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
11679
12059
|
if (!apiKey) {
|
|
@@ -11721,11 +12101,11 @@ async function generateImage(prompt) {
|
|
|
11721
12101
|
throw new Error(textResponse ?? "Gemini did not generate an image. The prompt may have been filtered.");
|
|
11722
12102
|
}
|
|
11723
12103
|
if (!existsSync18(IMAGE_OUTPUT_DIR)) {
|
|
11724
|
-
|
|
12104
|
+
mkdirSync7(IMAGE_OUTPUT_DIR, { recursive: true });
|
|
11725
12105
|
}
|
|
11726
12106
|
const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
|
|
11727
12107
|
const filename = `img_${Date.now()}.${ext}`;
|
|
11728
|
-
const filePath =
|
|
12108
|
+
const filePath = join19(IMAGE_OUTPUT_DIR, filename);
|
|
11729
12109
|
const buffer = Buffer.from(imageData, "base64");
|
|
11730
12110
|
await writeFile2(filePath, buffer);
|
|
11731
12111
|
log(`[image-gen] Saved ${buffer.length} bytes to ${filePath}`);
|
|
@@ -11740,8 +12120,8 @@ var init_image_gen = __esm({
|
|
|
11740
12120
|
"use strict";
|
|
11741
12121
|
init_log();
|
|
11742
12122
|
IMAGE_MODEL = "gemini-3.1-flash-image-preview";
|
|
11743
|
-
IMAGE_OUTPUT_DIR =
|
|
11744
|
-
process.env.CC_CLAW_HOME ??
|
|
12123
|
+
IMAGE_OUTPUT_DIR = join19(
|
|
12124
|
+
process.env.CC_CLAW_HOME ?? join19(process.env.HOME ?? "/tmp", ".cc-claw"),
|
|
11745
12125
|
"data",
|
|
11746
12126
|
"images"
|
|
11747
12127
|
);
|
|
@@ -12980,7 +13360,7 @@ var init_pagination = __esm({
|
|
|
12980
13360
|
import { readFile as readFile5, writeFile as writeFile3, unlink as unlink2, mkdir as mkdir2, readdir as readdir3, stat } from "fs/promises";
|
|
12981
13361
|
import { existsSync as existsSync19 } from "fs";
|
|
12982
13362
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
12983
|
-
import { resolve as resolvePath, join as
|
|
13363
|
+
import { resolve as resolvePath, join as join20 } from "path";
|
|
12984
13364
|
import { homedir as homedir6 } from "os";
|
|
12985
13365
|
function parseMcpListOutput(output2) {
|
|
12986
13366
|
const results = [];
|
|
@@ -13223,7 +13603,7 @@ function getMediaRetentionMs() {
|
|
|
13223
13603
|
async function saveMedia(buffer, prefix, ext) {
|
|
13224
13604
|
await mkdir2(MEDIA_INCOMING_PATH, { recursive: true });
|
|
13225
13605
|
const filename = `${prefix}-${Date.now()}.${ext}`;
|
|
13226
|
-
const fullPath =
|
|
13606
|
+
const fullPath = join20(MEDIA_INCOMING_PATH, filename);
|
|
13227
13607
|
await writeFile3(fullPath, buffer);
|
|
13228
13608
|
return fullPath;
|
|
13229
13609
|
}
|
|
@@ -13237,7 +13617,7 @@ async function cleanupOldMedia() {
|
|
|
13237
13617
|
let removed = 0;
|
|
13238
13618
|
for (const file of files) {
|
|
13239
13619
|
try {
|
|
13240
|
-
const filePath =
|
|
13620
|
+
const filePath = join20(MEDIA_INCOMING_PATH, file);
|
|
13241
13621
|
const s = await stat(filePath);
|
|
13242
13622
|
if (now - s.mtimeMs > retentionMs) {
|
|
13243
13623
|
await unlink2(filePath);
|
|
@@ -13288,6 +13668,28 @@ function stopAllSideQuests(chatId) {
|
|
|
13288
13668
|
}
|
|
13289
13669
|
}
|
|
13290
13670
|
}
|
|
13671
|
+
async function sendCurrentProposal(chatId, channel) {
|
|
13672
|
+
const { getReviewSession: getReviewSession2, getInsightById: getInsightById2, deleteReviewSession: deleteReviewSession2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
13673
|
+
const { formatProposalCardWithProgress: formatProposalCardWithProgress2, buildProposalKeyboard: buildProposalKeyboard2, buildReviewCompleteMessage: buildReviewCompleteMessage2 } = await Promise.resolve().then(() => (init_propose(), propose_exports));
|
|
13674
|
+
const session2 = getReviewSession2(getDb(), chatId);
|
|
13675
|
+
if (!session2) return;
|
|
13676
|
+
if (session2.currentIndex >= session2.insightIds.length) {
|
|
13677
|
+
const summary = buildReviewCompleteMessage2(session2.results);
|
|
13678
|
+
deleteReviewSession2(getDb(), chatId);
|
|
13679
|
+
await channel.sendText(chatId, summary, { parseMode: "plain" });
|
|
13680
|
+
return;
|
|
13681
|
+
}
|
|
13682
|
+
const insightId = session2.insightIds[session2.currentIndex];
|
|
13683
|
+
const insight = getInsightById2(getDb(), insightId);
|
|
13684
|
+
if (!insight || insight.status !== "pending") {
|
|
13685
|
+
const { advanceReviewSession: advanceReviewSession2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
13686
|
+
advanceReviewSession2(getDb(), chatId, insightId, "skipped");
|
|
13687
|
+
return sendCurrentProposal(chatId, channel);
|
|
13688
|
+
}
|
|
13689
|
+
const card = formatProposalCardWithProgress2(insight, session2.currentIndex, session2.insightIds.length);
|
|
13690
|
+
const kb = buildProposalKeyboard2(insight.id, insight.category);
|
|
13691
|
+
await channel.sendKeyboard(chatId, card, kb);
|
|
13692
|
+
}
|
|
13291
13693
|
async function handleResponseExhaustion(responseText, chatId, msg, channel) {
|
|
13292
13694
|
const raw = responseText.replace(/\n\n🧠 \[.+$/, "").trim();
|
|
13293
13695
|
if (raw.length > 300 || !isExhaustedMessage(raw)) return false;
|
|
@@ -14915,22 +15317,16 @@ Message: "${testMsg}"`, { parseMode: "plain" });
|
|
|
14915
15317
|
await channel.sendText(chatId, "Step 2/3: Analyzing for insights...", { parseMode: "plain" });
|
|
14916
15318
|
try {
|
|
14917
15319
|
const { runAnalysis: runAnalysis2 } = await Promise.resolve().then(() => (init_analyze(), analyze_exports));
|
|
14918
|
-
const { formatProposalCard: formatProposalCard2, buildProposalKeyboard: buildProposalKeyboard2 } = await Promise.resolve().then(() => (init_propose(), propose_exports));
|
|
14919
15320
|
const insights = await runAnalysis2(chatId, { force: true });
|
|
14920
15321
|
if (insights.length === 0) {
|
|
14921
15322
|
await channel.sendText(chatId, "Step 3/3: No actionable improvements found in this session.", { parseMode: "plain" });
|
|
14922
15323
|
} else {
|
|
14923
|
-
await channel.sendText(chatId, `Step 3/3: Found ${insights.length} proposal(s).`, { parseMode: "plain" });
|
|
14924
|
-
const { getPendingInsights: getPendingInsights2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
15324
|
+
await channel.sendText(chatId, `Step 3/3: Found ${insights.length} proposal(s). Let's review them one by one.`, { parseMode: "plain" });
|
|
15325
|
+
const { getPendingInsights: getPendingInsights2, createReviewSession: createReviewSession2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
14925
15326
|
const pending = getPendingInsights2(getDb(), chatId);
|
|
14926
|
-
|
|
14927
|
-
|
|
14928
|
-
|
|
14929
|
-
await channel.sendKeyboard(chatId, card, kb);
|
|
14930
|
-
}
|
|
14931
|
-
if (insights.length > 5) {
|
|
14932
|
-
await channel.sendText(chatId, `${insights.length - 5} more proposals. Use /evolve to review all.`, { parseMode: "plain" });
|
|
14933
|
-
}
|
|
15327
|
+
const insightIds = pending.slice(0, 5).map((p) => p.id);
|
|
15328
|
+
createReviewSession2(getDb(), chatId, insightIds);
|
|
15329
|
+
await sendCurrentProposal(chatId, channel);
|
|
14934
15330
|
}
|
|
14935
15331
|
} catch (e) {
|
|
14936
15332
|
await channel.sendText(chatId, `Analysis failed: ${e}. You can review any pending proposals with /evolve.`, { parseMode: "plain" });
|
|
@@ -16677,21 +17073,16 @@ Result: ${task.result.slice(0, 500)}` : ""
|
|
|
16677
17073
|
break;
|
|
16678
17074
|
}
|
|
16679
17075
|
case "review": {
|
|
16680
|
-
const { getPendingInsights: getPendingInsights2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
16681
|
-
const { formatProposalCard: formatProposalCard2, buildProposalKeyboard: buildProposalKeyboard2 } = await Promise.resolve().then(() => (init_propose(), propose_exports));
|
|
17076
|
+
const { getPendingInsights: getPendingInsights2, createReviewSession: createReviewSession2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
16682
17077
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
16683
17078
|
const pending = getPendingInsights2(getDb2(), chatId);
|
|
16684
17079
|
if (pending.length === 0) {
|
|
16685
17080
|
await channel.sendText(chatId, "No pending proposals.", { parseMode: "plain" });
|
|
16686
17081
|
} else {
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
|
|
16690
|
-
|
|
16691
|
-
}
|
|
16692
|
-
if (pending.length > 5) {
|
|
16693
|
-
await channel.sendText(chatId, `${pending.length - 5} more proposals. Run /evolve again to see next batch.`, { parseMode: "plain" });
|
|
16694
|
-
}
|
|
17082
|
+
const insightIds = pending.slice(0, 5).map((p) => p.id);
|
|
17083
|
+
createReviewSession2(getDb2(), chatId, insightIds);
|
|
17084
|
+
await channel.sendText(chatId, `${pending.length} proposal(s) ready. Let's review them one by one.`, { parseMode: "plain" });
|
|
17085
|
+
await sendCurrentProposal(chatId, channel);
|
|
16695
17086
|
}
|
|
16696
17087
|
break;
|
|
16697
17088
|
}
|
|
@@ -16709,10 +17100,16 @@ Result: ${task.result.slice(0, 500)}` : ""
|
|
|
16709
17100
|
const { applyInsight: applyInsight2 } = await Promise.resolve().then(() => (init_apply(), apply_exports));
|
|
16710
17101
|
const result = await applyInsight2(parseInt(idStr, 10));
|
|
16711
17102
|
await channel.sendText(chatId, result.message, { parseMode: "plain" });
|
|
17103
|
+
const { advanceReviewSession: arAdvance } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
17104
|
+
arAdvance(getDb(), chatId, parseInt(idStr, 10), "applied");
|
|
17105
|
+
await sendCurrentProposal(chatId, channel);
|
|
16712
17106
|
break;
|
|
16713
17107
|
}
|
|
16714
17108
|
case "skip": {
|
|
16715
17109
|
await channel.sendText(chatId, "Skipped \u2014 will show again next review.", { parseMode: "plain" });
|
|
17110
|
+
const { advanceReviewSession: skAdvance } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
17111
|
+
skAdvance(getDb(), chatId, parseInt(idStr, 10), "skipped");
|
|
17112
|
+
await sendCurrentProposal(chatId, channel);
|
|
16716
17113
|
break;
|
|
16717
17114
|
}
|
|
16718
17115
|
case "discuss": {
|
|
@@ -16781,14 +17178,14 @@ Result: ${task.result.slice(0, 500)}` : ""
|
|
|
16781
17178
|
{ label: "USER.md", path: "identity/USER.md" }
|
|
16782
17179
|
];
|
|
16783
17180
|
const skillDirs = [
|
|
16784
|
-
|
|
17181
|
+
join20(homedir6(), ".cc-claw", "workspace", "skills")
|
|
16785
17182
|
];
|
|
16786
17183
|
try {
|
|
16787
|
-
const { readdirSync:
|
|
17184
|
+
const { readdirSync: readdirSync9, statSync: statSync10 } = await import("fs");
|
|
16788
17185
|
for (const dir of skillDirs) {
|
|
16789
17186
|
if (!existsSync19(dir)) continue;
|
|
16790
|
-
for (const entry of
|
|
16791
|
-
if (
|
|
17187
|
+
for (const entry of readdirSync9(dir)) {
|
|
17188
|
+
if (statSync10(join20(dir, entry)).isDirectory()) {
|
|
16792
17189
|
targets.push({ label: `skills/${entry}`, path: `workspace/skills/${entry}/SKILL.md` });
|
|
16793
17190
|
}
|
|
16794
17191
|
}
|
|
@@ -16862,14 +17259,20 @@ Pick a different file for this change. Identity files (SOUL/USER) shape personal
|
|
|
16862
17259
|
break;
|
|
16863
17260
|
}
|
|
16864
17261
|
case "discuss-back": {
|
|
16865
|
-
const { getInsightById: bkIns } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
16866
|
-
const { formatProposalCard:
|
|
17262
|
+
const { getInsightById: bkIns, getReviewSession: bkSession } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
17263
|
+
const { formatProposalCardWithProgress: formatProposalCardWithProgress2, formatProposalCard: bkCardFn, buildProposalKeyboard: bkKb } = await Promise.resolve().then(() => (init_propose(), propose_exports));
|
|
16867
17264
|
const { getDb: bkDb } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
16868
17265
|
const bkInsight = bkIns(bkDb(), parseInt(idStr, 10));
|
|
16869
17266
|
if (bkInsight && bkInsight.status === "pending") {
|
|
16870
|
-
const
|
|
17267
|
+
const session2 = bkSession(bkDb(), chatId);
|
|
16871
17268
|
const kb = bkKb(bkInsight.id, bkInsight.category);
|
|
16872
|
-
|
|
17269
|
+
if (session2) {
|
|
17270
|
+
const card = formatProposalCardWithProgress2(bkInsight, session2.currentIndex, session2.insightIds.length);
|
|
17271
|
+
await channel.sendKeyboard(chatId, card, kb);
|
|
17272
|
+
} else {
|
|
17273
|
+
const card = bkCardFn(bkInsight);
|
|
17274
|
+
await channel.sendKeyboard(chatId, card, kb);
|
|
17275
|
+
}
|
|
16873
17276
|
}
|
|
16874
17277
|
break;
|
|
16875
17278
|
}
|
|
@@ -16878,6 +17281,9 @@ Pick a different file for this change. Identity files (SOUL/USER) shape personal
|
|
|
16878
17281
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
16879
17282
|
updateInsightStatus2(getDb2(), parseInt(idStr, 10), "rejected");
|
|
16880
17283
|
await channel.sendText(chatId, "Rejected. Won't propose similar changes.", { parseMode: "plain" });
|
|
17284
|
+
const { advanceReviewSession: rjAdvance } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
17285
|
+
rjAdvance(getDb2(), chatId, parseInt(idStr, 10), "rejected");
|
|
17286
|
+
await sendCurrentProposal(chatId, channel);
|
|
16881
17287
|
break;
|
|
16882
17288
|
}
|
|
16883
17289
|
case "stats": {
|
|
@@ -16932,10 +17338,10 @@ Pick a different file for this change. Identity files (SOUL/USER) shape personal
|
|
|
16932
17338
|
const current = getReflectionStatus2(getDb2(), chatId);
|
|
16933
17339
|
if (current === "frozen") {
|
|
16934
17340
|
const { readFileSync: readFileSync21, existsSync: existsSync47 } = await import("fs");
|
|
16935
|
-
const { join:
|
|
17341
|
+
const { join: join27 } = await import("path");
|
|
16936
17342
|
const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
16937
|
-
const soulPath =
|
|
16938
|
-
const userPath =
|
|
17343
|
+
const soulPath = join27(CC_CLAW_HOME3, "identity/SOUL.md");
|
|
17344
|
+
const userPath = join27(CC_CLAW_HOME3, "identity/USER.md");
|
|
16939
17345
|
const soul = existsSync47(soulPath) ? readFileSync21(soulPath, "utf-8") : "";
|
|
16940
17346
|
const user = existsSync47(userPath) ? readFileSync21(userPath, "utf-8") : "";
|
|
16941
17347
|
setReflectionStatus2(getDb2(), chatId, "active", soul, user);
|
|
@@ -17638,7 +18044,7 @@ var init_router = __esm({
|
|
|
17638
18044
|
]
|
|
17639
18045
|
};
|
|
17640
18046
|
USAGE_WINDOW_MAP = { "24h": "daily", "7d": "weekly" };
|
|
17641
|
-
MEDIA_INCOMING_PATH =
|
|
18047
|
+
MEDIA_INCOMING_PATH = join20(MEDIA_PATH, "incoming");
|
|
17642
18048
|
TONE_PATTERNS = [
|
|
17643
18049
|
// Humor / laughter
|
|
17644
18050
|
{ pattern: /\b(lol|lmao|rofl|haha|hehe|😂|🤣|funny|hilarious|joke)\b/i, emoji: "\u{1F923}" },
|
|
@@ -17775,7 +18181,7 @@ var init_router = __esm({
|
|
|
17775
18181
|
// src/skills/bootstrap.ts
|
|
17776
18182
|
import { existsSync as existsSync20 } from "fs";
|
|
17777
18183
|
import { readdir as readdir4, readFile as readFile6, writeFile as writeFile4, copyFile } from "fs/promises";
|
|
17778
|
-
import { join as
|
|
18184
|
+
import { join as join21, dirname as dirname3 } from "path";
|
|
17779
18185
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
17780
18186
|
async function copyAgentManifestSkills() {
|
|
17781
18187
|
if (!existsSync20(PKG_SKILLS)) return;
|
|
@@ -17783,8 +18189,8 @@ async function copyAgentManifestSkills() {
|
|
|
17783
18189
|
const entries = await readdir4(PKG_SKILLS, { withFileTypes: true });
|
|
17784
18190
|
for (const entry of entries) {
|
|
17785
18191
|
if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
|
|
17786
|
-
const src =
|
|
17787
|
-
const dest =
|
|
18192
|
+
const src = join21(PKG_SKILLS, entry.name);
|
|
18193
|
+
const dest = join21(SKILLS_PATH, entry.name);
|
|
17788
18194
|
if (existsSync20(dest)) continue;
|
|
17789
18195
|
await copyFile(src, dest);
|
|
17790
18196
|
log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
|
|
@@ -17795,7 +18201,7 @@ async function copyAgentManifestSkills() {
|
|
|
17795
18201
|
}
|
|
17796
18202
|
async function bootstrapSkills() {
|
|
17797
18203
|
await copyAgentManifestSkills();
|
|
17798
|
-
const usmDir =
|
|
18204
|
+
const usmDir = join21(SKILLS_PATH, USM_DIR_NAME);
|
|
17799
18205
|
if (existsSync20(usmDir)) return;
|
|
17800
18206
|
try {
|
|
17801
18207
|
const entries = await readdir4(SKILLS_PATH);
|
|
@@ -17818,7 +18224,7 @@ async function bootstrapSkills() {
|
|
|
17818
18224
|
}
|
|
17819
18225
|
}
|
|
17820
18226
|
async function patchUsmForCcClaw(usmDir) {
|
|
17821
|
-
const skillPath =
|
|
18227
|
+
const skillPath = join21(usmDir, "SKILL.md");
|
|
17822
18228
|
if (!existsSync20(skillPath)) return;
|
|
17823
18229
|
try {
|
|
17824
18230
|
let content = await readFile6(skillPath, "utf-8");
|
|
@@ -17864,8 +18270,8 @@ var init_bootstrap = __esm({
|
|
|
17864
18270
|
USM_REPO = "jacob-bd/universal-skills-manager";
|
|
17865
18271
|
USM_DIR_NAME = "universal-skills-manager";
|
|
17866
18272
|
CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
|
|
17867
|
-
PKG_ROOT =
|
|
17868
|
-
PKG_SKILLS =
|
|
18273
|
+
PKG_ROOT = join21(dirname3(fileURLToPath2(import.meta.url)), "..", "..");
|
|
18274
|
+
PKG_SKILLS = join21(PKG_ROOT, "skills");
|
|
17869
18275
|
}
|
|
17870
18276
|
});
|
|
17871
18277
|
|
|
@@ -18079,8 +18485,8 @@ __export(ai_skill_exports, {
|
|
|
18079
18485
|
generateAiSkill: () => generateAiSkill,
|
|
18080
18486
|
installAiSkill: () => installAiSkill
|
|
18081
18487
|
});
|
|
18082
|
-
import { existsSync as existsSync21, writeFileSync as
|
|
18083
|
-
import { join as
|
|
18488
|
+
import { existsSync as existsSync21, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8 } from "fs";
|
|
18489
|
+
import { join as join22 } from "path";
|
|
18084
18490
|
import { homedir as homedir7 } from "os";
|
|
18085
18491
|
function generateAiSkill() {
|
|
18086
18492
|
const version = VERSION;
|
|
@@ -18481,11 +18887,11 @@ function installAiSkill() {
|
|
|
18481
18887
|
const failed = [];
|
|
18482
18888
|
for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
|
|
18483
18889
|
for (const dir of dirs) {
|
|
18484
|
-
const skillDir =
|
|
18485
|
-
const skillPath =
|
|
18890
|
+
const skillDir = join22(dir, "cc-claw-cli");
|
|
18891
|
+
const skillPath = join22(skillDir, "SKILL.md");
|
|
18486
18892
|
try {
|
|
18487
|
-
|
|
18488
|
-
|
|
18893
|
+
mkdirSync8(skillDir, { recursive: true });
|
|
18894
|
+
writeFileSync7(skillPath, skill, "utf-8");
|
|
18489
18895
|
installed.push(skillPath);
|
|
18490
18896
|
} catch {
|
|
18491
18897
|
failed.push(skillPath);
|
|
@@ -18501,11 +18907,11 @@ var init_ai_skill = __esm({
|
|
|
18501
18907
|
init_paths();
|
|
18502
18908
|
init_version();
|
|
18503
18909
|
BACKEND_SKILL_DIRS2 = {
|
|
18504
|
-
"cc-claw": [
|
|
18505
|
-
claude: [
|
|
18506
|
-
gemini: [
|
|
18507
|
-
codex: [
|
|
18508
|
-
cursor: [
|
|
18910
|
+
"cc-claw": [join22(homedir7(), ".cc-claw", "workspace", "skills")],
|
|
18911
|
+
claude: [join22(homedir7(), ".claude", "skills")],
|
|
18912
|
+
gemini: [join22(homedir7(), ".gemini", "skills")],
|
|
18913
|
+
codex: [join22(homedir7(), ".agents", "skills")],
|
|
18914
|
+
cursor: [join22(homedir7(), ".cursor", "skills"), join22(homedir7(), ".cursor", "skills-cursor")]
|
|
18509
18915
|
};
|
|
18510
18916
|
}
|
|
18511
18917
|
});
|
|
@@ -18515,18 +18921,18 @@ var index_exports = {};
|
|
|
18515
18921
|
__export(index_exports, {
|
|
18516
18922
|
main: () => main
|
|
18517
18923
|
});
|
|
18518
|
-
import { mkdirSync as
|
|
18519
|
-
import { join as
|
|
18924
|
+
import { mkdirSync as mkdirSync9, existsSync as existsSync22, renameSync, statSync as statSync5, readFileSync as readFileSync12 } from "fs";
|
|
18925
|
+
import { join as join23 } from "path";
|
|
18520
18926
|
import dotenv from "dotenv";
|
|
18521
18927
|
function migrateLayout() {
|
|
18522
18928
|
const moves = [
|
|
18523
|
-
[
|
|
18524
|
-
[
|
|
18525
|
-
[
|
|
18526
|
-
[
|
|
18527
|
-
[
|
|
18528
|
-
[
|
|
18529
|
-
[
|
|
18929
|
+
[join23(CC_CLAW_HOME, "cc-claw.db"), join23(DATA_PATH, "cc-claw.db")],
|
|
18930
|
+
[join23(CC_CLAW_HOME, "cc-claw.db-shm"), join23(DATA_PATH, "cc-claw.db-shm")],
|
|
18931
|
+
[join23(CC_CLAW_HOME, "cc-claw.db-wal"), join23(DATA_PATH, "cc-claw.db-wal")],
|
|
18932
|
+
[join23(CC_CLAW_HOME, "cc-claw.log"), join23(LOGS_PATH, "cc-claw.log")],
|
|
18933
|
+
[join23(CC_CLAW_HOME, "cc-claw.log.1"), join23(LOGS_PATH, "cc-claw.log.1")],
|
|
18934
|
+
[join23(CC_CLAW_HOME, "cc-claw.error.log"), join23(LOGS_PATH, "cc-claw.error.log")],
|
|
18935
|
+
[join23(CC_CLAW_HOME, "cc-claw.error.log.1"), join23(LOGS_PATH, "cc-claw.error.log.1")]
|
|
18530
18936
|
];
|
|
18531
18937
|
for (const [from, to] of moves) {
|
|
18532
18938
|
if (existsSync22(from) && !existsSync22(to)) {
|
|
@@ -18540,7 +18946,7 @@ function migrateLayout() {
|
|
|
18540
18946
|
function rotateLogs() {
|
|
18541
18947
|
for (const file of [LOG_PATH, ERROR_LOG_PATH]) {
|
|
18542
18948
|
try {
|
|
18543
|
-
const { size } =
|
|
18949
|
+
const { size } = statSync5(file);
|
|
18544
18950
|
if (size > LOG_MAX_BYTES) {
|
|
18545
18951
|
const archivePath = `${file}.1`;
|
|
18546
18952
|
try {
|
|
@@ -18663,11 +19069,11 @@ async function main() {
|
|
|
18663
19069
|
bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
|
|
18664
19070
|
try {
|
|
18665
19071
|
const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
|
|
18666
|
-
const { writeFileSync:
|
|
18667
|
-
const { join:
|
|
18668
|
-
const skillDir =
|
|
18669
|
-
|
|
18670
|
-
|
|
19072
|
+
const { writeFileSync: writeFileSync11, mkdirSync: mkdirSync14 } = await import("fs");
|
|
19073
|
+
const { join: join27 } = await import("path");
|
|
19074
|
+
const skillDir = join27(SKILLS_PATH, "cc-claw-cli");
|
|
19075
|
+
mkdirSync14(skillDir, { recursive: true });
|
|
19076
|
+
writeFileSync11(join27(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
|
|
18671
19077
|
log("[cc-claw] AI skill updated");
|
|
18672
19078
|
} catch {
|
|
18673
19079
|
}
|
|
@@ -18738,7 +19144,7 @@ var init_index = __esm({
|
|
|
18738
19144
|
init_bootstrap2();
|
|
18739
19145
|
init_health3();
|
|
18740
19146
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
18741
|
-
if (!existsSync22(dir))
|
|
19147
|
+
if (!existsSync22(dir)) mkdirSync9(dir, { recursive: true });
|
|
18742
19148
|
}
|
|
18743
19149
|
migrateLayout();
|
|
18744
19150
|
if (existsSync22(ENV_PATH)) {
|
|
@@ -18862,10 +19268,10 @@ __export(service_exports, {
|
|
|
18862
19268
|
serviceStatus: () => serviceStatus,
|
|
18863
19269
|
uninstallService: () => uninstallService
|
|
18864
19270
|
});
|
|
18865
|
-
import { existsSync as existsSync24, mkdirSync as
|
|
19271
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, unlinkSync as unlinkSync6 } from "fs";
|
|
18866
19272
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
18867
19273
|
import { homedir as homedir8, platform } from "os";
|
|
18868
|
-
import { join as
|
|
19274
|
+
import { join as join24, dirname as dirname4 } from "path";
|
|
18869
19275
|
function resolveExecutable2(name) {
|
|
18870
19276
|
try {
|
|
18871
19277
|
return execFileSync2("which", [name], { encoding: "utf-8" }).trim();
|
|
@@ -18878,14 +19284,14 @@ function getPathDirs() {
|
|
|
18878
19284
|
const home = homedir8();
|
|
18879
19285
|
const dirs = /* @__PURE__ */ new Set([
|
|
18880
19286
|
nodeBin,
|
|
18881
|
-
|
|
19287
|
+
join24(home, ".local", "bin"),
|
|
18882
19288
|
"/usr/local/bin",
|
|
18883
19289
|
"/usr/bin",
|
|
18884
19290
|
"/bin"
|
|
18885
19291
|
]);
|
|
18886
19292
|
try {
|
|
18887
19293
|
const prefix = execSync7("npm config get prefix", { encoding: "utf-8" }).trim();
|
|
18888
|
-
if (prefix) dirs.add(
|
|
19294
|
+
if (prefix) dirs.add(join24(prefix, "bin"));
|
|
18889
19295
|
} catch {
|
|
18890
19296
|
}
|
|
18891
19297
|
return [...dirs].join(":");
|
|
@@ -18937,15 +19343,15 @@ function generatePlist() {
|
|
|
18937
19343
|
}
|
|
18938
19344
|
function installMacOS() {
|
|
18939
19345
|
const agentsDir = dirname4(PLIST_PATH);
|
|
18940
|
-
if (!existsSync24(agentsDir))
|
|
18941
|
-
if (!existsSync24(LOGS_PATH))
|
|
19346
|
+
if (!existsSync24(agentsDir)) mkdirSync10(agentsDir, { recursive: true });
|
|
19347
|
+
if (!existsSync24(LOGS_PATH)) mkdirSync10(LOGS_PATH, { recursive: true });
|
|
18942
19348
|
if (existsSync24(PLIST_PATH)) {
|
|
18943
19349
|
try {
|
|
18944
19350
|
execFileSync2("launchctl", ["unload", PLIST_PATH]);
|
|
18945
19351
|
} catch {
|
|
18946
19352
|
}
|
|
18947
19353
|
}
|
|
18948
|
-
|
|
19354
|
+
writeFileSync8(PLIST_PATH, generatePlist());
|
|
18949
19355
|
console.log(` Installed: ${PLIST_PATH}`);
|
|
18950
19356
|
execFileSync2("launchctl", ["load", PLIST_PATH]);
|
|
18951
19357
|
console.log(" Service loaded and starting.");
|
|
@@ -18959,7 +19365,7 @@ function uninstallMacOS() {
|
|
|
18959
19365
|
execFileSync2("launchctl", ["unload", PLIST_PATH]);
|
|
18960
19366
|
} catch {
|
|
18961
19367
|
}
|
|
18962
|
-
|
|
19368
|
+
unlinkSync6(PLIST_PATH);
|
|
18963
19369
|
console.log(" Service uninstalled.");
|
|
18964
19370
|
}
|
|
18965
19371
|
function formatUptime(seconds) {
|
|
@@ -19025,9 +19431,9 @@ WantedBy=default.target
|
|
|
19025
19431
|
`;
|
|
19026
19432
|
}
|
|
19027
19433
|
function installLinux() {
|
|
19028
|
-
if (!existsSync24(SYSTEMD_DIR))
|
|
19029
|
-
if (!existsSync24(LOGS_PATH))
|
|
19030
|
-
|
|
19434
|
+
if (!existsSync24(SYSTEMD_DIR)) mkdirSync10(SYSTEMD_DIR, { recursive: true });
|
|
19435
|
+
if (!existsSync24(LOGS_PATH)) mkdirSync10(LOGS_PATH, { recursive: true });
|
|
19436
|
+
writeFileSync8(UNIT_PATH, generateUnit());
|
|
19031
19437
|
console.log(` Installed: ${UNIT_PATH}`);
|
|
19032
19438
|
execFileSync2("systemctl", ["--user", "daemon-reload"]);
|
|
19033
19439
|
execFileSync2("systemctl", ["--user", "enable", "cc-claw"]);
|
|
@@ -19047,7 +19453,7 @@ function uninstallLinux() {
|
|
|
19047
19453
|
execFileSync2("systemctl", ["--user", "disable", "cc-claw"]);
|
|
19048
19454
|
} catch {
|
|
19049
19455
|
}
|
|
19050
|
-
|
|
19456
|
+
unlinkSync6(UNIT_PATH);
|
|
19051
19457
|
execFileSync2("systemctl", ["--user", "daemon-reload"]);
|
|
19052
19458
|
console.log(" Service uninstalled.");
|
|
19053
19459
|
}
|
|
@@ -19060,7 +19466,7 @@ function statusLinux() {
|
|
|
19060
19466
|
}
|
|
19061
19467
|
}
|
|
19062
19468
|
function installService() {
|
|
19063
|
-
if (!existsSync24(
|
|
19469
|
+
if (!existsSync24(join24(CC_CLAW_HOME, ".env"))) {
|
|
19064
19470
|
console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
|
|
19065
19471
|
console.error(" Run 'cc-claw setup' before installing the service.");
|
|
19066
19472
|
process.exitCode = 1;
|
|
@@ -19089,9 +19495,9 @@ var init_service = __esm({
|
|
|
19089
19495
|
"use strict";
|
|
19090
19496
|
init_paths();
|
|
19091
19497
|
PLIST_LABEL = "com.cc-claw";
|
|
19092
|
-
PLIST_PATH =
|
|
19093
|
-
SYSTEMD_DIR =
|
|
19094
|
-
UNIT_PATH =
|
|
19498
|
+
PLIST_PATH = join24(homedir8(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
19499
|
+
SYSTEMD_DIR = join24(homedir8(), ".config", "systemd", "user");
|
|
19500
|
+
UNIT_PATH = join24(SYSTEMD_DIR, "cc-claw.service");
|
|
19095
19501
|
}
|
|
19096
19502
|
});
|
|
19097
19503
|
|
|
@@ -19288,7 +19694,7 @@ var status_exports = {};
|
|
|
19288
19694
|
__export(status_exports, {
|
|
19289
19695
|
statusCommand: () => statusCommand
|
|
19290
19696
|
});
|
|
19291
|
-
import { existsSync as existsSync25, statSync as
|
|
19697
|
+
import { existsSync as existsSync25, statSync as statSync6 } from "fs";
|
|
19292
19698
|
async function statusCommand(globalOpts, localOpts) {
|
|
19293
19699
|
try {
|
|
19294
19700
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
@@ -19328,7 +19734,7 @@ async function statusCommand(globalOpts, localOpts) {
|
|
|
19328
19734
|
const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
|
|
19329
19735
|
const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
|
|
19330
19736
|
const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
|
|
19331
|
-
const dbStat = existsSync25(DB_PATH) ?
|
|
19737
|
+
const dbStat = existsSync25(DB_PATH) ? statSync6(DB_PATH) : null;
|
|
19332
19738
|
let daemonRunning = false;
|
|
19333
19739
|
let daemonInfo = {};
|
|
19334
19740
|
if (localOpts.deep) {
|
|
@@ -19419,12 +19825,12 @@ var doctor_exports = {};
|
|
|
19419
19825
|
__export(doctor_exports, {
|
|
19420
19826
|
doctorCommand: () => doctorCommand
|
|
19421
19827
|
});
|
|
19422
|
-
import { existsSync as existsSync26, statSync as
|
|
19828
|
+
import { existsSync as existsSync26, statSync as statSync7, accessSync, constants } from "fs";
|
|
19423
19829
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
19424
19830
|
async function doctorCommand(globalOpts, localOpts) {
|
|
19425
19831
|
const checks = [];
|
|
19426
19832
|
if (existsSync26(DB_PATH)) {
|
|
19427
|
-
const size =
|
|
19833
|
+
const size = statSync7(DB_PATH).size;
|
|
19428
19834
|
checks.push({ name: "Database", status: "ok", message: `${DB_PATH} (${(size / 1024).toFixed(0)}KB)` });
|
|
19429
19835
|
try {
|
|
19430
19836
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
@@ -19714,8 +20120,8 @@ __export(gemini_exports, {
|
|
|
19714
20120
|
geminiReorder: () => geminiReorder,
|
|
19715
20121
|
geminiRotation: () => geminiRotation
|
|
19716
20122
|
});
|
|
19717
|
-
import { existsSync as existsSync28, mkdirSync as
|
|
19718
|
-
import { join as
|
|
20123
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync11, writeFileSync as writeFileSync9, readFileSync as readFileSync17, chmodSync } from "fs";
|
|
20124
|
+
import { join as join25 } from "path";
|
|
19719
20125
|
import { createInterface as createInterface5 } from "readline";
|
|
19720
20126
|
function requireDb() {
|
|
19721
20127
|
if (!existsSync28(DB_PATH)) {
|
|
@@ -19743,7 +20149,7 @@ async function resolveSlotId(idOrLabel) {
|
|
|
19743
20149
|
function resolveOAuthEmail(configHome) {
|
|
19744
20150
|
if (!configHome) return null;
|
|
19745
20151
|
try {
|
|
19746
|
-
const accountsPath =
|
|
20152
|
+
const accountsPath = join25(configHome, ".gemini", "google_accounts.json");
|
|
19747
20153
|
if (!existsSync28(accountsPath)) return null;
|
|
19748
20154
|
const accounts = JSON.parse(readFileSync17(accountsPath, "utf-8"));
|
|
19749
20155
|
return accounts.active || null;
|
|
@@ -19827,14 +20233,14 @@ async function geminiAddKey(globalOpts, opts) {
|
|
|
19827
20233
|
}
|
|
19828
20234
|
async function geminiAddAccount(globalOpts, opts) {
|
|
19829
20235
|
await requireWriteDb();
|
|
19830
|
-
const slotsDir =
|
|
19831
|
-
if (!existsSync28(slotsDir))
|
|
20236
|
+
const slotsDir = join25(CC_CLAW_HOME, "gemini-slots");
|
|
20237
|
+
if (!existsSync28(slotsDir)) mkdirSync11(slotsDir, { recursive: true });
|
|
19832
20238
|
const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
19833
20239
|
const tempId = Date.now();
|
|
19834
|
-
const slotDir =
|
|
19835
|
-
|
|
19836
|
-
|
|
19837
|
-
|
|
20240
|
+
const slotDir = join25(slotsDir, `slot-${tempId}`);
|
|
20241
|
+
mkdirSync11(slotDir, { recursive: true, mode: 448 });
|
|
20242
|
+
mkdirSync11(join25(slotDir, ".gemini"), { recursive: true });
|
|
20243
|
+
writeFileSync9(join25(slotDir, ".gemini", "settings.json"), JSON.stringify({
|
|
19838
20244
|
security: { auth: { selectedType: "oauth-personal" } }
|
|
19839
20245
|
}, null, 2));
|
|
19840
20246
|
console.log("");
|
|
@@ -19851,7 +20257,7 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
19851
20257
|
});
|
|
19852
20258
|
} catch {
|
|
19853
20259
|
}
|
|
19854
|
-
const oauthPath =
|
|
20260
|
+
const oauthPath = join25(slotDir, ".gemini", "oauth_creds.json");
|
|
19855
20261
|
if (!existsSync28(oauthPath)) {
|
|
19856
20262
|
console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
|
|
19857
20263
|
console.log(" The slot directory is preserved at: " + slotDir);
|
|
@@ -19860,7 +20266,7 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
19860
20266
|
}
|
|
19861
20267
|
let accountEmail = "unknown";
|
|
19862
20268
|
try {
|
|
19863
|
-
const accounts = JSON.parse(__require("fs").readFileSync(
|
|
20269
|
+
const accounts = JSON.parse(__require("fs").readFileSync(join25(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
|
|
19864
20270
|
accountEmail = accounts.active || accountEmail;
|
|
19865
20271
|
} catch {
|
|
19866
20272
|
}
|
|
@@ -20677,7 +21083,7 @@ __export(db_exports, {
|
|
|
20677
21083
|
dbPath: () => dbPath,
|
|
20678
21084
|
dbStats: () => dbStats
|
|
20679
21085
|
});
|
|
20680
|
-
import { existsSync as existsSync34, statSync as
|
|
21086
|
+
import { existsSync as existsSync34, statSync as statSync8, copyFileSync as copyFileSync2, mkdirSync as mkdirSync12 } from "fs";
|
|
20681
21087
|
import { dirname as dirname5 } from "path";
|
|
20682
21088
|
async function dbStats(globalOpts) {
|
|
20683
21089
|
if (!existsSync34(DB_PATH)) {
|
|
@@ -20686,9 +21092,9 @@ async function dbStats(globalOpts) {
|
|
|
20686
21092
|
}
|
|
20687
21093
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
20688
21094
|
const readDb = openDatabaseReadOnly2();
|
|
20689
|
-
const mainSize =
|
|
21095
|
+
const mainSize = statSync8(DB_PATH).size;
|
|
20690
21096
|
const walPath = DB_PATH + "-wal";
|
|
20691
|
-
const walSize = existsSync34(walPath) ?
|
|
21097
|
+
const walSize = existsSync34(walPath) ? statSync8(walPath).size : 0;
|
|
20692
21098
|
const tableNames = readDb.prepare(
|
|
20693
21099
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
|
|
20694
21100
|
).all();
|
|
@@ -20728,11 +21134,11 @@ async function dbBackup(globalOpts, destPath) {
|
|
|
20728
21134
|
}
|
|
20729
21135
|
const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
20730
21136
|
try {
|
|
20731
|
-
|
|
21137
|
+
mkdirSync12(dirname5(dest), { recursive: true });
|
|
20732
21138
|
copyFileSync2(DB_PATH, dest);
|
|
20733
21139
|
const walPath = DB_PATH + "-wal";
|
|
20734
21140
|
if (existsSync34(walPath)) copyFileSync2(walPath, dest + "-wal");
|
|
20735
|
-
output({ path: dest, sizeBytes:
|
|
21141
|
+
output({ path: dest, sizeBytes: statSync8(dest).size }, (d) => {
|
|
20736
21142
|
const b = d;
|
|
20737
21143
|
return `
|
|
20738
21144
|
${success("Backup created:")} ${b.path} (${(b.sizeBytes / 1024).toFixed(0)}KB)
|
|
@@ -22136,6 +22542,7 @@ __export(evolve_exports, {
|
|
|
22136
22542
|
evolveOff: () => evolveOff,
|
|
22137
22543
|
evolveOn: () => evolveOn,
|
|
22138
22544
|
evolveReject: () => evolveReject,
|
|
22545
|
+
evolveSettings: () => evolveSettings,
|
|
22139
22546
|
evolveStats: () => evolveStats,
|
|
22140
22547
|
evolveStatus: () => evolveStatus,
|
|
22141
22548
|
evolveUndo: () => evolveUndo
|
|
@@ -22492,6 +22899,60 @@ async function evolveHistory(globalOpts, opts) {
|
|
|
22492
22899
|
return lines.join("\n");
|
|
22493
22900
|
});
|
|
22494
22901
|
}
|
|
22902
|
+
async function evolveSettings(globalOpts, opts) {
|
|
22903
|
+
ensureDb3();
|
|
22904
|
+
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
22905
|
+
const chatId = resolveChatId(globalOpts);
|
|
22906
|
+
const hasUpdates = opts.perFileCap !== void 0 || opts.backupRetentionDays !== void 0;
|
|
22907
|
+
if (hasUpdates) {
|
|
22908
|
+
await ensureDaemon();
|
|
22909
|
+
const { apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
22910
|
+
const body = {};
|
|
22911
|
+
if (opts.perFileCap !== void 0) {
|
|
22912
|
+
const val = parseInt(opts.perFileCap, 10);
|
|
22913
|
+
if (isNaN(val) || val < 1) {
|
|
22914
|
+
outputError("INVALID_VALUE", "per-file-cap must be a positive integer.");
|
|
22915
|
+
process.exit(1);
|
|
22916
|
+
}
|
|
22917
|
+
body.perFileCap = val;
|
|
22918
|
+
}
|
|
22919
|
+
if (opts.backupRetentionDays !== void 0) {
|
|
22920
|
+
const val = parseInt(opts.backupRetentionDays, 10);
|
|
22921
|
+
if (isNaN(val) || val < 1) {
|
|
22922
|
+
outputError("INVALID_VALUE", "backup-retention-days must be a positive integer.");
|
|
22923
|
+
process.exit(1);
|
|
22924
|
+
}
|
|
22925
|
+
body.backupRetentionDays = val;
|
|
22926
|
+
}
|
|
22927
|
+
const res = await apiPost2("/api/evolve/settings", { chatId, ...body });
|
|
22928
|
+
if (res.ok) {
|
|
22929
|
+
output(res.data, () => `
|
|
22930
|
+
${success("Reflection settings updated.")}
|
|
22931
|
+
`);
|
|
22932
|
+
} else {
|
|
22933
|
+
outputError("SETTINGS_FAILED", `Failed: ${JSON.stringify(res.data)}`);
|
|
22934
|
+
process.exit(1);
|
|
22935
|
+
}
|
|
22936
|
+
} else {
|
|
22937
|
+
const readDb = openDatabaseReadOnly2();
|
|
22938
|
+
const { getReflectionSettings: getReflectionSettings2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
22939
|
+
const settings = getReflectionSettings2(readDb, chatId);
|
|
22940
|
+
readDb.close();
|
|
22941
|
+
output(settings, () => {
|
|
22942
|
+
const lines = [
|
|
22943
|
+
"",
|
|
22944
|
+
divider("Reflection Settings"),
|
|
22945
|
+
"",
|
|
22946
|
+
kvLine("Per-file cap", `${settings.perFileCap} changes/day per file`),
|
|
22947
|
+
kvLine("Backup retention", `${settings.backupRetentionDays} days`),
|
|
22948
|
+
"",
|
|
22949
|
+
muted("Update with: cc-claw evolve settings --per-file-cap <n> --backup-retention-days <n>"),
|
|
22950
|
+
""
|
|
22951
|
+
];
|
|
22952
|
+
return lines.join("\n");
|
|
22953
|
+
});
|
|
22954
|
+
}
|
|
22955
|
+
}
|
|
22495
22956
|
var init_evolve = __esm({
|
|
22496
22957
|
"src/cli/commands/evolve.ts"() {
|
|
22497
22958
|
"use strict";
|
|
@@ -22504,10 +22965,10 @@ var init_evolve = __esm({
|
|
|
22504
22965
|
|
|
22505
22966
|
// src/setup.ts
|
|
22506
22967
|
var setup_exports = {};
|
|
22507
|
-
import { existsSync as existsSync46, writeFileSync as
|
|
22968
|
+
import { existsSync as existsSync46, writeFileSync as writeFileSync10, readFileSync as readFileSync20, copyFileSync as copyFileSync3, mkdirSync as mkdirSync13, statSync as statSync9 } from "fs";
|
|
22508
22969
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
22509
22970
|
import { createInterface as createInterface7 } from "readline";
|
|
22510
|
-
import { join as
|
|
22971
|
+
import { join as join26 } from "path";
|
|
22511
22972
|
function divider2() {
|
|
22512
22973
|
console.log(dim("\u2500".repeat(55)));
|
|
22513
22974
|
}
|
|
@@ -22582,7 +23043,7 @@ async function setup() {
|
|
|
22582
23043
|
}
|
|
22583
23044
|
console.log("");
|
|
22584
23045
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
22585
|
-
if (!existsSync46(dir))
|
|
23046
|
+
if (!existsSync46(dir)) mkdirSync13(dir, { recursive: true });
|
|
22586
23047
|
}
|
|
22587
23048
|
const env = {};
|
|
22588
23049
|
const envSource = existsSync46(ENV_PATH) ? ENV_PATH : existsSync46(".env") ? ".env" : null;
|
|
@@ -22595,9 +23056,9 @@ async function setup() {
|
|
|
22595
23056
|
if (match) env[match[1].trim()] = match[2].trim();
|
|
22596
23057
|
}
|
|
22597
23058
|
}
|
|
22598
|
-
const cwdDb =
|
|
23059
|
+
const cwdDb = join26(process.cwd(), "cc-claw.db");
|
|
22599
23060
|
if (existsSync46(cwdDb) && !existsSync46(DB_PATH)) {
|
|
22600
|
-
const { size } =
|
|
23061
|
+
const { size } = statSync9(cwdDb);
|
|
22601
23062
|
console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
|
|
22602
23063
|
const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
|
|
22603
23064
|
if (migrate) {
|
|
@@ -22813,7 +23274,7 @@ async function setup() {
|
|
|
22813
23274
|
envLines.push("", "# Video Analysis", `GEMINI_API_KEY=${env.GEMINI_API_KEY}`);
|
|
22814
23275
|
}
|
|
22815
23276
|
const envContent = envLines.join("\n") + "\n";
|
|
22816
|
-
|
|
23277
|
+
writeFileSync10(ENV_PATH, envContent, { mode: 384 });
|
|
22817
23278
|
console.log(green(` Config saved to ${ENV_PATH} (permissions: owner-only)`));
|
|
22818
23279
|
header(6, TOTAL_STEPS, "Run on Startup (Daemon)");
|
|
22819
23280
|
console.log(" CC-Claw can run automatically in the background, starting");
|
|
@@ -23407,6 +23868,10 @@ evolve.command("history").description("Insight history").option("--status <statu
|
|
|
23407
23868
|
const { evolveHistory: evolveHistory2 } = await Promise.resolve().then(() => (init_evolve(), evolve_exports));
|
|
23408
23869
|
await evolveHistory2(program.opts(), opts);
|
|
23409
23870
|
});
|
|
23871
|
+
evolve.command("settings").description("View or update reflection settings").option("--per-file-cap <n>", "Max applies per file per day").option("--backup-retention-days <n>", "Days to keep backup files").action(async (opts) => {
|
|
23872
|
+
const { evolveSettings: evolveSettings2 } = await Promise.resolve().then(() => (init_evolve(), evolve_exports));
|
|
23873
|
+
await evolveSettings2(program.opts(), opts);
|
|
23874
|
+
});
|
|
23410
23875
|
program.command("start", { hidden: true }).description("Run the bot in the foreground (use 'service start' for background daemon)").action(async () => {
|
|
23411
23876
|
await Promise.resolve().then(() => (init_index(), index_exports));
|
|
23412
23877
|
});
|