cc-claw 0.29.3 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1221 -389
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ var VERSION;
|
|
|
33
33
|
var init_version = __esm({
|
|
34
34
|
"src/version.ts"() {
|
|
35
35
|
"use strict";
|
|
36
|
-
VERSION = true ? "0.
|
|
36
|
+
VERSION = true ? "0.30.0" : (() => {
|
|
37
37
|
try {
|
|
38
38
|
return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
39
39
|
} catch {
|
|
@@ -806,6 +806,7 @@ __export(store_exports4, {
|
|
|
806
806
|
getRejectedInsights: () => getRejectedInsights,
|
|
807
807
|
getReviewSession: () => getReviewSession,
|
|
808
808
|
getSignalCountForChat: () => getSignalCountForChat,
|
|
809
|
+
getSkillCorrections: () => getSkillCorrections,
|
|
809
810
|
getUnprocessedSignalCount: () => getUnprocessedSignalCount,
|
|
810
811
|
getUnprocessedSignals: () => getUnprocessedSignals,
|
|
811
812
|
initReflectionTables: () => initReflectionTables,
|
|
@@ -872,11 +873,13 @@ function initReflectionTables(db3) {
|
|
|
872
873
|
backend TEXT,
|
|
873
874
|
model TEXT,
|
|
874
875
|
thinkingLevel TEXT,
|
|
876
|
+
skill_name TEXT,
|
|
875
877
|
processedAt TEXT,
|
|
876
878
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
877
879
|
);
|
|
878
880
|
CREATE INDEX IF NOT EXISTS idx_signals_chat_time ON feedback_signals (chatId, created_at DESC);
|
|
879
881
|
CREATE INDEX IF NOT EXISTS idx_signals_unprocessed ON feedback_signals (processedAt) WHERE processedAt IS NULL;
|
|
882
|
+
CREATE INDEX IF NOT EXISTS idx_signals_skill ON feedback_signals (skill_name) WHERE skill_name IS NOT NULL;
|
|
880
883
|
|
|
881
884
|
CREATE TABLE IF NOT EXISTS insights (
|
|
882
885
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -949,11 +952,17 @@ function initReflectionTables(db3) {
|
|
|
949
952
|
cleanupReflectionData(db3);
|
|
950
953
|
const settings = getReflectionSettings(db3, "global");
|
|
951
954
|
cleanupBackupFiles(CC_CLAW_HOME, settings.backupRetentionDays);
|
|
955
|
+
try {
|
|
956
|
+
db3.prepare("SELECT skill_name FROM feedback_signals LIMIT 0").get();
|
|
957
|
+
} catch {
|
|
958
|
+
db3.exec("ALTER TABLE feedback_signals ADD COLUMN skill_name TEXT");
|
|
959
|
+
db3.exec("CREATE INDEX IF NOT EXISTS idx_signals_skill ON feedback_signals (skill_name) WHERE skill_name IS NOT NULL");
|
|
960
|
+
}
|
|
952
961
|
}
|
|
953
962
|
function logSignal(db3, params) {
|
|
954
963
|
const result = db3.prepare(`
|
|
955
|
-
INSERT INTO feedback_signals (chatId, signalType, trigger, context, source, confidence, backend, model, thinkingLevel)
|
|
956
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
964
|
+
INSERT INTO feedback_signals (chatId, signalType, trigger, context, source, confidence, backend, model, thinkingLevel, skill_name)
|
|
965
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
957
966
|
`).run(
|
|
958
967
|
params.chatId,
|
|
959
968
|
params.signalType,
|
|
@@ -963,7 +972,8 @@ function logSignal(db3, params) {
|
|
|
963
972
|
params.confidence,
|
|
964
973
|
params.backend ?? null,
|
|
965
974
|
params.model ?? null,
|
|
966
|
-
params.thinkingLevel ?? null
|
|
975
|
+
params.thinkingLevel ?? null,
|
|
976
|
+
params.skillName ?? null
|
|
967
977
|
);
|
|
968
978
|
return Number(result.lastInsertRowid);
|
|
969
979
|
}
|
|
@@ -1004,6 +1014,56 @@ function getLastAnalysisTime(db3, chatId) {
|
|
|
1004
1014
|
`).get(chatId);
|
|
1005
1015
|
return row.lastTime;
|
|
1006
1016
|
}
|
|
1017
|
+
function getSkillCorrections(db3, windowDays = 30, minCorrections = 3) {
|
|
1018
|
+
const skillRows = db3.prepare(`
|
|
1019
|
+
SELECT
|
|
1020
|
+
skill_name,
|
|
1021
|
+
COUNT(*) AS cnt,
|
|
1022
|
+
GROUP_CONCAT(context, '|||') AS contexts_raw
|
|
1023
|
+
FROM feedback_signals
|
|
1024
|
+
WHERE
|
|
1025
|
+
signalType = 'correction'
|
|
1026
|
+
AND skill_name IS NOT NULL
|
|
1027
|
+
AND created_at >= datetime('now', '-' || ? || ' days')
|
|
1028
|
+
GROUP BY skill_name
|
|
1029
|
+
HAVING cnt >= ?
|
|
1030
|
+
ORDER BY cnt DESC
|
|
1031
|
+
`).all(windowDays, minCorrections);
|
|
1032
|
+
if (skillRows.length === 0) return [];
|
|
1033
|
+
const skillNames = skillRows.map((r) => r.skill_name);
|
|
1034
|
+
const placeholders = skillNames.map(() => "?").join(", ");
|
|
1035
|
+
const breakdownRows = db3.prepare(`
|
|
1036
|
+
SELECT
|
|
1037
|
+
skill_name,
|
|
1038
|
+
model,
|
|
1039
|
+
COUNT(*) AS cnt
|
|
1040
|
+
FROM feedback_signals
|
|
1041
|
+
WHERE
|
|
1042
|
+
signalType = 'correction'
|
|
1043
|
+
AND skill_name IN (${placeholders})
|
|
1044
|
+
AND model IS NOT NULL
|
|
1045
|
+
AND created_at >= datetime('now', '-' || ? || ' days')
|
|
1046
|
+
GROUP BY skill_name, model
|
|
1047
|
+
ORDER BY skill_name, cnt DESC
|
|
1048
|
+
`).all(...skillNames, windowDays);
|
|
1049
|
+
const breakdownMap = /* @__PURE__ */ new Map();
|
|
1050
|
+
for (const row of breakdownRows) {
|
|
1051
|
+
if (!breakdownMap.has(row.skill_name)) {
|
|
1052
|
+
breakdownMap.set(row.skill_name, []);
|
|
1053
|
+
}
|
|
1054
|
+
breakdownMap.get(row.skill_name).push({ model: row.model, count: row.cnt });
|
|
1055
|
+
}
|
|
1056
|
+
return skillRows.map((row) => {
|
|
1057
|
+
const rawContexts = row.contexts_raw ? row.contexts_raw.split("|||") : [];
|
|
1058
|
+
const contexts = rawContexts.filter((c) => c && c.trim().length > 0);
|
|
1059
|
+
return {
|
|
1060
|
+
skillName: row.skill_name,
|
|
1061
|
+
correctionCount: row.cnt,
|
|
1062
|
+
contexts,
|
|
1063
|
+
modelBreakdown: breakdownMap.get(row.skill_name) ?? []
|
|
1064
|
+
};
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1007
1067
|
function getReflectionStatus(db3, chatId) {
|
|
1008
1068
|
const row = db3.prepare("SELECT status FROM chat_reflection WHERE chatId = ?").get(chatId);
|
|
1009
1069
|
return row?.status ?? "frozen";
|
|
@@ -2009,6 +2069,12 @@ function initSchema(db3) {
|
|
|
2009
2069
|
value INTEGER NOT NULL DEFAULT 0
|
|
2010
2070
|
);
|
|
2011
2071
|
`);
|
|
2072
|
+
db3.exec(`
|
|
2073
|
+
CREATE TABLE IF NOT EXISTS chat_pinned_skills (
|
|
2074
|
+
chat_id TEXT PRIMARY KEY,
|
|
2075
|
+
skills TEXT NOT NULL DEFAULT '[]'
|
|
2076
|
+
);
|
|
2077
|
+
`);
|
|
2012
2078
|
db3.exec(`
|
|
2013
2079
|
CREATE TABLE IF NOT EXISTS backend_credentials (
|
|
2014
2080
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -2091,17 +2157,48 @@ function applySalienceDecay(db3) {
|
|
|
2091
2157
|
db3.prepare("DELETE FROM session_summaries WHERE salience < 0.1").run();
|
|
2092
2158
|
db3.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES ('last_salience_decay', ?)").run(now);
|
|
2093
2159
|
}
|
|
2160
|
+
function _setSchemaDbGetter(getter) {
|
|
2161
|
+
_getDb = getter;
|
|
2162
|
+
}
|
|
2094
2163
|
function getMetaValue(key) {
|
|
2095
|
-
|
|
2096
|
-
const db3 =
|
|
2164
|
+
if (!_getDb) throw new Error("[schema] DB getter not initialized \u2014 was _setSchemaDbGetter() called?");
|
|
2165
|
+
const db3 = _getDb();
|
|
2097
2166
|
const row = db3.prepare("SELECT value FROM meta WHERE key = ?").get(key);
|
|
2098
2167
|
return row?.value;
|
|
2099
2168
|
}
|
|
2100
2169
|
function setMetaValue(key, value) {
|
|
2101
|
-
|
|
2102
|
-
const db3 =
|
|
2170
|
+
if (!_getDb) throw new Error("[schema] DB getter not initialized \u2014 was _setSchemaDbGetter() called?");
|
|
2171
|
+
const db3 = _getDb();
|
|
2103
2172
|
db3.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run(key, value);
|
|
2104
2173
|
}
|
|
2174
|
+
function getDisabledBackends() {
|
|
2175
|
+
if (_disabledCache) return _disabledCache;
|
|
2176
|
+
const json = getMetaValue(DISABLED_BACKENDS_KEY);
|
|
2177
|
+
if (!json) {
|
|
2178
|
+
_disabledCache = [];
|
|
2179
|
+
return _disabledCache;
|
|
2180
|
+
}
|
|
2181
|
+
try {
|
|
2182
|
+
_disabledCache = JSON.parse(json);
|
|
2183
|
+
return _disabledCache;
|
|
2184
|
+
} catch {
|
|
2185
|
+
_disabledCache = [];
|
|
2186
|
+
return _disabledCache;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
function setBackendDisabled(backendId, disabled) {
|
|
2190
|
+
const current = [...getDisabledBackends()];
|
|
2191
|
+
if (disabled) {
|
|
2192
|
+
if (!current.includes(backendId)) {
|
|
2193
|
+
current.push(backendId);
|
|
2194
|
+
}
|
|
2195
|
+
} else {
|
|
2196
|
+
const idx = current.indexOf(backendId);
|
|
2197
|
+
if (idx !== -1) current.splice(idx, 1);
|
|
2198
|
+
}
|
|
2199
|
+
setMetaValue(DISABLED_BACKENDS_KEY, JSON.stringify(current));
|
|
2200
|
+
_disabledCache = current;
|
|
2201
|
+
}
|
|
2105
2202
|
function backfillJobTitles(database) {
|
|
2106
2203
|
const rows = database.prepare(
|
|
2107
2204
|
"SELECT id, description FROM jobs WHERE active = 1 AND (title IS NULL OR title LIKE 'No thinking%' OR title LIKE 'You must%' OR title LIKE 'You MUST%')"
|
|
@@ -2125,6 +2222,7 @@ function backfillJobTitles(database) {
|
|
|
2125
2222
|
database.prepare("UPDATE jobs SET title = ? WHERE id = ?").run(title, row.id);
|
|
2126
2223
|
}
|
|
2127
2224
|
}
|
|
2225
|
+
var _getDb, DISABLED_BACKENDS_KEY, _disabledCache;
|
|
2128
2226
|
var init_schema = __esm({
|
|
2129
2227
|
"src/memory/schema.ts"() {
|
|
2130
2228
|
"use strict";
|
|
@@ -2135,6 +2233,9 @@ var init_schema = __esm({
|
|
|
2135
2233
|
init_store4();
|
|
2136
2234
|
init_log();
|
|
2137
2235
|
init_classify();
|
|
2236
|
+
_getDb = null;
|
|
2237
|
+
DISABLED_BACKENDS_KEY = "disabled_backends";
|
|
2238
|
+
_disabledCache = null;
|
|
2138
2239
|
}
|
|
2139
2240
|
});
|
|
2140
2241
|
|
|
@@ -2819,6 +2920,7 @@ __export(chat_settings_exports, {
|
|
|
2819
2920
|
clearExecMode: () => clearExecMode,
|
|
2820
2921
|
clearModel: () => clearModel,
|
|
2821
2922
|
clearModelMap: () => clearModelMap,
|
|
2923
|
+
clearPinnedSkills: () => clearPinnedSkills,
|
|
2822
2924
|
clearSummarizer: () => clearSummarizer,
|
|
2823
2925
|
clearThinkingLevel: () => clearThinkingLevel,
|
|
2824
2926
|
countSummarizerOverrides: () => countSummarizerOverrides,
|
|
@@ -2837,6 +2939,7 @@ __export(chat_settings_exports, {
|
|
|
2837
2939
|
getMode: () => getMode,
|
|
2838
2940
|
getModel: () => getModel,
|
|
2839
2941
|
getPendingEscalation: () => getPendingEscalation,
|
|
2942
|
+
getPinnedSkills: () => getPinnedSkills,
|
|
2840
2943
|
getRecentBookmarks: () => getRecentBookmarks,
|
|
2841
2944
|
getSessionLogEnabled: () => getSessionLogEnabled,
|
|
2842
2945
|
getShowThinkingUi: () => getShowThinkingUi,
|
|
@@ -2856,6 +2959,7 @@ __export(chat_settings_exports, {
|
|
|
2856
2959
|
setGlobalSummarizer: () => setGlobalSummarizer,
|
|
2857
2960
|
setMode: () => setMode,
|
|
2858
2961
|
setModel: () => setModel,
|
|
2962
|
+
setPinnedSkills: () => setPinnedSkills,
|
|
2859
2963
|
setSessionLogEnabled: () => setSessionLogEnabled,
|
|
2860
2964
|
setShowThinkingUi: () => setShowThinkingUi,
|
|
2861
2965
|
setSkillSuggestionsEnabled: () => setSkillSuggestionsEnabled,
|
|
@@ -3265,6 +3369,27 @@ function toggleSessionLogEnabled(chatId) {
|
|
|
3265
3369
|
setSessionLogEnabled(chatId, next);
|
|
3266
3370
|
return next;
|
|
3267
3371
|
}
|
|
3372
|
+
function getPinnedSkills(chatId) {
|
|
3373
|
+
const row = getDb().prepare(
|
|
3374
|
+
"SELECT skills FROM chat_pinned_skills WHERE chat_id = ?"
|
|
3375
|
+
).get(chatId);
|
|
3376
|
+
if (!row?.skills) return [];
|
|
3377
|
+
try {
|
|
3378
|
+
return JSON.parse(row.skills);
|
|
3379
|
+
} catch {
|
|
3380
|
+
return [];
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
function setPinnedSkills(chatId, skills2) {
|
|
3384
|
+
getDb().prepare(`
|
|
3385
|
+
INSERT INTO chat_pinned_skills (chat_id, skills)
|
|
3386
|
+
VALUES (?, ?)
|
|
3387
|
+
ON CONFLICT(chat_id) DO UPDATE SET skills = ?
|
|
3388
|
+
`).run(chatId, JSON.stringify(skills2), JSON.stringify(skills2));
|
|
3389
|
+
}
|
|
3390
|
+
function clearPinnedSkills(chatId) {
|
|
3391
|
+
getDb().prepare("DELETE FROM chat_pinned_skills WHERE chat_id = ?").run(chatId);
|
|
3392
|
+
}
|
|
3268
3393
|
function getAllowPaidSlots(chatId, backend2) {
|
|
3269
3394
|
const row = getDb().prepare(
|
|
3270
3395
|
"SELECT 1 FROM chat_allow_paid_slots WHERE chat_id = ? AND backend = ?"
|
|
@@ -3648,6 +3773,7 @@ __export(jobs_exports, {
|
|
|
3648
3773
|
cancelJobById: () => cancelJobById,
|
|
3649
3774
|
completeJobRun: () => completeJobRun,
|
|
3650
3775
|
getActiveJobs: () => getActiveJobs,
|
|
3776
|
+
getActiveJobsByBackend: () => getActiveJobsByBackend,
|
|
3651
3777
|
getAllJobs: () => getAllJobs,
|
|
3652
3778
|
getJobById: () => getJobById,
|
|
3653
3779
|
getJobRuns: () => getJobRuns,
|
|
@@ -3655,6 +3781,7 @@ __export(jobs_exports, {
|
|
|
3655
3781
|
insertJob: () => insertJob,
|
|
3656
3782
|
insertJobRun: () => insertJobRun,
|
|
3657
3783
|
pruneJobRuns: () => pruneJobRuns,
|
|
3784
|
+
reassignJobsBackend: () => reassignJobsBackend,
|
|
3658
3785
|
resetJobFailures: () => resetJobFailures,
|
|
3659
3786
|
updateJob: () => updateJob,
|
|
3660
3787
|
updateJobEnabled: () => updateJobEnabled,
|
|
@@ -3711,6 +3838,15 @@ function getActiveJobs() {
|
|
|
3711
3838
|
function getAllJobs() {
|
|
3712
3839
|
return getDb().prepare(`${JOB_SELECT} WHERE active = 1 ORDER BY id`).all().map((r) => mapJobRow(r));
|
|
3713
3840
|
}
|
|
3841
|
+
function getActiveJobsByBackend(backendId) {
|
|
3842
|
+
return getDb().prepare(`${JOB_SELECT} WHERE active = 1 AND enabled = 1 AND backend = ?`).all(backendId).map((r) => mapJobRow(r));
|
|
3843
|
+
}
|
|
3844
|
+
function reassignJobsBackend(fromBackend, toBackend) {
|
|
3845
|
+
const result = getDb().prepare(
|
|
3846
|
+
"UPDATE jobs SET backend = ? WHERE active = 1 AND enabled = 1 AND backend = ?"
|
|
3847
|
+
).run(toBackend, fromBackend);
|
|
3848
|
+
return result.changes;
|
|
3849
|
+
}
|
|
3714
3850
|
function updateJobEnabled(id, enabled) {
|
|
3715
3851
|
const result = getDb().prepare("UPDATE jobs SET enabled = ? WHERE id = ?").run(enabled ? 1 : 0, id);
|
|
3716
3852
|
return result.changes > 0;
|
|
@@ -4904,6 +5040,7 @@ __export(store_exports5, {
|
|
|
4904
5040
|
clearMessageLog: () => clearMessageLog,
|
|
4905
5041
|
clearModel: () => clearModel,
|
|
4906
5042
|
clearModelMap: () => clearModelMap,
|
|
5043
|
+
clearPinnedSkills: () => clearPinnedSkills,
|
|
4907
5044
|
clearSession: () => clearSession,
|
|
4908
5045
|
clearSummarizer: () => clearSummarizer,
|
|
4909
5046
|
clearThinkingLevel: () => clearThinkingLevel,
|
|
@@ -4922,6 +5059,7 @@ __export(store_exports5, {
|
|
|
4922
5059
|
forget: () => forget,
|
|
4923
5060
|
forgetMemory: () => forgetMemory,
|
|
4924
5061
|
getActiveJobs: () => getActiveJobs,
|
|
5062
|
+
getActiveJobsByBackend: () => getActiveJobsByBackend,
|
|
4925
5063
|
getActiveWatches: () => getActiveWatches,
|
|
4926
5064
|
getAgentMode: () => getAgentMode,
|
|
4927
5065
|
getAllBackendLimits: () => getAllBackendLimits,
|
|
@@ -4948,6 +5086,7 @@ __export(store_exports5, {
|
|
|
4948
5086
|
getChatUsageByModel: () => getChatUsageByModel,
|
|
4949
5087
|
getCwd: () => getCwd,
|
|
4950
5088
|
getDb: () => getDb,
|
|
5089
|
+
getDisabledBackends: () => getDisabledBackends,
|
|
4951
5090
|
getEligibleBackendSlots: () => getEligibleBackendSlots,
|
|
4952
5091
|
getEligibleGeminiSlots: () => getEligibleGeminiSlots,
|
|
4953
5092
|
getEnabledTools: () => getEnabledTools,
|
|
@@ -4969,6 +5108,7 @@ __export(store_exports5, {
|
|
|
4969
5108
|
getNextBackendSlot: () => getNextBackendSlot,
|
|
4970
5109
|
getNextGeminiSlot: () => getNextGeminiSlot,
|
|
4971
5110
|
getPendingEscalation: () => getPendingEscalation,
|
|
5111
|
+
getPinnedSkills: () => getPinnedSkills,
|
|
4972
5112
|
getRecentBookmarks: () => getRecentBookmarks,
|
|
4973
5113
|
getRecentMemories: () => getRecentMemories,
|
|
4974
5114
|
getRecentMessageLog: () => getRecentMessageLog,
|
|
@@ -5010,6 +5150,7 @@ __export(store_exports5, {
|
|
|
5010
5150
|
pruneJobRuns: () => pruneJobRuns,
|
|
5011
5151
|
pruneMessageLog: () => pruneMessageLog,
|
|
5012
5152
|
queueHalfLifeExtension: () => queueHalfLifeExtension,
|
|
5153
|
+
reassignJobsBackend: () => reassignJobsBackend,
|
|
5013
5154
|
recall: () => recall,
|
|
5014
5155
|
reenableBackendSlot: () => reenableBackendSlot,
|
|
5015
5156
|
reenableSlot: () => reenableSlot,
|
|
@@ -5041,6 +5182,7 @@ __export(store_exports5, {
|
|
|
5041
5182
|
setAgentMode: () => setAgentMode,
|
|
5042
5183
|
setAllowPaidSlots: () => setAllowPaidSlots,
|
|
5043
5184
|
setBackend: () => setBackend,
|
|
5185
|
+
setBackendDisabled: () => setBackendDisabled,
|
|
5044
5186
|
setBackendLimit: () => setBackendLimit,
|
|
5045
5187
|
setBackendRotationMode: () => setBackendRotationMode,
|
|
5046
5188
|
setBackendSlotEnabled: () => setBackendSlotEnabled,
|
|
@@ -5056,6 +5198,7 @@ __export(store_exports5, {
|
|
|
5056
5198
|
setMode: () => setMode,
|
|
5057
5199
|
setModel: () => setModel,
|
|
5058
5200
|
setModelSignature: () => setModelSignature,
|
|
5201
|
+
setPinnedSkills: () => setPinnedSkills,
|
|
5059
5202
|
setResponseStyle: () => setResponseStyle,
|
|
5060
5203
|
setSessionId: () => setSessionId,
|
|
5061
5204
|
setSessionLogEnabled: () => setSessionLogEnabled,
|
|
@@ -5087,6 +5230,7 @@ function initDatabase() {
|
|
|
5087
5230
|
db = new Database(DB_PATH);
|
|
5088
5231
|
db.pragma("journal_mode = WAL");
|
|
5089
5232
|
db.pragma("foreign_keys = ON");
|
|
5233
|
+
_setSchemaDbGetter(() => db);
|
|
5090
5234
|
initSchema(db);
|
|
5091
5235
|
startMaintenanceTimers(db);
|
|
5092
5236
|
}
|
|
@@ -5102,6 +5246,7 @@ function getDb() {
|
|
|
5102
5246
|
function _setDbForTesting(testDb) {
|
|
5103
5247
|
db = testDb;
|
|
5104
5248
|
_testDbPath = testDb.name;
|
|
5249
|
+
_setSchemaDbGetter(() => db);
|
|
5105
5250
|
}
|
|
5106
5251
|
var db, _testDbPath;
|
|
5107
5252
|
var init_store5 = __esm({
|
|
@@ -7618,6 +7763,52 @@ var init_html = __esm({
|
|
|
7618
7763
|
}
|
|
7619
7764
|
});
|
|
7620
7765
|
|
|
7766
|
+
// src/format-time.ts
|
|
7767
|
+
function formatLocalDate(utcDatetime) {
|
|
7768
|
+
const d = parseUtcDatetime(utcDatetime);
|
|
7769
|
+
if (!d) return utcDatetime.split("T")[0] ?? utcDatetime.split(" ")[0];
|
|
7770
|
+
const year = d.getFullYear();
|
|
7771
|
+
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
7772
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
7773
|
+
return `${year}-${month}-${day}`;
|
|
7774
|
+
}
|
|
7775
|
+
function formatLocalDateTime(utcDatetime) {
|
|
7776
|
+
const d = parseUtcDatetime(utcDatetime);
|
|
7777
|
+
if (!d) return utcDatetime;
|
|
7778
|
+
const year = d.getFullYear();
|
|
7779
|
+
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
7780
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
7781
|
+
const hours = String(d.getHours()).padStart(2, "0");
|
|
7782
|
+
const minutes = String(d.getMinutes()).padStart(2, "0");
|
|
7783
|
+
const tzAbbr = getTimezoneAbbr(d);
|
|
7784
|
+
return `${year}-${month}-${day} ${hours}:${minutes} ${tzAbbr}`;
|
|
7785
|
+
}
|
|
7786
|
+
function parseUtcDatetime(utcDatetime) {
|
|
7787
|
+
if (!utcDatetime) return null;
|
|
7788
|
+
const normalized = utcDatetime.includes("T") ? utcDatetime : utcDatetime.replace(" ", "T");
|
|
7789
|
+
const withZ = normalized.endsWith("Z") ? normalized : normalized + "Z";
|
|
7790
|
+
const d = new Date(withZ);
|
|
7791
|
+
return isNaN(d.getTime()) ? null : d;
|
|
7792
|
+
}
|
|
7793
|
+
function getTimezoneAbbr(date) {
|
|
7794
|
+
try {
|
|
7795
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
7796
|
+
timeZone: systemTimezone,
|
|
7797
|
+
timeZoneName: "short"
|
|
7798
|
+
}).formatToParts(date);
|
|
7799
|
+
return parts.find((p) => p.type === "timeZoneName")?.value ?? "";
|
|
7800
|
+
} catch {
|
|
7801
|
+
return "";
|
|
7802
|
+
}
|
|
7803
|
+
}
|
|
7804
|
+
var systemTimezone;
|
|
7805
|
+
var init_format_time = __esm({
|
|
7806
|
+
"src/format-time.ts"() {
|
|
7807
|
+
"use strict";
|
|
7808
|
+
systemTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
7809
|
+
}
|
|
7810
|
+
});
|
|
7811
|
+
|
|
7621
7812
|
// src/channels/telegram-throttle.ts
|
|
7622
7813
|
var telegram_throttle_exports = {};
|
|
7623
7814
|
__export(telegram_throttle_exports, {
|
|
@@ -7645,6 +7836,7 @@ var init_telegram_throttle = __esm({
|
|
|
7645
7836
|
"src/channels/telegram-throttle.ts"() {
|
|
7646
7837
|
"use strict";
|
|
7647
7838
|
init_log();
|
|
7839
|
+
init_format_time();
|
|
7648
7840
|
PER_DM_INTERVAL_MS = 1e3;
|
|
7649
7841
|
PER_GROUP_INTERVAL_MS = 3500;
|
|
7650
7842
|
P0_PACING_MS = 150;
|
|
@@ -7826,7 +8018,7 @@ var init_telegram_throttle = __esm({
|
|
|
7826
8018
|
while (this.queue.length > 0) {
|
|
7827
8019
|
while (this.isPaused()) {
|
|
7828
8020
|
if (this.pauseStartedAt > 0 && Date.now() - this.pauseStartedAt > MAX_TOTAL_PAUSE_MS) {
|
|
7829
|
-
warn(`[throttle] Max pause duration exceeded (${MAX_TOTAL_PAUSE_MS / 6e4}min), dropping ${this.queue.length} items (pause remains until ${new Date(this.pausedUntil).toISOString()})`);
|
|
8021
|
+
warn(`[throttle] Max pause duration exceeded (${MAX_TOTAL_PAUSE_MS / 6e4}min), dropping ${this.queue.length} items (pause remains until ${formatLocalDateTime(new Date(this.pausedUntil).toISOString())})`);
|
|
7830
8022
|
this.flushQueueWithError("Telegram rate limit exceeded max wait time");
|
|
7831
8023
|
break;
|
|
7832
8024
|
}
|
|
@@ -8669,6 +8861,70 @@ function buildHandoffContract() {
|
|
|
8669
8861
|
"**Open questions:** Anything unresolved or needing the main agent's attention."
|
|
8670
8862
|
].join("\n");
|
|
8671
8863
|
}
|
|
8864
|
+
function buildAgenticCore() {
|
|
8865
|
+
return `## Task Execution
|
|
8866
|
+
|
|
8867
|
+
- Implement rather than suggest unless the request is clearly read-only.
|
|
8868
|
+
- Read relevant files before answering questions about code or proposing changes. Do not propose changes to code you have not read.
|
|
8869
|
+
- Do not add features, refactor code, or make improvements beyond what was asked. A bug fix does not need surrounding code cleaned up. A simple feature does not need extra configurability.
|
|
8870
|
+
- Do not create helpers, utilities, or abstractions for one-time operations. Do not design for hypothetical future requirements. Three similar lines of code is better than a premature abstraction.
|
|
8871
|
+
- Do not add error handling, fallbacks, or validation for scenarios that cannot happen. Trust internal code and framework guarantees. Only validate at system boundaries (user input, external APIs).
|
|
8872
|
+
- Do not create files unless absolutely necessary. Prefer editing existing files over creating new ones.
|
|
8873
|
+
- Avoid backwards-compatibility hacks. If something is unused, delete it completely.
|
|
8874
|
+
- Be careful not to introduce security vulnerabilities (injection, XSS, SQL injection, OWASP top 10). If you write insecure code, fix it immediately.
|
|
8875
|
+
- You are highly capable. Defer to user judgement about whether a task is too large to attempt.
|
|
8876
|
+
|
|
8877
|
+
## Action Safety
|
|
8878
|
+
|
|
8879
|
+
Take local, reversible actions freely (editing files, running tests). For actions that are hard to reverse, affect shared systems, or could be destructive, confirm with the user before proceeding.
|
|
8880
|
+
|
|
8881
|
+
Actions that require confirmation:
|
|
8882
|
+
- Destructive: deleting files/branches, dropping tables, rm -rf, overwriting uncommitted changes
|
|
8883
|
+
- Hard to reverse: force-pushing, git reset --hard, amending published commits, removing dependencies
|
|
8884
|
+
- Visible to others: pushing code, creating/commenting on PRs/issues, sending messages, posting to external services
|
|
8885
|
+
|
|
8886
|
+
When encountering an obstacle, investigate root causes rather than using destructive actions as shortcuts. If you discover unexpected state (unfamiliar files, branches, configuration), investigate before deleting or overwriting \u2014 it may be the user's in-progress work.
|
|
8887
|
+
|
|
8888
|
+
## Tool Usage
|
|
8889
|
+
|
|
8890
|
+
- Call multiple tools in parallel when they have no dependencies between them. Maximize parallel tool calls for efficiency. Only use sequential calls when outputs feed inputs.
|
|
8891
|
+
- Never use placeholders or guess missing parameters.
|
|
8892
|
+
- For git operations: never amend published commits or force-push without explicit instruction.
|
|
8893
|
+
|
|
8894
|
+
## Communication
|
|
8895
|
+
|
|
8896
|
+
- Before your first tool call, state in one sentence what you are about to do.
|
|
8897
|
+
- While working, give short updates at key moments: when you find something, change direction, or hit a blocker. One sentence per update is enough.
|
|
8898
|
+
- End-of-turn summary: one or two sentences \u2014 what changed and what is next. Nothing else.
|
|
8899
|
+
- Match responses to the task: a simple question gets a direct answer, not headers and sections.
|
|
8900
|
+
- Do not narrate your internal reasoning, tool selection logic, or thought process. Only output the final answer.
|
|
8901
|
+
|
|
8902
|
+
## Grounding
|
|
8903
|
+
|
|
8904
|
+
- Never invent library APIs, file paths, CLI commands, or documentation you are not certain exist.
|
|
8905
|
+
- If uncertain, say so. Label inferences clearly: "Based on X, I expect Y" \u2014 not stated as fact.
|
|
8906
|
+
- Verify paths before acting. User paths are often approximate.`;
|
|
8907
|
+
}
|
|
8908
|
+
function buildFollowThrough() {
|
|
8909
|
+
return `PERSISTENCE RULES:
|
|
8910
|
+
- Persist through the full lifecycle: gather context \u2192 plan \u2192 implement \u2192 verify \u2192 report.
|
|
8911
|
+
- Do not stop at analysis, partial fixes, or drafts.
|
|
8912
|
+
- Do not output a plan, status update, or progress summary as your final message.
|
|
8913
|
+
If there is more work to do, do the work. A status message without a following
|
|
8914
|
+
tool call will terminate your turn prematurely.
|
|
8915
|
+
- Only terminate your turn when you are sure the problem is fully solved.
|
|
8916
|
+
|
|
8917
|
+
TOOL PERSISTENCE:
|
|
8918
|
+
- Do not stop early when another tool call would materially improve correctness or completeness.
|
|
8919
|
+
- Keep calling tools until: (1) the task is complete, and (2) verification passes.
|
|
8920
|
+
- If a tool returns empty, errors, or partial results \u2014 retry with a different strategy. Tool errors are not stop conditions.
|
|
8921
|
+
|
|
8922
|
+
BIAS TO ACTION:
|
|
8923
|
+
- Default to implementing with reasonable assumptions rather than asking clarifying questions,
|
|
8924
|
+
unless truly blocked on a detail that would change correctness or safety, or involves an
|
|
8925
|
+
irreversible action.
|
|
8926
|
+
- Never stop after completing only part of the request.`;
|
|
8927
|
+
}
|
|
8672
8928
|
var REAL_HOME, TASK_WORKER_SKILL_BUDGET;
|
|
8673
8929
|
var init_shared = __esm({
|
|
8674
8930
|
"src/bootstrap/templates/shared.ts"() {
|
|
@@ -8684,6 +8940,7 @@ var discover_exports = {};
|
|
|
8684
8940
|
__export(discover_exports, {
|
|
8685
8941
|
discoverAllSkills: () => discoverAllSkills,
|
|
8686
8942
|
invalidateSkillCache: () => invalidateSkillCache,
|
|
8943
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
8687
8944
|
resolveSkillForTask: () => resolveSkillForTask,
|
|
8688
8945
|
stripFrontmatter: () => stripFrontmatter
|
|
8689
8946
|
});
|
|
@@ -8756,7 +9013,8 @@ async function scanSkillDir(skillsDir, source) {
|
|
|
8756
9013
|
contentHash: hash,
|
|
8757
9014
|
type: frontmatter.type,
|
|
8758
9015
|
status: frontmatter.status,
|
|
8759
|
-
requires: frontmatter.requires
|
|
9016
|
+
requires: frontmatter.requires,
|
|
9017
|
+
triggers: frontmatter.triggers
|
|
8760
9018
|
});
|
|
8761
9019
|
}
|
|
8762
9020
|
return results;
|
|
@@ -8788,7 +9046,8 @@ function mergeAndDeduplicate(raw) {
|
|
|
8788
9046
|
contentHash: primary.contentHash,
|
|
8789
9047
|
type: primary.type,
|
|
8790
9048
|
status: primary.status,
|
|
8791
|
-
requires: primary.requires
|
|
9049
|
+
requires: primary.requires,
|
|
9050
|
+
triggers: primary.triggers
|
|
8792
9051
|
});
|
|
8793
9052
|
} else {
|
|
8794
9053
|
for (const [hash, copies] of byHash) {
|
|
@@ -8803,7 +9062,8 @@ function mergeAndDeduplicate(raw) {
|
|
|
8803
9062
|
contentHash: hash,
|
|
8804
9063
|
type: primary.type,
|
|
8805
9064
|
status: primary.status,
|
|
8806
|
-
requires: primary.requires
|
|
9065
|
+
requires: primary.requires,
|
|
9066
|
+
triggers: primary.triggers
|
|
8807
9067
|
});
|
|
8808
9068
|
}
|
|
8809
9069
|
}
|
|
@@ -8823,7 +9083,8 @@ function parseFrontmatter(content, fallbackName, source) {
|
|
|
8823
9083
|
description: "",
|
|
8824
9084
|
type: "tool",
|
|
8825
9085
|
status: source === "cc-claw" ? "imported" : "external",
|
|
8826
|
-
requires: []
|
|
9086
|
+
requires: [],
|
|
9087
|
+
triggers: []
|
|
8827
9088
|
};
|
|
8828
9089
|
}
|
|
8829
9090
|
const fm = fmMatch[1];
|
|
@@ -8849,12 +9110,21 @@ function parseFrontmatter(content, fallbackName, source) {
|
|
|
8849
9110
|
if (cleaned2) requires.push(cleaned2);
|
|
8850
9111
|
}
|
|
8851
9112
|
}
|
|
9113
|
+
const triggersMatch = fm.match(/^triggers:\s*\[([^\]]*)\]/m);
|
|
9114
|
+
const triggers = [];
|
|
9115
|
+
if (triggersMatch?.[1]) {
|
|
9116
|
+
for (const item of triggersMatch[1].split(",")) {
|
|
9117
|
+
const cleaned2 = strip(item);
|
|
9118
|
+
if (cleaned2) triggers.push(cleaned2);
|
|
9119
|
+
}
|
|
9120
|
+
}
|
|
8852
9121
|
return {
|
|
8853
9122
|
name: nameMatch?.[1] ? strip(nameMatch[1]) : fallbackName,
|
|
8854
9123
|
description: descMatch?.[1] ? strip(descMatch[1]) : "",
|
|
8855
9124
|
type,
|
|
8856
9125
|
status,
|
|
8857
|
-
requires
|
|
9126
|
+
requires,
|
|
9127
|
+
triggers
|
|
8858
9128
|
};
|
|
8859
9129
|
}
|
|
8860
9130
|
function stripFrontmatter(content) {
|
|
@@ -8865,9 +9135,9 @@ function resolveSkillForTask(skillName) {
|
|
|
8865
9135
|
for (const candidate of SKILL_FILE_CANDIDATES3) {
|
|
8866
9136
|
const skillPath = join9(SKILLS_PATH, skillName, candidate);
|
|
8867
9137
|
try {
|
|
8868
|
-
const { readFileSync:
|
|
9138
|
+
const { readFileSync: readFileSync36, existsSync: existsSync62 } = __require("fs");
|
|
8869
9139
|
if (!existsSync62(skillPath)) continue;
|
|
8870
|
-
const raw =
|
|
9140
|
+
const raw = readFileSync36(skillPath, "utf-8");
|
|
8871
9141
|
const fm = parseFrontmatter(raw, skillName, "cc-claw");
|
|
8872
9142
|
if (fm.status !== "approved") {
|
|
8873
9143
|
log(`[skills] Skill "${skillName}" has status "${fm.status}" \u2014 only approved skills can be used as task worker identity`);
|
|
@@ -11330,6 +11600,12 @@ ${buildPlatformQuickReference()}
|
|
|
11330
11600
|
|
|
11331
11601
|
${buildToolUsageRules()}
|
|
11332
11602
|
|
|
11603
|
+
## Agentic Discipline
|
|
11604
|
+
${buildAgenticCore()}
|
|
11605
|
+
|
|
11606
|
+
## Follow-Through
|
|
11607
|
+
${buildFollowThrough()}
|
|
11608
|
+
|
|
11333
11609
|
## CC-Claw Constraints
|
|
11334
11610
|
${buildDatabaseSafetyBoundary()}
|
|
11335
11611
|
- Do not invent library APIs or documentation you are not certain exists.
|
|
@@ -11361,28 +11637,13 @@ ${user}
|
|
|
11361
11637
|
You are an autonomous agent \u2014 keep going until the user's request is completely
|
|
11362
11638
|
resolved before ending your turn and yielding back to the user.
|
|
11363
11639
|
|
|
11364
|
-
|
|
11365
|
-
- Persist through the full lifecycle: gather context \u2192 plan \u2192 implement \u2192 verify
|
|
11366
|
-
\u2192 report. Do not stop at analysis, partial fixes, or drafts.
|
|
11367
|
-
- Do not output a plan, status update, or progress summary as your final message.
|
|
11368
|
-
If there is more work to do, do the work. A status message without a following
|
|
11369
|
-
tool call will terminate your turn prematurely.
|
|
11370
|
-
- Only terminate your turn when you are sure the problem is fully solved.
|
|
11371
|
-
|
|
11372
|
-
TOOL PERSISTENCE:
|
|
11373
|
-
- Do not stop early when another tool call would materially improve correctness
|
|
11374
|
-
or completeness.
|
|
11375
|
-
- Keep calling tools until: (1) the task is complete, and (2) verification passes.
|
|
11376
|
-
- If a tool returns empty, errors, or partial results \u2014 retry with a different
|
|
11377
|
-
strategy. Tool errors are not stop conditions.
|
|
11378
|
-
|
|
11379
|
-
BIAS TO ACTION:
|
|
11380
|
-
- Default to implementing with reasonable assumptions rather than asking
|
|
11381
|
-
clarifying questions, unless truly blocked on a detail that would change
|
|
11382
|
-
correctness or safety, or involves an irreversible action.
|
|
11383
|
-
- Never stop after completing only part of the request.
|
|
11640
|
+
${buildFollowThrough()}
|
|
11384
11641
|
</default_follow_through_policy>
|
|
11385
11642
|
|
|
11643
|
+
<agentic_framework>
|
|
11644
|
+
${buildAgenticCore()}
|
|
11645
|
+
</agentic_framework>
|
|
11646
|
+
|
|
11386
11647
|
<output_contract>
|
|
11387
11648
|
- Simple answers: 1-4 sentences in Telegram HTML, no preamble
|
|
11388
11649
|
- Code tasks: show the change, explain what changed and why in 1-2 sentences
|
|
@@ -11447,18 +11708,15 @@ ${soul}
|
|
|
11447
11708
|
${user}
|
|
11448
11709
|
</user_profile>
|
|
11449
11710
|
|
|
11450
|
-
<
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
</instructions>
|
|
11711
|
+
<agentic_framework>
|
|
11712
|
+
${buildAgenticCore()}
|
|
11713
|
+
</agentic_framework>
|
|
11714
|
+
|
|
11715
|
+
<follow_through_policy>
|
|
11716
|
+
${buildFollowThrough()}
|
|
11717
|
+
</follow_through_policy>
|
|
11458
11718
|
|
|
11459
11719
|
<tool_guidance>
|
|
11460
|
-
Call multiple tools in parallel when they have no dependencies.
|
|
11461
|
-
Only make changes directly requested. Do not add features or refactor beyond what was asked.
|
|
11462
11720
|
${buildToolUsageRules()}
|
|
11463
11721
|
</tool_guidance>
|
|
11464
11722
|
|
|
@@ -11486,6 +11744,138 @@ var init_cursor2 = __esm({
|
|
|
11486
11744
|
}
|
|
11487
11745
|
});
|
|
11488
11746
|
|
|
11747
|
+
// src/bootstrap/templates/api.ts
|
|
11748
|
+
function buildApiTemplate(soul, user) {
|
|
11749
|
+
const date = getCurrentDate();
|
|
11750
|
+
return `<role>
|
|
11751
|
+
You are the agent described below, operating via Telegram. Current date: ${date}.
|
|
11752
|
+
You are running as a direct API model \u2014 not a CLI tool like Claude Code or Gemini CLI.
|
|
11753
|
+
CC-Claw is your agentic harness: it provides your tools, memory, identity, and orchestration layer.
|
|
11754
|
+
Follow these system instructions precisely. They define how you operate.
|
|
11755
|
+
</role>
|
|
11756
|
+
|
|
11757
|
+
<identity>
|
|
11758
|
+
${soul}
|
|
11759
|
+
</identity>
|
|
11760
|
+
|
|
11761
|
+
<user_profile>
|
|
11762
|
+
${user}
|
|
11763
|
+
</user_profile>
|
|
11764
|
+
|
|
11765
|
+
<agentic_framework>
|
|
11766
|
+
${buildAgenticCore()}
|
|
11767
|
+
</agentic_framework>
|
|
11768
|
+
|
|
11769
|
+
<follow_through_policy>
|
|
11770
|
+
${buildFollowThrough()}
|
|
11771
|
+
</follow_through_policy>
|
|
11772
|
+
|
|
11773
|
+
<tool_routing>
|
|
11774
|
+
## API Backend Tool Routing
|
|
11775
|
+
|
|
11776
|
+
You have access to tools provided by CC-Claw via function calling. Use them directly by name.
|
|
11777
|
+
|
|
11778
|
+
External CLI tools (gsearch, pwm, gws, gemcli, nlm, curl, python3, git, npm, cc-claw, etc.)
|
|
11779
|
+
are accessed ONLY via the \`restrictedBash\` tool. NEVER call external CLIs as direct tool
|
|
11780
|
+
names \u2014 they are not registered as native tools and will fail silently.
|
|
11781
|
+
|
|
11782
|
+
Correct: restrictedBash({"command": "gsearch \\"query\\" --type news"})
|
|
11783
|
+
Incorrect: gsearch({"query": "..."}) \u2190 this WILL FAIL
|
|
11784
|
+
|
|
11785
|
+
If a skill or instruction says to use a CLI tool, always route it through restrictedBash.
|
|
11786
|
+
When unsure about available commands, run: restrictedBash({"command": "cc-claw --ai"})
|
|
11787
|
+
|
|
11788
|
+
${buildCliEnvironment()}
|
|
11789
|
+
</tool_routing>
|
|
11790
|
+
|
|
11791
|
+
<verification_loop>
|
|
11792
|
+
Before finalizing any response, silently check:
|
|
11793
|
+
1. Is this correct and complete?
|
|
11794
|
+
2. Is every factual claim grounded in something verified?
|
|
11795
|
+
3. Does the format match the output contract below?
|
|
11796
|
+
4. Are there any safety concerns with the actions taken?
|
|
11797
|
+
</verification_loop>
|
|
11798
|
+
|
|
11799
|
+
<safety_boundary>
|
|
11800
|
+
${buildDatabaseSafetyBoundary()}
|
|
11801
|
+
${buildToolUsageRules()}
|
|
11802
|
+
</safety_boundary>
|
|
11803
|
+
|
|
11804
|
+
<platform_reference>
|
|
11805
|
+
${buildSystemCapabilities()}
|
|
11806
|
+
${buildPlatformQuickReference()}
|
|
11807
|
+
</platform_reference>
|
|
11808
|
+
|
|
11809
|
+
<output_format>
|
|
11810
|
+
Respond in Telegram HTML: <b>bold</b>, <code>inline</code>, <pre>blocks</pre>.
|
|
11811
|
+
No markdown formatting. No flattery openers. No pleasantries.
|
|
11812
|
+
Prose for conversation, structure only when the content requires it.
|
|
11813
|
+
Keep casual responses concise. Reserve detail for research, code, and complex tasks.
|
|
11814
|
+
</output_format>`;
|
|
11815
|
+
}
|
|
11816
|
+
var init_api = __esm({
|
|
11817
|
+
"src/bootstrap/templates/api.ts"() {
|
|
11818
|
+
"use strict";
|
|
11819
|
+
init_shared();
|
|
11820
|
+
}
|
|
11821
|
+
});
|
|
11822
|
+
|
|
11823
|
+
// src/bootstrap/templates/api-task.ts
|
|
11824
|
+
function buildApiTaskTemplate() {
|
|
11825
|
+
const date = getCurrentDate();
|
|
11826
|
+
return `<role>
|
|
11827
|
+
You are a specialist task worker operating via CC-Claw. Current date: ${date}.
|
|
11828
|
+
Your identity and expertise are defined by the skill injected into your prompt.
|
|
11829
|
+
You are a direct API model \u2014 use restrictedBash for all external CLI tools.
|
|
11830
|
+
</role>
|
|
11831
|
+
|
|
11832
|
+
<follow_through_policy>
|
|
11833
|
+
${buildFollowThrough()}
|
|
11834
|
+
</follow_through_policy>
|
|
11835
|
+
|
|
11836
|
+
<operating_rules>
|
|
11837
|
+
${buildTaskWorkerRules()}
|
|
11838
|
+
</operating_rules>
|
|
11839
|
+
|
|
11840
|
+
<tool_routing>
|
|
11841
|
+
External CLI tools are accessed ONLY via the restrictedBash tool.
|
|
11842
|
+
NEVER call external CLIs as direct tool names \u2014 they will fail silently.
|
|
11843
|
+
Correct: restrictedBash({"command": "command here"})
|
|
11844
|
+
Incorrect: command({"arg": "..."}) \u2190 this WILL FAIL
|
|
11845
|
+
</tool_routing>
|
|
11846
|
+
|
|
11847
|
+
<cli_environment>
|
|
11848
|
+
${buildCliEnvironment()}
|
|
11849
|
+
</cli_environment>
|
|
11850
|
+
|
|
11851
|
+
<verification_loop>
|
|
11852
|
+
Before finalizing any response, silently check:
|
|
11853
|
+
1. Is this correct and complete?
|
|
11854
|
+
2. Is every factual claim grounded in something verified?
|
|
11855
|
+
3. Does the output match the task requirements?
|
|
11856
|
+
</verification_loop>
|
|
11857
|
+
|
|
11858
|
+
<grounding_rules>
|
|
11859
|
+
Never invent library APIs, file paths, or documentation. If uncertain, say so.
|
|
11860
|
+
Verify paths before acting. User paths are often approximate.
|
|
11861
|
+
</grounding_rules>
|
|
11862
|
+
|
|
11863
|
+
<safety_boundary>
|
|
11864
|
+
Confirm before: deleting files, posting to external services, database schema changes.
|
|
11865
|
+
Do not access ~/.cc-claw/data/cc-claw.db directly.
|
|
11866
|
+
</safety_boundary>
|
|
11867
|
+
|
|
11868
|
+
<output_contract>
|
|
11869
|
+
${buildHandoffContract()}
|
|
11870
|
+
</output_contract>`;
|
|
11871
|
+
}
|
|
11872
|
+
var init_api_task = __esm({
|
|
11873
|
+
"src/bootstrap/templates/api-task.ts"() {
|
|
11874
|
+
"use strict";
|
|
11875
|
+
init_shared();
|
|
11876
|
+
}
|
|
11877
|
+
});
|
|
11878
|
+
|
|
11489
11879
|
// src/bootstrap/templates/claude-task.ts
|
|
11490
11880
|
function buildClaudeTaskTemplate() {
|
|
11491
11881
|
const date = getCurrentDate();
|
|
@@ -11544,26 +11934,7 @@ Your identity and expertise are defined by the skill injected into your prompt.
|
|
|
11544
11934
|
You are an autonomous agent \u2014 keep going until the task is completely resolved
|
|
11545
11935
|
before ending your turn and yielding back to the user.
|
|
11546
11936
|
|
|
11547
|
-
|
|
11548
|
-
- Persist through the full lifecycle: gather context \u2192 plan \u2192 implement \u2192 verify
|
|
11549
|
-
\u2192 report. Do not stop at analysis, partial fixes, or drafts.
|
|
11550
|
-
- Do not output a plan, status update, or progress summary as your final message.
|
|
11551
|
-
If there is more work to do, do the work. A status message without a following
|
|
11552
|
-
tool call will terminate your turn prematurely.
|
|
11553
|
-
- Only terminate your turn when you are sure the task is fully solved.
|
|
11554
|
-
|
|
11555
|
-
TOOL PERSISTENCE:
|
|
11556
|
-
- Do not stop early when another tool call would materially improve correctness
|
|
11557
|
-
or completeness.
|
|
11558
|
-
- Keep calling tools until: (1) the task is complete, and (2) verification passes.
|
|
11559
|
-
- If a tool returns empty, errors, or partial results \u2014 retry with a different
|
|
11560
|
-
strategy. Tool errors are not stop conditions.
|
|
11561
|
-
|
|
11562
|
-
BIAS TO ACTION:
|
|
11563
|
-
- Default to implementing with reasonable assumptions rather than asking
|
|
11564
|
-
clarifying questions, unless truly blocked on a detail that would change
|
|
11565
|
-
correctness or safety.
|
|
11566
|
-
- Never stop after completing only part of the task.
|
|
11937
|
+
${buildFollowThrough()}
|
|
11567
11938
|
</default_follow_through_policy>
|
|
11568
11939
|
|
|
11569
11940
|
<operating_rules>
|
|
@@ -11727,6 +12098,10 @@ function syncNativeCliFiles() {
|
|
|
11727
12098
|
writeFileSync6(join14(IDENTITY_PATH, "CC-CLAW-codex.md"), codexContent, "utf-8");
|
|
11728
12099
|
writeFileSync6(join14(WORKSPACE_PATH, "AGENTS.md"), codexContent, "utf-8");
|
|
11729
12100
|
writeFileSync6(join14(IDENTITY_PATH, "CC-CLAW-cursor.md"), cursorContent, "utf-8");
|
|
12101
|
+
const apiContent = buildApiTemplate(soul, user);
|
|
12102
|
+
writeFileSync6(join14(IDENTITY_PATH, "CC-CLAW-api.md"), apiContent, "utf-8");
|
|
12103
|
+
const apiTaskContent = buildApiTaskTemplate();
|
|
12104
|
+
writeFileSync6(join14(IDENTITY_PATH, "CC-CLAW-api-task.md"), apiTaskContent, "utf-8");
|
|
11730
12105
|
const fallbackContent = [
|
|
11731
12106
|
"# CC-Claw System Instructions",
|
|
11732
12107
|
"",
|
|
@@ -11749,7 +12124,7 @@ function syncNativeCliFiles() {
|
|
|
11749
12124
|
const codexTaskContent = buildCodexTaskTemplate();
|
|
11750
12125
|
writeFileSync6(join14(IDENTITY_PATH, "CC-CLAW-claude-task.md"), claudeTaskContent, "utf-8");
|
|
11751
12126
|
writeFileSync6(join14(IDENTITY_PATH, "CC-CLAW-codex-task.md"), codexTaskContent, "utf-8");
|
|
11752
|
-
log("[bootstrap] Synced identity files: CC-CLAW-claude.md, GEMINI.md, CC-CLAW-codex.md, CC-CLAW-cursor.md, CC-CLAW.md (fallback), CC-CLAW-claude-task.md, CC-CLAW-codex-task.md");
|
|
12127
|
+
log("[bootstrap] Synced identity files: CC-CLAW-claude.md, GEMINI.md, CC-CLAW-codex.md, CC-CLAW-cursor.md, CC-CLAW-api.md, CC-CLAW-api-task.md, CC-CLAW.md (fallback), CC-CLAW-claude-task.md, CC-CLAW-codex-task.md");
|
|
11753
12128
|
}
|
|
11754
12129
|
var SOUL_PATH, USER_PATH, CONTEXT_DIR, LEGACY_SOUL_PATH, LEGACY_USER_PATH, LEGACY_CLAUDE_MD, LEGACY_GEMINI_MD;
|
|
11755
12130
|
var init_init = __esm({
|
|
@@ -11761,6 +12136,8 @@ var init_init = __esm({
|
|
|
11761
12136
|
init_gemini2();
|
|
11762
12137
|
init_codex2();
|
|
11763
12138
|
init_cursor2();
|
|
12139
|
+
init_api();
|
|
12140
|
+
init_api_task();
|
|
11764
12141
|
init_claude_task();
|
|
11765
12142
|
init_codex_task();
|
|
11766
12143
|
init_shared();
|
|
@@ -11775,19 +12152,333 @@ var init_init = __esm({
|
|
|
11775
12152
|
}
|
|
11776
12153
|
});
|
|
11777
12154
|
|
|
11778
|
-
// src/
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
);
|
|
12155
|
+
// src/intent/complexity.ts
|
|
12156
|
+
var complexity_exports = {};
|
|
12157
|
+
__export(complexity_exports, {
|
|
12158
|
+
classifyComplexity: () => classifyComplexity
|
|
12159
|
+
});
|
|
12160
|
+
function wordCount(text) {
|
|
12161
|
+
return text.trim().split(/\s+/).filter(Boolean).length;
|
|
11785
12162
|
}
|
|
11786
|
-
function
|
|
11787
|
-
|
|
11788
|
-
const
|
|
11789
|
-
|
|
12163
|
+
function classifyComplexity(text) {
|
|
12164
|
+
const trimmed = text.trim();
|
|
12165
|
+
const lower = trimmed.toLowerCase();
|
|
12166
|
+
const words = wordCount(trimmed);
|
|
12167
|
+
if (TRIVIAL_EXACT.has(lower)) {
|
|
12168
|
+
log(`[complexity] "${lower}" -> trivial (exact match)`);
|
|
12169
|
+
return "trivial";
|
|
12170
|
+
}
|
|
12171
|
+
if (trimmed.length <= 4 && /^[\p{Emoji}\s]+$/u.test(trimmed)) {
|
|
12172
|
+
log(`[complexity] "${trimmed}" -> trivial (emoji-only)`);
|
|
12173
|
+
return "trivial";
|
|
12174
|
+
}
|
|
12175
|
+
if (COMPLEX_SIGNALS.test(trimmed) && (words > 15 || trimmed.length > 200)) {
|
|
12176
|
+
log(`[complexity] "${trimmed.slice(0, 40)}..." -> complex (signal words + length)`);
|
|
12177
|
+
return "complex";
|
|
12178
|
+
}
|
|
12179
|
+
if (MUTATION_VERBS.test(trimmed)) {
|
|
12180
|
+
const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
|
|
12181
|
+
log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (mutation verb)`);
|
|
12182
|
+
return tier;
|
|
12183
|
+
}
|
|
12184
|
+
for (const pattern of CODE_PATTERNS) {
|
|
12185
|
+
if (pattern.test(trimmed)) {
|
|
12186
|
+
const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
|
|
12187
|
+
log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (code pattern)`);
|
|
12188
|
+
return tier;
|
|
12189
|
+
}
|
|
12190
|
+
}
|
|
12191
|
+
if (trimmed.length > 200 || words > 25) {
|
|
12192
|
+
const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
|
|
12193
|
+
log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (long message)`);
|
|
12194
|
+
return tier;
|
|
12195
|
+
}
|
|
12196
|
+
for (const pattern of QUESTION_PATTERNS) {
|
|
12197
|
+
if (pattern.test(trimmed)) {
|
|
12198
|
+
log(`[complexity] "${trimmed.slice(0, 40)}..." -> simple (question)`);
|
|
12199
|
+
return "simple";
|
|
12200
|
+
}
|
|
12201
|
+
}
|
|
12202
|
+
log(`[complexity] "${trimmed.slice(0, 40)}..." -> moderate (default)`);
|
|
12203
|
+
return "moderate";
|
|
12204
|
+
}
|
|
12205
|
+
var TRIVIAL_EXACT, COMPLEX_SIGNALS, MUTATION_VERBS, CODE_PATTERNS, QUESTION_PATTERNS;
|
|
12206
|
+
var init_complexity = __esm({
|
|
12207
|
+
"src/intent/complexity.ts"() {
|
|
12208
|
+
"use strict";
|
|
12209
|
+
init_log();
|
|
12210
|
+
TRIVIAL_EXACT = /* @__PURE__ */ new Set([
|
|
12211
|
+
"hey",
|
|
12212
|
+
"hi",
|
|
12213
|
+
"hello",
|
|
12214
|
+
"yo",
|
|
12215
|
+
"sup",
|
|
12216
|
+
"howdy",
|
|
12217
|
+
"hiya",
|
|
12218
|
+
"thanks",
|
|
12219
|
+
"thank you",
|
|
12220
|
+
"thx",
|
|
12221
|
+
"ty",
|
|
12222
|
+
"thank u",
|
|
12223
|
+
"ok",
|
|
12224
|
+
"okay",
|
|
12225
|
+
"k",
|
|
12226
|
+
"kk",
|
|
12227
|
+
"cool",
|
|
12228
|
+
"nice",
|
|
12229
|
+
"great",
|
|
12230
|
+
"awesome",
|
|
12231
|
+
"perfect",
|
|
12232
|
+
"good morning",
|
|
12233
|
+
"good night",
|
|
12234
|
+
"good evening",
|
|
12235
|
+
"gm",
|
|
12236
|
+
"gn",
|
|
12237
|
+
"bye",
|
|
12238
|
+
"goodbye",
|
|
12239
|
+
"later",
|
|
12240
|
+
"see ya",
|
|
12241
|
+
"cya",
|
|
12242
|
+
"lol",
|
|
12243
|
+
"lmao",
|
|
12244
|
+
"haha",
|
|
12245
|
+
"heh",
|
|
12246
|
+
"np",
|
|
12247
|
+
"no problem",
|
|
12248
|
+
"no worries",
|
|
12249
|
+
"nw",
|
|
12250
|
+
"got it",
|
|
12251
|
+
"understood",
|
|
12252
|
+
"roger",
|
|
12253
|
+
"copy",
|
|
12254
|
+
"good",
|
|
12255
|
+
"fine",
|
|
12256
|
+
"alright",
|
|
12257
|
+
"sure",
|
|
12258
|
+
"yes",
|
|
12259
|
+
"no",
|
|
12260
|
+
"yep",
|
|
12261
|
+
"nope",
|
|
12262
|
+
"yeah",
|
|
12263
|
+
"nah"
|
|
12264
|
+
]);
|
|
12265
|
+
COMPLEX_SIGNALS = /\b(architect|design|research|plan|strategy|migration|microservice|distributed|end-to-end|trade-offs|pros\s+and\s+cons)\b/i;
|
|
12266
|
+
MUTATION_VERBS = /\b(fix|create|build|deploy|refactor|implement|write|add|update|edit|test|debug)\b/i;
|
|
12267
|
+
CODE_PATTERNS = [
|
|
12268
|
+
/```/,
|
|
12269
|
+
// code blocks
|
|
12270
|
+
/\.[a-z]{1,5}\b/,
|
|
12271
|
+
// file extensions (.ts, .py, .json)
|
|
12272
|
+
/[/\\][\w.-]+/
|
|
12273
|
+
// file paths (/src/foo, .\bar)
|
|
12274
|
+
];
|
|
12275
|
+
QUESTION_PATTERNS = [
|
|
12276
|
+
/^(?:what|which|where|when|why|how)\b/i,
|
|
12277
|
+
/^(?:show|tell|list|explain)\b/i,
|
|
12278
|
+
/^(?:is|are)\b/i
|
|
12279
|
+
];
|
|
12280
|
+
}
|
|
12281
|
+
});
|
|
12282
|
+
|
|
12283
|
+
// src/skills/inject.ts
|
|
12284
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
12285
|
+
function setInjectedSkills(chatId, skillNames) {
|
|
12286
|
+
injectedSkillsMap.set(chatId, skillNames);
|
|
12287
|
+
}
|
|
12288
|
+
function getAndClearInjectedSkills(chatId) {
|
|
12289
|
+
const skills2 = injectedSkillsMap.get(chatId) ?? [];
|
|
12290
|
+
injectedSkillsMap.delete(chatId);
|
|
12291
|
+
return skills2;
|
|
11790
12292
|
}
|
|
12293
|
+
function shouldSkipInjection(userMessage, profile, userExplicitNative) {
|
|
12294
|
+
if (userExplicitNative) return true;
|
|
12295
|
+
if (profile === "minimal") return true;
|
|
12296
|
+
const complexity = classifyComplexity(userMessage);
|
|
12297
|
+
return SKIP_COMPLEXITY.has(complexity);
|
|
12298
|
+
}
|
|
12299
|
+
function scoreSkills(userMessage, skills2) {
|
|
12300
|
+
const msgWords = tokenize(userMessage);
|
|
12301
|
+
const msgWordsAll = tokenizeAll(userMessage);
|
|
12302
|
+
if (msgWordsAll.size === 0) return [];
|
|
12303
|
+
const results = [];
|
|
12304
|
+
for (const skill of skills2) {
|
|
12305
|
+
if (skill.status !== "approved" && skill.status !== "imported") continue;
|
|
12306
|
+
let score = 0;
|
|
12307
|
+
const triggerWords = new Set(skill.triggers.map((t) => t.toLowerCase()));
|
|
12308
|
+
for (const word of msgWordsAll) {
|
|
12309
|
+
if (triggerWords.has(word)) score += 2;
|
|
12310
|
+
}
|
|
12311
|
+
const metaWords = tokenize([skill.name, skill.description].join(" "));
|
|
12312
|
+
for (const word of msgWords) {
|
|
12313
|
+
if (metaWords.has(word) && !STOPWORDS.has(word)) score++;
|
|
12314
|
+
}
|
|
12315
|
+
if (score >= MIN_SCORE) {
|
|
12316
|
+
results.push({ name: skill.name, score, filePath: skill.filePath, requires: skill.requires });
|
|
12317
|
+
}
|
|
12318
|
+
}
|
|
12319
|
+
return results.sort((a, b) => b.score - a.score);
|
|
12320
|
+
}
|
|
12321
|
+
function formatSkillBlock(skills2, budgetChars = TOTAL_BUDGET_CHARS) {
|
|
12322
|
+
if (skills2.length === 0) return null;
|
|
12323
|
+
const lines = ["[Skill context]"];
|
|
12324
|
+
let totalChars = 0;
|
|
12325
|
+
for (const skill of skills2) {
|
|
12326
|
+
let content = skill.content;
|
|
12327
|
+
const remaining = budgetChars - totalChars;
|
|
12328
|
+
if (remaining <= 0) break;
|
|
12329
|
+
if (content.length > remaining) {
|
|
12330
|
+
content = content.slice(0, remaining) + "\n\u2026(truncated)";
|
|
12331
|
+
}
|
|
12332
|
+
lines.push(`## ${skill.name}`);
|
|
12333
|
+
lines.push(content);
|
|
12334
|
+
lines.push("");
|
|
12335
|
+
totalChars += content.length;
|
|
12336
|
+
}
|
|
12337
|
+
lines.push("[End skill context]");
|
|
12338
|
+
return lines.join("\n");
|
|
12339
|
+
}
|
|
12340
|
+
function loadWithDeps(skill, allSkills, usedNames, entries, charsSoFar, charCap) {
|
|
12341
|
+
const content = readSkillContent(skill.filePath);
|
|
12342
|
+
if (!content) return charsSoFar;
|
|
12343
|
+
if (charsSoFar + content.length > charCap) return charsSoFar;
|
|
12344
|
+
entries.push({ name: skill.name, content });
|
|
12345
|
+
usedNames.add(skill.name);
|
|
12346
|
+
let chars = charsSoFar + content.length;
|
|
12347
|
+
for (const dep of skill.requires) {
|
|
12348
|
+
if (usedNames.has(dep)) continue;
|
|
12349
|
+
const depSkill = allSkills.find((s) => s.name === dep);
|
|
12350
|
+
if (!depSkill) continue;
|
|
12351
|
+
const depContent = readSkillContent(depSkill.filePath);
|
|
12352
|
+
if (!depContent) continue;
|
|
12353
|
+
if (chars + depContent.length > charCap) continue;
|
|
12354
|
+
entries.push({ name: depSkill.name, content: depContent });
|
|
12355
|
+
usedNames.add(depSkill.name);
|
|
12356
|
+
chars += depContent.length;
|
|
12357
|
+
}
|
|
12358
|
+
return chars;
|
|
12359
|
+
}
|
|
12360
|
+
function injectSkillContext(userMessage, allSkills, pinnedSkillNames, profile, userExplicitNative, chatId) {
|
|
12361
|
+
const hasPins = pinnedSkillNames.length > 0;
|
|
12362
|
+
const skipAuto = shouldSkipInjection(userMessage, profile, userExplicitNative);
|
|
12363
|
+
if (!hasPins && skipAuto) return null;
|
|
12364
|
+
const entries = [];
|
|
12365
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
12366
|
+
let pinnedChars = 0;
|
|
12367
|
+
for (const name of pinnedSkillNames) {
|
|
12368
|
+
if (usedNames.has(name)) continue;
|
|
12369
|
+
const skill = allSkills.find((s) => s.name === name);
|
|
12370
|
+
if (!skill) continue;
|
|
12371
|
+
pinnedChars = loadWithDeps(skill, allSkills, usedNames, entries, pinnedChars, PINNED_BUDGET_CHARS);
|
|
12372
|
+
}
|
|
12373
|
+
if (!skipAuto) {
|
|
12374
|
+
const scored = scoreSkills(userMessage, allSkills);
|
|
12375
|
+
let autoChars = 0;
|
|
12376
|
+
for (const match of scored) {
|
|
12377
|
+
if (usedNames.has(match.name)) continue;
|
|
12378
|
+
const skill = allSkills.find((s) => s.name === match.name);
|
|
12379
|
+
if (!skill) continue;
|
|
12380
|
+
autoChars = loadWithDeps(skill, allSkills, usedNames, entries, autoChars, AUTO_BUDGET_CHARS);
|
|
12381
|
+
}
|
|
12382
|
+
}
|
|
12383
|
+
if (entries.length === 0) return null;
|
|
12384
|
+
const injectedNames = entries.map((e) => e.name);
|
|
12385
|
+
if (chatId) {
|
|
12386
|
+
setInjectedSkills(chatId, injectedNames);
|
|
12387
|
+
}
|
|
12388
|
+
log(`[skills] Injected ${injectedNames.length} skill(s): ${injectedNames.join(", ")}`);
|
|
12389
|
+
return formatSkillBlock(entries);
|
|
12390
|
+
}
|
|
12391
|
+
function readSkillContent(filePath) {
|
|
12392
|
+
try {
|
|
12393
|
+
const raw = readFileSync10(filePath, "utf-8");
|
|
12394
|
+
return stripFrontmatter(raw);
|
|
12395
|
+
} catch {
|
|
12396
|
+
return null;
|
|
12397
|
+
}
|
|
12398
|
+
}
|
|
12399
|
+
var AUTO_BUDGET_CHARS, PINNED_BUDGET_CHARS, TOTAL_BUDGET_CHARS, MIN_SCORE, injectedSkillsMap, SKIP_COMPLEXITY, STOPWORDS, tokenize, tokenizeAll;
|
|
12400
|
+
var init_inject2 = __esm({
|
|
12401
|
+
"src/skills/inject.ts"() {
|
|
12402
|
+
"use strict";
|
|
12403
|
+
init_complexity();
|
|
12404
|
+
init_discover();
|
|
12405
|
+
init_text_utils();
|
|
12406
|
+
init_log();
|
|
12407
|
+
AUTO_BUDGET_CHARS = 3e3;
|
|
12408
|
+
PINNED_BUDGET_CHARS = 5e3;
|
|
12409
|
+
TOTAL_BUDGET_CHARS = 8e3;
|
|
12410
|
+
MIN_SCORE = 2;
|
|
12411
|
+
injectedSkillsMap = /* @__PURE__ */ new Map();
|
|
12412
|
+
SKIP_COMPLEXITY = /* @__PURE__ */ new Set(["trivial", "simple"]);
|
|
12413
|
+
STOPWORDS = /* @__PURE__ */ new Set([
|
|
12414
|
+
"about",
|
|
12415
|
+
"after",
|
|
12416
|
+
"also",
|
|
12417
|
+
"been",
|
|
12418
|
+
"before",
|
|
12419
|
+
"being",
|
|
12420
|
+
"between",
|
|
12421
|
+
"both",
|
|
12422
|
+
"could",
|
|
12423
|
+
"does",
|
|
12424
|
+
"doing",
|
|
12425
|
+
"done",
|
|
12426
|
+
"down",
|
|
12427
|
+
"during",
|
|
12428
|
+
"each",
|
|
12429
|
+
"even",
|
|
12430
|
+
"every",
|
|
12431
|
+
"from",
|
|
12432
|
+
"have",
|
|
12433
|
+
"having",
|
|
12434
|
+
"help",
|
|
12435
|
+
"here",
|
|
12436
|
+
"into",
|
|
12437
|
+
"just",
|
|
12438
|
+
"know",
|
|
12439
|
+
"like",
|
|
12440
|
+
"make",
|
|
12441
|
+
"more",
|
|
12442
|
+
"most",
|
|
12443
|
+
"much",
|
|
12444
|
+
"need",
|
|
12445
|
+
"only",
|
|
12446
|
+
"other",
|
|
12447
|
+
"over",
|
|
12448
|
+
"some",
|
|
12449
|
+
"such",
|
|
12450
|
+
"than",
|
|
12451
|
+
"that",
|
|
12452
|
+
"their",
|
|
12453
|
+
"them",
|
|
12454
|
+
"then",
|
|
12455
|
+
"there",
|
|
12456
|
+
"these",
|
|
12457
|
+
"they",
|
|
12458
|
+
"this",
|
|
12459
|
+
"through",
|
|
12460
|
+
"very",
|
|
12461
|
+
"want",
|
|
12462
|
+
"well",
|
|
12463
|
+
"were",
|
|
12464
|
+
"what",
|
|
12465
|
+
"when",
|
|
12466
|
+
"where",
|
|
12467
|
+
"which",
|
|
12468
|
+
"while",
|
|
12469
|
+
"will",
|
|
12470
|
+
"with",
|
|
12471
|
+
"would",
|
|
12472
|
+
"your"
|
|
12473
|
+
]);
|
|
12474
|
+
tokenize = (text) => tokenizeText(text, 4);
|
|
12475
|
+
tokenizeAll = (text) => tokenizeText(text, 1);
|
|
12476
|
+
}
|
|
12477
|
+
});
|
|
12478
|
+
|
|
12479
|
+
// src/bootstrap/loader.ts
|
|
12480
|
+
import { readFileSync as readFileSync11, readdirSync as readdirSync6 } from "fs";
|
|
12481
|
+
import { join as join15 } from "path";
|
|
11791
12482
|
function loadMarkdownDir(dir, cacheRef, wordSource = (c) => c) {
|
|
11792
12483
|
if (cacheRef.v && Date.now() - cacheRef.v.timestamp < CACHE_TTL_MS4) {
|
|
11793
12484
|
return cacheRef.v.files;
|
|
@@ -11797,8 +12488,8 @@ function loadMarkdownDir(dir, cacheRef, wordSource = (c) => c) {
|
|
|
11797
12488
|
for (const entry of readdirSync6(dir)) {
|
|
11798
12489
|
if (!entry.endsWith(".md")) continue;
|
|
11799
12490
|
try {
|
|
11800
|
-
const content =
|
|
11801
|
-
if (content) files.set(entry, { content, words:
|
|
12491
|
+
const content = readFileSync11(join15(dir, entry), "utf-8").trim();
|
|
12492
|
+
if (content) files.set(entry, { content, words: tokenize2(wordSource(content)) });
|
|
11802
12493
|
} catch {
|
|
11803
12494
|
continue;
|
|
11804
12495
|
}
|
|
@@ -11809,7 +12500,7 @@ function loadMarkdownDir(dir, cacheRef, wordSource = (c) => c) {
|
|
|
11809
12500
|
return files;
|
|
11810
12501
|
}
|
|
11811
12502
|
function findBestMatch(userMessage, files, opts) {
|
|
11812
|
-
const msgWords =
|
|
12503
|
+
const msgWords = tokenize2(userMessage);
|
|
11813
12504
|
if (msgWords.size === 0) return null;
|
|
11814
12505
|
let best = null;
|
|
11815
12506
|
for (const entry of files.values()) {
|
|
@@ -11832,16 +12523,6 @@ function searchContext(userMessage) {
|
|
|
11832
12523
|
{ maxChars: MAX_CONTEXT_CHARS }
|
|
11833
12524
|
);
|
|
11834
12525
|
}
|
|
11835
|
-
function searchSkill(userMessage) {
|
|
11836
|
-
return findBestMatch(
|
|
11837
|
-
userMessage,
|
|
11838
|
-
loadMarkdownDir(SKILLS_DIR, skillCacheRef, stripFrontmatter3),
|
|
11839
|
-
{
|
|
11840
|
-
maxChars: MAX_SKILL_CHARS,
|
|
11841
|
-
filter: ({ content }) => content.includes("status: approved") || content.includes("status: imported")
|
|
11842
|
-
}
|
|
11843
|
-
);
|
|
11844
|
-
}
|
|
11845
12526
|
async function assembleBootstrapPrompt(userMessage, entityType = "main", profile = "interactive", chatId, permMode, responseStyle, agentMode, sideQuestContext, planningDirective, chatContext, backendType) {
|
|
11846
12527
|
const sections = [];
|
|
11847
12528
|
if (planningDirective) {
|
|
@@ -11855,15 +12536,24 @@ async function assembleBootstrapPrompt(userMessage, entityType = "main", profile
|
|
|
11855
12536
|
sections.push(buildPermissionNotice(permMode));
|
|
11856
12537
|
}
|
|
11857
12538
|
if (backendType === "api") {
|
|
11858
|
-
|
|
12539
|
+
if (!apiHarnessCache.main || Date.now() - apiHarnessCache.cachedMs > 5e3) {
|
|
12540
|
+
try {
|
|
12541
|
+
apiHarnessCache.main = readFileSync11(join15(IDENTITY_PATH, "CC-CLAW-api.md"), "utf-8");
|
|
12542
|
+
apiHarnessCache.task = readFileSync11(join15(IDENTITY_PATH, "CC-CLAW-api-task.md"), "utf-8");
|
|
12543
|
+
apiHarnessCache.cachedMs = Date.now();
|
|
12544
|
+
} catch {
|
|
12545
|
+
}
|
|
12546
|
+
}
|
|
12547
|
+
const harness = entityType === "task" ? apiHarnessCache.task : apiHarnessCache.main;
|
|
12548
|
+
if (harness) {
|
|
12549
|
+
sections.push(harness);
|
|
12550
|
+
} else {
|
|
12551
|
+
warn("[bootstrap] API harness files not yet generated, using fallback");
|
|
12552
|
+
sections.push(`[API Backend \u2014 Tool Usage]
|
|
11859
12553
|
You are operating as a direct API model (not a CLI like Claude Code or Gemini CLI).
|
|
11860
|
-
External tools
|
|
11861
|
-
NEVER call external CLIs as direct tools by name \u2014 they are not registered as native tools.
|
|
11862
|
-
Correct: restrictedBash({"command": "gsearch \\"query\\" --type news"})
|
|
11863
|
-
Incorrect: gsearch({"query": "..."}) \u2190 this will fail silently
|
|
11864
|
-
If a skill or instruction says to use a CLI tool, always route it through restrictedBash.
|
|
11865
|
-
|
|
12554
|
+
External tools are accessed ONLY via the \`restrictedBash\` tool. NEVER call external CLIs as direct tool names.
|
|
11866
12555
|
${buildCliEnvironment()}`);
|
|
12556
|
+
}
|
|
11867
12557
|
}
|
|
11868
12558
|
if (responseStyle) {
|
|
11869
12559
|
if (responseStyle === "concise") {
|
|
@@ -11893,10 +12583,23 @@ ${ctx}`);
|
|
|
11893
12583
|
}
|
|
11894
12584
|
}
|
|
11895
12585
|
if (profile === "interactive" || profile === "chat") {
|
|
11896
|
-
const
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
12586
|
+
const pinnedSkills = chatId ? getPinnedSkills(chatId) : [];
|
|
12587
|
+
const userExplicitNative = agentMode === "native" && !sideQuestContext;
|
|
12588
|
+
try {
|
|
12589
|
+
const allSkills = await discoverAllSkills();
|
|
12590
|
+
const skillBlock = injectSkillContext(
|
|
12591
|
+
userMessage,
|
|
12592
|
+
allSkills,
|
|
12593
|
+
pinnedSkills,
|
|
12594
|
+
profile,
|
|
12595
|
+
userExplicitNative,
|
|
12596
|
+
chatId
|
|
12597
|
+
);
|
|
12598
|
+
if (skillBlock) {
|
|
12599
|
+
sections.push(skillBlock);
|
|
12600
|
+
}
|
|
12601
|
+
} catch (err) {
|
|
12602
|
+
warn(`[bootstrap] Skill injection failed: ${err instanceof Error ? err.message : err}`);
|
|
11900
12603
|
}
|
|
11901
12604
|
}
|
|
11902
12605
|
if (chatId && profile !== "minimal" && profile !== "chat") {
|
|
@@ -12064,7 +12767,7 @@ ${parts.join("\n")}${MEMORY_DISCIPLINE}`;
|
|
|
12064
12767
|
}
|
|
12065
12768
|
return null;
|
|
12066
12769
|
}
|
|
12067
|
-
var lastSyncMs, CONTEXT_DIR2, SKILLS_DIR, MAX_CONTEXT_CHARS,
|
|
12770
|
+
var lastSyncMs, apiHarnessCache, CONTEXT_DIR2, SKILLS_DIR, MAX_CONTEXT_CHARS, CACHE_TTL_MS4, tokenize2, contextCacheRef, ACTIVITY_TOKEN_BUDGET, INBOX_TOKEN_BUDGET, WHITEBOARD_TOKEN_BUDGET;
|
|
12068
12771
|
var init_loader2 = __esm({
|
|
12069
12772
|
"src/bootstrap/loader.ts"() {
|
|
12070
12773
|
"use strict";
|
|
@@ -12077,14 +12780,22 @@ var init_loader2 = __esm({
|
|
|
12077
12780
|
init_store5();
|
|
12078
12781
|
init_store();
|
|
12079
12782
|
init_backends();
|
|
12783
|
+
init_inject2();
|
|
12784
|
+
init_discover();
|
|
12785
|
+
init_chat_settings();
|
|
12786
|
+
init_text_utils();
|
|
12080
12787
|
lastSyncMs = 0;
|
|
12788
|
+
apiHarnessCache = {
|
|
12789
|
+
main: null,
|
|
12790
|
+
task: null,
|
|
12791
|
+
cachedMs: 0
|
|
12792
|
+
};
|
|
12081
12793
|
CONTEXT_DIR2 = join15(WORKSPACE_PATH, "context");
|
|
12082
12794
|
SKILLS_DIR = join15(WORKSPACE_PATH, "skills");
|
|
12083
12795
|
MAX_CONTEXT_CHARS = 4e3;
|
|
12084
|
-
MAX_SKILL_CHARS = 6e3;
|
|
12085
12796
|
CACHE_TTL_MS4 = 3e4;
|
|
12797
|
+
tokenize2 = (text) => tokenizeText(text, 4);
|
|
12086
12798
|
contextCacheRef = { v: null };
|
|
12087
|
-
skillCacheRef = { v: null };
|
|
12088
12799
|
ACTIVITY_TOKEN_BUDGET = 1500;
|
|
12089
12800
|
INBOX_TOKEN_BUDGET = 2e3;
|
|
12090
12801
|
WHITEBOARD_TOKEN_BUDGET = 500;
|
|
@@ -12119,7 +12830,8 @@ __export(client_exports, {
|
|
|
12119
12830
|
listModels: () => listModels,
|
|
12120
12831
|
ping: () => ping,
|
|
12121
12832
|
runningModels: () => runningModels,
|
|
12122
|
-
showModel: () => showModel
|
|
12833
|
+
showModel: () => showModel,
|
|
12834
|
+
unloadModel: () => unloadModel
|
|
12123
12835
|
});
|
|
12124
12836
|
function buildHeaders(apiKey) {
|
|
12125
12837
|
const headers = {
|
|
@@ -12205,6 +12917,30 @@ async function deleteModel(baseUrl, modelName, opts) {
|
|
|
12205
12917
|
clearTimeout(timeout);
|
|
12206
12918
|
}
|
|
12207
12919
|
}
|
|
12920
|
+
async function unloadModel(baseUrl, modelName, opts) {
|
|
12921
|
+
const controller = new AbortController();
|
|
12922
|
+
const timeout = setTimeout(
|
|
12923
|
+
() => controller.abort(),
|
|
12924
|
+
opts?.timeoutMs ?? 5e3
|
|
12925
|
+
// short timeout — unload is best-effort
|
|
12926
|
+
);
|
|
12927
|
+
try {
|
|
12928
|
+
const res = await fetch(`${baseUrl}/api/generate`, {
|
|
12929
|
+
method: "POST",
|
|
12930
|
+
headers: buildHeaders(opts?.apiKey),
|
|
12931
|
+
body: JSON.stringify({ model: modelName, keep_alive: 0 }),
|
|
12932
|
+
signal: controller.signal
|
|
12933
|
+
});
|
|
12934
|
+
if (!res.ok) {
|
|
12935
|
+
const body = await res.text().catch(() => "");
|
|
12936
|
+
throw new Error(`Ollama unload failed (${res.status}): ${body}`);
|
|
12937
|
+
}
|
|
12938
|
+
await res.text().catch(() => {
|
|
12939
|
+
});
|
|
12940
|
+
} finally {
|
|
12941
|
+
clearTimeout(timeout);
|
|
12942
|
+
}
|
|
12943
|
+
}
|
|
12208
12944
|
async function listModels(baseUrl, opts) {
|
|
12209
12945
|
const res = await fetch(`${baseUrl}/api/tags`, {
|
|
12210
12946
|
signal: opts?.signal,
|
|
@@ -12892,7 +13628,9 @@ __export(service_exports, {
|
|
|
12892
13628
|
isAnyServerOnline: () => isAnyServerOnline,
|
|
12893
13629
|
listServers: () => listServers2,
|
|
12894
13630
|
removeServer: () => removeServer2,
|
|
12895
|
-
runQualityGateTest: () => runQualityGateTest
|
|
13631
|
+
runQualityGateTest: () => runQualityGateTest,
|
|
13632
|
+
tryUnloadModel: () => tryUnloadModel,
|
|
13633
|
+
unloadModel: () => unloadModel2
|
|
12896
13634
|
});
|
|
12897
13635
|
function addServer2(name, host, port = 11434, apiKey) {
|
|
12898
13636
|
const existing = getServer(name);
|
|
@@ -13082,6 +13820,17 @@ function getServerForModel(modelName) {
|
|
|
13082
13820
|
apiKey: server.apiKey
|
|
13083
13821
|
};
|
|
13084
13822
|
}
|
|
13823
|
+
async function unloadModel2(modelName) {
|
|
13824
|
+
const serverInfo = getServerForModel(modelName);
|
|
13825
|
+
if (!serverInfo) return;
|
|
13826
|
+
await unloadModel(serverInfo.baseUrl, modelName, { apiKey: serverInfo.apiKey });
|
|
13827
|
+
log(`[ollama] Unloaded model: ${modelName}`);
|
|
13828
|
+
}
|
|
13829
|
+
function tryUnloadModel(modelName) {
|
|
13830
|
+
unloadModel2(modelName).catch((err) => {
|
|
13831
|
+
warn(`[ollama] Model unload failed for ${modelName}: ${err}`);
|
|
13832
|
+
});
|
|
13833
|
+
}
|
|
13085
13834
|
function extractContextWindow(show) {
|
|
13086
13835
|
const info = show.model_info ?? {};
|
|
13087
13836
|
for (const key of Object.keys(info)) {
|
|
@@ -13880,6 +14629,7 @@ function classifyReaction(emoji) {
|
|
|
13880
14629
|
return null;
|
|
13881
14630
|
}
|
|
13882
14631
|
async function detectAndLogSignals(chatId, userMessage, agentResponse, ctx = {}) {
|
|
14632
|
+
const injectedSkills = getAndClearInjectedSkills(chatId);
|
|
13883
14633
|
const db3 = getDb();
|
|
13884
14634
|
const status = getReflectionStatus(db3, chatId);
|
|
13885
14635
|
if (status === "frozen") return;
|
|
@@ -13887,18 +14637,29 @@ async function detectAndLogSignals(chatId, userMessage, agentResponse, ctx = {})
|
|
|
13887
14637
|
if (recentCount >= RATE_LIMIT_MAX_SIGNALS) return;
|
|
13888
14638
|
const signals = classifySignals(userMessage, agentResponse);
|
|
13889
14639
|
const context = agentResponse.slice(0, 500) || null;
|
|
14640
|
+
const uniqueByType = /* @__PURE__ */ new Map();
|
|
13890
14641
|
for (const signal of signals) {
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
14642
|
+
const existing = uniqueByType.get(signal.signalType);
|
|
14643
|
+
if (!existing || signal.confidence > existing.confidence) {
|
|
14644
|
+
uniqueByType.set(signal.signalType, signal);
|
|
14645
|
+
}
|
|
14646
|
+
}
|
|
14647
|
+
const skillList = injectedSkills.length > 0 ? injectedSkills : [void 0];
|
|
14648
|
+
for (const signal of uniqueByType.values()) {
|
|
14649
|
+
for (const skillName of skillList) {
|
|
14650
|
+
logSignal(db3, {
|
|
14651
|
+
chatId,
|
|
14652
|
+
signalType: signal.signalType,
|
|
14653
|
+
trigger: signal.trigger,
|
|
14654
|
+
context,
|
|
14655
|
+
source: signal.source,
|
|
14656
|
+
confidence: signal.confidence,
|
|
14657
|
+
backend: ctx.backendId ?? null,
|
|
14658
|
+
model: ctx.model ?? null,
|
|
14659
|
+
thinkingLevel: ctx.thinkingLevel ?? null,
|
|
14660
|
+
skillName
|
|
14661
|
+
});
|
|
14662
|
+
}
|
|
13902
14663
|
}
|
|
13903
14664
|
}
|
|
13904
14665
|
function logReactionSignal(chatId, emoji) {
|
|
@@ -13941,6 +14702,7 @@ var init_detect = __esm({
|
|
|
13941
14702
|
"use strict";
|
|
13942
14703
|
init_store4();
|
|
13943
14704
|
init_store5();
|
|
14705
|
+
init_inject2();
|
|
13944
14706
|
CORRECTION_PATTERNS = [
|
|
13945
14707
|
// Audit O36: Tightened — require "no" followed by correction context (not "No problem", "No worries")
|
|
13946
14708
|
/^no[,.\s!]+\s*(that'?s|it'?s|i\s|you|this|the|not|don'?t|stop|wrong)/i,
|
|
@@ -14019,9 +14781,11 @@ function killProcessGroup(proc, signal = "SIGTERM") {
|
|
|
14019
14781
|
function runCompaction(chatId, reason, onCompaction) {
|
|
14020
14782
|
return summarizeWithFallbackChain(chatId).then((saved) => {
|
|
14021
14783
|
if (saved) {
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
|
|
14784
|
+
return withChatLock(chatId, async () => {
|
|
14785
|
+
clearSession(chatId);
|
|
14786
|
+
clearUsage(chatId);
|
|
14787
|
+
onCompaction?.(chatId);
|
|
14788
|
+
});
|
|
14025
14789
|
}
|
|
14026
14790
|
}).catch((err) => {
|
|
14027
14791
|
warn(`[agent] Compaction failed for ${chatId} (${reason}): ${err}`);
|
|
@@ -14084,6 +14848,13 @@ function stopAgent(chatId) {
|
|
|
14084
14848
|
if (state.process) killProcessGroup(state.process, "SIGKILL");
|
|
14085
14849
|
}, 2e3);
|
|
14086
14850
|
}
|
|
14851
|
+
const modelToUnload = state.model;
|
|
14852
|
+
if (state.backendId === "ollama" && modelToUnload) {
|
|
14853
|
+
Promise.resolve().then(() => (init_ollama(), ollama_exports)).then(({ OllamaService }) => {
|
|
14854
|
+
OllamaService.tryUnloadModel(modelToUnload);
|
|
14855
|
+
}).catch(() => {
|
|
14856
|
+
});
|
|
14857
|
+
}
|
|
14087
14858
|
return true;
|
|
14088
14859
|
}
|
|
14089
14860
|
function getGeminiFallback(model2) {
|
|
@@ -14095,7 +14866,8 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
14095
14866
|
const thinkingConfig = thinkingLevel && thinkingLevel !== "auto" ? adapter.applyThinkingConfig(thinkingLevel, model2) : void 0;
|
|
14096
14867
|
const env = opts?.envOverride ? thinkingConfig?.envOverrides ? { ...opts.envOverride, ...thinkingConfig.envOverrides } : opts.envOverride : adapter.getEnv(thinkingConfig?.envOverrides);
|
|
14097
14868
|
const finalArgs = thinkingConfig?.extraArgs ? [...config2.args, ...thinkingConfig.extraArgs] : config2.args;
|
|
14098
|
-
|
|
14869
|
+
const hasResume = finalArgs.includes("--resume");
|
|
14870
|
+
log(`[agent:spawn] backend=${adapter.id} exe=${config2.executable} model=${model2} timeout=${effectiveTimeout / 1e3}s resume=${hasResume} cwd=${config2.cwd ?? "(inherited)"}`);
|
|
14099
14871
|
const stdinMode = adapter.id === "codex" ? "pipe" : "ignore";
|
|
14100
14872
|
const proc = spawn4(config2.executable, finalArgs, {
|
|
14101
14873
|
env,
|
|
@@ -14204,7 +14976,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
14204
14976
|
for (const ev of events) {
|
|
14205
14977
|
switch (ev.type) {
|
|
14206
14978
|
case "init":
|
|
14207
|
-
log(`[agent] Session init at ${elapsed()}`);
|
|
14979
|
+
log(`[agent] Session init at ${elapsed()} sessionId=${ev.sessionId ?? "(none)"}`);
|
|
14208
14980
|
if (ev.sessionId) sessionId = ev.sessionId;
|
|
14209
14981
|
resetContentSilenceTimer();
|
|
14210
14982
|
break;
|
|
@@ -14401,6 +15173,7 @@ Partial output: ${accumulatedText.slice(-500)}`;
|
|
|
14401
15173
|
return;
|
|
14402
15174
|
}
|
|
14403
15175
|
const cleanedResult = stripThinkingContent(resultText || accumulatedText);
|
|
15176
|
+
log(`[agent:spawn] Resolving: sessionId=${sessionId ?? "(none)"} hasText=${!!cleanedResult} code=${code}`);
|
|
14404
15177
|
resolve3({ resultText: cleanedResult, thinkingText: accumulatedThinking, sessionId, input, output: output2, cacheRead, contextSize: null, sawToolEvents, sawResultEvent });
|
|
14405
15178
|
});
|
|
14406
15179
|
});
|
|
@@ -14609,14 +15382,14 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
14609
15382
|
const responseStyle = getResponseStyle(settingsChat);
|
|
14610
15383
|
const thinkingLevel = opts?.thinkingLevel ?? getThinkingLevel(settingsChat);
|
|
14611
15384
|
const resolvedCwd = cwd ?? WORKSPACE_PATH;
|
|
14612
|
-
const { entityType, bootstrapProfile: profile } = optsEntityType && optsProfile ? { entityType: optsEntityType, bootstrapProfile: optsProfile } : resolveFromLegacyTier(bootstrapTier ?? "full");
|
|
15385
|
+
const { entityType, bootstrapProfile: profile } = optsEntityType && optsProfile ? { entityType: optsEntityType, bootstrapProfile: optsProfile } : optsProfile ? { entityType: "main", bootstrapProfile: optsProfile } : resolveFromLegacyTier(bootstrapTier ?? "full");
|
|
14613
15386
|
const effectiveAgentMode = optsAgentMode ?? getAgentMode(settingsChat);
|
|
14614
15387
|
const sideQuestCtx = settingsSourceChatId ? { parentChatId: settingsSourceChatId, actualChatId: chatId } : void 0;
|
|
14615
15388
|
const fullPrompt = await assembleBootstrapPrompt(userMessage, entityType, profile, settingsChat, mode, responseStyle, effectiveAgentMode, sideQuestCtx, planningDirective, opts?.chatContext, adapter.type);
|
|
14616
15389
|
if (adapter.streamDirect) {
|
|
14617
15390
|
const resolvedModel2 = model2 ?? adapter.defaultModel;
|
|
14618
15391
|
const abortController = new AbortController();
|
|
14619
|
-
const cancelState2 = { cancelled: false, userMessage, abortController };
|
|
15392
|
+
const cancelState2 = { cancelled: false, userMessage, abortController, backendId: adapter.id, model: resolvedModel2 };
|
|
14620
15393
|
activeChats.set(chatId, cancelState2);
|
|
14621
15394
|
try {
|
|
14622
15395
|
let messageHistory;
|
|
@@ -14676,9 +15449,16 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
14676
15449
|
};
|
|
14677
15450
|
} finally {
|
|
14678
15451
|
activeChats.delete(chatId);
|
|
15452
|
+
if (adapter.id === "ollama" && !cancelState2.cancelled) {
|
|
15453
|
+
Promise.resolve().then(() => (init_ollama(), ollama_exports)).then(({ OllamaService }) => {
|
|
15454
|
+
OllamaService.tryUnloadModel(resolvedModel2);
|
|
15455
|
+
}).catch(() => {
|
|
15456
|
+
});
|
|
15457
|
+
}
|
|
14679
15458
|
}
|
|
14680
15459
|
}
|
|
14681
15460
|
const existingSessionId = settingsSourceChatId ? null : getSessionId(settingsChat);
|
|
15461
|
+
log(`[agent:session] chatId=${chatId} settingsChat=${settingsChat} existingSessionId=${existingSessionId ?? "(none)"} backend=${adapter.id}`);
|
|
14682
15462
|
const allowedTools = getEnabledTools(settingsChat);
|
|
14683
15463
|
const mcpConfigPath = profile !== "minimal" && effectiveAgentMode !== "native" && MCP_CONFIG_FLAG[adapter.id] ? getMcpConfigPath(chatId) : null;
|
|
14684
15464
|
const baseConfig = adapter.buildSpawnConfig({
|
|
@@ -14917,7 +15697,10 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
14917
15697
|
return { text: "Stopped.", usage: { input: result.input, output: result.output, cacheRead: result.cacheRead, contextSize: result.contextSize } };
|
|
14918
15698
|
}
|
|
14919
15699
|
if (result.sessionId && !isSyntheticChatId(chatId)) {
|
|
15700
|
+
log(`[agent:session] Persisting session for chatId=${chatId}: ${result.sessionId}`);
|
|
14920
15701
|
setSessionId(chatId, result.sessionId);
|
|
15702
|
+
} else if (!result.sessionId) {
|
|
15703
|
+
log(`[agent:session] No sessionId in result for chatId=${chatId} \u2014 session will not resume`);
|
|
14921
15704
|
}
|
|
14922
15705
|
if (adapter.id === BACKEND.CLAUDE && result.resultText && result.sessionId && /InputValidationError/i.test(result.resultText) && /missing|required parameter/i.test(result.resultText)) {
|
|
14923
15706
|
const toolMatch = result.resultText.match(/(?:parameter\s+'|required parameter\s+['"]?)([\w-]+)/i);
|
|
@@ -14966,9 +15749,12 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
14966
15749
|
if (result.resultText && !isSyntheticChatId(chatId)) {
|
|
14967
15750
|
appendToLog(chatId, userMessage, result.resultText, adapter.id, model2 ?? null, result.sessionId ?? null);
|
|
14968
15751
|
const pairCount = profile !== "chat" ? getMessagePairCount(chatId) : 0;
|
|
14969
|
-
if (pairCount >= 30) {
|
|
15752
|
+
if (pairCount >= 30 && !compactionInFlight.has(chatId)) {
|
|
15753
|
+
compactionInFlight.add(chatId);
|
|
14970
15754
|
log(`[agent] Auto-summarizing chat ${chatId} after ${pairCount} turns`);
|
|
14971
|
-
runCompaction(chatId, "30-pair-threshold", opts?.onCompaction)
|
|
15755
|
+
runCompaction(chatId, "30-pair-threshold", opts?.onCompaction).finally(() => {
|
|
15756
|
+
compactionInFlight.delete(chatId);
|
|
15757
|
+
});
|
|
14972
15758
|
}
|
|
14973
15759
|
}
|
|
14974
15760
|
return {
|
|
@@ -15513,52 +16299,6 @@ var init_pagination = __esm({
|
|
|
15513
16299
|
}
|
|
15514
16300
|
});
|
|
15515
16301
|
|
|
15516
|
-
// src/format-time.ts
|
|
15517
|
-
function formatLocalDate(utcDatetime) {
|
|
15518
|
-
const d = parseUtcDatetime(utcDatetime);
|
|
15519
|
-
if (!d) return utcDatetime.split("T")[0] ?? utcDatetime.split(" ")[0];
|
|
15520
|
-
const year = d.getFullYear();
|
|
15521
|
-
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
15522
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
15523
|
-
return `${year}-${month}-${day}`;
|
|
15524
|
-
}
|
|
15525
|
-
function formatLocalDateTime(utcDatetime) {
|
|
15526
|
-
const d = parseUtcDatetime(utcDatetime);
|
|
15527
|
-
if (!d) return utcDatetime;
|
|
15528
|
-
const year = d.getFullYear();
|
|
15529
|
-
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
15530
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
15531
|
-
const hours = String(d.getHours()).padStart(2, "0");
|
|
15532
|
-
const minutes = String(d.getMinutes()).padStart(2, "0");
|
|
15533
|
-
const tzAbbr = getTimezoneAbbr(d);
|
|
15534
|
-
return `${year}-${month}-${day} ${hours}:${minutes} ${tzAbbr}`;
|
|
15535
|
-
}
|
|
15536
|
-
function parseUtcDatetime(utcDatetime) {
|
|
15537
|
-
if (!utcDatetime) return null;
|
|
15538
|
-
const normalized = utcDatetime.includes("T") ? utcDatetime : utcDatetime.replace(" ", "T");
|
|
15539
|
-
const withZ = normalized.endsWith("Z") ? normalized : normalized + "Z";
|
|
15540
|
-
const d = new Date(withZ);
|
|
15541
|
-
return isNaN(d.getTime()) ? null : d;
|
|
15542
|
-
}
|
|
15543
|
-
function getTimezoneAbbr(date) {
|
|
15544
|
-
try {
|
|
15545
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
15546
|
-
timeZone: systemTimezone,
|
|
15547
|
-
timeZoneName: "short"
|
|
15548
|
-
}).formatToParts(date);
|
|
15549
|
-
return parts.find((p) => p.type === "timeZoneName")?.value ?? "";
|
|
15550
|
-
} catch {
|
|
15551
|
-
return "";
|
|
15552
|
-
}
|
|
15553
|
-
}
|
|
15554
|
-
var systemTimezone;
|
|
15555
|
-
var init_format_time = __esm({
|
|
15556
|
-
"src/format-time.ts"() {
|
|
15557
|
-
"use strict";
|
|
15558
|
-
systemTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
15559
|
-
}
|
|
15560
|
-
});
|
|
15561
|
-
|
|
15562
16302
|
// src/scheduler/humanize.ts
|
|
15563
16303
|
function formatTime(hour, minute) {
|
|
15564
16304
|
const h = hour % 12 || 12;
|
|
@@ -16851,11 +17591,11 @@ var init_health2 = __esm({
|
|
|
16851
17591
|
});
|
|
16852
17592
|
|
|
16853
17593
|
// src/health/checks.ts
|
|
16854
|
-
import { existsSync as existsSync16, statSync as statSync5, readFileSync as
|
|
17594
|
+
import { existsSync as existsSync16, statSync as statSync5, readFileSync as readFileSync12 } from "fs";
|
|
16855
17595
|
import { execFileSync as execFileSync2, execSync as execSync2 } from "child_process";
|
|
16856
17596
|
function getRecentErrors() {
|
|
16857
17597
|
if (!existsSync16(ERROR_LOG_PATH)) return null;
|
|
16858
|
-
const logContent =
|
|
17598
|
+
const logContent = readFileSync12(ERROR_LOG_PATH, "utf-8");
|
|
16859
17599
|
const allLines = logContent.split("\n").filter(Boolean).slice(-500);
|
|
16860
17600
|
const last24h = Date.now() - 864e5;
|
|
16861
17601
|
const lines = allLines.filter((line) => {
|
|
@@ -17084,7 +17824,7 @@ __export(heartbeat_exports, {
|
|
|
17084
17824
|
stopHeartbeatForChat: () => stopHeartbeatForChat,
|
|
17085
17825
|
updateHeartbeatConfig: () => updateHeartbeatConfig
|
|
17086
17826
|
});
|
|
17087
|
-
import { readFileSync as
|
|
17827
|
+
import { readFileSync as readFileSync13, existsSync as existsSync17 } from "fs";
|
|
17088
17828
|
import { join as join17 } from "path";
|
|
17089
17829
|
function findHeartbeatJob() {
|
|
17090
17830
|
try {
|
|
@@ -17266,7 +18006,7 @@ ${watchLines.join("\n")}`);
|
|
|
17266
18006
|
}
|
|
17267
18007
|
if (existsSync17(HEARTBEAT_MD_PATH)) {
|
|
17268
18008
|
try {
|
|
17269
|
-
const custom =
|
|
18009
|
+
const custom = readFileSync13(HEARTBEAT_MD_PATH, "utf-8").trim();
|
|
17270
18010
|
if (custom) {
|
|
17271
18011
|
sections.push(`[Custom checks from HEARTBEAT.md]
|
|
17272
18012
|
${custom}`);
|
|
@@ -17515,6 +18255,7 @@ __export(ui_exports, {
|
|
|
17515
18255
|
ROTATION_MODE_LABELS: () => ROTATION_MODE_LABELS,
|
|
17516
18256
|
buildAccountSlotKeyboard: () => buildAccountSlotKeyboard,
|
|
17517
18257
|
doBackendSwitch: () => doBackendSwitch,
|
|
18258
|
+
executeBackendDisable: () => executeBackendDisable,
|
|
17518
18259
|
getJobScheduleText: () => getJobScheduleText,
|
|
17519
18260
|
getJobStatusEmoji: () => getJobStatusEmoji,
|
|
17520
18261
|
getJobStatusLabel: () => getJobStatusLabel,
|
|
@@ -17522,6 +18263,7 @@ __export(ui_exports, {
|
|
|
17522
18263
|
sendApiToolsKeyboard: () => sendApiToolsKeyboard,
|
|
17523
18264
|
sendBackendAccountPicker: () => sendBackendAccountPicker,
|
|
17524
18265
|
sendBackendConfigPanel: () => sendBackendConfigPanel,
|
|
18266
|
+
sendBackendDisableFlow: () => sendBackendDisableFlow,
|
|
17525
18267
|
sendBackendModelPicker: () => sendBackendModelPicker,
|
|
17526
18268
|
sendBackendPicker: () => sendBackendPicker,
|
|
17527
18269
|
sendBackendSwitchConfirmation: () => sendBackendSwitchConfirmation,
|
|
@@ -18265,9 +19007,24 @@ ${unapproved.length} CC-Claw skill${unapproved.length !== 1 ? "s" : ""} need rev
|
|
|
18265
19007
|
const safePage = Math.max(1, Math.min(page, totalPages));
|
|
18266
19008
|
const start = (safePage - 1) * SKILLS_PER_PAGE;
|
|
18267
19009
|
const pageSkills = approved.slice(start, start + SKILLS_PER_PAGE);
|
|
19010
|
+
const { getPinnedSkills: getPinnedSkills2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
19011
|
+
const pinned = getPinnedSkills2(chatId);
|
|
19012
|
+
let correctedSkills = /* @__PURE__ */ new Set();
|
|
19013
|
+
try {
|
|
19014
|
+
const { getSkillCorrections: getSkillCorrections2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
19015
|
+
const db3 = (await Promise.resolve().then(() => (init_store5(), store_exports5))).getDb();
|
|
19016
|
+
const corrections = getSkillCorrections2(db3, 30, 3);
|
|
19017
|
+
correctedSkills = new Set(corrections.map((c) => c.skillName));
|
|
19018
|
+
} catch {
|
|
19019
|
+
}
|
|
18268
19020
|
const typeIcon = (s) => s.type === "specialist" ? "\u{1F3AF}" : "\u{1F527}";
|
|
18269
19021
|
const buttons = pageSkills.map((s) => {
|
|
18270
|
-
|
|
19022
|
+
const isPinned = pinned.includes(s.name);
|
|
19023
|
+
const correctionBadge = correctedSkills.has(s.name) ? " \u26A0\uFE0F" : "";
|
|
19024
|
+
return [
|
|
19025
|
+
{ label: `${typeIcon(s)} ${s.name}${correctionBadge}`, data: `skill:${s.source}:${s.name}`, style: "success" },
|
|
19026
|
+
{ label: isPinned ? "\u{1F4CC}" : "\u25CB Pin", data: `pin:${s.name}` }
|
|
19027
|
+
];
|
|
18271
19028
|
});
|
|
18272
19029
|
if (totalPages > 1) {
|
|
18273
19030
|
const navRow = [];
|
|
@@ -18999,6 +19756,17 @@ async function sendBackendPicker(chatId, channel, messageId) {
|
|
|
18999
19756
|
}
|
|
19000
19757
|
async function sendBackendConfigPanel(chatId, backendId, channel, messageId, switched = false) {
|
|
19001
19758
|
if (typeof channel.sendKeyboard !== "function") return;
|
|
19759
|
+
const disabled = getDisabledBackends().includes(backendId);
|
|
19760
|
+
if (disabled) {
|
|
19761
|
+
const adapter = getAdapter(backendId);
|
|
19762
|
+
const text = `\u{1F534} ${adapter.displayName} is disabled`;
|
|
19763
|
+
const buttons2 = [
|
|
19764
|
+
[{ label: "Enable", data: `bconf:enable:${backendId}`, style: "success" }],
|
|
19765
|
+
[{ label: "\u2190 Back to Backends", data: "bconf:back" }]
|
|
19766
|
+
];
|
|
19767
|
+
await sendOrEditKeyboard(chatId, channel, messageId, text, buttons2);
|
|
19768
|
+
return;
|
|
19769
|
+
}
|
|
19002
19770
|
const summary = backendConfigSummary(chatId, backendId, switched);
|
|
19003
19771
|
const buttons = [
|
|
19004
19772
|
[
|
|
@@ -19006,10 +19774,80 @@ async function sendBackendConfigPanel(chatId, backendId, channel, messageId, swi
|
|
|
19006
19774
|
{ label: "Thinking", data: `bconf:thinking:${backendId}` },
|
|
19007
19775
|
{ label: "Account", data: `bconf:account:${backendId}` }
|
|
19008
19776
|
],
|
|
19777
|
+
[{ label: "Disable", data: `bconf:disable:${backendId}`, style: "danger" }],
|
|
19009
19778
|
[{ label: "\u2190 Back to Backends", data: "bconf:back" }]
|
|
19010
19779
|
];
|
|
19011
19780
|
await sendOrEditKeyboard(chatId, channel, messageId, summary, buttons);
|
|
19012
19781
|
}
|
|
19782
|
+
async function sendBackendDisableFlow(chatId, backendId, channel, messageId) {
|
|
19783
|
+
if (typeof channel.sendKeyboard !== "function") return;
|
|
19784
|
+
const { getActiveJobsByBackend: getActiveJobsByBackend2 } = await Promise.resolve().then(() => (init_jobs(), jobs_exports));
|
|
19785
|
+
const affectedJobs = getActiveJobsByBackend2(backendId);
|
|
19786
|
+
if (affectedJobs.length > 0) {
|
|
19787
|
+
await sendDisableJobReassign(chatId, backendId, affectedJobs, channel, messageId);
|
|
19788
|
+
return;
|
|
19789
|
+
}
|
|
19790
|
+
const current = getBackend(chatId);
|
|
19791
|
+
if (current === backendId) {
|
|
19792
|
+
await sendDisableBackendSwitch(chatId, backendId, channel, messageId);
|
|
19793
|
+
return;
|
|
19794
|
+
}
|
|
19795
|
+
await executeBackendDisable(chatId, backendId, channel, messageId);
|
|
19796
|
+
}
|
|
19797
|
+
async function sendDisableJobReassign(chatId, backendId, jobs, channel, messageId) {
|
|
19798
|
+
const adapter = getAdapter(backendId);
|
|
19799
|
+
const jobList = jobs.slice(0, 5).map((j) => ` \u2022 ${j.title ?? j.description}`).join("\n");
|
|
19800
|
+
const extra = jobs.length > 5 ? `
|
|
19801
|
+
\u2026and ${jobs.length - 5} more` : "";
|
|
19802
|
+
const text = [
|
|
19803
|
+
`\u26A0\uFE0F ${jobs.length} cron job(s) use ${adapter.displayName}:`,
|
|
19804
|
+
"",
|
|
19805
|
+
jobList + extra,
|
|
19806
|
+
"",
|
|
19807
|
+
"Reassign these jobs to:"
|
|
19808
|
+
].join("\n");
|
|
19809
|
+
const ids = getAvailableChatBackendIds().filter((id) => id !== backendId);
|
|
19810
|
+
const buttons = ids.map((id) => [{
|
|
19811
|
+
label: getAdapter(id).displayName,
|
|
19812
|
+
data: `bconf:reassign:${backendId}:${id}`
|
|
19813
|
+
}]);
|
|
19814
|
+
buttons.push([{ label: "Cancel", data: `bconf:panel:${backendId}` }]);
|
|
19815
|
+
await sendOrEditKeyboard(chatId, channel, messageId, text, buttons);
|
|
19816
|
+
}
|
|
19817
|
+
async function sendDisableBackendSwitch(chatId, backendId, channel, messageId) {
|
|
19818
|
+
const adapter = getAdapter(backendId);
|
|
19819
|
+
const text = `${adapter.displayName} is your active backend.
|
|
19820
|
+
|
|
19821
|
+
Switch to:`;
|
|
19822
|
+
const ids = getAvailableChatBackendIds().filter((id) => id !== backendId);
|
|
19823
|
+
const buttons = ids.map((id) => [{
|
|
19824
|
+
label: getAdapter(id).displayName,
|
|
19825
|
+
data: `bconf:disableswitch:${backendId}:${id}`
|
|
19826
|
+
}]);
|
|
19827
|
+
buttons.push([{ label: "Cancel", data: `bconf:panel:${backendId}` }]);
|
|
19828
|
+
await sendOrEditKeyboard(chatId, channel, messageId, text, buttons);
|
|
19829
|
+
}
|
|
19830
|
+
async function executeBackendDisable(chatId, backendId, channel, messageId, opts) {
|
|
19831
|
+
const adapter = getAdapter(backendId);
|
|
19832
|
+
const parts = [];
|
|
19833
|
+
if (opts?.reassignTo) {
|
|
19834
|
+
const { reassignJobsBackend: reassignJobsBackend2 } = await Promise.resolve().then(() => (init_jobs(), jobs_exports));
|
|
19835
|
+
const count = reassignJobsBackend2(backendId, opts.reassignTo);
|
|
19836
|
+
const targetName = getAdapter(opts.reassignTo).displayName;
|
|
19837
|
+
if (count > 0) parts.push(`${count} job(s) reassigned to ${targetName}`);
|
|
19838
|
+
}
|
|
19839
|
+
if (opts?.switchTo) {
|
|
19840
|
+
await doBackendSwitch(chatId, opts.switchTo, channel, { skipContext: true });
|
|
19841
|
+
parts.push(`Switched to ${getAdapter(opts.switchTo).displayName}`);
|
|
19842
|
+
}
|
|
19843
|
+
setBackendDisabled(backendId, true);
|
|
19844
|
+
const detail = parts.length > 0 ? `
|
|
19845
|
+
${parts.join(". ")}.` : "";
|
|
19846
|
+
const text = `\u2705 ${adapter.displayName} disabled.${detail}`;
|
|
19847
|
+
await sendOrEditKeyboard(chatId, channel, messageId, text, [
|
|
19848
|
+
[{ label: "\u2190 Back to Backends", data: "bconf:back" }]
|
|
19849
|
+
]);
|
|
19850
|
+
}
|
|
19013
19851
|
async function sendBackendModelPicker(chatId, backendId, channel, messageId) {
|
|
19014
19852
|
if (typeof channel.sendKeyboard !== "function") return;
|
|
19015
19853
|
const adapter = getAdapter(backendId);
|
|
@@ -19083,7 +19921,15 @@ async function sendBackendThinkingPicker(chatId, backendId, channel, messageId)
|
|
|
19083
19921
|
return;
|
|
19084
19922
|
}
|
|
19085
19923
|
const current = getThinkingLevel(chatId) ?? "auto";
|
|
19086
|
-
const
|
|
19924
|
+
const LEVEL_LABELS = {
|
|
19925
|
+
auto: "Auto",
|
|
19926
|
+
off: "Off",
|
|
19927
|
+
low: "Low",
|
|
19928
|
+
medium: "Medium",
|
|
19929
|
+
high: backendId === "ollama" ? "On" : "High",
|
|
19930
|
+
extra_high: "Extra High"
|
|
19931
|
+
};
|
|
19932
|
+
const defaultLevels = [
|
|
19087
19933
|
["auto", "Auto"],
|
|
19088
19934
|
["off", "Off"],
|
|
19089
19935
|
["low", "Low"],
|
|
@@ -19091,6 +19937,7 @@ async function sendBackendThinkingPicker(chatId, backendId, channel, messageId)
|
|
|
19091
19937
|
["high", "High"],
|
|
19092
19938
|
["extra_high", "Extra High"]
|
|
19093
19939
|
];
|
|
19940
|
+
const levels = modelInfo?.thinkingLevels ? modelInfo.thinkingLevels.map((l) => [l, LEVEL_LABELS[l] ?? capitalize(l.replace("_", " "))]) : defaultLevels;
|
|
19094
19941
|
const buttons = levels.map(([val, label2]) => [{
|
|
19095
19942
|
label: `${val === current ? "\u2713 " : ""}${label2}`,
|
|
19096
19943
|
data: `bconf:setthinking:${backendId}:${val}`,
|
|
@@ -19151,6 +19998,16 @@ async function doBackendSwitch(chatId, backendId, channel, opts) {
|
|
|
19151
19998
|
const bridge = buildContextBridge(chatId, 15, interrupted);
|
|
19152
19999
|
if (bridge) setPendingContextBridge(chatId, bridge);
|
|
19153
20000
|
}
|
|
20001
|
+
const previousBackend = getBackend(chatId);
|
|
20002
|
+
if (previousBackend === "ollama") {
|
|
20003
|
+
const previousModel = getModel(chatId);
|
|
20004
|
+
if (previousModel) {
|
|
20005
|
+
Promise.resolve().then(() => (init_ollama(), ollama_exports)).then(({ OllamaService }) => {
|
|
20006
|
+
OllamaService.tryUnloadModel(previousModel);
|
|
20007
|
+
}).catch(() => {
|
|
20008
|
+
});
|
|
20009
|
+
}
|
|
20010
|
+
}
|
|
19154
20011
|
clearSession(chatId);
|
|
19155
20012
|
clearModel(chatId);
|
|
19156
20013
|
clearThinkingLevel(chatId);
|
|
@@ -20641,7 +21498,7 @@ __export(analyze_exports, {
|
|
|
20641
21498
|
});
|
|
20642
21499
|
import { spawn as spawn5 } from "child_process";
|
|
20643
21500
|
import { createInterface as createInterface4 } from "readline";
|
|
20644
|
-
import { readFileSync as
|
|
21501
|
+
import { readFileSync as readFileSync14, existsSync as existsSync18, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
|
|
20645
21502
|
import { join as join18 } from "path";
|
|
20646
21503
|
import { homedir as homedir6 } from "os";
|
|
20647
21504
|
function applySignalDecay(confidence, createdAt) {
|
|
@@ -20663,7 +21520,7 @@ function discoverReflectionTargets() {
|
|
|
20663
21520
|
if (!existsSync18(skillFile)) continue;
|
|
20664
21521
|
let desc = "skill";
|
|
20665
21522
|
try {
|
|
20666
|
-
const content =
|
|
21523
|
+
const content = readFileSync14(skillFile, "utf-8");
|
|
20667
21524
|
const descMatch = content.match(/description:\s*["']?([^"'\n]+)/);
|
|
20668
21525
|
if (descMatch) desc = descMatch[1].trim().slice(0, 80);
|
|
20669
21526
|
} catch {
|
|
@@ -20738,6 +21595,21 @@ ${categoryList}`);
|
|
|
20738
21595
|
sections.push(skill.content);
|
|
20739
21596
|
}
|
|
20740
21597
|
}
|
|
21598
|
+
if (params.skillCorrections && params.skillCorrections.length > 0) {
|
|
21599
|
+
sections.push("[Underperforming Skills]");
|
|
21600
|
+
sections.push(
|
|
21601
|
+
"These skills have received repeated corrections. The per-model breakdown helps distinguish skill quality issues from model capability limits. If corrections concentrate on weaker models (Flash, Haiku, Lite) while stronger models (Opus, Pro) handle the skill correctly, this likely reflects model capability rather than skill quality \u2014 consider adding a simplified-instructions section for weaker models rather than a full rewrite."
|
|
21602
|
+
);
|
|
21603
|
+
for (const sc of params.skillCorrections) {
|
|
21604
|
+
const modelSummary = sc.modelBreakdown.map((m) => `${m.model}: ${m.count}`).join(", ");
|
|
21605
|
+
sections.push(`- **${sc.skillName}** \u2014 ${sc.correctionCount} corrections in last 30 days`);
|
|
21606
|
+
sections.push(` Models: ${modelSummary || "unknown"}`);
|
|
21607
|
+
const uniqueContexts = [...new Set(sc.contexts)].slice(0, 5);
|
|
21608
|
+
for (const ctx of uniqueContexts) {
|
|
21609
|
+
sections.push(` Correction: "${ctx}"`);
|
|
21610
|
+
}
|
|
21611
|
+
}
|
|
21612
|
+
}
|
|
20741
21613
|
sections.push("[Previously Applied Insights]");
|
|
20742
21614
|
if (appliedInsights.length === 0) {
|
|
20743
21615
|
sections.push("(none)");
|
|
@@ -20872,7 +21744,7 @@ function resolveReflectionAdapter(chatId) {
|
|
|
20872
21744
|
}
|
|
20873
21745
|
function readIdentityFile(filename) {
|
|
20874
21746
|
try {
|
|
20875
|
-
return
|
|
21747
|
+
return readFileSync14(join18(IDENTITY_PATH, filename), "utf-8");
|
|
20876
21748
|
} catch {
|
|
20877
21749
|
return "";
|
|
20878
21750
|
}
|
|
@@ -21031,7 +21903,7 @@ async function runAnalysisImpl(chatId, opts) {
|
|
|
21031
21903
|
try {
|
|
21032
21904
|
const fullPath = join18(ccClawHome, target.path);
|
|
21033
21905
|
if (existsSync18(fullPath)) {
|
|
21034
|
-
const content =
|
|
21906
|
+
const content = readFileSync14(fullPath, "utf-8");
|
|
21035
21907
|
if (totalSkillChars + content.length > SKILL_CONTENT_CAP) break;
|
|
21036
21908
|
skillContents.push({ path: target.path, content });
|
|
21037
21909
|
totalSkillChars += content.length;
|
|
@@ -21039,6 +21911,7 @@ async function runAnalysisImpl(chatId, opts) {
|
|
|
21039
21911
|
} catch {
|
|
21040
21912
|
}
|
|
21041
21913
|
}
|
|
21914
|
+
const skillCorrections = getSkillCorrections(db3, 30, 3);
|
|
21042
21915
|
const prompt = buildAnalysisPrompt({
|
|
21043
21916
|
signals: signals.map((s) => {
|
|
21044
21917
|
const decayedConfidence = applySignalDecay(s.confidence, s.created_at);
|
|
@@ -21061,7 +21934,8 @@ async function runAnalysisImpl(chatId, opts) {
|
|
|
21061
21934
|
})),
|
|
21062
21935
|
codebaseEnabled,
|
|
21063
21936
|
availableTargets,
|
|
21064
|
-
skillContents
|
|
21937
|
+
skillContents,
|
|
21938
|
+
skillCorrections
|
|
21065
21939
|
});
|
|
21066
21940
|
const resolved = resolveReflectionAdapter(chatId);
|
|
21067
21941
|
if (!resolved) {
|
|
@@ -21411,7 +22285,7 @@ __export(apply_exports, {
|
|
|
21411
22285
|
isTargetAllowed: () => isTargetAllowed,
|
|
21412
22286
|
rollbackInsight: () => rollbackInsight
|
|
21413
22287
|
});
|
|
21414
|
-
import { readFileSync as
|
|
22288
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync7, existsSync as existsSync19, mkdirSync as mkdirSync7, readdirSync as readdirSync8, unlinkSync as unlinkSync5 } from "fs";
|
|
21415
22289
|
import { join as join19, dirname as dirname4 } from "path";
|
|
21416
22290
|
function isTargetAllowed(relativePath) {
|
|
21417
22291
|
if (relativePath.includes("..")) return false;
|
|
@@ -21499,7 +22373,7 @@ async function applyInsight(insightId) {
|
|
|
21499
22373
|
const absolutePath = join19(CC_CLAW_HOME, insight.targetFile);
|
|
21500
22374
|
if (insight.proposedAction === "append" && insight.targetFile === "identity/SOUL.md") {
|
|
21501
22375
|
if (existsSync19(absolutePath)) {
|
|
21502
|
-
const currentContent =
|
|
22376
|
+
const currentContent = readFileSync15(absolutePath, "utf-8");
|
|
21503
22377
|
const lineCount = currentContent.split("\n").length;
|
|
21504
22378
|
if (lineCount >= SOUL_LINE_CAP) {
|
|
21505
22379
|
return {
|
|
@@ -21521,7 +22395,7 @@ async function applyInsight(insightId) {
|
|
|
21521
22395
|
}
|
|
21522
22396
|
let original = "";
|
|
21523
22397
|
if (existsSync19(absolutePath)) {
|
|
21524
|
-
original =
|
|
22398
|
+
original = readFileSync15(absolutePath, "utf-8");
|
|
21525
22399
|
} else if (insight.proposedAction !== "create") {
|
|
21526
22400
|
return { success: false, message: `Target file "${insight.targetFile}" does not exist` };
|
|
21527
22401
|
}
|
|
@@ -21662,7 +22536,7 @@ function computeLineDrift(baseline, absolutePath) {
|
|
|
21662
22536
|
let current = "";
|
|
21663
22537
|
try {
|
|
21664
22538
|
if (existsSync19(absolutePath)) {
|
|
21665
|
-
current =
|
|
22539
|
+
current = readFileSync15(absolutePath, "utf-8");
|
|
21666
22540
|
}
|
|
21667
22541
|
} catch {
|
|
21668
22542
|
return 1;
|
|
@@ -22394,6 +23268,14 @@ var init_api_mcp = __esm({
|
|
|
22394
23268
|
|
|
22395
23269
|
// src/backends/api-common.ts
|
|
22396
23270
|
import { streamText, stepCountIs, NoOutputGeneratedError, APICallError } from "ai";
|
|
23271
|
+
function mapToolActionToApiFormat(cb) {
|
|
23272
|
+
if (!cb) return void 0;
|
|
23273
|
+
return (event) => {
|
|
23274
|
+
const input = event.input ?? {};
|
|
23275
|
+
const result = event.type === "tool_end" ? typeof event.output === "string" ? event.output : event.output != null ? JSON.stringify(event.output) : "" : void 0;
|
|
23276
|
+
cb(event.toolName, input, result);
|
|
23277
|
+
};
|
|
23278
|
+
}
|
|
22397
23279
|
function toModelMessage(msg) {
|
|
22398
23280
|
switch (msg.role) {
|
|
22399
23281
|
case "system":
|
|
@@ -22590,6 +23472,7 @@ var init_ollama2 = __esm({
|
|
|
22590
23472
|
"src/backends/ollama.ts"() {
|
|
22591
23473
|
"use strict";
|
|
22592
23474
|
init_api_common();
|
|
23475
|
+
init_api_common();
|
|
22593
23476
|
init_ollama();
|
|
22594
23477
|
init_prompt();
|
|
22595
23478
|
OLLAMA_HTTP_SENTINEL = "__ollama_http__";
|
|
@@ -22677,29 +23560,31 @@ var init_ollama2 = __esm({
|
|
|
22677
23560
|
*/
|
|
22678
23561
|
async streamDirect(prompt, model2, opts) {
|
|
22679
23562
|
const cleanPrompt = stripForLocalModel(prompt);
|
|
22680
|
-
let disableThinking = false;
|
|
22681
23563
|
let modelContextWindow;
|
|
23564
|
+
const ollamaProviderOpts = {};
|
|
22682
23565
|
try {
|
|
22683
23566
|
const { OllamaStore } = (init_ollama(), __toCommonJS(ollama_exports));
|
|
22684
23567
|
const modelRecord = OllamaStore.getModelByName(model2);
|
|
22685
|
-
|
|
22686
|
-
|
|
22687
|
-
|
|
22688
|
-
|
|
23568
|
+
const chatLevel = opts?.thinkingLevel;
|
|
23569
|
+
if (chatLevel === "off") {
|
|
23570
|
+
ollamaProviderOpts.think = false;
|
|
23571
|
+
} else if (chatLevel && chatLevel !== "auto") {
|
|
23572
|
+
ollamaProviderOpts.think = true;
|
|
23573
|
+
} else if (modelRecord?.forceThinkOff) {
|
|
23574
|
+
ollamaProviderOpts.think = false;
|
|
22689
23575
|
}
|
|
22690
23576
|
if (modelRecord?.contextWindow && modelRecord.contextWindow > 4096) {
|
|
22691
23577
|
modelContextWindow = modelRecord.contextWindow;
|
|
22692
23578
|
}
|
|
22693
23579
|
} catch {
|
|
22694
23580
|
}
|
|
22695
|
-
const ollamaProviderOpts = {};
|
|
22696
|
-
if (disableThinking) ollamaProviderOpts.think = false;
|
|
22697
23581
|
if (modelContextWindow) ollamaProviderOpts.num_ctx = modelContextWindow;
|
|
22698
23582
|
const apiOpts = {
|
|
22699
23583
|
timeoutMs: opts?.timeoutMs,
|
|
22700
23584
|
onStream: opts?.onStream,
|
|
22701
23585
|
signal: opts?.signal,
|
|
22702
23586
|
messageHistory: opts?.messageHistory,
|
|
23587
|
+
onToolAction: mapToolActionToApiFormat(opts?.onToolAction),
|
|
22703
23588
|
permMode: opts?.permMode,
|
|
22704
23589
|
thinkingLevel: opts?.thinkingLevel,
|
|
22705
23590
|
onThinking: opts?.onThinking,
|
|
@@ -22728,10 +23613,11 @@ var init_ollama2 = __esm({
|
|
|
22728
23613
|
const { OllamaStore } = (init_ollama(), __toCommonJS(ollama_exports));
|
|
22729
23614
|
const models = OllamaStore.getAvailableModels();
|
|
22730
23615
|
for (const m of models) {
|
|
22731
|
-
const isThinkingCapable = m.capability === "thinking" && !m.forceThinkOff;
|
|
22732
23616
|
this.availableModels[m.name] = {
|
|
22733
23617
|
label: `${m.name}${m.parameterSize ? ` (${m.parameterSize})` : ""}`,
|
|
22734
|
-
thinking:
|
|
23618
|
+
thinking: "adjustable",
|
|
23619
|
+
// all Ollama models support think: true/false toggle
|
|
23620
|
+
thinkingLevels: ["auto", "off", "high"]
|
|
22735
23621
|
};
|
|
22736
23622
|
this.pricing[m.name] = { in: 0, out: 0, cache: 0 };
|
|
22737
23623
|
this.contextWindow[m.name] = m.contextWindow ?? 4096;
|
|
@@ -22748,6 +23634,7 @@ var init_openrouter = __esm({
|
|
|
22748
23634
|
"src/backends/openrouter.ts"() {
|
|
22749
23635
|
"use strict";
|
|
22750
23636
|
init_api_common();
|
|
23637
|
+
init_api_common();
|
|
22751
23638
|
OPENROUTER_HTTP_SENTINEL = "__openrouter_api__";
|
|
22752
23639
|
DEFAULT_FREE_MODEL = "qwen/qwen3.6-plus:free";
|
|
22753
23640
|
OpenRouterAdapter = class extends ApiBackendBase {
|
|
@@ -22837,17 +23724,12 @@ var init_openrouter = __esm({
|
|
|
22837
23724
|
* including tool actions, permission mode, thinking tokens, and conversation history.
|
|
22838
23725
|
*/
|
|
22839
23726
|
async streamDirect(prompt, model2, opts) {
|
|
22840
|
-
const onToolAction = opts?.onToolAction ? (event) => {
|
|
22841
|
-
const input = event.input ?? {};
|
|
22842
|
-
const result2 = event.type === "tool_end" ? typeof event.output === "string" ? event.output : JSON.stringify(event.output ?? "") : void 0;
|
|
22843
|
-
opts.onToolAction(event.toolName, input, result2);
|
|
22844
|
-
} : void 0;
|
|
22845
23727
|
const apiOpts = {
|
|
22846
23728
|
timeoutMs: opts?.timeoutMs,
|
|
22847
23729
|
onStream: opts?.onStream,
|
|
22848
23730
|
signal: opts?.signal,
|
|
22849
23731
|
messageHistory: opts?.messageHistory,
|
|
22850
|
-
onToolAction,
|
|
23732
|
+
onToolAction: mapToolActionToApiFormat(opts?.onToolAction),
|
|
22851
23733
|
permMode: opts?.permMode,
|
|
22852
23734
|
thinkingLevel: opts?.thinkingLevel,
|
|
22853
23735
|
onThinking: opts?.onThinking
|
|
@@ -23023,7 +23905,10 @@ function getAvailableBackendIds() {
|
|
|
23023
23905
|
return [...availableSet];
|
|
23024
23906
|
}
|
|
23025
23907
|
function getAvailableChatBackendIds() {
|
|
23026
|
-
|
|
23908
|
+
const disabled = getDisabledBackends();
|
|
23909
|
+
return CHAT_BACKEND_IDS.filter(
|
|
23910
|
+
(id) => (availableSet.size === 0 || availableSet.has(id)) && !disabled.includes(id)
|
|
23911
|
+
);
|
|
23027
23912
|
}
|
|
23028
23913
|
var openRouterAdapter, adapters, CHAT_BACKEND_IDS, availableSet;
|
|
23029
23914
|
var init_backends = __esm({
|
|
@@ -23036,6 +23921,7 @@ var init_backends = __esm({
|
|
|
23036
23921
|
init_ollama2();
|
|
23037
23922
|
init_openrouter();
|
|
23038
23923
|
init_store5();
|
|
23924
|
+
init_schema();
|
|
23039
23925
|
init_log();
|
|
23040
23926
|
init_types();
|
|
23041
23927
|
openRouterAdapter = new OpenRouterAdapter();
|
|
@@ -23325,7 +24211,7 @@ var init_retry = __esm({
|
|
|
23325
24211
|
});
|
|
23326
24212
|
|
|
23327
24213
|
// src/bootstrap/profile.ts
|
|
23328
|
-
import { readFileSync as
|
|
24214
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync8, existsSync as existsSync22 } from "fs";
|
|
23329
24215
|
import { join as join21 } from "path";
|
|
23330
24216
|
function hasActiveProfile(chatId) {
|
|
23331
24217
|
return activeProfiles.has(chatId);
|
|
@@ -23456,7 +24342,7 @@ function extractUserUpdates(text) {
|
|
|
23456
24342
|
}
|
|
23457
24343
|
function appendToUserProfile(key, value) {
|
|
23458
24344
|
if (!existsSync22(USER_PATH2)) return;
|
|
23459
|
-
const content =
|
|
24345
|
+
const content = readFileSync16(USER_PATH2, "utf-8");
|
|
23460
24346
|
const line = `- **${key}**: ${value}`;
|
|
23461
24347
|
if (content.includes(line)) return;
|
|
23462
24348
|
const updated = content.trimEnd() + `
|
|
@@ -26759,12 +27645,12 @@ async function handleEvolveCallback(chatId, data, channel, messageId) {
|
|
|
26759
27645
|
);
|
|
26760
27646
|
break;
|
|
26761
27647
|
}
|
|
26762
|
-
const { readFileSync:
|
|
27648
|
+
const { readFileSync: readFileSync36, existsSync: existsSync62 } = await import("fs");
|
|
26763
27649
|
const { join: join42 } = await import("path");
|
|
26764
27650
|
const targetPath = join42(homedir7(), ".cc-claw", insight.targetFile);
|
|
26765
27651
|
let previewText;
|
|
26766
27652
|
if (existsSync62(targetPath)) {
|
|
26767
|
-
const current =
|
|
27653
|
+
const current = readFileSync36(targetPath, "utf-8");
|
|
26768
27654
|
const diffLines = insight.proposedDiff.split("\n");
|
|
26769
27655
|
const additions = diffLines.filter((l) => l.startsWith("+")).map((l) => ` + ${l.slice(1).trim()}`);
|
|
26770
27656
|
const removals = diffLines.filter((l) => l.startsWith("-")).map((l) => ` - ${l.slice(1).trim()}`);
|
|
@@ -26836,13 +27722,13 @@ async function handleEvolveCallback(chatId, data, channel, messageId) {
|
|
|
26836
27722
|
const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
|
|
26837
27723
|
const current = getReflectionStatus2(getDb(), chatId);
|
|
26838
27724
|
if (current === "frozen") {
|
|
26839
|
-
const { readFileSync:
|
|
27725
|
+
const { readFileSync: readFileSync36, existsSync: existsSync62 } = await import("fs");
|
|
26840
27726
|
const { join: join42 } = await import("path");
|
|
26841
27727
|
const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
26842
27728
|
const soulPath = join42(CC_CLAW_HOME3, "identity/SOUL.md");
|
|
26843
27729
|
const userPath = join42(CC_CLAW_HOME3, "identity/USER.md");
|
|
26844
|
-
const soul = existsSync62(soulPath) ?
|
|
26845
|
-
const user = existsSync62(userPath) ?
|
|
27730
|
+
const soul = existsSync62(soulPath) ? readFileSync36(soulPath, "utf-8") : "";
|
|
27731
|
+
const user = existsSync62(userPath) ? readFileSync36(userPath, "utf-8") : "";
|
|
26846
27732
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
26847
27733
|
logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
|
|
26848
27734
|
await sendEvolveDashboard(chatId, reflChatId, channel, messageId);
|
|
@@ -26981,11 +27867,11 @@ var init_evolve2 = __esm({
|
|
|
26981
27867
|
});
|
|
26982
27868
|
|
|
26983
27869
|
// src/optimizer/identity-audit.ts
|
|
26984
|
-
import { readFileSync as
|
|
27870
|
+
import { readFileSync as readFileSync17, existsSync as existsSync26, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
|
|
26985
27871
|
import { join as join26 } from "path";
|
|
26986
27872
|
function readIdentityFile2(filename) {
|
|
26987
27873
|
try {
|
|
26988
|
-
return
|
|
27874
|
+
return readFileSync17(join26(IDENTITY_PATH, filename), "utf-8");
|
|
26989
27875
|
} catch {
|
|
26990
27876
|
return "";
|
|
26991
27877
|
}
|
|
@@ -27138,7 +28024,7 @@ var init_identity_audit = __esm({
|
|
|
27138
28024
|
});
|
|
27139
28025
|
|
|
27140
28026
|
// src/optimizer/skill-audit.ts
|
|
27141
|
-
import { readFileSync as
|
|
28027
|
+
import { readFileSync as readFileSync18, existsSync as existsSync27 } from "fs";
|
|
27142
28028
|
import { join as join27, basename as basename3 } from "path";
|
|
27143
28029
|
function parseFrontmatter3(content) {
|
|
27144
28030
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -27184,7 +28070,7 @@ function detectDependentSkills(content) {
|
|
|
27184
28070
|
return Array.from(deps);
|
|
27185
28071
|
}
|
|
27186
28072
|
function computeSkillStats(skillPath) {
|
|
27187
|
-
const content =
|
|
28073
|
+
const content = readFileSync18(skillPath, "utf-8");
|
|
27188
28074
|
const lines = content.split("\n");
|
|
27189
28075
|
return {
|
|
27190
28076
|
skillName: basename3(skillPath, ".md") === "SKILL" ? basename3(join27(skillPath, "..")) : basename3(skillPath, ".md"),
|
|
@@ -27213,7 +28099,7 @@ function loadDependentSkillContents(depNames, ccClawSkillsDir) {
|
|
|
27213
28099
|
for (const candidate of candidates) {
|
|
27214
28100
|
if (existsSync27(candidate)) {
|
|
27215
28101
|
try {
|
|
27216
|
-
const content =
|
|
28102
|
+
const content = readFileSync18(candidate, "utf-8");
|
|
27217
28103
|
results.push({
|
|
27218
28104
|
name,
|
|
27219
28105
|
content: content.length > 3e3 ? content.slice(0, 3e3) + "\n[...truncated]" : content
|
|
@@ -27357,7 +28243,7 @@ __export(analyze_exports2, {
|
|
|
27357
28243
|
});
|
|
27358
28244
|
import { spawn as spawn7 } from "child_process";
|
|
27359
28245
|
import { createInterface as createInterface7 } from "readline";
|
|
27360
|
-
import { readFileSync as
|
|
28246
|
+
import { readFileSync as readFileSync19, existsSync as existsSync28, readdirSync as readdirSync12 } from "fs";
|
|
27361
28247
|
import { join as join28 } from "path";
|
|
27362
28248
|
import { homedir as homedir8 } from "os";
|
|
27363
28249
|
function parseOptimizeOutput(raw, validAreas) {
|
|
@@ -27488,7 +28374,7 @@ function getModelDisplayInfo(chatId) {
|
|
|
27488
28374
|
}
|
|
27489
28375
|
function readIdentityFile3(filename) {
|
|
27490
28376
|
try {
|
|
27491
|
-
return
|
|
28377
|
+
return readFileSync19(join28(IDENTITY_PATH, filename), "utf-8");
|
|
27492
28378
|
} catch {
|
|
27493
28379
|
return "";
|
|
27494
28380
|
}
|
|
@@ -27501,7 +28387,7 @@ function loadContextFiles() {
|
|
|
27501
28387
|
for (const entry of readdirSync12(contextDir)) {
|
|
27502
28388
|
if (!entry.endsWith(".md")) continue;
|
|
27503
28389
|
try {
|
|
27504
|
-
const content =
|
|
28390
|
+
const content = readFileSync19(join28(contextDir, entry), "utf-8");
|
|
27505
28391
|
results.push({ name: entry, content });
|
|
27506
28392
|
} catch {
|
|
27507
28393
|
}
|
|
@@ -27553,7 +28439,7 @@ async function runSkillAudit(chatId, skillPath) {
|
|
|
27553
28439
|
log(`[optimizer] Running skill audit on ${stats.skillName} with ${adapter.id}:${model2}`);
|
|
27554
28440
|
const soulMd = readIdentityFile3("SOUL.md");
|
|
27555
28441
|
const ccClawSkillsDir = join28(homedir8(), ".cc-claw", "workspace", "skills");
|
|
27556
|
-
const skillContent =
|
|
28442
|
+
const skillContent = readFileSync19(skillPath, "utf-8");
|
|
27557
28443
|
const prompt = buildSkillAuditPrompt(skillContent, stats, soulMd, ccClawSkillsDir);
|
|
27558
28444
|
const raw = await spawnAnalysis2(adapter, model2, prompt);
|
|
27559
28445
|
const findings = parseOptimizeOutput(raw, VALID_SKILL_AREAS);
|
|
@@ -27576,7 +28462,7 @@ function listCcClawSkills() {
|
|
|
27576
28462
|
if (!existsSync28(skillFile)) continue;
|
|
27577
28463
|
let description = "skill";
|
|
27578
28464
|
try {
|
|
27579
|
-
const content =
|
|
28465
|
+
const content = readFileSync19(skillFile, "utf-8");
|
|
27580
28466
|
const descMatch = content.match(/description:\s*>?\s*\n?\s*(.+)/);
|
|
27581
28467
|
if (descMatch) description = descMatch[1].trim().slice(0, 60);
|
|
27582
28468
|
} catch {
|
|
@@ -27903,7 +28789,7 @@ __export(optimize_exports2, {
|
|
|
27903
28789
|
handleOptimizeCallback: () => handleOptimizeCallback,
|
|
27904
28790
|
handleOptimizeCommand: () => handleOptimizeCommand
|
|
27905
28791
|
});
|
|
27906
|
-
import { readFileSync as
|
|
28792
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync9, existsSync as existsSync29, readdirSync as readdirSync13, unlinkSync as unlinkSync7 } from "fs";
|
|
27907
28793
|
import { join as join29, dirname as dirname5 } from "path";
|
|
27908
28794
|
import { homedir as homedir9 } from "os";
|
|
27909
28795
|
async function handleOptimizeCommand(chatId, channel, _args, messageId) {
|
|
@@ -28133,7 +29019,7 @@ async function applyFinding(chatId, channel, index, messageId) {
|
|
|
28133
29019
|
await showFinding(chatId, channel, index + 1, effectiveMsgId);
|
|
28134
29020
|
return;
|
|
28135
29021
|
}
|
|
28136
|
-
const original =
|
|
29022
|
+
const original = readFileSync20(targetPath, "utf-8");
|
|
28137
29023
|
const backupPath = targetPath + `.bak.${Date.now()}`;
|
|
28138
29024
|
writeFileSync9(backupPath, original, "utf-8");
|
|
28139
29025
|
pruneBackups2(targetPath);
|
|
@@ -29688,14 +30574,19 @@ async function handleStatusCommand(chatId, commandArgs, msg, channel) {
|
|
|
29688
30574
|
const iDeep = iStats.agentic;
|
|
29689
30575
|
const intentLine = iTotal > 0 ? `\u26A1 ${iTotal} messages: ${iQuick} quick, ${iDeep} deep` : `\u26A1 No messages classified yet`;
|
|
29690
30576
|
const sqCount = getActiveSideQuestCount(chatId);
|
|
30577
|
+
const { getPinnedSkills: getPinnedSkills2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
30578
|
+
const pinnedSkills = getPinnedSkills2(chatId);
|
|
30579
|
+
const pinnedLine = pinnedSkills.length > 0 ? `\u{1F4CC} Pinned: ${pinnedSkills.join(", ")}` : `\u{1F4CC} Pinned: none`;
|
|
29691
30580
|
const lines = [
|
|
29692
30581
|
`\u{1F43E} CC-Claw v${VERSION}`,
|
|
29693
30582
|
`\u23F1 Uptime: ${uptimeStr}`,
|
|
30583
|
+
isChatBusy(chatId) ? `\u{1F534} Agent: Busy` : `\u{1F7E2} Agent: Idle`,
|
|
29694
30584
|
``,
|
|
29695
30585
|
buildSectionHeader("Engine"),
|
|
29696
30586
|
`\u{1F9E0} ${adapter?.displayName ?? backendId ?? "not set"} \xB7 ${formatModelShort(model2)}${slotInfo}`,
|
|
29697
30587
|
`\u{1F4AD} Think: ${thinking2} \xB7 Mode: ${mode}`,
|
|
29698
30588
|
`\u{1F916} Agents: ${getAgentMode(chatId)}`,
|
|
30589
|
+
pinnedLine,
|
|
29699
30590
|
`\u{1F507} Voice: ${voice2 ? "on" : "off"} \xB7 Sig: ${modelSig}`,
|
|
29700
30591
|
`\u{1F4DD} Summarizer: ${summarizerStatusLine(chatId, adapter)}`,
|
|
29701
30592
|
``,
|
|
@@ -29741,11 +30632,16 @@ async function handleBackendCommand2(chatId, commandArgs, msg, channel) {
|
|
|
29741
30632
|
async function handleBackendShortcutCommand(chatId, commandArgs, msg, channel) {
|
|
29742
30633
|
const command = msg.command;
|
|
29743
30634
|
const backendId = command;
|
|
29744
|
-
if (getAllBackendIds().includes(backendId)) {
|
|
29745
|
-
await sendBackendSwitchConfirmation(chatId, backendId, channel);
|
|
29746
|
-
} else {
|
|
30635
|
+
if (!getAllBackendIds().includes(backendId)) {
|
|
29747
30636
|
await channel.sendText(chatId, `Backend "${command}" is not available.`, { parseMode: "plain" });
|
|
30637
|
+
return;
|
|
30638
|
+
}
|
|
30639
|
+
if (getDisabledBackends().includes(backendId)) {
|
|
30640
|
+
const { sendBackendConfigPanel: sendBackendConfigPanel2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
30641
|
+
await sendBackendConfigPanel2(chatId, backendId, channel);
|
|
30642
|
+
return;
|
|
29748
30643
|
}
|
|
30644
|
+
await sendBackendSwitchConfirmation(chatId, backendId, channel);
|
|
29749
30645
|
}
|
|
29750
30646
|
async function handleModelCommand(chatId, commandArgs, msg, channel) {
|
|
29751
30647
|
await sendModelKeyboard(chatId, channel);
|
|
@@ -30895,7 +31791,7 @@ __export(import_exports, {
|
|
|
30895
31791
|
parseClaudeConfig: () => parseClaudeConfig,
|
|
30896
31792
|
parseCursorConfig: () => parseCursorConfig
|
|
30897
31793
|
});
|
|
30898
|
-
import { readFileSync as
|
|
31794
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
30899
31795
|
import { join as join31 } from "path";
|
|
30900
31796
|
import { homedir as homedir10 } from "os";
|
|
30901
31797
|
function parseClaudeConfig(config2) {
|
|
@@ -30912,7 +31808,7 @@ async function discoverFromSource(source) {
|
|
|
30912
31808
|
case "claude": {
|
|
30913
31809
|
const path = join31(homedir10(), ".claude", "settings.json");
|
|
30914
31810
|
try {
|
|
30915
|
-
return parseClaudeConfig(JSON.parse(
|
|
31811
|
+
return parseClaudeConfig(JSON.parse(readFileSync21(path, "utf-8")));
|
|
30916
31812
|
} catch {
|
|
30917
31813
|
warn(`[mcp-import] Could not read ${path}`);
|
|
30918
31814
|
return [];
|
|
@@ -30921,7 +31817,7 @@ async function discoverFromSource(source) {
|
|
|
30921
31817
|
case "cursor": {
|
|
30922
31818
|
const path = join31(homedir10(), ".cursor", "mcp.json");
|
|
30923
31819
|
try {
|
|
30924
|
-
return parseCursorConfig(JSON.parse(
|
|
31820
|
+
return parseCursorConfig(JSON.parse(readFileSync21(path, "utf-8")));
|
|
30925
31821
|
} catch {
|
|
30926
31822
|
warn(`[mcp-import] Could not read ${path}`);
|
|
30927
31823
|
return [];
|
|
@@ -31585,6 +32481,10 @@ async function handleCallback(chatId, data, channel, messageId) {
|
|
|
31585
32481
|
if (data.startsWith("backend:")) {
|
|
31586
32482
|
const chosen = data.slice(8);
|
|
31587
32483
|
if (!getAllBackendIds().includes(chosen)) return;
|
|
32484
|
+
if (getDisabledBackends().includes(chosen)) {
|
|
32485
|
+
await sendBackendConfigPanel(chatId, chosen, channel, messageId, false);
|
|
32486
|
+
return;
|
|
32487
|
+
}
|
|
31588
32488
|
const previous = getBackend(chatId);
|
|
31589
32489
|
if (chosen === previous) {
|
|
31590
32490
|
await sendBackendConfigPanel(chatId, chosen, channel, messageId, false);
|
|
@@ -31638,6 +32538,32 @@ async function handleCallback(chatId, data, channel, messageId) {
|
|
|
31638
32538
|
}
|
|
31639
32539
|
}
|
|
31640
32540
|
await sendBackendConfigPanel(chatId, backendId, channel, messageId, false);
|
|
32541
|
+
} else if (rest.startsWith("disable:")) {
|
|
32542
|
+
const backendId = rest.slice(8);
|
|
32543
|
+
const { sendBackendDisableFlow: sendBackendDisableFlow2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
32544
|
+
await sendBackendDisableFlow2(chatId, backendId, channel, messageId);
|
|
32545
|
+
} else if (rest.startsWith("enable:")) {
|
|
32546
|
+
const backendId = rest.slice(7);
|
|
32547
|
+
setBackendDisabled(backendId, false);
|
|
32548
|
+
await sendBackendConfigPanel(chatId, backendId, channel, messageId, false);
|
|
32549
|
+
} else if (rest.startsWith("reassign:")) {
|
|
32550
|
+
const parts = rest.slice(9).split(":");
|
|
32551
|
+
const disablingBackend = parts[0];
|
|
32552
|
+
const targetBackend = parts[1];
|
|
32553
|
+
const current = getBackend(chatId);
|
|
32554
|
+
const { executeBackendDisable: executeBackendDisable2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
32555
|
+
await executeBackendDisable2(chatId, disablingBackend, channel, messageId, {
|
|
32556
|
+
reassignTo: targetBackend,
|
|
32557
|
+
...current === disablingBackend ? { switchTo: targetBackend } : {}
|
|
32558
|
+
});
|
|
32559
|
+
} else if (rest.startsWith("disableswitch:")) {
|
|
32560
|
+
const parts = rest.slice(14).split(":");
|
|
32561
|
+
const disablingBackend = parts[0];
|
|
32562
|
+
const switchToBackend = parts[1];
|
|
32563
|
+
const { executeBackendDisable: executeBackendDisable2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
32564
|
+
await executeBackendDisable2(chatId, disablingBackend, channel, messageId, {
|
|
32565
|
+
switchTo: switchToBackend
|
|
32566
|
+
});
|
|
31641
32567
|
}
|
|
31642
32568
|
} else if (data.startsWith("backend_confirm_clear:")) {
|
|
31643
32569
|
const target = data.slice("backend_confirm_clear:".length);
|
|
@@ -33478,10 +34404,10 @@ ${formatValidationReport2(validation)}` : "\n\n\u2705 Quality checks passed.";
|
|
|
33478
34404
|
return;
|
|
33479
34405
|
}
|
|
33480
34406
|
try {
|
|
33481
|
-
const { readFileSync:
|
|
34407
|
+
const { readFileSync: readFileSync36, writeFileSync: writeFileSync16 } = await import("fs");
|
|
33482
34408
|
const { updateFrontmatter: updateFrontmatter2, ensureThreeTierFrontmatter: ensureThreeTierFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
33483
34409
|
const { invalidateSkillCache: invalidateSkillCache2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
33484
|
-
const raw =
|
|
34410
|
+
const raw = readFileSync36(skill.filePath, "utf-8");
|
|
33485
34411
|
let updated = ensureThreeTierFrontmatter2(raw, { name: skillName, source: "cc-claw" });
|
|
33486
34412
|
updated = updateFrontmatter2(updated, { status: "approved" });
|
|
33487
34413
|
writeFileSync16(skill.filePath, updated, "utf-8");
|
|
@@ -33531,14 +34457,14 @@ ${stillUnapproved.length} more skill${stillUnapproved.length !== 1 ? "s" : ""} t
|
|
|
33531
34457
|
return;
|
|
33532
34458
|
}
|
|
33533
34459
|
try {
|
|
33534
|
-
const { readFileSync:
|
|
34460
|
+
const { readFileSync: readFileSync36, writeFileSync: writeFileSync16 } = await import("fs");
|
|
33535
34461
|
const { updateFrontmatter: updateFrontmatter2, ensureThreeTierFrontmatter: ensureThreeTierFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
33536
34462
|
const { invalidateSkillCache: invalidateSkillCache2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
33537
34463
|
let approvedCount = 0;
|
|
33538
34464
|
const issues = [];
|
|
33539
34465
|
for (const skill of unapproved) {
|
|
33540
34466
|
try {
|
|
33541
|
-
const raw =
|
|
34467
|
+
const raw = readFileSync36(skill.filePath, "utf-8");
|
|
33542
34468
|
let updated = ensureThreeTierFrontmatter2(raw, { name: skill.name, source: "cc-claw" });
|
|
33543
34469
|
updated = updateFrontmatter2(updated, { status: "approved" });
|
|
33544
34470
|
writeFileSync16(skill.filePath, updated, "utf-8");
|
|
@@ -33572,6 +34498,29 @@ ${issues.join("\n")}`;
|
|
|
33572
34498
|
);
|
|
33573
34499
|
}
|
|
33574
34500
|
return;
|
|
34501
|
+
} else if (data.startsWith("pin:")) {
|
|
34502
|
+
const skillName = data.slice(4);
|
|
34503
|
+
const { getPinnedSkills: getPinnedSkills2, setPinnedSkills: setPinnedSkills2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
|
|
34504
|
+
const pinned = getPinnedSkills2(chatId);
|
|
34505
|
+
if (pinned.includes(skillName)) {
|
|
34506
|
+
setPinnedSkills2(chatId, pinned.filter((n) => n !== skillName));
|
|
34507
|
+
await sendOrEditKeyboard(
|
|
34508
|
+
chatId,
|
|
34509
|
+
channel,
|
|
34510
|
+
messageId,
|
|
34511
|
+
`\u{1F4CC} Unpinned "${skillName}" from this chat.`,
|
|
34512
|
+
[[{ label: "\u2190 Skills", data: "skills:page:1" }]]
|
|
34513
|
+
);
|
|
34514
|
+
} else {
|
|
34515
|
+
setPinnedSkills2(chatId, [...pinned, skillName]);
|
|
34516
|
+
await sendOrEditKeyboard(
|
|
34517
|
+
chatId,
|
|
34518
|
+
channel,
|
|
34519
|
+
messageId,
|
|
34520
|
+
`\u{1F4CC} Pinned "${skillName}" to this chat. It will always inject regardless of message content.`,
|
|
34521
|
+
[[{ label: "\u2190 Skills", data: "skills:page:1" }]]
|
|
34522
|
+
);
|
|
34523
|
+
}
|
|
33575
34524
|
} else if (data.startsWith("skill:")) {
|
|
33576
34525
|
const parts = data.slice(6).split(":");
|
|
33577
34526
|
let skillName;
|
|
@@ -33779,134 +34728,6 @@ var init_thread_wrapper = __esm({
|
|
|
33779
34728
|
}
|
|
33780
34729
|
});
|
|
33781
34730
|
|
|
33782
|
-
// src/intent/complexity.ts
|
|
33783
|
-
var complexity_exports = {};
|
|
33784
|
-
__export(complexity_exports, {
|
|
33785
|
-
classifyComplexity: () => classifyComplexity
|
|
33786
|
-
});
|
|
33787
|
-
function wordCount(text) {
|
|
33788
|
-
return text.trim().split(/\s+/).filter(Boolean).length;
|
|
33789
|
-
}
|
|
33790
|
-
function classifyComplexity(text) {
|
|
33791
|
-
const trimmed = text.trim();
|
|
33792
|
-
const lower = trimmed.toLowerCase();
|
|
33793
|
-
const words = wordCount(trimmed);
|
|
33794
|
-
if (TRIVIAL_EXACT.has(lower)) {
|
|
33795
|
-
log(`[complexity] "${lower}" -> trivial (exact match)`);
|
|
33796
|
-
return "trivial";
|
|
33797
|
-
}
|
|
33798
|
-
if (trimmed.length <= 4 && /^[\p{Emoji}\s]+$/u.test(trimmed)) {
|
|
33799
|
-
log(`[complexity] "${trimmed}" -> trivial (emoji-only)`);
|
|
33800
|
-
return "trivial";
|
|
33801
|
-
}
|
|
33802
|
-
if (COMPLEX_SIGNALS.test(trimmed) && (words > 15 || trimmed.length > 200)) {
|
|
33803
|
-
log(`[complexity] "${trimmed.slice(0, 40)}..." -> complex (signal words + length)`);
|
|
33804
|
-
return "complex";
|
|
33805
|
-
}
|
|
33806
|
-
if (MUTATION_VERBS.test(trimmed)) {
|
|
33807
|
-
const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
|
|
33808
|
-
log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (mutation verb)`);
|
|
33809
|
-
return tier;
|
|
33810
|
-
}
|
|
33811
|
-
for (const pattern of CODE_PATTERNS) {
|
|
33812
|
-
if (pattern.test(trimmed)) {
|
|
33813
|
-
const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
|
|
33814
|
-
log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (code pattern)`);
|
|
33815
|
-
return tier;
|
|
33816
|
-
}
|
|
33817
|
-
}
|
|
33818
|
-
if (trimmed.length > 200 || words > 25) {
|
|
33819
|
-
const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
|
|
33820
|
-
log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (long message)`);
|
|
33821
|
-
return tier;
|
|
33822
|
-
}
|
|
33823
|
-
for (const pattern of QUESTION_PATTERNS) {
|
|
33824
|
-
if (pattern.test(trimmed)) {
|
|
33825
|
-
log(`[complexity] "${trimmed.slice(0, 40)}..." -> simple (question)`);
|
|
33826
|
-
return "simple";
|
|
33827
|
-
}
|
|
33828
|
-
}
|
|
33829
|
-
log(`[complexity] "${trimmed.slice(0, 40)}..." -> moderate (default)`);
|
|
33830
|
-
return "moderate";
|
|
33831
|
-
}
|
|
33832
|
-
var TRIVIAL_EXACT, COMPLEX_SIGNALS, MUTATION_VERBS, CODE_PATTERNS, QUESTION_PATTERNS;
|
|
33833
|
-
var init_complexity = __esm({
|
|
33834
|
-
"src/intent/complexity.ts"() {
|
|
33835
|
-
"use strict";
|
|
33836
|
-
init_log();
|
|
33837
|
-
TRIVIAL_EXACT = /* @__PURE__ */ new Set([
|
|
33838
|
-
"hey",
|
|
33839
|
-
"hi",
|
|
33840
|
-
"hello",
|
|
33841
|
-
"yo",
|
|
33842
|
-
"sup",
|
|
33843
|
-
"howdy",
|
|
33844
|
-
"hiya",
|
|
33845
|
-
"thanks",
|
|
33846
|
-
"thank you",
|
|
33847
|
-
"thx",
|
|
33848
|
-
"ty",
|
|
33849
|
-
"thank u",
|
|
33850
|
-
"ok",
|
|
33851
|
-
"okay",
|
|
33852
|
-
"k",
|
|
33853
|
-
"kk",
|
|
33854
|
-
"cool",
|
|
33855
|
-
"nice",
|
|
33856
|
-
"great",
|
|
33857
|
-
"awesome",
|
|
33858
|
-
"perfect",
|
|
33859
|
-
"good morning",
|
|
33860
|
-
"good night",
|
|
33861
|
-
"good evening",
|
|
33862
|
-
"gm",
|
|
33863
|
-
"gn",
|
|
33864
|
-
"bye",
|
|
33865
|
-
"goodbye",
|
|
33866
|
-
"later",
|
|
33867
|
-
"see ya",
|
|
33868
|
-
"cya",
|
|
33869
|
-
"lol",
|
|
33870
|
-
"lmao",
|
|
33871
|
-
"haha",
|
|
33872
|
-
"heh",
|
|
33873
|
-
"np",
|
|
33874
|
-
"no problem",
|
|
33875
|
-
"no worries",
|
|
33876
|
-
"nw",
|
|
33877
|
-
"got it",
|
|
33878
|
-
"understood",
|
|
33879
|
-
"roger",
|
|
33880
|
-
"copy",
|
|
33881
|
-
"good",
|
|
33882
|
-
"fine",
|
|
33883
|
-
"alright",
|
|
33884
|
-
"sure",
|
|
33885
|
-
"yes",
|
|
33886
|
-
"no",
|
|
33887
|
-
"yep",
|
|
33888
|
-
"nope",
|
|
33889
|
-
"yeah",
|
|
33890
|
-
"nah"
|
|
33891
|
-
]);
|
|
33892
|
-
COMPLEX_SIGNALS = /\b(architect|design|research|plan|strategy|migration|microservice|distributed|end-to-end|trade-offs|pros\s+and\s+cons)\b/i;
|
|
33893
|
-
MUTATION_VERBS = /\b(fix|create|build|deploy|refactor|implement|write|add|update|edit|test|debug)\b/i;
|
|
33894
|
-
CODE_PATTERNS = [
|
|
33895
|
-
/```/,
|
|
33896
|
-
// code blocks
|
|
33897
|
-
/\.[a-z]{1,5}\b/,
|
|
33898
|
-
// file extensions (.ts, .py, .json)
|
|
33899
|
-
/[/\\][\w.-]+/
|
|
33900
|
-
// file paths (/src/foo, .\bar)
|
|
33901
|
-
];
|
|
33902
|
-
QUESTION_PATTERNS = [
|
|
33903
|
-
/^(?:what|which|where|when|why|how)\b/i,
|
|
33904
|
-
/^(?:show|tell|list|explain)\b/i,
|
|
33905
|
-
/^(?:is|are)\b/i
|
|
33906
|
-
];
|
|
33907
|
-
}
|
|
33908
|
-
});
|
|
33909
|
-
|
|
33910
34731
|
// src/intent/auto-route.ts
|
|
33911
34732
|
var auto_route_exports = {};
|
|
33912
34733
|
__export(auto_route_exports, {
|
|
@@ -35257,6 +36078,12 @@ async function executeJob(job) {
|
|
|
35257
36078
|
log(`[scheduler] Running job #${job.id}: ${job.description} (model=${resolvedModel})`);
|
|
35258
36079
|
try {
|
|
35259
36080
|
const backendId = resolveJobBackendId(job);
|
|
36081
|
+
if (getDisabledBackends().includes(backendId)) {
|
|
36082
|
+
const msg = `Backend "${backendId}" is disabled. Reassign this job with /editjob or re-enable the backend.`;
|
|
36083
|
+
completeJobRun(runId, "skipped", { error: msg, durationMs: Date.now() - t0 });
|
|
36084
|
+
await notifyJobFailure(job, msg);
|
|
36085
|
+
return;
|
|
36086
|
+
}
|
|
35260
36087
|
const limitMsg = checkBackendLimits(backendId);
|
|
35261
36088
|
if (limitMsg) {
|
|
35262
36089
|
completeJobRun(runId, "skipped", { error: limitMsg, durationMs: Date.now() - t0 });
|
|
@@ -35687,7 +36514,7 @@ var init_wrap_backend = __esm({
|
|
|
35687
36514
|
});
|
|
35688
36515
|
|
|
35689
36516
|
// src/agents/runners/config-loader.ts
|
|
35690
|
-
import { readFileSync as
|
|
36517
|
+
import { readFileSync as readFileSync22, readdirSync as readdirSync14, existsSync as existsSync30, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
|
|
35691
36518
|
import { join as join33 } from "path";
|
|
35692
36519
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
35693
36520
|
function resolveExecutable2(config2) {
|
|
@@ -35829,7 +36656,7 @@ function configToRunner(config2) {
|
|
|
35829
36656
|
}
|
|
35830
36657
|
function loadRunnerConfig(filePath) {
|
|
35831
36658
|
try {
|
|
35832
|
-
const content =
|
|
36659
|
+
const content = readFileSync22(filePath, "utf-8");
|
|
35833
36660
|
return JSON.parse(content);
|
|
35834
36661
|
} catch (err) {
|
|
35835
36662
|
warn(`[runners] Failed to load config ${filePath}: ${err}`);
|
|
@@ -37244,7 +38071,7 @@ var init_telegram2 = __esm({
|
|
|
37244
38071
|
});
|
|
37245
38072
|
|
|
37246
38073
|
// src/skills/bootstrap.ts
|
|
37247
|
-
import { existsSync as existsSync31, readFileSync as
|
|
38074
|
+
import { existsSync as existsSync31, readFileSync as readFileSync23, writeFileSync as writeFileSync10, copyFileSync as copyFileSync3, readdirSync as readdirSync15 } from "fs";
|
|
37248
38075
|
import { readdir as readdir6, copyFile } from "fs/promises";
|
|
37249
38076
|
import { join as join34, dirname as dirname6 } from "path";
|
|
37250
38077
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -37293,7 +38120,7 @@ function migrateSkillsToThreeTier() {
|
|
|
37293
38120
|
}
|
|
37294
38121
|
if (!skillPath) continue;
|
|
37295
38122
|
try {
|
|
37296
|
-
const raw =
|
|
38123
|
+
const raw = readFileSync23(skillPath, "utf-8");
|
|
37297
38124
|
const fmMatch = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
37298
38125
|
if (fmMatch) {
|
|
37299
38126
|
const fm = fmMatch[1];
|
|
@@ -37936,7 +38763,7 @@ var index_exports = {};
|
|
|
37936
38763
|
__export(index_exports, {
|
|
37937
38764
|
main: () => main
|
|
37938
38765
|
});
|
|
37939
|
-
import { mkdirSync as mkdirSync12, existsSync as existsSync33, renameSync as renameSync2, statSync as statSync9, readFileSync as
|
|
38766
|
+
import { mkdirSync as mkdirSync12, existsSync as existsSync33, renameSync as renameSync2, statSync as statSync9, readFileSync as readFileSync25 } from "fs";
|
|
37940
38767
|
import { join as join36 } from "path";
|
|
37941
38768
|
import dotenv from "dotenv";
|
|
37942
38769
|
function migrateLayout() {
|
|
@@ -37979,7 +38806,7 @@ async function main() {
|
|
|
37979
38806
|
let version = "unknown";
|
|
37980
38807
|
try {
|
|
37981
38808
|
const pkgPath = new URL("../package.json", import.meta.url);
|
|
37982
|
-
version = JSON.parse(
|
|
38809
|
+
version = JSON.parse(readFileSync25(pkgPath, "utf-8")).version;
|
|
37983
38810
|
} catch {
|
|
37984
38811
|
}
|
|
37985
38812
|
log(`[cc-claw] Starting v${version}`);
|
|
@@ -38207,6 +39034,11 @@ ${lines.join("\n")}`;
|
|
|
38207
39034
|
log("[cc-claw] Ready!");
|
|
38208
39035
|
const shutdown = async (signal) => {
|
|
38209
39036
|
log(`[cc-claw] Received ${signal}, shutting down...`);
|
|
39037
|
+
const forceExit = setTimeout(() => {
|
|
39038
|
+
error("[cc-claw] Shutdown timed out after 30s \u2014 forcing exit.");
|
|
39039
|
+
process.exit(1);
|
|
39040
|
+
}, 3e4);
|
|
39041
|
+
forceExit.unref();
|
|
38210
39042
|
try {
|
|
38211
39043
|
const { stopAllActiveAgents: stopAllActiveAgents2, stopStaleChatSweep: stopStaleChatSweep2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
|
|
38212
39044
|
stopAllActiveAgents2();
|
|
@@ -38718,13 +39550,13 @@ var init_daemon = __esm({
|
|
|
38718
39550
|
});
|
|
38719
39551
|
|
|
38720
39552
|
// src/cli/resolve-chat.ts
|
|
38721
|
-
import { readFileSync as
|
|
39553
|
+
import { readFileSync as readFileSync27 } from "fs";
|
|
38722
39554
|
function resolveChatId2(globalOpts) {
|
|
38723
39555
|
const explicit = globalOpts.chat;
|
|
38724
39556
|
if (explicit) return explicit;
|
|
38725
39557
|
if (_cachedDefault) return _cachedDefault;
|
|
38726
39558
|
try {
|
|
38727
|
-
const content =
|
|
39559
|
+
const content = readFileSync27(ENV_PATH, "utf-8");
|
|
38728
39560
|
const match = content.match(/^ALLOWED_CHAT_ID=(.+)$/m);
|
|
38729
39561
|
if (match) {
|
|
38730
39562
|
_cachedDefault = match[1].split(",")[0].trim();
|
|
@@ -39186,7 +40018,7 @@ var logs_exports = {};
|
|
|
39186
40018
|
__export(logs_exports, {
|
|
39187
40019
|
logsCommand: () => logsCommand
|
|
39188
40020
|
});
|
|
39189
|
-
import { existsSync as existsSync37, readFileSync as
|
|
40021
|
+
import { existsSync as existsSync37, readFileSync as readFileSync29, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
|
|
39190
40022
|
async function logsCommand(opts) {
|
|
39191
40023
|
const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
|
|
39192
40024
|
if (!existsSync37(logFile)) {
|
|
@@ -39194,7 +40026,7 @@ async function logsCommand(opts) {
|
|
|
39194
40026
|
process.exit(1);
|
|
39195
40027
|
}
|
|
39196
40028
|
const maxLines = parseInt(opts.lines ?? "100", 10);
|
|
39197
|
-
const content =
|
|
40029
|
+
const content = readFileSync29(logFile, "utf-8");
|
|
39198
40030
|
const allLines = content.split("\n");
|
|
39199
40031
|
const tailLines = allLines.slice(-maxLines);
|
|
39200
40032
|
console.log(muted(` \u2500\u2500 ${logFile} (last ${tailLines.length} lines) \u2500\u2500`));
|
|
@@ -39205,7 +40037,7 @@ async function logsCommand(opts) {
|
|
|
39205
40037
|
let lastLength = content.length;
|
|
39206
40038
|
watchFile2(logFile, { interval: 500 }, () => {
|
|
39207
40039
|
try {
|
|
39208
|
-
const newContent =
|
|
40040
|
+
const newContent = readFileSync29(logFile, "utf-8");
|
|
39209
40041
|
if (newContent.length > lastLength) {
|
|
39210
40042
|
const newPart = newContent.slice(lastLength);
|
|
39211
40043
|
process.stdout.write(newPart);
|
|
@@ -39237,7 +40069,7 @@ __export(session_logs_exports, {
|
|
|
39237
40069
|
sessionLogsList: () => sessionLogsList,
|
|
39238
40070
|
sessionLogsTail: () => sessionLogsTail
|
|
39239
40071
|
});
|
|
39240
|
-
import { readFileSync as
|
|
40072
|
+
import { readFileSync as readFileSync30, watchFile as watchFile3, unwatchFile as unwatchFile3 } from "fs";
|
|
39241
40073
|
async function sessionLogsList(opts) {
|
|
39242
40074
|
const logs = listSessionLogs();
|
|
39243
40075
|
if (logs.length === 0) {
|
|
@@ -39295,12 +40127,12 @@ async function sessionLogsTail(opts) {
|
|
|
39295
40127
|
console.log(muted("\n Following... (Ctrl+C to stop)\n"));
|
|
39296
40128
|
let lastLength = 0;
|
|
39297
40129
|
try {
|
|
39298
|
-
lastLength =
|
|
40130
|
+
lastLength = readFileSync30(targetPath, "utf-8").length;
|
|
39299
40131
|
} catch {
|
|
39300
40132
|
}
|
|
39301
40133
|
watchFile3(targetPath, { interval: 500 }, () => {
|
|
39302
40134
|
try {
|
|
39303
|
-
const content =
|
|
40135
|
+
const content = readFileSync30(targetPath, "utf-8");
|
|
39304
40136
|
if (content.length > lastLength) {
|
|
39305
40137
|
process.stdout.write(content.slice(lastLength));
|
|
39306
40138
|
lastLength = content.length;
|
|
@@ -39344,7 +40176,7 @@ __export(gemini_exports, {
|
|
|
39344
40176
|
geminiReorder: () => geminiReorder,
|
|
39345
40177
|
geminiRotation: () => geminiRotation
|
|
39346
40178
|
});
|
|
39347
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync14, writeFileSync as writeFileSync13, readFileSync as
|
|
40179
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync14, writeFileSync as writeFileSync13, readFileSync as readFileSync31, chmodSync } from "fs";
|
|
39348
40180
|
import { join as join38 } from "path";
|
|
39349
40181
|
import { createInterface as createInterface8 } from "readline";
|
|
39350
40182
|
function requireDb() {
|
|
@@ -39375,7 +40207,7 @@ function resolveOAuthEmail(configHome) {
|
|
|
39375
40207
|
try {
|
|
39376
40208
|
const accountsPath = join38(configHome, ".gemini", "google_accounts.json");
|
|
39377
40209
|
if (!existsSync39(accountsPath)) return null;
|
|
39378
|
-
const accounts = JSON.parse(
|
|
40210
|
+
const accounts = JSON.parse(readFileSync31(accountsPath, "utf-8"));
|
|
39379
40211
|
return accounts.active || null;
|
|
39380
40212
|
} catch {
|
|
39381
40213
|
return null;
|
|
@@ -39638,7 +40470,7 @@ async function geminiRelogin(globalOpts, idOrLabel) {
|
|
|
39638
40470
|
setGeminiSlotEnabled2(slotId, true);
|
|
39639
40471
|
let accountEmail = slot.label;
|
|
39640
40472
|
try {
|
|
39641
|
-
const accounts = JSON.parse(
|
|
40473
|
+
const accounts = JSON.parse(readFileSync31(join38(slot.configHome, ".gemini", "google_accounts.json"), "utf-8"));
|
|
39642
40474
|
if (accounts.active) accountEmail = accounts.active;
|
|
39643
40475
|
} catch {
|
|
39644
40476
|
}
|
|
@@ -39697,7 +40529,7 @@ __export(backend_cmd_factory_exports, {
|
|
|
39697
40529
|
makeReorder: () => makeReorder,
|
|
39698
40530
|
registerBackendSlotCommands: () => registerBackendSlotCommands
|
|
39699
40531
|
});
|
|
39700
|
-
import { existsSync as existsSync40, mkdirSync as mkdirSync15, readFileSync as
|
|
40532
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync15, readFileSync as readFileSync32 } from "fs";
|
|
39701
40533
|
import { join as join39 } from "path";
|
|
39702
40534
|
import { createInterface as createInterface9 } from "readline";
|
|
39703
40535
|
function requireDb2() {
|
|
@@ -40051,7 +40883,7 @@ var init_backend_cmd_factory = __esm({
|
|
|
40051
40883
|
const claudeJsonNested = join39(slotDir, ".claude", ".claude.json");
|
|
40052
40884
|
if (existsSync40(claudeJson)) {
|
|
40053
40885
|
try {
|
|
40054
|
-
const data = JSON.parse(
|
|
40886
|
+
const data = JSON.parse(readFileSync32(claudeJson, "utf-8"));
|
|
40055
40887
|
return Boolean(data.oauthAccount);
|
|
40056
40888
|
} catch {
|
|
40057
40889
|
return false;
|
|
@@ -40059,7 +40891,7 @@ var init_backend_cmd_factory = __esm({
|
|
|
40059
40891
|
}
|
|
40060
40892
|
if (existsSync40(claudeJsonNested)) {
|
|
40061
40893
|
try {
|
|
40062
|
-
const data = JSON.parse(
|
|
40894
|
+
const data = JSON.parse(readFileSync32(claudeJsonNested, "utf-8"));
|
|
40063
40895
|
return Boolean(data.oauthAccount);
|
|
40064
40896
|
} catch {
|
|
40065
40897
|
return false;
|
|
@@ -40082,7 +40914,7 @@ var init_backend_cmd_factory = __esm({
|
|
|
40082
40914
|
try {
|
|
40083
40915
|
const claudeJson = join39(slotDir, ".claude.json");
|
|
40084
40916
|
if (existsSync40(claudeJson)) {
|
|
40085
|
-
const data = JSON.parse(
|
|
40917
|
+
const data = JSON.parse(readFileSync32(claudeJson, "utf-8"));
|
|
40086
40918
|
if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
|
|
40087
40919
|
}
|
|
40088
40920
|
} catch {
|
|
@@ -40101,7 +40933,7 @@ var init_backend_cmd_factory = __esm({
|
|
|
40101
40933
|
},
|
|
40102
40934
|
extractLabel: (slotDir) => {
|
|
40103
40935
|
try {
|
|
40104
|
-
const authData = JSON.parse(
|
|
40936
|
+
const authData = JSON.parse(readFileSync32(join39(slotDir, "auth.json"), "utf-8"));
|
|
40105
40937
|
if (authData.email) return authData.email;
|
|
40106
40938
|
if (authData.account_name) return authData.account_name;
|
|
40107
40939
|
if (authData.user?.email) return authData.user.email;
|
|
@@ -41468,7 +42300,7 @@ __export(config_exports2, {
|
|
|
41468
42300
|
configList: () => configList,
|
|
41469
42301
|
configSet: () => configSet
|
|
41470
42302
|
});
|
|
41471
|
-
import { existsSync as existsSync49, readFileSync as
|
|
42303
|
+
import { existsSync as existsSync49, readFileSync as readFileSync33 } from "fs";
|
|
41472
42304
|
async function configList(globalOpts) {
|
|
41473
42305
|
if (!existsSync49(DB_PATH)) {
|
|
41474
42306
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
@@ -41554,7 +42386,7 @@ async function configEnv(_globalOpts) {
|
|
|
41554
42386
|
outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
|
|
41555
42387
|
process.exit(1);
|
|
41556
42388
|
}
|
|
41557
|
-
const content =
|
|
42389
|
+
const content = readFileSync33(ENV_PATH, "utf-8");
|
|
41558
42390
|
const entries = {};
|
|
41559
42391
|
const secretPatterns = /TOKEN|KEY|SECRET|PASSWORD|CREDENTIALS/i;
|
|
41560
42392
|
for (const line of content.split("\n")) {
|
|
@@ -42550,11 +43382,11 @@ __export(chat_exports2, {
|
|
|
42550
43382
|
chatSend: () => chatSend
|
|
42551
43383
|
});
|
|
42552
43384
|
import { request as httpRequest2 } from "http";
|
|
42553
|
-
import { readFileSync as
|
|
43385
|
+
import { readFileSync as readFileSync34, existsSync as existsSync59 } from "fs";
|
|
42554
43386
|
function getToken2() {
|
|
42555
43387
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
42556
43388
|
try {
|
|
42557
|
-
if (existsSync59(TOKEN_PATH)) return
|
|
43389
|
+
if (existsSync59(TOKEN_PATH)) return readFileSync34(TOKEN_PATH, "utf-8").trim();
|
|
42558
43390
|
} catch {
|
|
42559
43391
|
}
|
|
42560
43392
|
return null;
|
|
@@ -43711,7 +44543,7 @@ var init_optimize3 = __esm({
|
|
|
43711
44543
|
|
|
43712
44544
|
// src/setup.ts
|
|
43713
44545
|
var setup_exports = {};
|
|
43714
|
-
import { existsSync as existsSync61, writeFileSync as writeFileSync15, readFileSync as
|
|
44546
|
+
import { existsSync as existsSync61, writeFileSync as writeFileSync15, readFileSync as readFileSync35, copyFileSync as copyFileSync5, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
|
|
43715
44547
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
43716
44548
|
import { createInterface as createInterface11 } from "readline";
|
|
43717
44549
|
import { join as join41 } from "path";
|
|
@@ -43803,7 +44635,7 @@ async function setup() {
|
|
|
43803
44635
|
if (envSource) {
|
|
43804
44636
|
console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
|
|
43805
44637
|
console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
|
|
43806
|
-
const existing =
|
|
44638
|
+
const existing = readFileSync35(envSource, "utf-8");
|
|
43807
44639
|
for (const line of existing.split("\n")) {
|
|
43808
44640
|
const match = line.match(/^([^#=]+)=(.*)$/);
|
|
43809
44641
|
if (match) env[match[1].trim()] = match[2].trim();
|