cc-claw 0.5.6 → 0.6.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/README.md +3 -1
- package/dist/cli.js +912 -106
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,12 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
7
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
8
|
+
}) : x)(function(x) {
|
|
9
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
10
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
11
|
+
});
|
|
6
12
|
var __esm = (fn, res) => function __init() {
|
|
7
13
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
14
|
};
|
|
@@ -49,7 +55,7 @@ var VERSION;
|
|
|
49
55
|
var init_version = __esm({
|
|
50
56
|
"src/version.ts"() {
|
|
51
57
|
"use strict";
|
|
52
|
-
VERSION = true ? "0.
|
|
58
|
+
VERSION = true ? "0.6.0" : (() => {
|
|
53
59
|
try {
|
|
54
60
|
return JSON.parse(readFileSync(join2(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
55
61
|
} catch {
|
|
@@ -921,14 +927,17 @@ var init_embeddings = __esm({
|
|
|
921
927
|
var store_exports3 = {};
|
|
922
928
|
__export(store_exports3, {
|
|
923
929
|
ALL_TOOLS: () => ALL_TOOLS,
|
|
930
|
+
addGeminiSlot: () => addGeminiSlot,
|
|
924
931
|
addHeartbeatWatch: () => addHeartbeatWatch,
|
|
925
932
|
addUsage: () => addUsage,
|
|
926
933
|
appendMessageLog: () => appendMessageLog,
|
|
927
934
|
cancelJobById: () => cancelJobById,
|
|
928
935
|
checkBackendLimits: () => checkBackendLimits,
|
|
929
936
|
cleanExpiredWatches: () => cleanExpiredWatches,
|
|
937
|
+
clearAgentMode: () => clearAgentMode,
|
|
930
938
|
clearAllSessions: () => clearAllSessions,
|
|
931
939
|
clearBackendLimit: () => clearBackendLimit,
|
|
940
|
+
clearChatGeminiSlot: () => clearChatGeminiSlot,
|
|
932
941
|
clearCwd: () => clearCwd,
|
|
933
942
|
clearMessageLog: () => clearMessageLog,
|
|
934
943
|
clearModel: () => clearModel,
|
|
@@ -943,6 +952,7 @@ __export(store_exports3, {
|
|
|
943
952
|
forgetMemory: () => forgetMemory,
|
|
944
953
|
getActiveJobs: () => getActiveJobs,
|
|
945
954
|
getActiveWatches: () => getActiveWatches,
|
|
955
|
+
getAgentMode: () => getAgentMode,
|
|
946
956
|
getAllBackendLimits: () => getAllBackendLimits,
|
|
947
957
|
getAllBookmarks: () => getAllBookmarks,
|
|
948
958
|
getAllChatAliases: () => getAllChatAliases,
|
|
@@ -958,7 +968,9 @@ __export(store_exports3, {
|
|
|
958
968
|
getChatUsageByModel: () => getChatUsageByModel,
|
|
959
969
|
getCwd: () => getCwd,
|
|
960
970
|
getDb: () => getDb,
|
|
971
|
+
getEligibleGeminiSlots: () => getEligibleGeminiSlots,
|
|
961
972
|
getEnabledTools: () => getEnabledTools,
|
|
973
|
+
getGeminiSlots: () => getGeminiSlots,
|
|
962
974
|
getHeartbeatConfig: () => getHeartbeatConfig,
|
|
963
975
|
getJobById: () => getJobById,
|
|
964
976
|
getJobRuns: () => getJobRuns,
|
|
@@ -966,6 +978,7 @@ __export(store_exports3, {
|
|
|
966
978
|
getMode: () => getMode,
|
|
967
979
|
getModel: () => getModel,
|
|
968
980
|
getModelSignature: () => getModelSignature,
|
|
981
|
+
getNextGeminiSlot: () => getNextGeminiSlot,
|
|
969
982
|
getPendingEscalation: () => getPendingEscalation,
|
|
970
983
|
getRecentBookmarks: () => getRecentBookmarks,
|
|
971
984
|
getRecentMemories: () => getRecentMemories,
|
|
@@ -988,12 +1001,17 @@ __export(store_exports3, {
|
|
|
988
1001
|
listMemories: () => listMemories,
|
|
989
1002
|
listSessionSummaries: () => listSessionSummaries,
|
|
990
1003
|
markMessageLogSummarized: () => markMessageLogSummarized,
|
|
1004
|
+
markSlotExhausted: () => markSlotExhausted,
|
|
1005
|
+
markSlotSuccess: () => markSlotSuccess,
|
|
991
1006
|
openDatabaseReadOnly: () => openDatabaseReadOnly,
|
|
1007
|
+
pinChatGeminiSlot: () => pinChatGeminiSlot,
|
|
992
1008
|
pruneJobRuns: () => pruneJobRuns,
|
|
993
1009
|
pruneMessageLog: () => pruneMessageLog,
|
|
994
1010
|
removeChatAlias: () => removeChatAlias,
|
|
1011
|
+
removeGeminiSlot: () => removeGeminiSlot,
|
|
995
1012
|
removeHeartbeatWatch: () => removeHeartbeatWatch,
|
|
996
1013
|
removePendingEscalation: () => removePendingEscalation,
|
|
1014
|
+
reorderGeminiSlot: () => reorderGeminiSlot,
|
|
997
1015
|
resetJobFailures: () => resetJobFailures,
|
|
998
1016
|
resetTools: () => resetTools,
|
|
999
1017
|
saveMemory: () => saveMemory,
|
|
@@ -1004,11 +1022,13 @@ __export(store_exports3, {
|
|
|
1004
1022
|
searchMemoriesReadOnly: () => searchMemoriesReadOnly,
|
|
1005
1023
|
searchMessageLog: () => searchMessageLog,
|
|
1006
1024
|
searchSessionSummaries: () => searchSessionSummaries,
|
|
1025
|
+
setAgentMode: () => setAgentMode,
|
|
1007
1026
|
setBackend: () => setBackend,
|
|
1008
1027
|
setBackendLimit: () => setBackendLimit,
|
|
1009
1028
|
setBootTime: () => setBootTime,
|
|
1010
1029
|
setChatAlias: () => setChatAlias,
|
|
1011
1030
|
setCwd: () => setCwd,
|
|
1031
|
+
setGeminiSlotEnabled: () => setGeminiSlotEnabled,
|
|
1012
1032
|
setHeartbeatConfig: () => setHeartbeatConfig,
|
|
1013
1033
|
setMode: () => setMode,
|
|
1014
1034
|
setModel: () => setModel,
|
|
@@ -1495,6 +1515,33 @@ function initDatabase() {
|
|
|
1495
1515
|
value TEXT NOT NULL DEFAULT 'off'
|
|
1496
1516
|
);
|
|
1497
1517
|
`);
|
|
1518
|
+
db.exec(`
|
|
1519
|
+
CREATE TABLE IF NOT EXISTS gemini_credentials (
|
|
1520
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1521
|
+
slot_type TEXT NOT NULL DEFAULT 'api_key',
|
|
1522
|
+
label TEXT,
|
|
1523
|
+
api_key TEXT,
|
|
1524
|
+
config_home TEXT,
|
|
1525
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
1526
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
1527
|
+
cooldown_until TEXT,
|
|
1528
|
+
last_used TEXT,
|
|
1529
|
+
consecutive_errors INTEGER NOT NULL DEFAULT 0,
|
|
1530
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1531
|
+
);
|
|
1532
|
+
`);
|
|
1533
|
+
db.exec(`
|
|
1534
|
+
CREATE TABLE IF NOT EXISTS chat_gemini_slot (
|
|
1535
|
+
chat_id TEXT PRIMARY KEY,
|
|
1536
|
+
slot_id INTEGER
|
|
1537
|
+
);
|
|
1538
|
+
`);
|
|
1539
|
+
db.exec(`
|
|
1540
|
+
CREATE TABLE IF NOT EXISTS chat_agent_mode (
|
|
1541
|
+
chat_id TEXT PRIMARY KEY,
|
|
1542
|
+
mode TEXT NOT NULL DEFAULT 'auto'
|
|
1543
|
+
);
|
|
1544
|
+
`);
|
|
1498
1545
|
}
|
|
1499
1546
|
function getDb() {
|
|
1500
1547
|
return db;
|
|
@@ -2351,6 +2398,95 @@ function getUnsummarizedChatIds() {
|
|
|
2351
2398
|
).all();
|
|
2352
2399
|
return rows.map((r) => r.chat_id);
|
|
2353
2400
|
}
|
|
2401
|
+
function getGeminiSlots() {
|
|
2402
|
+
return db.prepare(`
|
|
2403
|
+
SELECT id, slot_type AS slotType, label, api_key AS apiKey, config_home AS configHome,
|
|
2404
|
+
priority, enabled, cooldown_until AS cooldownUntil, last_used AS lastUsed,
|
|
2405
|
+
consecutive_errors AS consecutiveErrors, created_at AS createdAt
|
|
2406
|
+
FROM gemini_credentials ORDER BY priority ASC, id ASC
|
|
2407
|
+
`).all();
|
|
2408
|
+
}
|
|
2409
|
+
function getEligibleGeminiSlots() {
|
|
2410
|
+
return db.prepare(`
|
|
2411
|
+
SELECT id, slot_type AS slotType, label, api_key AS apiKey, config_home AS configHome,
|
|
2412
|
+
priority, enabled, cooldown_until AS cooldownUntil, last_used AS lastUsed,
|
|
2413
|
+
consecutive_errors AS consecutiveErrors, created_at AS createdAt
|
|
2414
|
+
FROM gemini_credentials
|
|
2415
|
+
WHERE enabled = 1 AND (cooldown_until IS NULL OR cooldown_until <= datetime('now'))
|
|
2416
|
+
ORDER BY priority ASC, last_used ASC NULLS FIRST
|
|
2417
|
+
`).all();
|
|
2418
|
+
}
|
|
2419
|
+
function getNextGeminiSlot(chatId) {
|
|
2420
|
+
const pinned = db.prepare(`
|
|
2421
|
+
SELECT gc.id, gc.slot_type AS slotType, gc.label, gc.api_key AS apiKey, gc.config_home AS configHome,
|
|
2422
|
+
gc.priority, gc.enabled, gc.cooldown_until AS cooldownUntil, gc.last_used AS lastUsed,
|
|
2423
|
+
gc.consecutive_errors AS consecutiveErrors, gc.created_at AS createdAt
|
|
2424
|
+
FROM chat_gemini_slot cgs JOIN gemini_credentials gc ON cgs.slot_id = gc.id
|
|
2425
|
+
WHERE cgs.chat_id = ? AND gc.enabled = 1
|
|
2426
|
+
AND (gc.cooldown_until IS NULL OR gc.cooldown_until <= datetime('now'))
|
|
2427
|
+
`).get(chatId);
|
|
2428
|
+
if (pinned) return pinned;
|
|
2429
|
+
const eligible = getEligibleGeminiSlots();
|
|
2430
|
+
return eligible.length > 0 ? eligible[0] : null;
|
|
2431
|
+
}
|
|
2432
|
+
function markSlotExhausted(slotId, quotaClass) {
|
|
2433
|
+
const cooldownHours = quotaClass === "billing" ? 24 : 6;
|
|
2434
|
+
const disable = quotaClass === "billing" ? 1 : 0;
|
|
2435
|
+
db.prepare(`
|
|
2436
|
+
UPDATE gemini_credentials
|
|
2437
|
+
SET cooldown_until = datetime('now', '+${cooldownHours} hours'),
|
|
2438
|
+
consecutive_errors = consecutive_errors + 1,
|
|
2439
|
+
enabled = CASE WHEN consecutive_errors + 1 >= 10 THEN 0 ELSE CASE WHEN ? = 1 THEN 0 ELSE enabled END END
|
|
2440
|
+
WHERE id = ?
|
|
2441
|
+
`).run(disable, slotId);
|
|
2442
|
+
}
|
|
2443
|
+
function markSlotSuccess(slotId) {
|
|
2444
|
+
db.prepare(`
|
|
2445
|
+
UPDATE gemini_credentials
|
|
2446
|
+
SET last_used = datetime('now'), consecutive_errors = 0, cooldown_until = NULL
|
|
2447
|
+
WHERE id = ?
|
|
2448
|
+
`).run(slotId);
|
|
2449
|
+
}
|
|
2450
|
+
function pinChatGeminiSlot(chatId, slotId) {
|
|
2451
|
+
db.prepare(`
|
|
2452
|
+
INSERT INTO chat_gemini_slot (chat_id, slot_id) VALUES (?, ?)
|
|
2453
|
+
ON CONFLICT(chat_id) DO UPDATE SET slot_id = excluded.slot_id
|
|
2454
|
+
`).run(chatId, slotId);
|
|
2455
|
+
}
|
|
2456
|
+
function clearChatGeminiSlot(chatId) {
|
|
2457
|
+
db.prepare("DELETE FROM chat_gemini_slot WHERE chat_id = ?").run(chatId);
|
|
2458
|
+
}
|
|
2459
|
+
function addGeminiSlot(opts) {
|
|
2460
|
+
const result = db.prepare(`
|
|
2461
|
+
INSERT INTO gemini_credentials (slot_type, label, api_key, config_home, priority)
|
|
2462
|
+
VALUES (?, ?, ?, ?, ?)
|
|
2463
|
+
`).run(opts.slotType, opts.label ?? null, opts.apiKey ?? null, opts.configHome ?? null, opts.priority ?? 0);
|
|
2464
|
+
return Number(result.lastInsertRowid);
|
|
2465
|
+
}
|
|
2466
|
+
function removeGeminiSlot(id) {
|
|
2467
|
+
db.prepare("DELETE FROM chat_gemini_slot WHERE slot_id = ?").run(id);
|
|
2468
|
+
return db.prepare("DELETE FROM gemini_credentials WHERE id = ?").run(id).changes > 0;
|
|
2469
|
+
}
|
|
2470
|
+
function setGeminiSlotEnabled(id, enabled) {
|
|
2471
|
+
db.prepare("UPDATE gemini_credentials SET enabled = ? WHERE id = ?").run(enabled ? 1 : 0, id);
|
|
2472
|
+
}
|
|
2473
|
+
function reorderGeminiSlot(id, priority) {
|
|
2474
|
+
db.prepare("UPDATE gemini_credentials SET priority = ? WHERE id = ?").run(priority, id);
|
|
2475
|
+
}
|
|
2476
|
+
function getAgentMode(chatId) {
|
|
2477
|
+
const row = db.prepare("SELECT mode FROM chat_agent_mode WHERE chat_id = ?").get(chatId);
|
|
2478
|
+
return row?.mode ?? "auto";
|
|
2479
|
+
}
|
|
2480
|
+
function setAgentMode(chatId, mode) {
|
|
2481
|
+
db.prepare(`
|
|
2482
|
+
INSERT INTO chat_agent_mode (chat_id, mode)
|
|
2483
|
+
VALUES (?, ?)
|
|
2484
|
+
ON CONFLICT(chat_id) DO UPDATE SET mode = excluded.mode
|
|
2485
|
+
`).run(chatId, mode);
|
|
2486
|
+
}
|
|
2487
|
+
function clearAgentMode(chatId) {
|
|
2488
|
+
db.prepare("DELETE FROM chat_agent_mode WHERE chat_id = ?").run(chatId);
|
|
2489
|
+
}
|
|
2354
2490
|
function pruneMessageLog(retentionDays = 30, rowCapPerChat = 2e3) {
|
|
2355
2491
|
const db3 = getDb();
|
|
2356
2492
|
db3.prepare(`
|
|
@@ -2739,6 +2875,9 @@ var init_claude = __esm({
|
|
|
2739
2875
|
}
|
|
2740
2876
|
return events;
|
|
2741
2877
|
}
|
|
2878
|
+
getSubagentInstructions() {
|
|
2879
|
+
return "You have native sub-agents via the Agent tool. Built-in types: Explore (fast codebase search), Plan (architecture), general-purpose (multi-step tasks), Bash (command execution). Use them for parallel work within this backend.";
|
|
2880
|
+
}
|
|
2742
2881
|
shouldKillOnResult() {
|
|
2743
2882
|
return true;
|
|
2744
2883
|
}
|
|
@@ -2754,6 +2893,7 @@ var GeminiAdapter;
|
|
|
2754
2893
|
var init_gemini = __esm({
|
|
2755
2894
|
"src/backends/gemini.ts"() {
|
|
2756
2895
|
"use strict";
|
|
2896
|
+
init_store4();
|
|
2757
2897
|
init_env();
|
|
2758
2898
|
init_paths();
|
|
2759
2899
|
GeminiAdapter = class {
|
|
@@ -2879,6 +3019,27 @@ var init_gemini = __esm({
|
|
|
2879
3019
|
}
|
|
2880
3020
|
return events;
|
|
2881
3021
|
}
|
|
3022
|
+
/**
|
|
3023
|
+
* Build an env for a specific credential slot. API key slots inject GEMINI_API_KEY;
|
|
3024
|
+
* OAuth slots set GEMINI_CLI_HOME for isolated config and unset GEMINI_API_KEY so
|
|
3025
|
+
* the CLI uses OAuth instead. Returns the slot used (or null for default behavior).
|
|
3026
|
+
*/
|
|
3027
|
+
getEnvForSlot(chatId, thinkingOverrides) {
|
|
3028
|
+
const slot = getNextGeminiSlot(chatId);
|
|
3029
|
+
const env = this.getEnv(thinkingOverrides);
|
|
3030
|
+
if (!slot) return { env, slot: null };
|
|
3031
|
+
if (slot.slotType === "api_key" && slot.apiKey) {
|
|
3032
|
+
env.GEMINI_API_KEY = slot.apiKey;
|
|
3033
|
+
} else if (slot.slotType === "oauth" && slot.configHome) {
|
|
3034
|
+
env.GEMINI_CLI_HOME = slot.configHome;
|
|
3035
|
+
delete env.GEMINI_API_KEY;
|
|
3036
|
+
delete env.GOOGLE_API_KEY;
|
|
3037
|
+
}
|
|
3038
|
+
return { env, slot };
|
|
3039
|
+
}
|
|
3040
|
+
getSubagentInstructions() {
|
|
3041
|
+
return "You have native subagents. Built-in: codebase_investigator (deep code analysis), cli_help (Gemini CLI docs), browser_agent (web automation). Use @subagent_name to force delegation.";
|
|
3042
|
+
}
|
|
2882
3043
|
shouldKillOnResult() {
|
|
2883
3044
|
return false;
|
|
2884
3045
|
}
|
|
@@ -3051,6 +3212,9 @@ var init_codex = __esm({
|
|
|
3051
3212
|
}
|
|
3052
3213
|
return events;
|
|
3053
3214
|
}
|
|
3215
|
+
getSubagentInstructions() {
|
|
3216
|
+
return "You can spawn native subagents for parallel work. Built-in agents: explorer (read-only codebase exploration), worker (implementation), default (general). Use spawn_agent for parallel fan-out.";
|
|
3217
|
+
}
|
|
3054
3218
|
shouldKillOnResult() {
|
|
3055
3219
|
return false;
|
|
3056
3220
|
}
|
|
@@ -3579,7 +3743,7 @@ function searchContext(userMessage) {
|
|
|
3579
3743
|
}
|
|
3580
3744
|
return null;
|
|
3581
3745
|
}
|
|
3582
|
-
async function assembleBootstrapPrompt(userMessage, tier = "full", chatId, permMode, responseStyle) {
|
|
3746
|
+
async function assembleBootstrapPrompt(userMessage, tier = "full", chatId, permMode, responseStyle, agentMode) {
|
|
3583
3747
|
const sections = [];
|
|
3584
3748
|
if (Date.now() - lastSyncMs >= 5e3) {
|
|
3585
3749
|
syncNativeCliFiles();
|
|
@@ -3620,6 +3784,10 @@ ${ctx}`);
|
|
|
3620
3784
|
sections.push(orchestrationContext);
|
|
3621
3785
|
}
|
|
3622
3786
|
}
|
|
3787
|
+
if (chatId && tier === "full" && agentMode) {
|
|
3788
|
+
const agentCtx = buildAgentModeContext(chatId, agentMode);
|
|
3789
|
+
if (agentCtx) sections.push(agentCtx);
|
|
3790
|
+
}
|
|
3623
3791
|
sections.push(userMessage);
|
|
3624
3792
|
const result = sections.join("\n\n");
|
|
3625
3793
|
log(`[bootstrap] Assembled prompt: tier=${tier}, sections=${sections.length}, totalChars=${result.length}`);
|
|
@@ -3675,6 +3843,35 @@ ${boardText}`);
|
|
|
3675
3843
|
return null;
|
|
3676
3844
|
}
|
|
3677
3845
|
}
|
|
3846
|
+
function buildAgentModeContext(chatId, agentMode) {
|
|
3847
|
+
if (agentMode === "native") {
|
|
3848
|
+
try {
|
|
3849
|
+
const adapter = getAdapterForChat(chatId);
|
|
3850
|
+
const instructions = adapter.getSubagentInstructions?.();
|
|
3851
|
+
if (instructions) return `[Sub-agent capabilities]
|
|
3852
|
+
${instructions}`;
|
|
3853
|
+
} catch {
|
|
3854
|
+
}
|
|
3855
|
+
return null;
|
|
3856
|
+
}
|
|
3857
|
+
if (agentMode === "claw") {
|
|
3858
|
+
return "[Sub-agent capabilities]\nCC-Claw orchestration is active. Use the cc-claw MCP tools (spawn_agent, send_message, list_tasks, etc.) for cross-backend agent coordination, inter-agent communication, and shared task management.";
|
|
3859
|
+
}
|
|
3860
|
+
if (agentMode === "auto" && process.env.DASHBOARD_ENABLED === "1") {
|
|
3861
|
+
try {
|
|
3862
|
+
const adapter = getAdapterForChat(chatId);
|
|
3863
|
+
const nativeInstructions = adapter.getSubagentInstructions?.();
|
|
3864
|
+
const parts = [];
|
|
3865
|
+
if (nativeInstructions) parts.push(`Native: ${nativeInstructions}`);
|
|
3866
|
+
parts.push("CC-Claw: For cross-backend coordination, inter-agent debate, or shared task management, use the cc-claw MCP tools (spawn_agent, send_message, etc.).");
|
|
3867
|
+
return `[Sub-agent capabilities]
|
|
3868
|
+
You have two sub-agent modes:
|
|
3869
|
+
${parts.join("\n")}`;
|
|
3870
|
+
} catch {
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
return null;
|
|
3874
|
+
}
|
|
3678
3875
|
var lastSyncMs, CONTEXT_DIR2, MAX_CONTEXT_CHARS, ACTIVITY_TOKEN_BUDGET, INBOX_TOKEN_BUDGET, WHITEBOARD_TOKEN_BUDGET;
|
|
3679
3876
|
var init_loader = __esm({
|
|
3680
3877
|
"src/bootstrap/loader.ts"() {
|
|
@@ -3686,6 +3883,7 @@ var init_loader = __esm({
|
|
|
3686
3883
|
init_store3();
|
|
3687
3884
|
init_store4();
|
|
3688
3885
|
init_store();
|
|
3886
|
+
init_backends();
|
|
3689
3887
|
lastSyncMs = 0;
|
|
3690
3888
|
CONTEXT_DIR2 = join6(WORKSPACE_PATH, "context");
|
|
3691
3889
|
MAX_CONTEXT_CHARS = 4e3;
|
|
@@ -3993,6 +4191,46 @@ Be specific. The new assistant has no prior context. Cover any domain \u2014 per
|
|
|
3993
4191
|
}
|
|
3994
4192
|
});
|
|
3995
4193
|
|
|
4194
|
+
// src/gemini/quota.ts
|
|
4195
|
+
function classifyGeminiQuota(errorText) {
|
|
4196
|
+
for (const p of RATE_LIMITED_PATTERNS) {
|
|
4197
|
+
if (p.test(errorText)) return "rate_limited";
|
|
4198
|
+
}
|
|
4199
|
+
for (const p of BILLING_PATTERNS) {
|
|
4200
|
+
if (p.test(errorText)) return "billing";
|
|
4201
|
+
}
|
|
4202
|
+
for (const p of DAILY_QUOTA_PATTERNS) {
|
|
4203
|
+
if (p.test(errorText)) return "daily_quota";
|
|
4204
|
+
}
|
|
4205
|
+
return "unknown";
|
|
4206
|
+
}
|
|
4207
|
+
var RATE_LIMITED_PATTERNS, BILLING_PATTERNS, DAILY_QUOTA_PATTERNS, GEMINI_SLOTS_EXHAUSTED_MSG;
|
|
4208
|
+
var init_quota = __esm({
|
|
4209
|
+
"src/gemini/quota.ts"() {
|
|
4210
|
+
"use strict";
|
|
4211
|
+
RATE_LIMITED_PATTERNS = [
|
|
4212
|
+
/quota exceeded.*per minute/i,
|
|
4213
|
+
/rate.?limit/i,
|
|
4214
|
+
/too many requests/i,
|
|
4215
|
+
/\bretry after\b/i
|
|
4216
|
+
];
|
|
4217
|
+
BILLING_PATTERNS = [
|
|
4218
|
+
/billing account/i,
|
|
4219
|
+
/insufficient.*credit/i,
|
|
4220
|
+
/payment.*required/i,
|
|
4221
|
+
/billing.*disabled/i
|
|
4222
|
+
];
|
|
4223
|
+
DAILY_QUOTA_PATTERNS = [
|
|
4224
|
+
/quota exceeded.*per day/i,
|
|
4225
|
+
/resource.?exhausted/i,
|
|
4226
|
+
/check.?quota/i,
|
|
4227
|
+
/RESOURCE_EXHAUSTED/,
|
|
4228
|
+
/exhausted.*quota/i
|
|
4229
|
+
];
|
|
4230
|
+
GEMINI_SLOTS_EXHAUSTED_MSG = "Gemini usage limit \u2014 all credential slots exhausted";
|
|
4231
|
+
}
|
|
4232
|
+
});
|
|
4233
|
+
|
|
3996
4234
|
// src/agents/registry.ts
|
|
3997
4235
|
var registry_exports = {};
|
|
3998
4236
|
__export(registry_exports, {
|
|
@@ -6178,6 +6416,119 @@ var init_server = __esm({
|
|
|
6178
6416
|
}
|
|
6179
6417
|
});
|
|
6180
6418
|
|
|
6419
|
+
// src/agents/detect-subagent.ts
|
|
6420
|
+
function detectSubagentActivity(backendId, parsedLine) {
|
|
6421
|
+
if (typeof parsedLine !== "object" || parsedLine === null) return null;
|
|
6422
|
+
const line = parsedLine;
|
|
6423
|
+
switch (backendId) {
|
|
6424
|
+
case "claude":
|
|
6425
|
+
return detectClaude(line);
|
|
6426
|
+
case "codex":
|
|
6427
|
+
return detectCodex(line);
|
|
6428
|
+
case "gemini":
|
|
6429
|
+
return detectGemini(line);
|
|
6430
|
+
default:
|
|
6431
|
+
return null;
|
|
6432
|
+
}
|
|
6433
|
+
}
|
|
6434
|
+
function detectClaude(line) {
|
|
6435
|
+
if (line.type === "assistant") {
|
|
6436
|
+
const message = line.message;
|
|
6437
|
+
const content = message?.content ?? [];
|
|
6438
|
+
for (const block of content) {
|
|
6439
|
+
if (block.type === "tool_use" && (block.name === "Agent" || block.name === "Task")) {
|
|
6440
|
+
const input = block.input ?? {};
|
|
6441
|
+
if (!input.subagent_type) continue;
|
|
6442
|
+
return {
|
|
6443
|
+
name: input.subagent_type ?? "unknown",
|
|
6444
|
+
status: "started",
|
|
6445
|
+
description: input.description,
|
|
6446
|
+
id: block.id
|
|
6447
|
+
};
|
|
6448
|
+
}
|
|
6449
|
+
}
|
|
6450
|
+
return null;
|
|
6451
|
+
}
|
|
6452
|
+
if (line.type === "system" && line.subtype === "task_notification") {
|
|
6453
|
+
if (line.status === "completed") {
|
|
6454
|
+
return {
|
|
6455
|
+
id: line.task_id,
|
|
6456
|
+
name: line.summary ?? line.description ?? "unknown",
|
|
6457
|
+
status: "completed"
|
|
6458
|
+
};
|
|
6459
|
+
}
|
|
6460
|
+
}
|
|
6461
|
+
return null;
|
|
6462
|
+
}
|
|
6463
|
+
function detectCodex(line) {
|
|
6464
|
+
if (line.type !== "item.completed") return null;
|
|
6465
|
+
const item = line.item;
|
|
6466
|
+
if (!item || item.type !== "collab_tool_call") return null;
|
|
6467
|
+
const tool = item.tool;
|
|
6468
|
+
if (tool === "spawn_agent") {
|
|
6469
|
+
const receiverIds = item.receiver_thread_ids;
|
|
6470
|
+
return {
|
|
6471
|
+
name: "agent",
|
|
6472
|
+
status: "started",
|
|
6473
|
+
description: item.prompt ?? void 0,
|
|
6474
|
+
id: receiverIds?.[0]
|
|
6475
|
+
};
|
|
6476
|
+
}
|
|
6477
|
+
if (tool === "wait") {
|
|
6478
|
+
const states = item.agents_states;
|
|
6479
|
+
if (!states) return null;
|
|
6480
|
+
for (const [threadId, state] of Object.entries(states)) {
|
|
6481
|
+
if (state.status === "completed") {
|
|
6482
|
+
return {
|
|
6483
|
+
id: threadId,
|
|
6484
|
+
name: "agent",
|
|
6485
|
+
status: "completed",
|
|
6486
|
+
description: state.message ?? void 0
|
|
6487
|
+
};
|
|
6488
|
+
}
|
|
6489
|
+
}
|
|
6490
|
+
}
|
|
6491
|
+
return null;
|
|
6492
|
+
}
|
|
6493
|
+
function detectGemini(line) {
|
|
6494
|
+
if (line.type === "tool_use") {
|
|
6495
|
+
const toolName = line.tool_name;
|
|
6496
|
+
if (toolName && GEMINI_SUBAGENT_NAMES.has(toolName)) {
|
|
6497
|
+
return {
|
|
6498
|
+
name: toolName,
|
|
6499
|
+
status: "started",
|
|
6500
|
+
id: line.tool_id
|
|
6501
|
+
};
|
|
6502
|
+
}
|
|
6503
|
+
return null;
|
|
6504
|
+
}
|
|
6505
|
+
if (line.type === "tool_result") {
|
|
6506
|
+
const output2 = line.output ?? "";
|
|
6507
|
+
const match = GEMINI_FINISHED_RE.exec(output2);
|
|
6508
|
+
if (match) {
|
|
6509
|
+
return {
|
|
6510
|
+
name: match[1],
|
|
6511
|
+
status: "completed",
|
|
6512
|
+
id: line.tool_id
|
|
6513
|
+
};
|
|
6514
|
+
}
|
|
6515
|
+
}
|
|
6516
|
+
return null;
|
|
6517
|
+
}
|
|
6518
|
+
var GEMINI_SUBAGENT_NAMES, GEMINI_FINISHED_RE;
|
|
6519
|
+
var init_detect_subagent = __esm({
|
|
6520
|
+
"src/agents/detect-subagent.ts"() {
|
|
6521
|
+
"use strict";
|
|
6522
|
+
GEMINI_SUBAGENT_NAMES = /* @__PURE__ */ new Set([
|
|
6523
|
+
"codebase_investigator",
|
|
6524
|
+
"cli_help",
|
|
6525
|
+
"generalist_agent",
|
|
6526
|
+
"browser_agent"
|
|
6527
|
+
]);
|
|
6528
|
+
GEMINI_FINISHED_RE = /Subagent\s+(\S+)\s+Finished/i;
|
|
6529
|
+
}
|
|
6530
|
+
});
|
|
6531
|
+
|
|
6181
6532
|
// src/agent.ts
|
|
6182
6533
|
var agent_exports = {};
|
|
6183
6534
|
__export(agent_exports, {
|
|
@@ -6224,11 +6575,11 @@ function stopAgent(chatId) {
|
|
|
6224
6575
|
}
|
|
6225
6576
|
return true;
|
|
6226
6577
|
}
|
|
6227
|
-
function spawnQuery(adapter, config2, model2, cancelState,
|
|
6578
|
+
function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, opts) {
|
|
6228
6579
|
const effectiveTimeout = timeoutMs ?? SPAWN_TIMEOUT_MS;
|
|
6229
6580
|
return new Promise((resolve, reject) => {
|
|
6230
6581
|
const thinkingConfig = thinkingLevel && thinkingLevel !== "auto" ? adapter.applyThinkingConfig(thinkingLevel, model2) : void 0;
|
|
6231
|
-
const env = adapter.getEnv(thinkingConfig?.envOverrides);
|
|
6582
|
+
const env = opts?.envOverride ? thinkingConfig?.envOverrides ? { ...opts.envOverride, ...thinkingConfig.envOverrides } : opts.envOverride : adapter.getEnv(thinkingConfig?.envOverrides);
|
|
6232
6583
|
const finalArgs = thinkingConfig?.extraArgs ? [...config2.args, ...thinkingConfig.extraArgs] : config2.args;
|
|
6233
6584
|
log(`[agent:spawn] backend=${adapter.id} exe=${config2.executable} model=${model2} timeout=${effectiveTimeout / 1e3}s cwd=${config2.cwd ?? "(inherited)"}`);
|
|
6234
6585
|
const proc = spawn4(config2.executable, finalArgs, {
|
|
@@ -6275,6 +6626,10 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
6275
6626
|
} catch {
|
|
6276
6627
|
return;
|
|
6277
6628
|
}
|
|
6629
|
+
const subagent = detectSubagentActivity(adapter.id, msg);
|
|
6630
|
+
if (subagent && opts?.onSubagentActivity) {
|
|
6631
|
+
opts.onSubagentActivity(adapter.id, subagent);
|
|
6632
|
+
}
|
|
6278
6633
|
const events = adapter.parseLine(msg);
|
|
6279
6634
|
for (const ev of events) {
|
|
6280
6635
|
switch (ev.type) {
|
|
@@ -6285,15 +6640,15 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
6285
6640
|
case "text":
|
|
6286
6641
|
if (ev.text) {
|
|
6287
6642
|
accumulatedText += ev.text;
|
|
6288
|
-
if (onStream) onStream(ev.text);
|
|
6643
|
+
if (opts?.onStream) opts.onStream(ev.text);
|
|
6289
6644
|
}
|
|
6290
6645
|
break;
|
|
6291
6646
|
case "tool_start":
|
|
6292
6647
|
sawToolEvents = true;
|
|
6293
|
-
if (onToolAction && ev.toolName) {
|
|
6648
|
+
if (opts?.onToolAction && ev.toolName) {
|
|
6294
6649
|
const toolInput = ev.toolInput ?? {};
|
|
6295
6650
|
if (ev.toolId) pendingTools.set(ev.toolId, { name: ev.toolName, input: toolInput });
|
|
6296
|
-
onToolAction(ev.toolName, toolInput, void 0).catch((err) => {
|
|
6651
|
+
opts.onToolAction(ev.toolName, toolInput, void 0).catch((err) => {
|
|
6297
6652
|
error("[agent] tool action error:", err);
|
|
6298
6653
|
});
|
|
6299
6654
|
}
|
|
@@ -6306,15 +6661,15 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
6306
6661
|
}
|
|
6307
6662
|
break;
|
|
6308
6663
|
case "tool_end":
|
|
6309
|
-
if (onToolAction) {
|
|
6664
|
+
if (opts?.onToolAction) {
|
|
6310
6665
|
const pending = ev.toolId ? pendingTools.get(ev.toolId) : void 0;
|
|
6311
6666
|
if (pending) {
|
|
6312
6667
|
pendingTools.delete(ev.toolId);
|
|
6313
|
-
onToolAction(pending.name, pending.input, ev.toolOutput ?? "").catch((err) => {
|
|
6668
|
+
opts.onToolAction(pending.name, pending.input, ev.toolOutput ?? "").catch((err) => {
|
|
6314
6669
|
error("[agent] tool action error:", err);
|
|
6315
6670
|
});
|
|
6316
6671
|
} else if (ev.toolName) {
|
|
6317
|
-
onToolAction(ev.toolName, {}, ev.toolOutput ?? "").catch((err) => {
|
|
6672
|
+
opts.onToolAction(ev.toolName, {}, ev.toolOutput ?? "").catch((err) => {
|
|
6318
6673
|
error("[agent] tool action error:", err);
|
|
6319
6674
|
});
|
|
6320
6675
|
}
|
|
@@ -6382,21 +6737,69 @@ function spawnQuery(adapter, config2, model2, cancelState, onStream, onToolActio
|
|
|
6382
6737
|
});
|
|
6383
6738
|
});
|
|
6384
6739
|
}
|
|
6740
|
+
async function spawnGeminiWithRotation(chatId, adapter, config2, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, opts, onSlotRotation) {
|
|
6741
|
+
const geminiAdapter = adapter;
|
|
6742
|
+
const slots = getEligibleGeminiSlots();
|
|
6743
|
+
if (slots.length === 0) {
|
|
6744
|
+
return spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, opts);
|
|
6745
|
+
}
|
|
6746
|
+
const maxAttempts = Math.min(slots.length, 10);
|
|
6747
|
+
let lastError;
|
|
6748
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
6749
|
+
const { env, slot } = geminiAdapter.getEnvForSlot(chatId, void 0);
|
|
6750
|
+
if (!slot) break;
|
|
6751
|
+
const slotLabel = slot.label || `slot-${slot.id}`;
|
|
6752
|
+
log(`[agent:gemini-rotation] Trying ${slotLabel} (${slot.slotType}, attempt ${i + 1}/${maxAttempts})`);
|
|
6753
|
+
if (i === 0) pinChatGeminiSlot(chatId, slot.id);
|
|
6754
|
+
try {
|
|
6755
|
+
const result = await spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, { ...opts, envOverride: env });
|
|
6756
|
+
const combinedText = result.resultText || "";
|
|
6757
|
+
if (combinedText && /RESOURCE.?EXHAUSTED|resource has been exhausted/i.test(combinedText)) {
|
|
6758
|
+
throw new Error(combinedText);
|
|
6759
|
+
}
|
|
6760
|
+
markSlotSuccess(slot.id);
|
|
6761
|
+
return result;
|
|
6762
|
+
} catch (err) {
|
|
6763
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
6764
|
+
const quotaClass = classifyGeminiQuota(errMsg);
|
|
6765
|
+
if (quotaClass === "rate_limited") {
|
|
6766
|
+
throw err;
|
|
6767
|
+
}
|
|
6768
|
+
const effectiveClass = quotaClass === "unknown" ? "daily_quota" : quotaClass;
|
|
6769
|
+
warn(`[agent:gemini-rotation] Slot ${slotLabel} exhausted (${effectiveClass}): ${errMsg.slice(0, 200)}`);
|
|
6770
|
+
markSlotExhausted(slot.id, effectiveClass);
|
|
6771
|
+
lastError = err instanceof Error ? err : new Error(errMsg);
|
|
6772
|
+
try {
|
|
6773
|
+
await summarizeWithFallbackChain(chatId);
|
|
6774
|
+
clearSession(chatId);
|
|
6775
|
+
} catch {
|
|
6776
|
+
}
|
|
6777
|
+
const nextSlot = getEligibleGeminiSlots()[0];
|
|
6778
|
+
if (nextSlot && onSlotRotation) {
|
|
6779
|
+
const nextLabel = nextSlot.label || `slot-${nextSlot.id}`;
|
|
6780
|
+
onSlotRotation(slotLabel, nextLabel);
|
|
6781
|
+
pinChatGeminiSlot(chatId, nextSlot.id);
|
|
6782
|
+
}
|
|
6783
|
+
}
|
|
6784
|
+
}
|
|
6785
|
+
throw new Error(GEMINI_SLOTS_EXHAUSTED_MSG);
|
|
6786
|
+
}
|
|
6385
6787
|
function askAgent(chatId, userMessage, opts) {
|
|
6386
6788
|
return withChatLock(chatId, () => askAgentImpl(chatId, userMessage, opts));
|
|
6387
6789
|
}
|
|
6388
6790
|
async function askAgentImpl(chatId, userMessage, opts) {
|
|
6389
|
-
const { cwd, onStream, model: model2, backend: backend2, permMode, onToolAction, bootstrapTier, timeoutMs, maxTurns } = opts ?? {};
|
|
6791
|
+
const { cwd, onStream, model: model2, backend: backend2, permMode, onToolAction, bootstrapTier, timeoutMs, maxTurns, onSlotRotation, agentMode: optsAgentMode, onSubagentActivity } = opts ?? {};
|
|
6390
6792
|
const adapter = backend2 ? getAdapter(backend2) : getAdapterForChat(chatId);
|
|
6391
6793
|
const mode = permMode ?? getMode(chatId);
|
|
6392
6794
|
const responseStyle = getResponseStyle(chatId);
|
|
6393
6795
|
const thinkingLevel = getThinkingLevel(chatId);
|
|
6394
6796
|
const resolvedCwd = cwd ?? WORKSPACE_PATH;
|
|
6395
6797
|
const tier = bootstrapTier ?? "full";
|
|
6396
|
-
const
|
|
6798
|
+
const effectiveAgentMode = optsAgentMode ?? getAgentMode(chatId);
|
|
6799
|
+
const fullPrompt = await assembleBootstrapPrompt(userMessage, tier, chatId, mode, responseStyle, effectiveAgentMode);
|
|
6397
6800
|
const existingSessionId = getSessionId(chatId);
|
|
6398
6801
|
const allowedTools = getEnabledTools(chatId);
|
|
6399
|
-
const mcpConfigPath = getMcpConfigPath(chatId);
|
|
6802
|
+
const mcpConfigPath = tier !== "slim" && effectiveAgentMode !== "native" && MCP_CONFIG_FLAG[adapter.id] ? getMcpConfigPath(chatId) : null;
|
|
6400
6803
|
const baseConfig = adapter.buildSpawnConfig({
|
|
6401
6804
|
prompt: fullPrompt,
|
|
6402
6805
|
model: model2,
|
|
@@ -6427,16 +6830,28 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
6427
6830
|
})() : baseConfig;
|
|
6428
6831
|
const cancelState = { cancelled: false };
|
|
6429
6832
|
activeChats.set(chatId, cancelState);
|
|
6833
|
+
const spawnOpts = { onStream, onToolAction, onSubagentActivity };
|
|
6430
6834
|
const resolvedModel = model2 ?? adapter.defaultModel;
|
|
6431
6835
|
let result = { resultText: "", sessionId: void 0, input: 0, output: 0, cacheRead: 0, sawToolEvents: false, sawResultEvent: false };
|
|
6836
|
+
const useGeminiRotation = adapter.id === "gemini" && getEligibleGeminiSlots().length > 0;
|
|
6432
6837
|
try {
|
|
6433
|
-
|
|
6838
|
+
if (useGeminiRotation) {
|
|
6839
|
+
const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
|
|
6840
|
+
result = await spawnGeminiWithRotation(chatId, adapter, configWithSession, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, spawnOpts, rotationCb);
|
|
6841
|
+
} else {
|
|
6842
|
+
result = await spawnQuery(adapter, configWithSession, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, spawnOpts);
|
|
6843
|
+
}
|
|
6434
6844
|
const wasEmptyResponse = !result.resultText && !result.sawToolEvents && !result.sawResultEvent;
|
|
6435
6845
|
if (wasEmptyResponse && !cancelState.cancelled && existingSessionId) {
|
|
6436
6846
|
warn(`[agent] No result with session ${existingSessionId} for chat ${chatId} \u2014 retrying fresh`);
|
|
6437
6847
|
await summarizeSession(chatId);
|
|
6438
6848
|
clearSession(chatId);
|
|
6439
|
-
|
|
6849
|
+
if (useGeminiRotation) {
|
|
6850
|
+
const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
|
|
6851
|
+
result = await spawnGeminiWithRotation(chatId, adapter, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, spawnOpts, rotationCb);
|
|
6852
|
+
} else {
|
|
6853
|
+
result = await spawnQuery(adapter, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, spawnOpts);
|
|
6854
|
+
}
|
|
6440
6855
|
}
|
|
6441
6856
|
} finally {
|
|
6442
6857
|
activeChats.delete(chatId);
|
|
@@ -6496,8 +6911,12 @@ var init_agent = __esm({
|
|
|
6496
6911
|
init_log();
|
|
6497
6912
|
init_session_log();
|
|
6498
6913
|
init_summarize();
|
|
6914
|
+
init_quota();
|
|
6915
|
+
init_store4();
|
|
6499
6916
|
init_server();
|
|
6500
6917
|
init_mcp_config();
|
|
6918
|
+
init_store4();
|
|
6919
|
+
init_detect_subagent();
|
|
6501
6920
|
activeChats = /* @__PURE__ */ new Map();
|
|
6502
6921
|
chatLocks = /* @__PURE__ */ new Map();
|
|
6503
6922
|
SPAWN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
@@ -6666,6 +7085,9 @@ var init_delivery = __esm({
|
|
|
6666
7085
|
});
|
|
6667
7086
|
|
|
6668
7087
|
// src/scheduler/retry.ts
|
|
7088
|
+
function isExhaustedMessage(text) {
|
|
7089
|
+
return EXHAUSTED_PATTERNS.some((p) => p.test(text));
|
|
7090
|
+
}
|
|
6669
7091
|
function classifyError(err) {
|
|
6670
7092
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6671
7093
|
if (/spawn timeout/i.test(msg)) return "permanent";
|
|
@@ -6714,8 +7136,7 @@ var init_retry = __esm({
|
|
|
6714
7136
|
/network.?error/i,
|
|
6715
7137
|
/timeout/i,
|
|
6716
7138
|
/server error/i,
|
|
6717
|
-
/cloudflare/i
|
|
6718
|
-
/resource.?exhausted/i
|
|
7139
|
+
/cloudflare/i
|
|
6719
7140
|
];
|
|
6720
7141
|
PERMANENT_PATTERNS = [
|
|
6721
7142
|
/invalid.*api.*key/i,
|
|
@@ -9762,6 +10183,60 @@ var init_video = __esm({
|
|
|
9762
10183
|
}
|
|
9763
10184
|
});
|
|
9764
10185
|
|
|
10186
|
+
// src/agents/classify.ts
|
|
10187
|
+
function classifyAgentIntent(message) {
|
|
10188
|
+
const NOT_DETECTED = { detected: false, suggestedMode: "native" };
|
|
10189
|
+
for (const pat of NEGATIVE_PATTERNS) {
|
|
10190
|
+
if (pat.test(message)) return NOT_DETECTED;
|
|
10191
|
+
}
|
|
10192
|
+
for (const pat of CLAW_SIGNAL_PATTERNS) {
|
|
10193
|
+
if (pat.test(message)) {
|
|
10194
|
+
return { detected: true, suggestedMode: "claw", reason: "cross-backend or inter-agent communication detected" };
|
|
10195
|
+
}
|
|
10196
|
+
}
|
|
10197
|
+
for (const pat of AGENT_SIGNAL_PATTERNS) {
|
|
10198
|
+
if (pat.test(message)) {
|
|
10199
|
+
return { detected: true, suggestedMode: "native" };
|
|
10200
|
+
}
|
|
10201
|
+
}
|
|
10202
|
+
return NOT_DETECTED;
|
|
10203
|
+
}
|
|
10204
|
+
var AGENT_SIGNAL_PATTERNS, CLAW_SIGNAL_PATTERNS, NEGATIVE_PATTERNS;
|
|
10205
|
+
var init_classify2 = __esm({
|
|
10206
|
+
"src/agents/classify.ts"() {
|
|
10207
|
+
"use strict";
|
|
10208
|
+
AGENT_SIGNAL_PATTERNS = [
|
|
10209
|
+
/\bspawn\s+(?:\d+\s+)?agents?\b/i,
|
|
10210
|
+
/\bsub-?agents?\b/i,
|
|
10211
|
+
/\bparallel\s+agents?\b/i,
|
|
10212
|
+
/\bfan\s+out\b/i,
|
|
10213
|
+
/\bdispatch\s+agents?\b/i,
|
|
10214
|
+
/\bmulti-?agent\b/i
|
|
10215
|
+
];
|
|
10216
|
+
CLAW_SIGNAL_PATTERNS = [
|
|
10217
|
+
/\breview\s+each\s+other/i,
|
|
10218
|
+
/\bdiscuss\s+between\b/i,
|
|
10219
|
+
/\bcross-?backend\b/i,
|
|
10220
|
+
/\bagent\s+team\b/i,
|
|
10221
|
+
/\bagent\s+inbox\b/i,
|
|
10222
|
+
/\bagent\s+whiteboard\b/i,
|
|
10223
|
+
/\bagents?\s+.*debate\b/i,
|
|
10224
|
+
/\bclaude\b.*\bagents?\b.*\bgemini\b/i,
|
|
10225
|
+
/\bgemini\b.*\bagents?\b.*\bclaude\b/i,
|
|
10226
|
+
/\bcodex\b.*\bagents?\b.*\bclaude\b/i,
|
|
10227
|
+
/\bclaude\b.*\bagents?\b.*\bcodex\b/i,
|
|
10228
|
+
/\bgemini\b.*\bagents?\b.*\bcodex\b/i,
|
|
10229
|
+
/\bcodex\b.*\bagents?\b.*\bgemini\b/i
|
|
10230
|
+
];
|
|
10231
|
+
NEGATIVE_PATTERNS = [
|
|
10232
|
+
/\bhow\s+does\s+.*\bwork\b/i,
|
|
10233
|
+
/\bwhat\s+is\s+.*\bfunction\b/i,
|
|
10234
|
+
/\bexplain\s+.*\bagent/i,
|
|
10235
|
+
/src\/agents?\//
|
|
10236
|
+
];
|
|
10237
|
+
}
|
|
10238
|
+
});
|
|
10239
|
+
|
|
9765
10240
|
// src/shell/guard.ts
|
|
9766
10241
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
9767
10242
|
function isDestructive(command) {
|
|
@@ -10033,6 +10508,33 @@ function pickReactionEmoji(msg) {
|
|
|
10033
10508
|
return "\u{1F468}\u200D\u{1F4BB}";
|
|
10034
10509
|
}
|
|
10035
10510
|
}
|
|
10511
|
+
async function handleResponseExhaustion(responseText, chatId, msg, channel) {
|
|
10512
|
+
const raw = responseText.replace(/\n\n🧠 \[.+$/, "").trim();
|
|
10513
|
+
if (raw.length > 300 || !isExhaustedMessage(raw)) return false;
|
|
10514
|
+
if (typeof channel.sendKeyboard === "function") {
|
|
10515
|
+
const currentBackend = getBackend(chatId) ?? "claude";
|
|
10516
|
+
const otherBackends = getAllAdapters().filter((a) => a.id !== currentBackend);
|
|
10517
|
+
if (otherBackends.length > 0) {
|
|
10518
|
+
pendingFallbackMessages.set(chatId, { msg, channel, agentMode: msg.agentMode });
|
|
10519
|
+
const buttons = otherBackends.map((a) => ({
|
|
10520
|
+
label: `\u{1F504} ${a.displayName}`,
|
|
10521
|
+
data: `fallback:${a.id}:${chatId}`
|
|
10522
|
+
}));
|
|
10523
|
+
buttons.push({ label: "\u274C Wait", data: `fallback:wait:${chatId}` });
|
|
10524
|
+
await channel.sendKeyboard(
|
|
10525
|
+
chatId,
|
|
10526
|
+
`\u26A0\uFE0F ${getAdapter(currentBackend).displayName} is out of usage.
|
|
10527
|
+
|
|
10528
|
+
${raw}
|
|
10529
|
+
|
|
10530
|
+
Switch to another backend?`,
|
|
10531
|
+
[buttons]
|
|
10532
|
+
);
|
|
10533
|
+
return true;
|
|
10534
|
+
}
|
|
10535
|
+
}
|
|
10536
|
+
return false;
|
|
10537
|
+
}
|
|
10036
10538
|
async function handleMessage(msg, channel) {
|
|
10037
10539
|
const { chatId } = msg;
|
|
10038
10540
|
if (msg.messageId && typeof channel.reactToMessage === "function" && msg.type !== "text" && msg.type !== "command") {
|
|
@@ -10086,7 +10588,7 @@ async function handleCommand(msg, channel) {
|
|
|
10086
10588
|
case "help":
|
|
10087
10589
|
await channel.sendText(
|
|
10088
10590
|
chatId,
|
|
10089
|
-
"Hey! I'm CC-Claw \u2014 your personal AI assistant on Telegram.\n\nI use AI coding CLIs (Claude, Gemini, Codex) as my brain. Just send me a message to get started.\n\nCommands:\n/backend [name] - Switch AI backend (or /claude /gemini /codex)\n/model - Switch model for active backend\n/summarizer - Configure session summarization model\n/status - Show session, model, backend, and usage\n/cost - Show estimated API cost (use /cost all for all-time)\n/usage - Show usage per backend with limits\n/limits - Configure usage limits per backend\n/newchat - Start a fresh conversation\n/summarize - Save session to memory (without resetting)\n/summarize all - Summarize all pending sessions (pre-restart)\n/cwd <path> - Set working directory\n/cwd - Show current working directory\n/memory - List stored memories\n/remember <text> - Save a memory\n/forget <keyword> - Remove a memory\n/voice - Toggle voice responses\n/voice_config - Configure voice provider and voice\n/imagine <prompt> - Generate an image (or /image)\n/cron <description> - Schedule a task (or /schedule)\n/cron - List scheduled jobs (or /jobs)\n/cron cancel <id> - Cancel a job\n/cron pause <id> - Pause a job\n/cron resume <id> - Resume a job\n/cron run <id> - Trigger a job now\n/cron runs [id] - View run history\n/cron edit <id> - Edit a job\n/cron health - Scheduler health\n/skills - List skills from all backends\n/skill-install <url> - Install a skill from GitHub\n/setup-profile - Set up your user profile\n/chats - List authorized chats and aliases\n/heartbeat - Proactive awareness (on/off/interval/hours)\n/history - List recent session summaries\n/stop - Cancel the current running task\n/tools - Configure which tools the agent can use\n/permissions - Switch permission mode (yolo/safe/plan)\n/verbose - Tool visibility (off/normal/verbose)\n/model_signature - Toggle model+thinking signature on responses\n/intent <msg> - Test intent classifier (chat vs agentic)\n/agents - List active sub-agents\n/tasks - Show task board for current orchestration\n/stopagent <id> - Cancel a specific sub-agent\n/stopall - Cancel all sub-agents in this chat\n/runners - List registered CLI runners\n/mcps - List registered MCP servers\n/help - Show this message",
|
|
10591
|
+
"Hey! I'm CC-Claw \u2014 your personal AI assistant on Telegram.\n\nI use AI coding CLIs (Claude, Gemini, Codex) as my brain. Just send me a message to get started.\n\nCommands:\n/backend [name] - Switch AI backend (or /claude /gemini /codex)\n/model - Switch model for active backend\n/summarizer - Configure session summarization model\n/status - Show session, model, backend, and usage\n/cost - Show estimated API cost (use /cost all for all-time)\n/usage - Show usage per backend with limits\n/limits - Configure usage limits per backend\n/newchat - Start a fresh conversation\n/summarize - Save session to memory (without resetting)\n/summarize all - Summarize all pending sessions (pre-restart)\n/cwd <path> - Set working directory\n/cwd - Show current working directory\n/memory - List stored memories\n/remember <text> - Save a memory\n/forget <keyword> - Remove a memory\n/voice - Toggle voice responses\n/voice_config - Configure voice provider and voice\n/imagine <prompt> - Generate an image (or /image)\n/cron <description> - Schedule a task (or /schedule)\n/cron - List scheduled jobs (or /jobs)\n/cron cancel <id> - Cancel a job\n/cron pause <id> - Pause a job\n/cron resume <id> - Resume a job\n/cron run <id> - Trigger a job now\n/cron runs [id] - View run history\n/cron edit <id> - Edit a job\n/cron health - Scheduler health\n/skills - List skills from all backends\n/skill-install <url> - Install a skill from GitHub\n/setup-profile - Set up your user profile\n/chats - List authorized chats and aliases\n/heartbeat - Proactive awareness (on/off/interval/hours)\n/history - List recent session summaries\n/stop - Cancel the current running task\n/tools - Configure which tools the agent can use\n/permissions - Switch permission mode (yolo/safe/plan)\n/verbose - Tool visibility (off/normal/verbose)\n/model_signature - Toggle model+thinking signature on responses\n/intent <msg> - Test intent classifier (chat vs agentic)\n/agents - List active sub-agents\n/agents mode [auto|native|claw] - Set agent mode (native vs orchestrated)\n/agents history - Native sub-agent activity (24h)\n/tasks - Show task board for current orchestration\n/stopagent <id> - Cancel a specific sub-agent\n/stopall - Cancel all sub-agents in this chat\n/runners - List registered CLI runners\n/mcps - List registered MCP servers\n/help - Show this message",
|
|
10090
10592
|
"plain"
|
|
10091
10593
|
);
|
|
10092
10594
|
break;
|
|
@@ -10163,6 +10665,7 @@ Tap to toggle:`,
|
|
|
10163
10665
|
case "newchat": {
|
|
10164
10666
|
const summarized = await summarizeSession(chatId);
|
|
10165
10667
|
clearSession(chatId);
|
|
10668
|
+
clearChatGeminiSlot(chatId);
|
|
10166
10669
|
setSessionStartedAt(chatId);
|
|
10167
10670
|
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: "New session started", detail: { field: "session", action: "reset", summarized } });
|
|
10168
10671
|
const msg2 = summarized ? "Session summarized and saved. Fresh conversation started!" : "Fresh conversation started. What's on your mind?";
|
|
@@ -10255,6 +10758,7 @@ Tap to toggle:`,
|
|
|
10255
10758
|
`\u2501\u2501 Engine \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
|
|
10256
10759
|
`\u{1F9E0} ${adapter?.displayName ?? backendId ?? "not set"} \xB7 ${formatModelShort(model2)}`,
|
|
10257
10760
|
`\u{1F4AD} Think: ${thinking2} \xB7 Mode: ${mode}`,
|
|
10761
|
+
`\u{1F916} Agents: ${getAgentMode(chatId)}`,
|
|
10258
10762
|
`\u{1F507} Voice: ${voice2 ? "on" : "off"} \xB7 Sig: ${modelSig}`,
|
|
10259
10763
|
``,
|
|
10260
10764
|
`\u2501\u2501 Session \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
|
|
@@ -11003,6 +11507,54 @@ Use /skills to see it.`, "plain");
|
|
|
11003
11507
|
break;
|
|
11004
11508
|
}
|
|
11005
11509
|
case "agents": {
|
|
11510
|
+
if (commandArgs?.startsWith("mode")) {
|
|
11511
|
+
const modeArg = commandArgs.slice(5).trim().toLowerCase();
|
|
11512
|
+
if (modeArg === "native" || modeArg === "claw" || modeArg === "auto") {
|
|
11513
|
+
setAgentMode(chatId, modeArg);
|
|
11514
|
+
try {
|
|
11515
|
+
await summarizeSession(chatId);
|
|
11516
|
+
} catch {
|
|
11517
|
+
}
|
|
11518
|
+
clearSession(chatId);
|
|
11519
|
+
await channel.sendText(chatId, `Agent mode set to <b>${modeArg}</b>. Session cleared.`, "html");
|
|
11520
|
+
} else if (typeof channel.sendKeyboard === "function") {
|
|
11521
|
+
const current = getAgentMode(chatId);
|
|
11522
|
+
await channel.sendKeyboard(chatId, `Agent mode: <b>${current}</b>
|
|
11523
|
+
|
|
11524
|
+
Choose a mode:`, [
|
|
11525
|
+
[
|
|
11526
|
+
{ label: "Auto (recommended)", data: "agentmode:auto" },
|
|
11527
|
+
{ label: "Native (fast)", data: "agentmode:native" },
|
|
11528
|
+
{ label: "Orchestrated", data: "agentmode:claw" }
|
|
11529
|
+
]
|
|
11530
|
+
]);
|
|
11531
|
+
} else {
|
|
11532
|
+
const current = getAgentMode(chatId);
|
|
11533
|
+
await channel.sendText(chatId, `Agent mode: ${current}. Use /agents mode <auto|native|claw> to change.`, "plain");
|
|
11534
|
+
}
|
|
11535
|
+
return;
|
|
11536
|
+
}
|
|
11537
|
+
if (commandArgs?.startsWith("history")) {
|
|
11538
|
+
const db4 = getDb();
|
|
11539
|
+
const events = db4.prepare(`
|
|
11540
|
+
SELECT summary, detail, createdAt FROM activity_log
|
|
11541
|
+
WHERE chatId = ? AND eventType = 'native_subagent'
|
|
11542
|
+
AND createdAt > datetime('now', '-1 day')
|
|
11543
|
+
ORDER BY createdAt DESC LIMIT 20
|
|
11544
|
+
`).all(chatId);
|
|
11545
|
+
if (events.length === 0) {
|
|
11546
|
+
await channel.sendText(chatId, "No native sub-agent activity in the last 24h.", "plain");
|
|
11547
|
+
} else {
|
|
11548
|
+
const lines2 = events.map((e) => {
|
|
11549
|
+
const d = e.detail ? JSON.parse(e.detail) : {};
|
|
11550
|
+
return `\u2022 ${e.summary} (${d.backend ?? "?"}, ${e.createdAt})`;
|
|
11551
|
+
});
|
|
11552
|
+
await channel.sendText(chatId, `<b>Native agent history (24h)</b>
|
|
11553
|
+
|
|
11554
|
+
${lines2.join("\n")}`, "html");
|
|
11555
|
+
}
|
|
11556
|
+
return;
|
|
11557
|
+
}
|
|
11006
11558
|
const db3 = getDb();
|
|
11007
11559
|
const agents2 = listActiveAgents(db3);
|
|
11008
11560
|
const STATUS_EMOJI = {
|
|
@@ -11329,6 +11881,7 @@ async function handleVoice(msg, channel) {
|
|
|
11329
11881
|
const vToolCb = vVerbose !== "off" ? makeToolActionCallback(chatId, channel, vVerbose) : void 0;
|
|
11330
11882
|
const response = await askAgent(chatId, transcript, { cwd: getCwd(chatId), model: vModel, permMode: mode, onToolAction: vToolCb });
|
|
11331
11883
|
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, vModel);
|
|
11884
|
+
if (await handleResponseExhaustion(response.text, chatId, msg, channel)) return;
|
|
11332
11885
|
await sendResponse(chatId, channel, response.text, msg.messageId);
|
|
11333
11886
|
} catch (err) {
|
|
11334
11887
|
error("[router] Voice error:", err);
|
|
@@ -11396,6 +11949,10 @@ Acknowledge receipt. Do NOT analyze the video unless they ask you to.`;
|
|
|
11396
11949
|
const vidToolCb = vidVerbose !== "off" ? makeToolActionCallback(chatId, channel, vidVerbose) : void 0;
|
|
11397
11950
|
const response2 = await askAgent(chatId, prompt2, { cwd: getCwd(chatId), model: vidModel, permMode: vMode, onToolAction: vidToolCb });
|
|
11398
11951
|
if (response2.usage) addUsage(chatId, response2.usage.input, response2.usage.output, response2.usage.cacheRead, vidModel);
|
|
11952
|
+
if (await handleResponseExhaustion(response2.text, chatId, msg, channel)) {
|
|
11953
|
+
cleanupVideo();
|
|
11954
|
+
return;
|
|
11955
|
+
}
|
|
11399
11956
|
await sendResponse(chatId, channel, response2.text, msg.messageId);
|
|
11400
11957
|
cleanupVideo();
|
|
11401
11958
|
return;
|
|
@@ -11438,6 +11995,11 @@ ${content}
|
|
|
11438
11995
|
const mToolCb = mVerbose !== "off" ? makeToolActionCallback(chatId, channel, mVerbose) : void 0;
|
|
11439
11996
|
const response = await askAgent(chatId, prompt, { cwd: getCwd(chatId), model: mediaModel, permMode: mMode, onToolAction: mToolCb });
|
|
11440
11997
|
if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, mediaModel);
|
|
11998
|
+
if (await handleResponseExhaustion(response.text, chatId, msg, channel)) {
|
|
11999
|
+
if (tempFilePath) unlink2(tempFilePath).catch(() => {
|
|
12000
|
+
});
|
|
12001
|
+
return;
|
|
12002
|
+
}
|
|
11441
12003
|
await sendResponse(chatId, channel, response.text, msg.messageId);
|
|
11442
12004
|
if (tempFilePath) {
|
|
11443
12005
|
unlink2(tempFilePath).catch(() => {
|
|
@@ -11482,10 +12044,29 @@ async function handleText(msg, channel) {
|
|
|
11482
12044
|
await channel.sendText(chatId, limitMsg, "plain");
|
|
11483
12045
|
return;
|
|
11484
12046
|
}
|
|
11485
|
-
|
|
12047
|
+
let intent = classifyIntent(text, chatId);
|
|
11486
12048
|
const cleanText = text.startsWith(">>") ? text.slice(2).trim() : text;
|
|
11487
|
-
|
|
11488
|
-
|
|
12049
|
+
let bootstrapTier = intent === "chat" ? "chat" : void 0;
|
|
12050
|
+
let maxTurns = intent === "chat" ? 1 : void 0;
|
|
12051
|
+
let effectiveAgentMode = msg.agentMode ?? getAgentMode(chatId);
|
|
12052
|
+
const observedSubagents = /* @__PURE__ */ new Set();
|
|
12053
|
+
if (effectiveAgentMode === "auto" && !text.startsWith(">>")) {
|
|
12054
|
+
const agentIntent = classifyAgentIntent(text);
|
|
12055
|
+
if (agentIntent.detected) {
|
|
12056
|
+
intent = "agentic";
|
|
12057
|
+
bootstrapTier = void 0;
|
|
12058
|
+
maxTurns = void 0;
|
|
12059
|
+
effectiveAgentMode = agentIntent.suggestedMode;
|
|
12060
|
+
}
|
|
12061
|
+
}
|
|
12062
|
+
if (effectiveAgentMode === "claw" && process.env.DASHBOARD_ENABLED !== "1") {
|
|
12063
|
+
const lastWarn = dashboardClawWarnings.get(chatId) ?? 0;
|
|
12064
|
+
if (Date.now() - lastWarn > 3e5) {
|
|
12065
|
+
dashboardClawWarnings.set(chatId, Date.now());
|
|
12066
|
+
await channel.sendText(chatId, "\u26A0\uFE0F CC-Claw orchestration requires DASHBOARD_ENABLED=1. Using native agents.", "plain");
|
|
12067
|
+
}
|
|
12068
|
+
effectiveAgentMode = "native";
|
|
12069
|
+
}
|
|
11489
12070
|
if (isChatBusy(chatId) && !bypassBusyCheck.delete(chatId)) {
|
|
11490
12071
|
if (typeof channel.sendKeyboard === "function") {
|
|
11491
12072
|
pendingInterrupts.set(chatId, { msg, channel });
|
|
@@ -11525,9 +12106,27 @@ async function handleText(msg, channel) {
|
|
|
11525
12106
|
onToolAction: tToolCb,
|
|
11526
12107
|
bootstrapTier,
|
|
11527
12108
|
maxTurns,
|
|
12109
|
+
agentMode: effectiveAgentMode,
|
|
12110
|
+
onSubagentActivity: (backendId2, info) => {
|
|
12111
|
+
observedSubagents.add(info.name);
|
|
12112
|
+
try {
|
|
12113
|
+
logActivity(getDb(), {
|
|
12114
|
+
chatId,
|
|
12115
|
+
source: "agent",
|
|
12116
|
+
eventType: "native_subagent",
|
|
12117
|
+
summary: `${info.name} ${info.status}`,
|
|
12118
|
+
detail: { id: info.id, description: info.description, backend: backendId2 }
|
|
12119
|
+
});
|
|
12120
|
+
} catch {
|
|
12121
|
+
}
|
|
12122
|
+
},
|
|
11528
12123
|
onCompaction: (cid) => {
|
|
11529
12124
|
channel.sendText(cid, "\u{1F4BE} Context saved to memory.").catch(() => {
|
|
11530
12125
|
});
|
|
12126
|
+
},
|
|
12127
|
+
onSlotRotation: (cid, from, to) => {
|
|
12128
|
+
channel.sendText(cid, `\u{1F511} Gemini quota reached on ${from} \u2014 continuing on ${to}. Context saved.`).catch(() => {
|
|
12129
|
+
});
|
|
11531
12130
|
}
|
|
11532
12131
|
});
|
|
11533
12132
|
const elapsedSec = ((Date.now() - sigT0) / 1e3).toFixed(1);
|
|
@@ -11542,6 +12141,12 @@ async function handleText(msg, channel) {
|
|
|
11542
12141
|
responseText += `
|
|
11543
12142
|
|
|
11544
12143
|
\u{1F9E0} [${shortModel} | ${capitalize(thinking2)}] \u23F1\uFE0F ${elapsedSec}s`;
|
|
12144
|
+
}
|
|
12145
|
+
if (observedSubagents.size > 0) {
|
|
12146
|
+
const names = [...observedSubagents].join(", ");
|
|
12147
|
+
responseText += `
|
|
12148
|
+
|
|
12149
|
+
\u26A1 Native agents used: ${names}`;
|
|
11545
12150
|
}
|
|
11546
12151
|
if (responseText.includes("[NEED_PERMISSION]") && tMode !== "yolo") {
|
|
11547
12152
|
const cleanText2 = responseText.replace(/\[NEED_PERMISSION\]/g, "").trim();
|
|
@@ -11555,33 +12160,14 @@ async function handleText(msg, channel) {
|
|
|
11555
12160
|
}
|
|
11556
12161
|
return;
|
|
11557
12162
|
}
|
|
12163
|
+
if (await handleResponseExhaustion(responseText, chatId, msg, channel)) return;
|
|
11558
12164
|
await sendResponse(chatId, channel, responseText, msg.messageId);
|
|
11559
12165
|
} catch (err) {
|
|
11560
12166
|
error("[router] Error:", err);
|
|
11561
12167
|
const errMsg = errorMessage(err);
|
|
11562
12168
|
const errorClass = classifyError(err);
|
|
11563
|
-
if (errorClass === "exhausted"
|
|
11564
|
-
|
|
11565
|
-
const { getAllAdapters: getAllAdapters2 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
11566
|
-
const otherBackends = getAllAdapters2().filter((a) => a.id !== currentBackend);
|
|
11567
|
-
if (otherBackends.length > 0) {
|
|
11568
|
-
pendingFallbackMessages.set(chatId, { msg, channel });
|
|
11569
|
-
const buttons = otherBackends.map((a) => ({
|
|
11570
|
-
label: `\u{1F504} ${a.displayName}`,
|
|
11571
|
-
data: `fallback:${a.id}:${chatId}`
|
|
11572
|
-
}));
|
|
11573
|
-
buttons.push({ label: "\u274C Wait", data: `fallback:wait:${chatId}` });
|
|
11574
|
-
await channel.sendKeyboard(
|
|
11575
|
-
chatId,
|
|
11576
|
-
`\u26A0\uFE0F ${getAdapter(currentBackend).displayName} is out of usage.
|
|
11577
|
-
|
|
11578
|
-
${errMsg}
|
|
11579
|
-
|
|
11580
|
-
Switch to another backend?`,
|
|
11581
|
-
[buttons]
|
|
11582
|
-
);
|
|
11583
|
-
return;
|
|
11584
|
-
}
|
|
12169
|
+
if (errorClass === "exhausted") {
|
|
12170
|
+
if (await handleResponseExhaustion(errMsg, chatId, msg, channel)) return;
|
|
11585
12171
|
}
|
|
11586
12172
|
const userMsg = diagnoseAgentError(errMsg, chatId);
|
|
11587
12173
|
await channel.sendText(chatId, userMsg, "plain");
|
|
@@ -11919,6 +12505,7 @@ async function doBackendSwitch(chatId, backendId, channel) {
|
|
|
11919
12505
|
clearSession(chatId);
|
|
11920
12506
|
clearModel(chatId);
|
|
11921
12507
|
clearThinkingLevel(chatId);
|
|
12508
|
+
clearChatGeminiSlot(chatId);
|
|
11922
12509
|
setBackend(chatId, backendId);
|
|
11923
12510
|
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Backend switched to ${targetAdapter.displayName}`, detail: { field: "backend", value: backendId } });
|
|
11924
12511
|
await channel.sendText(chatId, `\u2705 Switched to ${targetAdapter.displayName}. Ready!`, "plain");
|
|
@@ -11935,7 +12522,7 @@ async function handleCallback(chatId, data, channel) {
|
|
|
11935
12522
|
}
|
|
11936
12523
|
await sendBackendSwitchConfirmation(chatId, chosen, channel);
|
|
11937
12524
|
} else if (data.startsWith("backend_confirm_clear:")) {
|
|
11938
|
-
const target = data.slice(
|
|
12525
|
+
const target = data.slice("backend_confirm_clear:".length);
|
|
11939
12526
|
if (!getAllBackendIds().includes(target)) return;
|
|
11940
12527
|
clearMessageLog(chatId);
|
|
11941
12528
|
await doBackendSwitch(chatId, target, channel);
|
|
@@ -12137,6 +12724,7 @@ ${PERM_MODES[chosen]}`,
|
|
|
12137
12724
|
await channel.sendText(chatId, "OK \u2014 you can switch manually with /backend when ready.", "plain");
|
|
12138
12725
|
} else if (pendingMsg) {
|
|
12139
12726
|
pendingFallbackMessages.delete(targetChatId);
|
|
12727
|
+
if (pendingMsg.agentMode) pendingMsg.msg.agentMode = pendingMsg.agentMode;
|
|
12140
12728
|
await summarizeWithFallbackChain(targetChatId, targetBackend);
|
|
12141
12729
|
const bridge = buildContextBridge(targetChatId);
|
|
12142
12730
|
if (bridge) setPendingContextBridge(targetChatId, bridge);
|
|
@@ -12171,6 +12759,18 @@ ${PERM_MODES[chosen]}`,
|
|
|
12171
12759
|
}
|
|
12172
12760
|
await channel.sendText(chatId, `Response style set to: ${selectedStyle}`, "plain");
|
|
12173
12761
|
}
|
|
12762
|
+
} else if (data.startsWith("agentmode:")) {
|
|
12763
|
+
const mode = data.split(":")[1];
|
|
12764
|
+
if (mode === "auto" || mode === "native" || mode === "claw") {
|
|
12765
|
+
setAgentMode(chatId, mode);
|
|
12766
|
+
try {
|
|
12767
|
+
await summarizeSession(chatId);
|
|
12768
|
+
} catch {
|
|
12769
|
+
}
|
|
12770
|
+
clearSession(chatId);
|
|
12771
|
+
await channel.sendText(chatId, `Agent mode set to <b>${mode}</b>. Session cleared.`, "html");
|
|
12772
|
+
}
|
|
12773
|
+
return;
|
|
12174
12774
|
} else if (data.startsWith("model_sig:")) {
|
|
12175
12775
|
const value = data.slice(10);
|
|
12176
12776
|
setModelSignature(chatId, value);
|
|
@@ -12421,7 +13021,7 @@ Use /skills <page> to navigate (e.g. /skills 2)` : "";
|
|
|
12421
13021
|
const header2 = totalPages > 1 ? `${skills2.length} skills (page ${safePage}/${totalPages}). Select one to invoke:` : `${skills2.length} skills available. Select one to invoke:`;
|
|
12422
13022
|
await channel.sendKeyboard(chatId, header2, buttons);
|
|
12423
13023
|
}
|
|
12424
|
-
var PERM_MODES, VERBOSE_LEVELS, pendingInterrupts, bypassBusyCheck, pendingFallbackMessages, CLI_INSTALL_HINTS, BLOCKED_PATH_PATTERNS2, ALLOWED_REACTION_EMOJIS, SKILLS_PER_PAGE;
|
|
13024
|
+
var PERM_MODES, VERBOSE_LEVELS, pendingInterrupts, bypassBusyCheck, pendingFallbackMessages, dashboardClawWarnings, CLI_INSTALL_HINTS, BLOCKED_PATH_PATTERNS2, ALLOWED_REACTION_EMOJIS, SKILLS_PER_PAGE;
|
|
12425
13025
|
var init_router = __esm({
|
|
12426
13026
|
"src/router.ts"() {
|
|
12427
13027
|
"use strict";
|
|
@@ -12450,6 +13050,7 @@ var init_router = __esm({
|
|
|
12450
13050
|
init_store();
|
|
12451
13051
|
init_orchestrator();
|
|
12452
13052
|
init_registry();
|
|
13053
|
+
init_classify2();
|
|
12453
13054
|
init_registry2();
|
|
12454
13055
|
init_store3();
|
|
12455
13056
|
init_guard();
|
|
@@ -12468,6 +13069,7 @@ var init_router = __esm({
|
|
|
12468
13069
|
pendingInterrupts = /* @__PURE__ */ new Map();
|
|
12469
13070
|
bypassBusyCheck = /* @__PURE__ */ new Set();
|
|
12470
13071
|
pendingFallbackMessages = /* @__PURE__ */ new Map();
|
|
13072
|
+
dashboardClawWarnings = /* @__PURE__ */ new Map();
|
|
12471
13073
|
CLI_INSTALL_HINTS = {
|
|
12472
13074
|
claude: "Install: npm install -g @anthropic-ai/claude-code",
|
|
12473
13075
|
gemini: "Install: npm install -g @google/gemini-cli",
|
|
@@ -13302,6 +13904,17 @@ async function main() {
|
|
|
13302
13904
|
});
|
|
13303
13905
|
});
|
|
13304
13906
|
log("[cc-claw] Agent orchestrator initialized");
|
|
13907
|
+
try {
|
|
13908
|
+
const { execSync: execSync7 } = await import("child_process");
|
|
13909
|
+
const codexPath = execSync7("which codex", { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
13910
|
+
if (codexPath) {
|
|
13911
|
+
const features = execSync7("codex features list", { encoding: "utf-8", timeout: 1e4 });
|
|
13912
|
+
if (/multi_agent\s+\S+\s+false/.test(features)) {
|
|
13913
|
+
warn("[cc-claw] Codex multi_agent feature is disabled \u2014 native sub-agent detection will not work. Run: codex features enable multi_agent");
|
|
13914
|
+
}
|
|
13915
|
+
}
|
|
13916
|
+
} catch {
|
|
13917
|
+
}
|
|
13305
13918
|
Promise.resolve().then(() => (init_registry2(), registry_exports2)).then(({ syncMcps: syncMcps2 }) => {
|
|
13306
13919
|
Promise.resolve().then(() => (init_registry(), registry_exports)).then(({ getAllRunners: getAllRunners2 }) => {
|
|
13307
13920
|
syncMcps2(getDb(), getAllRunners2()).catch((err) => {
|
|
@@ -13319,11 +13932,11 @@ async function main() {
|
|
|
13319
13932
|
bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
|
|
13320
13933
|
try {
|
|
13321
13934
|
const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
|
|
13322
|
-
const { writeFileSync:
|
|
13323
|
-
const { join:
|
|
13324
|
-
const skillDir =
|
|
13325
|
-
|
|
13326
|
-
|
|
13935
|
+
const { writeFileSync: writeFileSync9, mkdirSync: mkdirSync12 } = await import("fs");
|
|
13936
|
+
const { join: join22 } = await import("path");
|
|
13937
|
+
const skillDir = join22(SKILLS_PATH, "cc-claw-cli");
|
|
13938
|
+
mkdirSync12(skillDir, { recursive: true });
|
|
13939
|
+
writeFileSync9(join22(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
|
|
13327
13940
|
log("[cc-claw] AI skill updated");
|
|
13328
13941
|
} catch {
|
|
13329
13942
|
}
|
|
@@ -14341,6 +14954,170 @@ var init_logs = __esm({
|
|
|
14341
14954
|
}
|
|
14342
14955
|
});
|
|
14343
14956
|
|
|
14957
|
+
// src/cli/commands/gemini.ts
|
|
14958
|
+
var gemini_exports = {};
|
|
14959
|
+
__export(gemini_exports, {
|
|
14960
|
+
geminiAddAccount: () => geminiAddAccount,
|
|
14961
|
+
geminiAddKey: () => geminiAddKey,
|
|
14962
|
+
geminiDisable: () => geminiDisable,
|
|
14963
|
+
geminiEnable: () => geminiEnable,
|
|
14964
|
+
geminiList: () => geminiList,
|
|
14965
|
+
geminiRemove: () => geminiRemove,
|
|
14966
|
+
geminiReorder: () => geminiReorder
|
|
14967
|
+
});
|
|
14968
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, writeFileSync as writeFileSync7, chmodSync } from "fs";
|
|
14969
|
+
import { join as join20 } from "path";
|
|
14970
|
+
import { createInterface as createInterface4 } from "readline";
|
|
14971
|
+
function requireDb() {
|
|
14972
|
+
if (!existsSync22(DB_PATH)) {
|
|
14973
|
+
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
14974
|
+
process.exit(1);
|
|
14975
|
+
}
|
|
14976
|
+
}
|
|
14977
|
+
async function geminiList(globalOpts) {
|
|
14978
|
+
requireDb();
|
|
14979
|
+
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
14980
|
+
const readDb = openDatabaseReadOnly2();
|
|
14981
|
+
const slots = readDb.prepare(`
|
|
14982
|
+
SELECT id, slot_type, label, priority, enabled, cooldown_until, last_used, consecutive_errors, created_at
|
|
14983
|
+
FROM gemini_credentials ORDER BY priority ASC, id ASC
|
|
14984
|
+
`).all();
|
|
14985
|
+
readDb.close();
|
|
14986
|
+
if (slots.length === 0) {
|
|
14987
|
+
output({ slots: [] }, () => "No Gemini credential slots configured.\nAdd one with: cc-claw gemini add-key or cc-claw gemini add-account");
|
|
14988
|
+
return;
|
|
14989
|
+
}
|
|
14990
|
+
output(slots, (data) => {
|
|
14991
|
+
const list = data;
|
|
14992
|
+
const lines = ["", divider("Gemini Credential Slots"), ""];
|
|
14993
|
+
for (const s of list) {
|
|
14994
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
14995
|
+
const inCooldown = s.cooldown_until && s.cooldown_until > now;
|
|
14996
|
+
const icon = !s.enabled ? error2("\u25CB disabled") : inCooldown ? warning("\u25D1 cooldown") : success("\u25CF active");
|
|
14997
|
+
const label2 = s.label || `slot-${s.id}`;
|
|
14998
|
+
const type = s.slot_type === "oauth" ? "OAuth" : "API key";
|
|
14999
|
+
lines.push(` ${icon} ${label2} ${muted(`(${type}, #${s.id}, priority ${s.priority})`)}`);
|
|
15000
|
+
if (inCooldown) lines.push(` Cooldown until: ${warning(s.cooldown_until)}`);
|
|
15001
|
+
if (s.consecutive_errors > 0) lines.push(` Consecutive errors: ${warning(String(s.consecutive_errors))}`);
|
|
15002
|
+
if (s.last_used) lines.push(` Last used: ${muted(s.last_used)}`);
|
|
15003
|
+
}
|
|
15004
|
+
lines.push("");
|
|
15005
|
+
return lines.join("\n");
|
|
15006
|
+
});
|
|
15007
|
+
}
|
|
15008
|
+
async function geminiAddKey(globalOpts, opts) {
|
|
15009
|
+
requireDb();
|
|
15010
|
+
const rl2 = createInterface4({ input: process.stdin, output: process.stdout });
|
|
15011
|
+
const ask2 = (q) => new Promise((r) => rl2.question(q, r));
|
|
15012
|
+
const key = await ask2("Paste your Gemini API key: ");
|
|
15013
|
+
rl2.close();
|
|
15014
|
+
if (!key.trim()) {
|
|
15015
|
+
outputError("EMPTY_KEY", "No key provided.");
|
|
15016
|
+
process.exit(1);
|
|
15017
|
+
}
|
|
15018
|
+
const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
15019
|
+
const id = addGeminiSlot2({
|
|
15020
|
+
slotType: "api_key",
|
|
15021
|
+
label: opts.label,
|
|
15022
|
+
apiKey: key.trim(),
|
|
15023
|
+
priority: opts.priority ? parseInt(opts.priority, 10) : 0
|
|
15024
|
+
});
|
|
15025
|
+
output(
|
|
15026
|
+
{ id, type: "api_key", label: opts.label ?? null },
|
|
15027
|
+
() => success(`Added API key slot #${id}${opts.label ? ` (${opts.label})` : ""}`)
|
|
15028
|
+
);
|
|
15029
|
+
}
|
|
15030
|
+
async function geminiAddAccount(globalOpts, opts) {
|
|
15031
|
+
requireDb();
|
|
15032
|
+
const slotsDir = join20(CC_CLAW_HOME, "gemini-slots");
|
|
15033
|
+
if (!existsSync22(slotsDir)) mkdirSync9(slotsDir, { recursive: true });
|
|
15034
|
+
const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
15035
|
+
const tempId = Date.now();
|
|
15036
|
+
const slotDir = join20(slotsDir, `slot-${tempId}`);
|
|
15037
|
+
mkdirSync9(slotDir, { recursive: true, mode: 448 });
|
|
15038
|
+
mkdirSync9(join20(slotDir, ".gemini"), { recursive: true });
|
|
15039
|
+
writeFileSync7(join20(slotDir, ".gemini", "settings.json"), JSON.stringify({
|
|
15040
|
+
security: { auth: { selectedType: "oauth-personal" } }
|
|
15041
|
+
}, null, 2));
|
|
15042
|
+
console.log("");
|
|
15043
|
+
console.log(" Opening Gemini CLI for Google sign-in...");
|
|
15044
|
+
console.log(" Sign in with the Google account you want for this slot.");
|
|
15045
|
+
console.log(" After sign-in, type /quit to return here.");
|
|
15046
|
+
console.log("");
|
|
15047
|
+
const { execSync: execSync7 } = await import("child_process");
|
|
15048
|
+
try {
|
|
15049
|
+
execSync7(`GEMINI_CLI_HOME=${slotDir} gemini`, {
|
|
15050
|
+
stdio: "inherit",
|
|
15051
|
+
env: { ...process.env, GEMINI_CLI_HOME: slotDir, GEMINI_API_KEY: void 0, GOOGLE_API_KEY: void 0 },
|
|
15052
|
+
cwd: slotDir
|
|
15053
|
+
});
|
|
15054
|
+
} catch {
|
|
15055
|
+
}
|
|
15056
|
+
const oauthPath = join20(slotDir, ".gemini", "oauth_creds.json");
|
|
15057
|
+
if (!existsSync22(oauthPath)) {
|
|
15058
|
+
console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
|
|
15059
|
+
console.log(" The slot directory is preserved at: " + slotDir);
|
|
15060
|
+
console.log(" Re-run: cc-claw gemini add-account\n");
|
|
15061
|
+
process.exit(1);
|
|
15062
|
+
}
|
|
15063
|
+
let accountEmail = "unknown";
|
|
15064
|
+
try {
|
|
15065
|
+
const accounts = JSON.parse(__require("fs").readFileSync(join20(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
|
|
15066
|
+
accountEmail = accounts.active || accountEmail;
|
|
15067
|
+
} catch {
|
|
15068
|
+
}
|
|
15069
|
+
chmodSync(slotDir, 448);
|
|
15070
|
+
const id = addGeminiSlot2({
|
|
15071
|
+
slotType: "oauth",
|
|
15072
|
+
label: opts.label || accountEmail,
|
|
15073
|
+
configHome: slotDir,
|
|
15074
|
+
priority: opts.priority ? parseInt(opts.priority, 10) : 0
|
|
15075
|
+
});
|
|
15076
|
+
output(
|
|
15077
|
+
{ id, type: "oauth", label: opts.label || accountEmail, configHome: slotDir },
|
|
15078
|
+
() => success(`
|
|
15079
|
+
Added OAuth slot #${id} (${accountEmail})`)
|
|
15080
|
+
);
|
|
15081
|
+
}
|
|
15082
|
+
async function geminiRemove(globalOpts, id) {
|
|
15083
|
+
requireDb();
|
|
15084
|
+
const { removeGeminiSlot: removeGeminiSlot2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
15085
|
+
const removed = removeGeminiSlot2(parseInt(id, 10));
|
|
15086
|
+
if (removed) {
|
|
15087
|
+
output({ removed: true, id: parseInt(id, 10) }, () => success(`Removed slot #${id}`));
|
|
15088
|
+
} else {
|
|
15089
|
+
outputError("NOT_FOUND", `Slot #${id} not found.`);
|
|
15090
|
+
}
|
|
15091
|
+
}
|
|
15092
|
+
async function geminiEnable(globalOpts, id) {
|
|
15093
|
+
requireDb();
|
|
15094
|
+
const { setGeminiSlotEnabled: setGeminiSlotEnabled2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
15095
|
+
setGeminiSlotEnabled2(parseInt(id, 10), true);
|
|
15096
|
+
output({ id: parseInt(id, 10), enabled: true }, () => success(`Enabled slot #${id}`));
|
|
15097
|
+
}
|
|
15098
|
+
async function geminiDisable(globalOpts, id) {
|
|
15099
|
+
requireDb();
|
|
15100
|
+
const { setGeminiSlotEnabled: setGeminiSlotEnabled2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
15101
|
+
setGeminiSlotEnabled2(parseInt(id, 10), false);
|
|
15102
|
+
output({ id: parseInt(id, 10), enabled: false }, () => warning(`Disabled slot #${id}`));
|
|
15103
|
+
}
|
|
15104
|
+
async function geminiReorder(globalOpts, id, priority) {
|
|
15105
|
+
requireDb();
|
|
15106
|
+
const { reorderGeminiSlot: reorderGeminiSlot2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
15107
|
+
reorderGeminiSlot2(parseInt(id, 10), parseInt(priority, 10));
|
|
15108
|
+
output(
|
|
15109
|
+
{ id: parseInt(id, 10), priority: parseInt(priority, 10) },
|
|
15110
|
+
() => success(`Slot #${id} priority set to ${priority}`)
|
|
15111
|
+
);
|
|
15112
|
+
}
|
|
15113
|
+
var init_gemini2 = __esm({
|
|
15114
|
+
"src/cli/commands/gemini.ts"() {
|
|
15115
|
+
"use strict";
|
|
15116
|
+
init_format();
|
|
15117
|
+
init_paths();
|
|
15118
|
+
}
|
|
15119
|
+
});
|
|
15120
|
+
|
|
14344
15121
|
// src/cli/commands/backend.ts
|
|
14345
15122
|
var backend_exports = {};
|
|
14346
15123
|
__export(backend_exports, {
|
|
@@ -14348,12 +15125,12 @@ __export(backend_exports, {
|
|
|
14348
15125
|
backendList: () => backendList,
|
|
14349
15126
|
backendSet: () => backendSet
|
|
14350
15127
|
});
|
|
14351
|
-
import { existsSync as
|
|
15128
|
+
import { existsSync as existsSync23 } from "fs";
|
|
14352
15129
|
async function backendList(globalOpts) {
|
|
14353
15130
|
const { getAllAdapters: getAllAdapters2 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
14354
15131
|
const chatId = resolveChatId(globalOpts);
|
|
14355
15132
|
let activeBackend = null;
|
|
14356
|
-
if (
|
|
15133
|
+
if (existsSync23(DB_PATH)) {
|
|
14357
15134
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
14358
15135
|
const readDb = openDatabaseReadOnly2();
|
|
14359
15136
|
try {
|
|
@@ -14384,7 +15161,7 @@ async function backendList(globalOpts) {
|
|
|
14384
15161
|
}
|
|
14385
15162
|
async function backendGet(globalOpts) {
|
|
14386
15163
|
const chatId = resolveChatId(globalOpts);
|
|
14387
|
-
if (!
|
|
15164
|
+
if (!existsSync23(DB_PATH)) {
|
|
14388
15165
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
14389
15166
|
process.exit(1);
|
|
14390
15167
|
}
|
|
@@ -14428,13 +15205,13 @@ __export(model_exports, {
|
|
|
14428
15205
|
modelList: () => modelList,
|
|
14429
15206
|
modelSet: () => modelSet
|
|
14430
15207
|
});
|
|
14431
|
-
import { existsSync as
|
|
15208
|
+
import { existsSync as existsSync24 } from "fs";
|
|
14432
15209
|
async function modelList(globalOpts) {
|
|
14433
15210
|
const chatId = resolveChatId(globalOpts);
|
|
14434
15211
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
14435
15212
|
const { getAdapter: getAdapter2, getAllAdapters: getAllAdapters2 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
14436
15213
|
let backendId = "claude";
|
|
14437
|
-
if (
|
|
15214
|
+
if (existsSync24(DB_PATH)) {
|
|
14438
15215
|
const readDb = openDatabaseReadOnly2();
|
|
14439
15216
|
try {
|
|
14440
15217
|
const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
|
|
@@ -14467,7 +15244,7 @@ async function modelList(globalOpts) {
|
|
|
14467
15244
|
}
|
|
14468
15245
|
async function modelGet(globalOpts) {
|
|
14469
15246
|
const chatId = resolveChatId(globalOpts);
|
|
14470
|
-
if (!
|
|
15247
|
+
if (!existsSync24(DB_PATH)) {
|
|
14471
15248
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14472
15249
|
process.exit(1);
|
|
14473
15250
|
}
|
|
@@ -14511,9 +15288,9 @@ __export(memory_exports, {
|
|
|
14511
15288
|
memoryList: () => memoryList,
|
|
14512
15289
|
memorySearch: () => memorySearch
|
|
14513
15290
|
});
|
|
14514
|
-
import { existsSync as
|
|
15291
|
+
import { existsSync as existsSync25 } from "fs";
|
|
14515
15292
|
async function memoryList(globalOpts) {
|
|
14516
|
-
if (!
|
|
15293
|
+
if (!existsSync25(DB_PATH)) {
|
|
14517
15294
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
14518
15295
|
process.exit(1);
|
|
14519
15296
|
}
|
|
@@ -14537,7 +15314,7 @@ async function memoryList(globalOpts) {
|
|
|
14537
15314
|
});
|
|
14538
15315
|
}
|
|
14539
15316
|
async function memorySearch(globalOpts, query) {
|
|
14540
|
-
if (!
|
|
15317
|
+
if (!existsSync25(DB_PATH)) {
|
|
14541
15318
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14542
15319
|
process.exit(1);
|
|
14543
15320
|
}
|
|
@@ -14559,7 +15336,7 @@ async function memorySearch(globalOpts, query) {
|
|
|
14559
15336
|
});
|
|
14560
15337
|
}
|
|
14561
15338
|
async function memoryHistory(globalOpts, opts) {
|
|
14562
|
-
if (!
|
|
15339
|
+
if (!existsSync25(DB_PATH)) {
|
|
14563
15340
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14564
15341
|
process.exit(1);
|
|
14565
15342
|
}
|
|
@@ -14607,7 +15384,7 @@ __export(cron_exports2, {
|
|
|
14607
15384
|
cronList: () => cronList,
|
|
14608
15385
|
cronRuns: () => cronRuns
|
|
14609
15386
|
});
|
|
14610
|
-
import { existsSync as
|
|
15387
|
+
import { existsSync as existsSync26 } from "fs";
|
|
14611
15388
|
function parseFallbacks(raw) {
|
|
14612
15389
|
return raw.slice(0, 3).map((f) => {
|
|
14613
15390
|
const [backend2, ...rest] = f.split(":");
|
|
@@ -14628,7 +15405,7 @@ function parseAndValidateTimeout(raw) {
|
|
|
14628
15405
|
return val;
|
|
14629
15406
|
}
|
|
14630
15407
|
async function cronList(globalOpts) {
|
|
14631
|
-
if (!
|
|
15408
|
+
if (!existsSync26(DB_PATH)) {
|
|
14632
15409
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14633
15410
|
process.exit(1);
|
|
14634
15411
|
}
|
|
@@ -14666,7 +15443,7 @@ async function cronList(globalOpts) {
|
|
|
14666
15443
|
});
|
|
14667
15444
|
}
|
|
14668
15445
|
async function cronHealth(globalOpts) {
|
|
14669
|
-
if (!
|
|
15446
|
+
if (!existsSync26(DB_PATH)) {
|
|
14670
15447
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14671
15448
|
process.exit(1);
|
|
14672
15449
|
}
|
|
@@ -14846,7 +15623,7 @@ async function cronEdit(globalOpts, id, opts) {
|
|
|
14846
15623
|
}
|
|
14847
15624
|
}
|
|
14848
15625
|
async function cronRuns(globalOpts, jobId, opts) {
|
|
14849
|
-
if (!
|
|
15626
|
+
if (!existsSync26(DB_PATH)) {
|
|
14850
15627
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14851
15628
|
process.exit(1);
|
|
14852
15629
|
}
|
|
@@ -14893,9 +15670,9 @@ __export(agents_exports, {
|
|
|
14893
15670
|
runnersList: () => runnersList,
|
|
14894
15671
|
tasksList: () => tasksList
|
|
14895
15672
|
});
|
|
14896
|
-
import { existsSync as
|
|
15673
|
+
import { existsSync as existsSync27 } from "fs";
|
|
14897
15674
|
async function agentsList(globalOpts) {
|
|
14898
|
-
if (!
|
|
15675
|
+
if (!existsSync27(DB_PATH)) {
|
|
14899
15676
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14900
15677
|
process.exit(1);
|
|
14901
15678
|
}
|
|
@@ -14926,7 +15703,7 @@ async function agentsList(globalOpts) {
|
|
|
14926
15703
|
});
|
|
14927
15704
|
}
|
|
14928
15705
|
async function tasksList(globalOpts) {
|
|
14929
|
-
if (!
|
|
15706
|
+
if (!existsSync27(DB_PATH)) {
|
|
14930
15707
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14931
15708
|
process.exit(1);
|
|
14932
15709
|
}
|
|
@@ -15054,10 +15831,10 @@ __export(db_exports, {
|
|
|
15054
15831
|
dbPath: () => dbPath,
|
|
15055
15832
|
dbStats: () => dbStats
|
|
15056
15833
|
});
|
|
15057
|
-
import { existsSync as
|
|
15834
|
+
import { existsSync as existsSync28, statSync as statSync5, copyFileSync as copyFileSync2, mkdirSync as mkdirSync10 } from "fs";
|
|
15058
15835
|
import { dirname as dirname4 } from "path";
|
|
15059
15836
|
async function dbStats(globalOpts) {
|
|
15060
|
-
if (!
|
|
15837
|
+
if (!existsSync28(DB_PATH)) {
|
|
15061
15838
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
15062
15839
|
process.exit(1);
|
|
15063
15840
|
}
|
|
@@ -15065,7 +15842,7 @@ async function dbStats(globalOpts) {
|
|
|
15065
15842
|
const readDb = openDatabaseReadOnly2();
|
|
15066
15843
|
const mainSize = statSync5(DB_PATH).size;
|
|
15067
15844
|
const walPath = DB_PATH + "-wal";
|
|
15068
|
-
const walSize =
|
|
15845
|
+
const walSize = existsSync28(walPath) ? statSync5(walPath).size : 0;
|
|
15069
15846
|
const tableNames = readDb.prepare(
|
|
15070
15847
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
|
|
15071
15848
|
).all();
|
|
@@ -15099,16 +15876,16 @@ async function dbPath(globalOpts) {
|
|
|
15099
15876
|
output({ path: DB_PATH }, (d) => d.path);
|
|
15100
15877
|
}
|
|
15101
15878
|
async function dbBackup(globalOpts, destPath) {
|
|
15102
|
-
if (!
|
|
15879
|
+
if (!existsSync28(DB_PATH)) {
|
|
15103
15880
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
15104
15881
|
process.exit(1);
|
|
15105
15882
|
}
|
|
15106
15883
|
const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
15107
15884
|
try {
|
|
15108
|
-
|
|
15885
|
+
mkdirSync10(dirname4(dest), { recursive: true });
|
|
15109
15886
|
copyFileSync2(DB_PATH, dest);
|
|
15110
15887
|
const walPath = DB_PATH + "-wal";
|
|
15111
|
-
if (
|
|
15888
|
+
if (existsSync28(walPath)) copyFileSync2(walPath, dest + "-wal");
|
|
15112
15889
|
output({ path: dest, sizeBytes: statSync5(dest).size }, (d) => {
|
|
15113
15890
|
const b = d;
|
|
15114
15891
|
return `
|
|
@@ -15137,9 +15914,9 @@ __export(usage_exports, {
|
|
|
15137
15914
|
usageCost: () => usageCost,
|
|
15138
15915
|
usageTokens: () => usageTokens
|
|
15139
15916
|
});
|
|
15140
|
-
import { existsSync as
|
|
15917
|
+
import { existsSync as existsSync29 } from "fs";
|
|
15141
15918
|
function ensureDb() {
|
|
15142
|
-
if (!
|
|
15919
|
+
if (!existsSync29(DB_PATH)) {
|
|
15143
15920
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
15144
15921
|
process.exit(1);
|
|
15145
15922
|
}
|
|
@@ -15329,9 +16106,9 @@ __export(config_exports, {
|
|
|
15329
16106
|
configList: () => configList,
|
|
15330
16107
|
configSet: () => configSet
|
|
15331
16108
|
});
|
|
15332
|
-
import { existsSync as
|
|
16109
|
+
import { existsSync as existsSync30, readFileSync as readFileSync15 } from "fs";
|
|
15333
16110
|
async function configList(globalOpts) {
|
|
15334
|
-
if (!
|
|
16111
|
+
if (!existsSync30(DB_PATH)) {
|
|
15335
16112
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15336
16113
|
process.exit(1);
|
|
15337
16114
|
}
|
|
@@ -15365,7 +16142,7 @@ async function configGet(globalOpts, key) {
|
|
|
15365
16142
|
outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
|
|
15366
16143
|
process.exit(1);
|
|
15367
16144
|
}
|
|
15368
|
-
if (!
|
|
16145
|
+
if (!existsSync30(DB_PATH)) {
|
|
15369
16146
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15370
16147
|
process.exit(1);
|
|
15371
16148
|
}
|
|
@@ -15411,7 +16188,7 @@ async function configSet(globalOpts, key, value) {
|
|
|
15411
16188
|
}
|
|
15412
16189
|
}
|
|
15413
16190
|
async function configEnv(_globalOpts) {
|
|
15414
|
-
if (!
|
|
16191
|
+
if (!existsSync30(ENV_PATH)) {
|
|
15415
16192
|
outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
|
|
15416
16193
|
process.exit(1);
|
|
15417
16194
|
}
|
|
@@ -15465,9 +16242,9 @@ __export(session_exports, {
|
|
|
15465
16242
|
sessionGet: () => sessionGet,
|
|
15466
16243
|
sessionNew: () => sessionNew
|
|
15467
16244
|
});
|
|
15468
|
-
import { existsSync as
|
|
16245
|
+
import { existsSync as existsSync31 } from "fs";
|
|
15469
16246
|
async function sessionGet(globalOpts) {
|
|
15470
|
-
if (!
|
|
16247
|
+
if (!existsSync31(DB_PATH)) {
|
|
15471
16248
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15472
16249
|
process.exit(1);
|
|
15473
16250
|
}
|
|
@@ -15528,9 +16305,9 @@ __export(permissions_exports, {
|
|
|
15528
16305
|
verboseGet: () => verboseGet,
|
|
15529
16306
|
verboseSet: () => verboseSet
|
|
15530
16307
|
});
|
|
15531
|
-
import { existsSync as
|
|
16308
|
+
import { existsSync as existsSync32 } from "fs";
|
|
15532
16309
|
function ensureDb2() {
|
|
15533
|
-
if (!
|
|
16310
|
+
if (!existsSync32(DB_PATH)) {
|
|
15534
16311
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15535
16312
|
process.exit(1);
|
|
15536
16313
|
}
|
|
@@ -15677,9 +16454,9 @@ __export(cwd_exports, {
|
|
|
15677
16454
|
cwdGet: () => cwdGet,
|
|
15678
16455
|
cwdSet: () => cwdSet
|
|
15679
16456
|
});
|
|
15680
|
-
import { existsSync as
|
|
16457
|
+
import { existsSync as existsSync33 } from "fs";
|
|
15681
16458
|
async function cwdGet(globalOpts) {
|
|
15682
|
-
if (!
|
|
16459
|
+
if (!existsSync33(DB_PATH)) {
|
|
15683
16460
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15684
16461
|
process.exit(1);
|
|
15685
16462
|
}
|
|
@@ -15741,9 +16518,9 @@ __export(voice_exports, {
|
|
|
15741
16518
|
voiceGet: () => voiceGet,
|
|
15742
16519
|
voiceSet: () => voiceSet
|
|
15743
16520
|
});
|
|
15744
|
-
import { existsSync as
|
|
16521
|
+
import { existsSync as existsSync34 } from "fs";
|
|
15745
16522
|
async function voiceGet(globalOpts) {
|
|
15746
|
-
if (!
|
|
16523
|
+
if (!existsSync34(DB_PATH)) {
|
|
15747
16524
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15748
16525
|
process.exit(1);
|
|
15749
16526
|
}
|
|
@@ -15792,9 +16569,9 @@ __export(heartbeat_exports, {
|
|
|
15792
16569
|
heartbeatGet: () => heartbeatGet,
|
|
15793
16570
|
heartbeatSet: () => heartbeatSet
|
|
15794
16571
|
});
|
|
15795
|
-
import { existsSync as
|
|
16572
|
+
import { existsSync as existsSync35 } from "fs";
|
|
15796
16573
|
async function heartbeatGet(globalOpts) {
|
|
15797
|
-
if (!
|
|
16574
|
+
if (!existsSync35(DB_PATH)) {
|
|
15798
16575
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15799
16576
|
process.exit(1);
|
|
15800
16577
|
}
|
|
@@ -15904,9 +16681,9 @@ __export(chats_exports, {
|
|
|
15904
16681
|
chatsList: () => chatsList,
|
|
15905
16682
|
chatsRemoveAlias: () => chatsRemoveAlias
|
|
15906
16683
|
});
|
|
15907
|
-
import { existsSync as
|
|
16684
|
+
import { existsSync as existsSync36 } from "fs";
|
|
15908
16685
|
async function chatsList(_globalOpts) {
|
|
15909
|
-
if (!
|
|
16686
|
+
if (!existsSync36(DB_PATH)) {
|
|
15910
16687
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15911
16688
|
process.exit(1);
|
|
15912
16689
|
}
|
|
@@ -16034,9 +16811,9 @@ var mcps_exports = {};
|
|
|
16034
16811
|
__export(mcps_exports, {
|
|
16035
16812
|
mcpsList: () => mcpsList
|
|
16036
16813
|
});
|
|
16037
|
-
import { existsSync as
|
|
16814
|
+
import { existsSync as existsSync37 } from "fs";
|
|
16038
16815
|
async function mcpsList(_globalOpts) {
|
|
16039
|
-
if (!
|
|
16816
|
+
if (!existsSync37(DB_PATH)) {
|
|
16040
16817
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
16041
16818
|
process.exit(1);
|
|
16042
16819
|
}
|
|
@@ -16073,11 +16850,11 @@ __export(chat_exports, {
|
|
|
16073
16850
|
chatSend: () => chatSend
|
|
16074
16851
|
});
|
|
16075
16852
|
import { request as httpRequest2 } from "http";
|
|
16076
|
-
import { readFileSync as readFileSync16, existsSync as
|
|
16853
|
+
import { readFileSync as readFileSync16, existsSync as existsSync38 } from "fs";
|
|
16077
16854
|
function getToken2() {
|
|
16078
16855
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
16079
16856
|
try {
|
|
16080
|
-
if (
|
|
16857
|
+
if (existsSync38(TOKEN_PATH2)) return readFileSync16(TOKEN_PATH2, "utf-8").trim();
|
|
16081
16858
|
} catch {
|
|
16082
16859
|
}
|
|
16083
16860
|
return null;
|
|
@@ -16214,7 +16991,7 @@ var tui_exports = {};
|
|
|
16214
16991
|
__export(tui_exports, {
|
|
16215
16992
|
tuiCommand: () => tuiCommand
|
|
16216
16993
|
});
|
|
16217
|
-
import { createInterface as
|
|
16994
|
+
import { createInterface as createInterface5 } from "readline";
|
|
16218
16995
|
import pc2 from "picocolors";
|
|
16219
16996
|
async function tuiCommand(globalOpts, cmdOpts) {
|
|
16220
16997
|
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
@@ -16224,7 +17001,7 @@ async function tuiCommand(globalOpts, cmdOpts) {
|
|
|
16224
17001
|
}
|
|
16225
17002
|
const chatId = resolveChatId(globalOpts);
|
|
16226
17003
|
const { chatSend: chatSend2 } = await Promise.resolve().then(() => (init_chat(), chat_exports));
|
|
16227
|
-
const rl2 =
|
|
17004
|
+
const rl2 = createInterface5({
|
|
16228
17005
|
input: process.stdin,
|
|
16229
17006
|
output: process.stdout,
|
|
16230
17007
|
prompt: pc2.cyan("you > "),
|
|
@@ -16503,10 +17280,10 @@ var init_completion = __esm({
|
|
|
16503
17280
|
|
|
16504
17281
|
// src/setup.ts
|
|
16505
17282
|
var setup_exports = {};
|
|
16506
|
-
import { existsSync as
|
|
17283
|
+
import { existsSync as existsSync39, writeFileSync as writeFileSync8, readFileSync as readFileSync17, copyFileSync as copyFileSync3, mkdirSync as mkdirSync11, statSync as statSync6 } from "fs";
|
|
16507
17284
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
16508
|
-
import { createInterface as
|
|
16509
|
-
import { join as
|
|
17285
|
+
import { createInterface as createInterface6 } from "readline";
|
|
17286
|
+
import { join as join21 } from "path";
|
|
16510
17287
|
function divider2() {
|
|
16511
17288
|
console.log(dim("\u2500".repeat(55)));
|
|
16512
17289
|
}
|
|
@@ -16580,10 +17357,10 @@ async function setup() {
|
|
|
16580
17357
|
}
|
|
16581
17358
|
console.log("");
|
|
16582
17359
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
16583
|
-
if (!
|
|
17360
|
+
if (!existsSync39(dir)) mkdirSync11(dir, { recursive: true });
|
|
16584
17361
|
}
|
|
16585
17362
|
const env = {};
|
|
16586
|
-
const envSource =
|
|
17363
|
+
const envSource = existsSync39(ENV_PATH) ? ENV_PATH : existsSync39(".env") ? ".env" : null;
|
|
16587
17364
|
if (envSource) {
|
|
16588
17365
|
console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
|
|
16589
17366
|
console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
|
|
@@ -16593,8 +17370,8 @@ async function setup() {
|
|
|
16593
17370
|
if (match) env[match[1].trim()] = match[2].trim();
|
|
16594
17371
|
}
|
|
16595
17372
|
}
|
|
16596
|
-
const cwdDb =
|
|
16597
|
-
if (
|
|
17373
|
+
const cwdDb = join21(process.cwd(), "cc-claw.db");
|
|
17374
|
+
if (existsSync39(cwdDb) && !existsSync39(DB_PATH)) {
|
|
16598
17375
|
const { size } = statSync6(cwdDb);
|
|
16599
17376
|
console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
|
|
16600
17377
|
const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
|
|
@@ -16807,7 +17584,7 @@ async function setup() {
|
|
|
16807
17584
|
envLines.push("", "# Video Analysis", `GEMINI_API_KEY=${env.GEMINI_API_KEY}`);
|
|
16808
17585
|
}
|
|
16809
17586
|
const envContent = envLines.join("\n") + "\n";
|
|
16810
|
-
|
|
17587
|
+
writeFileSync8(ENV_PATH, envContent, { mode: 384 });
|
|
16811
17588
|
console.log(green(` Config saved to ${ENV_PATH} (permissions: owner-only)`));
|
|
16812
17589
|
header(6, TOTAL_STEPS, "Run on Startup (Daemon)");
|
|
16813
17590
|
console.log(" CC-Claw can run automatically in the background, starting");
|
|
@@ -16862,7 +17639,7 @@ var init_setup = __esm({
|
|
|
16862
17639
|
"src/setup.ts"() {
|
|
16863
17640
|
"use strict";
|
|
16864
17641
|
init_paths();
|
|
16865
|
-
rl =
|
|
17642
|
+
rl = createInterface6({ input: process.stdin, output: process.stdout });
|
|
16866
17643
|
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
16867
17644
|
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
16868
17645
|
green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
@@ -16932,6 +17709,35 @@ program.command("logs").description("Tail daemon logs").option("-f, --follow", "
|
|
|
16932
17709
|
const { logsCommand: logsCommand2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
|
|
16933
17710
|
await logsCommand2(opts);
|
|
16934
17711
|
});
|
|
17712
|
+
var gemini = program.command("gemini").description("Manage Gemini credential slots for rotation");
|
|
17713
|
+
gemini.command("list").description("Show all configured Gemini credential slots").action(async () => {
|
|
17714
|
+
const { geminiList: geminiList2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
|
|
17715
|
+
await geminiList2(program.opts());
|
|
17716
|
+
});
|
|
17717
|
+
gemini.command("add-key").description("Add an API key slot (prompts for key in terminal)").option("--label <name>", "Friendly label for this slot").option("--priority <n>", "Priority (lower = preferred)", "0").action(async (opts) => {
|
|
17718
|
+
const { geminiAddKey: geminiAddKey2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
|
|
17719
|
+
await geminiAddKey2(program.opts(), opts);
|
|
17720
|
+
});
|
|
17721
|
+
gemini.command("add-account").description("Add an OAuth account slot (opens browser for Google sign-in)").option("--label <name>", "Friendly label for this slot").option("--priority <n>", "Priority (lower = preferred)", "0").action(async (opts) => {
|
|
17722
|
+
const { geminiAddAccount: geminiAddAccount2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
|
|
17723
|
+
await geminiAddAccount2(program.opts(), opts);
|
|
17724
|
+
});
|
|
17725
|
+
gemini.command("remove <id>").description("Remove a credential slot").action(async (id) => {
|
|
17726
|
+
const { geminiRemove: geminiRemove2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
|
|
17727
|
+
await geminiRemove2(program.opts(), id);
|
|
17728
|
+
});
|
|
17729
|
+
gemini.command("enable <id>").description("Re-enable a disabled slot").action(async (id) => {
|
|
17730
|
+
const { geminiEnable: geminiEnable2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
|
|
17731
|
+
await geminiEnable2(program.opts(), id);
|
|
17732
|
+
});
|
|
17733
|
+
gemini.command("disable <id>").description("Disable a slot (skip during rotation)").action(async (id) => {
|
|
17734
|
+
const { geminiDisable: geminiDisable2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
|
|
17735
|
+
await geminiDisable2(program.opts(), id);
|
|
17736
|
+
});
|
|
17737
|
+
gemini.command("reorder <id> <priority>").description("Set slot priority (lower = preferred)").action(async (id, priority) => {
|
|
17738
|
+
const { geminiReorder: geminiReorder2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
|
|
17739
|
+
await geminiReorder2(program.opts(), id, priority);
|
|
17740
|
+
});
|
|
16935
17741
|
var backend = program.command("backend").description("Manage AI backend");
|
|
16936
17742
|
backend.command("list").description("Available backends with status").action(async () => {
|
|
16937
17743
|
const { backendList: backendList2 } = await Promise.resolve().then(() => (init_backend(), backend_exports));
|