cc-claw 0.5.5 → 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 +919 -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,38 +12160,26 @@ 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");
|
|
11588
12174
|
} finally {
|
|
11589
12175
|
typingActive = false;
|
|
12176
|
+
const pending = pendingInterrupts.get(chatId);
|
|
12177
|
+
if (pending) {
|
|
12178
|
+
pendingInterrupts.delete(chatId);
|
|
12179
|
+
bypassBusyCheck.add(chatId);
|
|
12180
|
+
handleMessage(pending.msg, pending.channel).catch(() => {
|
|
12181
|
+
});
|
|
12182
|
+
}
|
|
11590
12183
|
}
|
|
11591
12184
|
}
|
|
11592
12185
|
function diagnoseAgentError(msg, chatId) {
|
|
@@ -11912,6 +12505,7 @@ async function doBackendSwitch(chatId, backendId, channel) {
|
|
|
11912
12505
|
clearSession(chatId);
|
|
11913
12506
|
clearModel(chatId);
|
|
11914
12507
|
clearThinkingLevel(chatId);
|
|
12508
|
+
clearChatGeminiSlot(chatId);
|
|
11915
12509
|
setBackend(chatId, backendId);
|
|
11916
12510
|
logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Backend switched to ${targetAdapter.displayName}`, detail: { field: "backend", value: backendId } });
|
|
11917
12511
|
await channel.sendText(chatId, `\u2705 Switched to ${targetAdapter.displayName}. Ready!`, "plain");
|
|
@@ -11928,7 +12522,7 @@ async function handleCallback(chatId, data, channel) {
|
|
|
11928
12522
|
}
|
|
11929
12523
|
await sendBackendSwitchConfirmation(chatId, chosen, channel);
|
|
11930
12524
|
} else if (data.startsWith("backend_confirm_clear:")) {
|
|
11931
|
-
const target = data.slice(
|
|
12525
|
+
const target = data.slice("backend_confirm_clear:".length);
|
|
11932
12526
|
if (!getAllBackendIds().includes(target)) return;
|
|
11933
12527
|
clearMessageLog(chatId);
|
|
11934
12528
|
await doBackendSwitch(chatId, target, channel);
|
|
@@ -12130,6 +12724,7 @@ ${PERM_MODES[chosen]}`,
|
|
|
12130
12724
|
await channel.sendText(chatId, "OK \u2014 you can switch manually with /backend when ready.", "plain");
|
|
12131
12725
|
} else if (pendingMsg) {
|
|
12132
12726
|
pendingFallbackMessages.delete(targetChatId);
|
|
12727
|
+
if (pendingMsg.agentMode) pendingMsg.msg.agentMode = pendingMsg.agentMode;
|
|
12133
12728
|
await summarizeWithFallbackChain(targetChatId, targetBackend);
|
|
12134
12729
|
const bridge = buildContextBridge(targetChatId);
|
|
12135
12730
|
if (bridge) setPendingContextBridge(targetChatId, bridge);
|
|
@@ -12164,6 +12759,18 @@ ${PERM_MODES[chosen]}`,
|
|
|
12164
12759
|
}
|
|
12165
12760
|
await channel.sendText(chatId, `Response style set to: ${selectedStyle}`, "plain");
|
|
12166
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;
|
|
12167
12774
|
} else if (data.startsWith("model_sig:")) {
|
|
12168
12775
|
const value = data.slice(10);
|
|
12169
12776
|
setModelSignature(chatId, value);
|
|
@@ -12414,7 +13021,7 @@ Use /skills <page> to navigate (e.g. /skills 2)` : "";
|
|
|
12414
13021
|
const header2 = totalPages > 1 ? `${skills2.length} skills (page ${safePage}/${totalPages}). Select one to invoke:` : `${skills2.length} skills available. Select one to invoke:`;
|
|
12415
13022
|
await channel.sendKeyboard(chatId, header2, buttons);
|
|
12416
13023
|
}
|
|
12417
|
-
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;
|
|
12418
13025
|
var init_router = __esm({
|
|
12419
13026
|
"src/router.ts"() {
|
|
12420
13027
|
"use strict";
|
|
@@ -12443,6 +13050,7 @@ var init_router = __esm({
|
|
|
12443
13050
|
init_store();
|
|
12444
13051
|
init_orchestrator();
|
|
12445
13052
|
init_registry();
|
|
13053
|
+
init_classify2();
|
|
12446
13054
|
init_registry2();
|
|
12447
13055
|
init_store3();
|
|
12448
13056
|
init_guard();
|
|
@@ -12461,6 +13069,7 @@ var init_router = __esm({
|
|
|
12461
13069
|
pendingInterrupts = /* @__PURE__ */ new Map();
|
|
12462
13070
|
bypassBusyCheck = /* @__PURE__ */ new Set();
|
|
12463
13071
|
pendingFallbackMessages = /* @__PURE__ */ new Map();
|
|
13072
|
+
dashboardClawWarnings = /* @__PURE__ */ new Map();
|
|
12464
13073
|
CLI_INSTALL_HINTS = {
|
|
12465
13074
|
claude: "Install: npm install -g @anthropic-ai/claude-code",
|
|
12466
13075
|
gemini: "Install: npm install -g @google/gemini-cli",
|
|
@@ -13295,6 +13904,17 @@ async function main() {
|
|
|
13295
13904
|
});
|
|
13296
13905
|
});
|
|
13297
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
|
+
}
|
|
13298
13918
|
Promise.resolve().then(() => (init_registry2(), registry_exports2)).then(({ syncMcps: syncMcps2 }) => {
|
|
13299
13919
|
Promise.resolve().then(() => (init_registry(), registry_exports)).then(({ getAllRunners: getAllRunners2 }) => {
|
|
13300
13920
|
syncMcps2(getDb(), getAllRunners2()).catch((err) => {
|
|
@@ -13312,11 +13932,11 @@ async function main() {
|
|
|
13312
13932
|
bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
|
|
13313
13933
|
try {
|
|
13314
13934
|
const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
|
|
13315
|
-
const { writeFileSync:
|
|
13316
|
-
const { join:
|
|
13317
|
-
const skillDir =
|
|
13318
|
-
|
|
13319
|
-
|
|
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");
|
|
13320
13940
|
log("[cc-claw] AI skill updated");
|
|
13321
13941
|
} catch {
|
|
13322
13942
|
}
|
|
@@ -14334,6 +14954,170 @@ var init_logs = __esm({
|
|
|
14334
14954
|
}
|
|
14335
14955
|
});
|
|
14336
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
|
+
|
|
14337
15121
|
// src/cli/commands/backend.ts
|
|
14338
15122
|
var backend_exports = {};
|
|
14339
15123
|
__export(backend_exports, {
|
|
@@ -14341,12 +15125,12 @@ __export(backend_exports, {
|
|
|
14341
15125
|
backendList: () => backendList,
|
|
14342
15126
|
backendSet: () => backendSet
|
|
14343
15127
|
});
|
|
14344
|
-
import { existsSync as
|
|
15128
|
+
import { existsSync as existsSync23 } from "fs";
|
|
14345
15129
|
async function backendList(globalOpts) {
|
|
14346
15130
|
const { getAllAdapters: getAllAdapters2 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
14347
15131
|
const chatId = resolveChatId(globalOpts);
|
|
14348
15132
|
let activeBackend = null;
|
|
14349
|
-
if (
|
|
15133
|
+
if (existsSync23(DB_PATH)) {
|
|
14350
15134
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
14351
15135
|
const readDb = openDatabaseReadOnly2();
|
|
14352
15136
|
try {
|
|
@@ -14377,7 +15161,7 @@ async function backendList(globalOpts) {
|
|
|
14377
15161
|
}
|
|
14378
15162
|
async function backendGet(globalOpts) {
|
|
14379
15163
|
const chatId = resolveChatId(globalOpts);
|
|
14380
|
-
if (!
|
|
15164
|
+
if (!existsSync23(DB_PATH)) {
|
|
14381
15165
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
14382
15166
|
process.exit(1);
|
|
14383
15167
|
}
|
|
@@ -14421,13 +15205,13 @@ __export(model_exports, {
|
|
|
14421
15205
|
modelList: () => modelList,
|
|
14422
15206
|
modelSet: () => modelSet
|
|
14423
15207
|
});
|
|
14424
|
-
import { existsSync as
|
|
15208
|
+
import { existsSync as existsSync24 } from "fs";
|
|
14425
15209
|
async function modelList(globalOpts) {
|
|
14426
15210
|
const chatId = resolveChatId(globalOpts);
|
|
14427
15211
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store4(), store_exports3));
|
|
14428
15212
|
const { getAdapter: getAdapter2, getAllAdapters: getAllAdapters2 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
14429
15213
|
let backendId = "claude";
|
|
14430
|
-
if (
|
|
15214
|
+
if (existsSync24(DB_PATH)) {
|
|
14431
15215
|
const readDb = openDatabaseReadOnly2();
|
|
14432
15216
|
try {
|
|
14433
15217
|
const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
|
|
@@ -14460,7 +15244,7 @@ async function modelList(globalOpts) {
|
|
|
14460
15244
|
}
|
|
14461
15245
|
async function modelGet(globalOpts) {
|
|
14462
15246
|
const chatId = resolveChatId(globalOpts);
|
|
14463
|
-
if (!
|
|
15247
|
+
if (!existsSync24(DB_PATH)) {
|
|
14464
15248
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14465
15249
|
process.exit(1);
|
|
14466
15250
|
}
|
|
@@ -14504,9 +15288,9 @@ __export(memory_exports, {
|
|
|
14504
15288
|
memoryList: () => memoryList,
|
|
14505
15289
|
memorySearch: () => memorySearch
|
|
14506
15290
|
});
|
|
14507
|
-
import { existsSync as
|
|
15291
|
+
import { existsSync as existsSync25 } from "fs";
|
|
14508
15292
|
async function memoryList(globalOpts) {
|
|
14509
|
-
if (!
|
|
15293
|
+
if (!existsSync25(DB_PATH)) {
|
|
14510
15294
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
14511
15295
|
process.exit(1);
|
|
14512
15296
|
}
|
|
@@ -14530,7 +15314,7 @@ async function memoryList(globalOpts) {
|
|
|
14530
15314
|
});
|
|
14531
15315
|
}
|
|
14532
15316
|
async function memorySearch(globalOpts, query) {
|
|
14533
|
-
if (!
|
|
15317
|
+
if (!existsSync25(DB_PATH)) {
|
|
14534
15318
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14535
15319
|
process.exit(1);
|
|
14536
15320
|
}
|
|
@@ -14552,7 +15336,7 @@ async function memorySearch(globalOpts, query) {
|
|
|
14552
15336
|
});
|
|
14553
15337
|
}
|
|
14554
15338
|
async function memoryHistory(globalOpts, opts) {
|
|
14555
|
-
if (!
|
|
15339
|
+
if (!existsSync25(DB_PATH)) {
|
|
14556
15340
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14557
15341
|
process.exit(1);
|
|
14558
15342
|
}
|
|
@@ -14600,7 +15384,7 @@ __export(cron_exports2, {
|
|
|
14600
15384
|
cronList: () => cronList,
|
|
14601
15385
|
cronRuns: () => cronRuns
|
|
14602
15386
|
});
|
|
14603
|
-
import { existsSync as
|
|
15387
|
+
import { existsSync as existsSync26 } from "fs";
|
|
14604
15388
|
function parseFallbacks(raw) {
|
|
14605
15389
|
return raw.slice(0, 3).map((f) => {
|
|
14606
15390
|
const [backend2, ...rest] = f.split(":");
|
|
@@ -14621,7 +15405,7 @@ function parseAndValidateTimeout(raw) {
|
|
|
14621
15405
|
return val;
|
|
14622
15406
|
}
|
|
14623
15407
|
async function cronList(globalOpts) {
|
|
14624
|
-
if (!
|
|
15408
|
+
if (!existsSync26(DB_PATH)) {
|
|
14625
15409
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14626
15410
|
process.exit(1);
|
|
14627
15411
|
}
|
|
@@ -14659,7 +15443,7 @@ async function cronList(globalOpts) {
|
|
|
14659
15443
|
});
|
|
14660
15444
|
}
|
|
14661
15445
|
async function cronHealth(globalOpts) {
|
|
14662
|
-
if (!
|
|
15446
|
+
if (!existsSync26(DB_PATH)) {
|
|
14663
15447
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14664
15448
|
process.exit(1);
|
|
14665
15449
|
}
|
|
@@ -14839,7 +15623,7 @@ async function cronEdit(globalOpts, id, opts) {
|
|
|
14839
15623
|
}
|
|
14840
15624
|
}
|
|
14841
15625
|
async function cronRuns(globalOpts, jobId, opts) {
|
|
14842
|
-
if (!
|
|
15626
|
+
if (!existsSync26(DB_PATH)) {
|
|
14843
15627
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14844
15628
|
process.exit(1);
|
|
14845
15629
|
}
|
|
@@ -14886,9 +15670,9 @@ __export(agents_exports, {
|
|
|
14886
15670
|
runnersList: () => runnersList,
|
|
14887
15671
|
tasksList: () => tasksList
|
|
14888
15672
|
});
|
|
14889
|
-
import { existsSync as
|
|
15673
|
+
import { existsSync as existsSync27 } from "fs";
|
|
14890
15674
|
async function agentsList(globalOpts) {
|
|
14891
|
-
if (!
|
|
15675
|
+
if (!existsSync27(DB_PATH)) {
|
|
14892
15676
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14893
15677
|
process.exit(1);
|
|
14894
15678
|
}
|
|
@@ -14919,7 +15703,7 @@ async function agentsList(globalOpts) {
|
|
|
14919
15703
|
});
|
|
14920
15704
|
}
|
|
14921
15705
|
async function tasksList(globalOpts) {
|
|
14922
|
-
if (!
|
|
15706
|
+
if (!existsSync27(DB_PATH)) {
|
|
14923
15707
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
14924
15708
|
process.exit(1);
|
|
14925
15709
|
}
|
|
@@ -15047,10 +15831,10 @@ __export(db_exports, {
|
|
|
15047
15831
|
dbPath: () => dbPath,
|
|
15048
15832
|
dbStats: () => dbStats
|
|
15049
15833
|
});
|
|
15050
|
-
import { existsSync as
|
|
15834
|
+
import { existsSync as existsSync28, statSync as statSync5, copyFileSync as copyFileSync2, mkdirSync as mkdirSync10 } from "fs";
|
|
15051
15835
|
import { dirname as dirname4 } from "path";
|
|
15052
15836
|
async function dbStats(globalOpts) {
|
|
15053
|
-
if (!
|
|
15837
|
+
if (!existsSync28(DB_PATH)) {
|
|
15054
15838
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
15055
15839
|
process.exit(1);
|
|
15056
15840
|
}
|
|
@@ -15058,7 +15842,7 @@ async function dbStats(globalOpts) {
|
|
|
15058
15842
|
const readDb = openDatabaseReadOnly2();
|
|
15059
15843
|
const mainSize = statSync5(DB_PATH).size;
|
|
15060
15844
|
const walPath = DB_PATH + "-wal";
|
|
15061
|
-
const walSize =
|
|
15845
|
+
const walSize = existsSync28(walPath) ? statSync5(walPath).size : 0;
|
|
15062
15846
|
const tableNames = readDb.prepare(
|
|
15063
15847
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
|
|
15064
15848
|
).all();
|
|
@@ -15092,16 +15876,16 @@ async function dbPath(globalOpts) {
|
|
|
15092
15876
|
output({ path: DB_PATH }, (d) => d.path);
|
|
15093
15877
|
}
|
|
15094
15878
|
async function dbBackup(globalOpts, destPath) {
|
|
15095
|
-
if (!
|
|
15879
|
+
if (!existsSync28(DB_PATH)) {
|
|
15096
15880
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
15097
15881
|
process.exit(1);
|
|
15098
15882
|
}
|
|
15099
15883
|
const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
15100
15884
|
try {
|
|
15101
|
-
|
|
15885
|
+
mkdirSync10(dirname4(dest), { recursive: true });
|
|
15102
15886
|
copyFileSync2(DB_PATH, dest);
|
|
15103
15887
|
const walPath = DB_PATH + "-wal";
|
|
15104
|
-
if (
|
|
15888
|
+
if (existsSync28(walPath)) copyFileSync2(walPath, dest + "-wal");
|
|
15105
15889
|
output({ path: dest, sizeBytes: statSync5(dest).size }, (d) => {
|
|
15106
15890
|
const b = d;
|
|
15107
15891
|
return `
|
|
@@ -15130,9 +15914,9 @@ __export(usage_exports, {
|
|
|
15130
15914
|
usageCost: () => usageCost,
|
|
15131
15915
|
usageTokens: () => usageTokens
|
|
15132
15916
|
});
|
|
15133
|
-
import { existsSync as
|
|
15917
|
+
import { existsSync as existsSync29 } from "fs";
|
|
15134
15918
|
function ensureDb() {
|
|
15135
|
-
if (!
|
|
15919
|
+
if (!existsSync29(DB_PATH)) {
|
|
15136
15920
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
15137
15921
|
process.exit(1);
|
|
15138
15922
|
}
|
|
@@ -15322,9 +16106,9 @@ __export(config_exports, {
|
|
|
15322
16106
|
configList: () => configList,
|
|
15323
16107
|
configSet: () => configSet
|
|
15324
16108
|
});
|
|
15325
|
-
import { existsSync as
|
|
16109
|
+
import { existsSync as existsSync30, readFileSync as readFileSync15 } from "fs";
|
|
15326
16110
|
async function configList(globalOpts) {
|
|
15327
|
-
if (!
|
|
16111
|
+
if (!existsSync30(DB_PATH)) {
|
|
15328
16112
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15329
16113
|
process.exit(1);
|
|
15330
16114
|
}
|
|
@@ -15358,7 +16142,7 @@ async function configGet(globalOpts, key) {
|
|
|
15358
16142
|
outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
|
|
15359
16143
|
process.exit(1);
|
|
15360
16144
|
}
|
|
15361
|
-
if (!
|
|
16145
|
+
if (!existsSync30(DB_PATH)) {
|
|
15362
16146
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15363
16147
|
process.exit(1);
|
|
15364
16148
|
}
|
|
@@ -15404,7 +16188,7 @@ async function configSet(globalOpts, key, value) {
|
|
|
15404
16188
|
}
|
|
15405
16189
|
}
|
|
15406
16190
|
async function configEnv(_globalOpts) {
|
|
15407
|
-
if (!
|
|
16191
|
+
if (!existsSync30(ENV_PATH)) {
|
|
15408
16192
|
outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
|
|
15409
16193
|
process.exit(1);
|
|
15410
16194
|
}
|
|
@@ -15458,9 +16242,9 @@ __export(session_exports, {
|
|
|
15458
16242
|
sessionGet: () => sessionGet,
|
|
15459
16243
|
sessionNew: () => sessionNew
|
|
15460
16244
|
});
|
|
15461
|
-
import { existsSync as
|
|
16245
|
+
import { existsSync as existsSync31 } from "fs";
|
|
15462
16246
|
async function sessionGet(globalOpts) {
|
|
15463
|
-
if (!
|
|
16247
|
+
if (!existsSync31(DB_PATH)) {
|
|
15464
16248
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15465
16249
|
process.exit(1);
|
|
15466
16250
|
}
|
|
@@ -15521,9 +16305,9 @@ __export(permissions_exports, {
|
|
|
15521
16305
|
verboseGet: () => verboseGet,
|
|
15522
16306
|
verboseSet: () => verboseSet
|
|
15523
16307
|
});
|
|
15524
|
-
import { existsSync as
|
|
16308
|
+
import { existsSync as existsSync32 } from "fs";
|
|
15525
16309
|
function ensureDb2() {
|
|
15526
|
-
if (!
|
|
16310
|
+
if (!existsSync32(DB_PATH)) {
|
|
15527
16311
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15528
16312
|
process.exit(1);
|
|
15529
16313
|
}
|
|
@@ -15670,9 +16454,9 @@ __export(cwd_exports, {
|
|
|
15670
16454
|
cwdGet: () => cwdGet,
|
|
15671
16455
|
cwdSet: () => cwdSet
|
|
15672
16456
|
});
|
|
15673
|
-
import { existsSync as
|
|
16457
|
+
import { existsSync as existsSync33 } from "fs";
|
|
15674
16458
|
async function cwdGet(globalOpts) {
|
|
15675
|
-
if (!
|
|
16459
|
+
if (!existsSync33(DB_PATH)) {
|
|
15676
16460
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15677
16461
|
process.exit(1);
|
|
15678
16462
|
}
|
|
@@ -15734,9 +16518,9 @@ __export(voice_exports, {
|
|
|
15734
16518
|
voiceGet: () => voiceGet,
|
|
15735
16519
|
voiceSet: () => voiceSet
|
|
15736
16520
|
});
|
|
15737
|
-
import { existsSync as
|
|
16521
|
+
import { existsSync as existsSync34 } from "fs";
|
|
15738
16522
|
async function voiceGet(globalOpts) {
|
|
15739
|
-
if (!
|
|
16523
|
+
if (!existsSync34(DB_PATH)) {
|
|
15740
16524
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15741
16525
|
process.exit(1);
|
|
15742
16526
|
}
|
|
@@ -15785,9 +16569,9 @@ __export(heartbeat_exports, {
|
|
|
15785
16569
|
heartbeatGet: () => heartbeatGet,
|
|
15786
16570
|
heartbeatSet: () => heartbeatSet
|
|
15787
16571
|
});
|
|
15788
|
-
import { existsSync as
|
|
16572
|
+
import { existsSync as existsSync35 } from "fs";
|
|
15789
16573
|
async function heartbeatGet(globalOpts) {
|
|
15790
|
-
if (!
|
|
16574
|
+
if (!existsSync35(DB_PATH)) {
|
|
15791
16575
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15792
16576
|
process.exit(1);
|
|
15793
16577
|
}
|
|
@@ -15897,9 +16681,9 @@ __export(chats_exports, {
|
|
|
15897
16681
|
chatsList: () => chatsList,
|
|
15898
16682
|
chatsRemoveAlias: () => chatsRemoveAlias
|
|
15899
16683
|
});
|
|
15900
|
-
import { existsSync as
|
|
16684
|
+
import { existsSync as existsSync36 } from "fs";
|
|
15901
16685
|
async function chatsList(_globalOpts) {
|
|
15902
|
-
if (!
|
|
16686
|
+
if (!existsSync36(DB_PATH)) {
|
|
15903
16687
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
15904
16688
|
process.exit(1);
|
|
15905
16689
|
}
|
|
@@ -16027,9 +16811,9 @@ var mcps_exports = {};
|
|
|
16027
16811
|
__export(mcps_exports, {
|
|
16028
16812
|
mcpsList: () => mcpsList
|
|
16029
16813
|
});
|
|
16030
|
-
import { existsSync as
|
|
16814
|
+
import { existsSync as existsSync37 } from "fs";
|
|
16031
16815
|
async function mcpsList(_globalOpts) {
|
|
16032
|
-
if (!
|
|
16816
|
+
if (!existsSync37(DB_PATH)) {
|
|
16033
16817
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
16034
16818
|
process.exit(1);
|
|
16035
16819
|
}
|
|
@@ -16066,11 +16850,11 @@ __export(chat_exports, {
|
|
|
16066
16850
|
chatSend: () => chatSend
|
|
16067
16851
|
});
|
|
16068
16852
|
import { request as httpRequest2 } from "http";
|
|
16069
|
-
import { readFileSync as readFileSync16, existsSync as
|
|
16853
|
+
import { readFileSync as readFileSync16, existsSync as existsSync38 } from "fs";
|
|
16070
16854
|
function getToken2() {
|
|
16071
16855
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
16072
16856
|
try {
|
|
16073
|
-
if (
|
|
16857
|
+
if (existsSync38(TOKEN_PATH2)) return readFileSync16(TOKEN_PATH2, "utf-8").trim();
|
|
16074
16858
|
} catch {
|
|
16075
16859
|
}
|
|
16076
16860
|
return null;
|
|
@@ -16207,7 +16991,7 @@ var tui_exports = {};
|
|
|
16207
16991
|
__export(tui_exports, {
|
|
16208
16992
|
tuiCommand: () => tuiCommand
|
|
16209
16993
|
});
|
|
16210
|
-
import { createInterface as
|
|
16994
|
+
import { createInterface as createInterface5 } from "readline";
|
|
16211
16995
|
import pc2 from "picocolors";
|
|
16212
16996
|
async function tuiCommand(globalOpts, cmdOpts) {
|
|
16213
16997
|
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
@@ -16217,7 +17001,7 @@ async function tuiCommand(globalOpts, cmdOpts) {
|
|
|
16217
17001
|
}
|
|
16218
17002
|
const chatId = resolveChatId(globalOpts);
|
|
16219
17003
|
const { chatSend: chatSend2 } = await Promise.resolve().then(() => (init_chat(), chat_exports));
|
|
16220
|
-
const rl2 =
|
|
17004
|
+
const rl2 = createInterface5({
|
|
16221
17005
|
input: process.stdin,
|
|
16222
17006
|
output: process.stdout,
|
|
16223
17007
|
prompt: pc2.cyan("you > "),
|
|
@@ -16496,10 +17280,10 @@ var init_completion = __esm({
|
|
|
16496
17280
|
|
|
16497
17281
|
// src/setup.ts
|
|
16498
17282
|
var setup_exports = {};
|
|
16499
|
-
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";
|
|
16500
17284
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
16501
|
-
import { createInterface as
|
|
16502
|
-
import { join as
|
|
17285
|
+
import { createInterface as createInterface6 } from "readline";
|
|
17286
|
+
import { join as join21 } from "path";
|
|
16503
17287
|
function divider2() {
|
|
16504
17288
|
console.log(dim("\u2500".repeat(55)));
|
|
16505
17289
|
}
|
|
@@ -16573,10 +17357,10 @@ async function setup() {
|
|
|
16573
17357
|
}
|
|
16574
17358
|
console.log("");
|
|
16575
17359
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
16576
|
-
if (!
|
|
17360
|
+
if (!existsSync39(dir)) mkdirSync11(dir, { recursive: true });
|
|
16577
17361
|
}
|
|
16578
17362
|
const env = {};
|
|
16579
|
-
const envSource =
|
|
17363
|
+
const envSource = existsSync39(ENV_PATH) ? ENV_PATH : existsSync39(".env") ? ".env" : null;
|
|
16580
17364
|
if (envSource) {
|
|
16581
17365
|
console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
|
|
16582
17366
|
console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
|
|
@@ -16586,8 +17370,8 @@ async function setup() {
|
|
|
16586
17370
|
if (match) env[match[1].trim()] = match[2].trim();
|
|
16587
17371
|
}
|
|
16588
17372
|
}
|
|
16589
|
-
const cwdDb =
|
|
16590
|
-
if (
|
|
17373
|
+
const cwdDb = join21(process.cwd(), "cc-claw.db");
|
|
17374
|
+
if (existsSync39(cwdDb) && !existsSync39(DB_PATH)) {
|
|
16591
17375
|
const { size } = statSync6(cwdDb);
|
|
16592
17376
|
console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
|
|
16593
17377
|
const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
|
|
@@ -16800,7 +17584,7 @@ async function setup() {
|
|
|
16800
17584
|
envLines.push("", "# Video Analysis", `GEMINI_API_KEY=${env.GEMINI_API_KEY}`);
|
|
16801
17585
|
}
|
|
16802
17586
|
const envContent = envLines.join("\n") + "\n";
|
|
16803
|
-
|
|
17587
|
+
writeFileSync8(ENV_PATH, envContent, { mode: 384 });
|
|
16804
17588
|
console.log(green(` Config saved to ${ENV_PATH} (permissions: owner-only)`));
|
|
16805
17589
|
header(6, TOTAL_STEPS, "Run on Startup (Daemon)");
|
|
16806
17590
|
console.log(" CC-Claw can run automatically in the background, starting");
|
|
@@ -16855,7 +17639,7 @@ var init_setup = __esm({
|
|
|
16855
17639
|
"src/setup.ts"() {
|
|
16856
17640
|
"use strict";
|
|
16857
17641
|
init_paths();
|
|
16858
|
-
rl =
|
|
17642
|
+
rl = createInterface6({ input: process.stdin, output: process.stdout });
|
|
16859
17643
|
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
16860
17644
|
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
16861
17645
|
green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
@@ -16925,6 +17709,35 @@ program.command("logs").description("Tail daemon logs").option("-f, --follow", "
|
|
|
16925
17709
|
const { logsCommand: logsCommand2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
|
|
16926
17710
|
await logsCommand2(opts);
|
|
16927
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
|
+
});
|
|
16928
17741
|
var backend = program.command("backend").description("Manage AI backend");
|
|
16929
17742
|
backend.command("list").description("Available backends with status").action(async () => {
|
|
16930
17743
|
const { backendList: backendList2 } = await Promise.resolve().then(() => (init_backend(), backend_exports));
|