cc-claw 0.18.0 → 0.18.2

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.
Files changed (2) hide show
  1. package/dist/cli.js +924 -303
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -33,7 +33,7 @@ var VERSION;
33
33
  var init_version = __esm({
34
34
  "src/version.ts"() {
35
35
  "use strict";
36
- VERSION = true ? "0.18.0" : (() => {
36
+ VERSION = true ? "0.18.2" : (() => {
37
37
  try {
38
38
  return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
39
39
  } catch {
@@ -57,6 +57,7 @@ __export(paths_exports, {
57
57
  LOG_PATH: () => LOG_PATH,
58
58
  MEDIA_PATH: () => MEDIA_PATH,
59
59
  RUNNERS_PATH: () => RUNNERS_PATH,
60
+ SESSION_LOGS_PATH: () => SESSION_LOGS_PATH,
60
61
  SKILLS_PATH: () => SKILLS_PATH,
61
62
  WORKSPACE_PATH: () => WORKSPACE_PATH
62
63
  });
@@ -70,7 +71,7 @@ function resolveRealHome() {
70
71
  }
71
72
  return homedir();
72
73
  }
73
- var CC_CLAW_HOME, ENV_PATH, DATA_PATH, DB_PATH, LOGS_PATH, LOG_PATH, ERROR_LOG_PATH, IDENTITY_PATH, WORKSPACE_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH, MEDIA_PATH;
74
+ var CC_CLAW_HOME, ENV_PATH, DATA_PATH, DB_PATH, LOGS_PATH, LOG_PATH, ERROR_LOG_PATH, IDENTITY_PATH, WORKSPACE_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH, SESSION_LOGS_PATH, MEDIA_PATH;
74
75
  var init_paths = __esm({
75
76
  "src/paths.ts"() {
76
77
  "use strict";
@@ -86,6 +87,7 @@ var init_paths = __esm({
86
87
  SKILLS_PATH = join2(WORKSPACE_PATH, "skills");
87
88
  RUNNERS_PATH = join2(CC_CLAW_HOME, "runners");
88
89
  AGENTS_PATH = join2(CC_CLAW_HOME, "agents");
90
+ SESSION_LOGS_PATH = join2(LOGS_PATH, "sessions");
89
91
  MEDIA_PATH = join2(CC_CLAW_HOME, "media");
90
92
  }
91
93
  });
@@ -1340,7 +1342,8 @@ function initSchema(db3) {
1340
1342
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
1341
1343
  last_run_at TEXT,
1342
1344
  next_run_at TEXT,
1343
- consecutive_failures INTEGER NOT NULL DEFAULT 0
1345
+ consecutive_failures INTEGER NOT NULL DEFAULT 0,
1346
+ allow_paid_slots INTEGER NOT NULL DEFAULT 0
1344
1347
  );
1345
1348
  `);
1346
1349
  try {
@@ -1496,6 +1499,10 @@ function initSchema(db3) {
1496
1499
  db3.exec("ALTER TABLE jobs ADD COLUMN job_type TEXT DEFAULT 'normal'");
1497
1500
  } catch {
1498
1501
  }
1502
+ try {
1503
+ db3.exec("ALTER TABLE jobs ADD COLUMN allow_paid_slots INTEGER NOT NULL DEFAULT 0");
1504
+ } catch {
1505
+ }
1499
1506
  try {
1500
1507
  db3.exec("UPDATE jobs SET job_type = 'reflection' WHERE description LIKE '%reflection analysis%' AND job_type = 'normal'");
1501
1508
  } catch {
@@ -1749,6 +1756,12 @@ function initSchema(db3) {
1749
1756
  value INTEGER NOT NULL DEFAULT 0
1750
1757
  );
1751
1758
  `);
1759
+ db3.exec(`
1760
+ CREATE TABLE IF NOT EXISTS chat_session_log (
1761
+ chat_id TEXT PRIMARY KEY,
1762
+ value INTEGER NOT NULL DEFAULT 0
1763
+ );
1764
+ `);
1752
1765
  db3.exec(`
1753
1766
  CREATE TABLE IF NOT EXISTS backend_credentials (
1754
1767
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -1773,6 +1786,13 @@ function initSchema(db3) {
1773
1786
  PRIMARY KEY (chat_id, backend)
1774
1787
  );
1775
1788
  `);
1789
+ db3.exec(`
1790
+ CREATE TABLE IF NOT EXISTS chat_allow_paid_slots (
1791
+ chat_id TEXT NOT NULL,
1792
+ backend TEXT NOT NULL,
1793
+ PRIMARY KEY (chat_id, backend)
1794
+ );
1795
+ `);
1776
1796
  try {
1777
1797
  const deleted = db3.prepare(
1778
1798
  "DELETE FROM usage_log WHERE created_at < datetime('now', '-90 days')"
@@ -2437,6 +2457,8 @@ var chat_settings_exports = {};
2437
2457
  __export(chat_settings_exports, {
2438
2458
  ALL_TOOLS: () => ALL_TOOLS,
2439
2459
  clearAgentMode: () => clearAgentMode,
2460
+ clearAllPaidSlots: () => clearAllPaidSlots,
2461
+ clearChatPaidSlots: () => clearChatPaidSlots,
2440
2462
  clearCwd: () => clearCwd,
2441
2463
  clearExecMode: () => clearExecMode,
2442
2464
  clearModel: () => clearModel,
@@ -2447,6 +2469,7 @@ __export(chat_settings_exports, {
2447
2469
  findBookmarksByPrefix: () => findBookmarksByPrefix,
2448
2470
  getAgentMode: () => getAgentMode,
2449
2471
  getAllBookmarks: () => getAllBookmarks,
2472
+ getAllowPaidSlots: () => getAllowPaidSlots,
2450
2473
  getBackend: () => getBackend,
2451
2474
  getBookmark: () => getBookmark,
2452
2475
  getCwd: () => getCwd,
@@ -2456,6 +2479,7 @@ __export(chat_settings_exports, {
2456
2479
  getModel: () => getModel,
2457
2480
  getPendingEscalation: () => getPendingEscalation,
2458
2481
  getRecentBookmarks: () => getRecentBookmarks,
2482
+ getSessionLogEnabled: () => getSessionLogEnabled,
2459
2483
  getShowThinkingUi: () => getShowThinkingUi,
2460
2484
  getSummarizer: () => getSummarizer,
2461
2485
  getThinkingLevel: () => getThinkingLevel,
@@ -2464,16 +2488,19 @@ __export(chat_settings_exports, {
2464
2488
  removePendingEscalation: () => removePendingEscalation,
2465
2489
  resetTools: () => resetTools,
2466
2490
  setAgentMode: () => setAgentMode,
2491
+ setAllowPaidSlots: () => setAllowPaidSlots,
2467
2492
  setBackend: () => setBackend,
2468
2493
  setCwd: () => setCwd,
2469
2494
  setExecMode: () => setExecMode,
2470
2495
  setMode: () => setMode,
2471
2496
  setModel: () => setModel,
2497
+ setSessionLogEnabled: () => setSessionLogEnabled,
2472
2498
  setShowThinkingUi: () => setShowThinkingUi,
2473
2499
  setSummarizer: () => setSummarizer,
2474
2500
  setThinkingLevel: () => setThinkingLevel,
2475
2501
  setVerboseLevel: () => setVerboseLevel,
2476
2502
  storePendingEscalation: () => storePendingEscalation,
2503
+ toggleSessionLogEnabled: () => toggleSessionLogEnabled,
2477
2504
  toggleShowThinkingUi: () => toggleShowThinkingUi,
2478
2505
  toggleTool: () => toggleTool,
2479
2506
  touchBookmark: () => touchBookmark,
@@ -2744,6 +2771,42 @@ function setExecMode(chatId, mode) {
2744
2771
  function clearExecMode(chatId) {
2745
2772
  getDb().prepare("DELETE FROM chat_exec_mode WHERE chat_id = ?").run(chatId);
2746
2773
  }
2774
+ function getSessionLogEnabled(chatId) {
2775
+ const row = getDb().prepare(
2776
+ "SELECT value FROM chat_session_log WHERE chat_id = ?"
2777
+ ).get(chatId);
2778
+ return (row?.value ?? 0) === 1;
2779
+ }
2780
+ function setSessionLogEnabled(chatId, enabled) {
2781
+ getDb().prepare(`
2782
+ INSERT INTO chat_session_log (chat_id, value)
2783
+ VALUES (?, ?)
2784
+ ON CONFLICT(chat_id) DO UPDATE SET value = ?
2785
+ `).run(chatId, enabled ? 1 : 0, enabled ? 1 : 0);
2786
+ }
2787
+ function toggleSessionLogEnabled(chatId) {
2788
+ const current = getSessionLogEnabled(chatId);
2789
+ const next = !current;
2790
+ setSessionLogEnabled(chatId, next);
2791
+ return next;
2792
+ }
2793
+ function getAllowPaidSlots(chatId, backend2) {
2794
+ const row = getDb().prepare(
2795
+ "SELECT 1 FROM chat_allow_paid_slots WHERE chat_id = ? AND backend = ?"
2796
+ ).get(chatId, backend2);
2797
+ return !!row;
2798
+ }
2799
+ function setAllowPaidSlots(chatId, backend2) {
2800
+ getDb().prepare(`
2801
+ INSERT OR IGNORE INTO chat_allow_paid_slots (chat_id, backend) VALUES (?, ?)
2802
+ `).run(chatId, backend2);
2803
+ }
2804
+ function clearChatPaidSlots(chatId) {
2805
+ getDb().prepare("DELETE FROM chat_allow_paid_slots WHERE chat_id = ?").run(chatId);
2806
+ }
2807
+ function clearAllPaidSlots() {
2808
+ getDb().prepare("DELETE FROM chat_allow_paid_slots").run();
2809
+ }
2747
2810
  var pendingEscalations, ESCALATION_TTL_MS, ALL_TOOLS;
2748
2811
  var init_chat_settings = __esm({
2749
2812
  "src/memory/chat-settings.ts"() {
@@ -3008,8 +3071,8 @@ function insertJob(params) {
3008
3071
  const db3 = getDb();
3009
3072
  const result = db3.prepare(`
3010
3073
  INSERT INTO jobs (schedule_type, cron, at_time, every_ms, title, description, chat_id,
3011
- backend, model, thinking, timeout, fallbacks, session_type, channel, target, delivery_mode, timezone, job_type)
3012
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3074
+ backend, model, thinking, timeout, fallbacks, session_type, channel, target, delivery_mode, timezone, job_type, allow_paid_slots)
3075
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3013
3076
  `).run(
3014
3077
  params.scheduleType,
3015
3078
  params.cron ?? null,
@@ -3028,13 +3091,15 @@ function insertJob(params) {
3028
3091
  params.target ?? null,
3029
3092
  params.deliveryMode ?? "announce",
3030
3093
  params.timezone ?? "UTC",
3031
- params.jobType ?? "normal"
3094
+ params.jobType ?? "normal",
3095
+ params.allowPaidSlots ? 1 : 0
3032
3096
  );
3033
3097
  return getJobById(Number(result.lastInsertRowid));
3034
3098
  }
3035
3099
  function mapJobRow(row) {
3036
3100
  if (!row) return void 0;
3037
3101
  row.fallbacks = row.fallbacks ? JSON.parse(row.fallbacks) : [];
3102
+ row.allowPaidSlots = !!row.allowPaidSlots;
3038
3103
  return row;
3039
3104
  }
3040
3105
  function getJobById(id) {
@@ -3088,7 +3153,8 @@ function updateJob(id, fields) {
3088
3153
  target: "target",
3089
3154
  deliveryMode: "delivery_mode",
3090
3155
  timezone: "timezone",
3091
- jobType: "job_type"
3156
+ jobType: "job_type",
3157
+ allowPaidSlots: "allow_paid_slots"
3092
3158
  };
3093
3159
  for (const [key, val] of Object.entries(fields)) {
3094
3160
  const col = fieldMap[key];
@@ -3160,7 +3226,8 @@ var init_jobs = __esm({
3160
3226
  title, description, chat_id as chatId, backend, model, thinking, timeout, fallbacks,
3161
3227
  session_type as sessionType, channel, target, delivery_mode as deliveryMode,
3162
3228
  timezone, job_type as jobType, enabled, active, created_at as createdAt, last_run_at as lastRunAt,
3163
- next_run_at as nextRunAt, consecutive_failures as consecutiveFailures
3229
+ next_run_at as nextRunAt, consecutive_failures as consecutiveFailures,
3230
+ allow_paid_slots as allowPaidSlots
3164
3231
  FROM jobs
3165
3232
  `;
3166
3233
  }
@@ -3340,9 +3407,13 @@ function getGeminiSlots() {
3340
3407
  FROM gemini_credentials ORDER BY priority ASC, id ASC
3341
3408
  `).all();
3342
3409
  }
3343
- function getEligibleGeminiSlots(mode) {
3410
+ function getEligibleGeminiSlots(mode, allowPaid) {
3344
3411
  if (mode === "off") return [];
3345
- const slotTypeFilter = mode === "accounts" ? "AND slot_type = 'oauth'" : mode === "keys" ? "AND slot_type = 'api_key'" : "";
3412
+ const effectiveAllowPaid = mode === "keys" ? true : allowPaid ?? false;
3413
+ const slotTypeFilter = mode === "accounts" ? "AND slot_type = 'oauth'" : mode === "keys" ? "AND slot_type = 'api_key'" : (
3414
+ // "all" or undefined: exclude paid slots unless allowed
3415
+ !effectiveAllowPaid ? "AND slot_type != 'api_key'" : ""
3416
+ );
3346
3417
  return getDb().prepare(`
3347
3418
  SELECT id, slot_type AS slotType, label, api_key AS apiKey, config_home AS configHome,
3348
3419
  priority, enabled, cooldown_until AS cooldownUntil, last_used AS lastUsed,
@@ -3350,7 +3421,8 @@ function getEligibleGeminiSlots(mode) {
3350
3421
  FROM gemini_credentials
3351
3422
  WHERE enabled = 1 AND (cooldown_until IS NULL OR cooldown_until <= datetime('now'))
3352
3423
  ${slotTypeFilter}
3353
- ORDER BY priority ASC, last_used ASC NULLS FIRST
3424
+ ORDER BY CASE WHEN slot_type = 'api_key' THEN 1 ELSE 0 END ASC,
3425
+ priority ASC, last_used ASC NULLS FIRST
3354
3426
  `).all();
3355
3427
  }
3356
3428
  function getChatGeminiSlotId(chatId) {
@@ -3443,13 +3515,20 @@ function getBackendSlots(backend2) {
3443
3515
  FROM backend_credentials bc WHERE bc.backend = ? ORDER BY bc.priority ASC, bc.id ASC
3444
3516
  `).all(backend2);
3445
3517
  }
3446
- function getEligibleBackendSlots(backend2) {
3518
+ function getEligibleBackendSlots(backend2, mode, allowPaid) {
3519
+ if (mode === "off") return [];
3520
+ const slotTypeFilter = mode === "accounts" ? "AND bc.slot_type = 'oauth'" : mode === "keys" ? "AND bc.slot_type = 'api_key'" : (
3521
+ // "all" or undefined: exclude paid slots unless allowed
3522
+ !allowPaid ? "AND bc.slot_type != 'api_key'" : ""
3523
+ );
3447
3524
  return getDb().prepare(`
3448
3525
  SELECT ${SLOT_COLUMNS}
3449
3526
  FROM backend_credentials bc
3450
3527
  WHERE bc.backend = ? AND bc.enabled = 1
3451
3528
  AND (bc.cooldown_until IS NULL OR bc.cooldown_until <= datetime('now'))
3452
- ORDER BY bc.priority ASC, bc.last_used ASC NULLS FIRST
3529
+ ${slotTypeFilter}
3530
+ ORDER BY CASE WHEN bc.slot_type = 'api_key' THEN 1 ELSE 0 END ASC,
3531
+ bc.priority ASC, bc.last_used ASC NULLS FIRST
3453
3532
  `).all(backend2);
3454
3533
  }
3455
3534
  function getChatBackendSlotId(chatId, backend2) {
@@ -3520,6 +3599,13 @@ function reenableBackendSlot(slotId) {
3520
3599
  WHERE id = ?
3521
3600
  `).run(slotId);
3522
3601
  }
3602
+ function getBackendRotationMode(backend2) {
3603
+ const row = getDb().prepare("SELECT value FROM meta WHERE key = ?").get(`${backend2}_rotation_mode`);
3604
+ return row?.value ?? "all";
3605
+ }
3606
+ function setBackendRotationMode(backend2, mode) {
3607
+ getDb().prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run(`${backend2}_rotation_mode`, mode);
3608
+ }
3523
3609
  var SLOT_COLUMNS;
3524
3610
  var init_backend_slots = __esm({
3525
3611
  "src/memory/backend-slots.ts"() {
@@ -3546,10 +3632,12 @@ __export(store_exports5, {
3546
3632
  checkBackendLimits: () => checkBackendLimits,
3547
3633
  cleanExpiredWatches: () => cleanExpiredWatches,
3548
3634
  clearAgentMode: () => clearAgentMode,
3635
+ clearAllPaidSlots: () => clearAllPaidSlots,
3549
3636
  clearAllSessions: () => clearAllSessions,
3550
3637
  clearBackendLimit: () => clearBackendLimit,
3551
3638
  clearChatBackendSlot: () => clearChatBackendSlot,
3552
3639
  clearChatGeminiSlot: () => clearChatGeminiSlot,
3640
+ clearChatPaidSlots: () => clearChatPaidSlots,
3553
3641
  clearCwd: () => clearCwd,
3554
3642
  clearExecMode: () => clearExecMode,
3555
3643
  clearMessageLog: () => clearMessageLog,
@@ -3575,8 +3663,10 @@ __export(store_exports5, {
3575
3663
  getAllMemoriesWithEmbeddings: () => getAllMemoriesWithEmbeddings,
3576
3664
  getAllSessionSummariesWithEmbeddings: () => getAllSessionSummariesWithEmbeddings,
3577
3665
  getAllTimeUsage: () => getAllTimeUsage,
3666
+ getAllowPaidSlots: () => getAllowPaidSlots,
3578
3667
  getBackend: () => getBackend,
3579
3668
  getBackendLimit: () => getBackendLimit,
3669
+ getBackendRotationMode: () => getBackendRotationMode,
3580
3670
  getBackendSlots: () => getBackendSlots,
3581
3671
  getBackendUsageInWindow: () => getBackendUsageInWindow,
3582
3672
  getBookmark: () => getBookmark,
@@ -3608,6 +3698,7 @@ __export(store_exports5, {
3608
3698
  getRecentMessageLog: () => getRecentMessageLog,
3609
3699
  getResponseStyle: () => getResponseStyle,
3610
3700
  getSessionId: () => getSessionId,
3701
+ getSessionLogEnabled: () => getSessionLogEnabled,
3611
3702
  getSessionStartedAt: () => getSessionStartedAt,
3612
3703
  getSessionSummaries: () => getSessionSummaries,
3613
3704
  getSessionSummariesWithoutEmbeddings: () => getSessionSummariesWithoutEmbeddings,
@@ -3655,8 +3746,10 @@ __export(store_exports5, {
3655
3746
  searchMessageLog: () => searchMessageLog,
3656
3747
  searchSessionSummaries: () => searchSessionSummaries,
3657
3748
  setAgentMode: () => setAgentMode,
3749
+ setAllowPaidSlots: () => setAllowPaidSlots,
3658
3750
  setBackend: () => setBackend,
3659
3751
  setBackendLimit: () => setBackendLimit,
3752
+ setBackendRotationMode: () => setBackendRotationMode,
3660
3753
  setBackendSlotEnabled: () => setBackendSlotEnabled,
3661
3754
  setBootTime: () => setBootTime,
3662
3755
  setChatAlias: () => setChatAlias,
@@ -3670,6 +3763,7 @@ __export(store_exports5, {
3670
3763
  setModelSignature: () => setModelSignature,
3671
3764
  setResponseStyle: () => setResponseStyle,
3672
3765
  setSessionId: () => setSessionId,
3766
+ setSessionLogEnabled: () => setSessionLogEnabled,
3673
3767
  setSessionStartedAt: () => setSessionStartedAt,
3674
3768
  setShowThinkingUi: () => setShowThinkingUi,
3675
3769
  setSummarizer: () => setSummarizer,
@@ -3677,6 +3771,7 @@ __export(store_exports5, {
3677
3771
  setVerboseLevel: () => setVerboseLevel,
3678
3772
  storePendingEscalation: () => storePendingEscalation,
3679
3773
  toFts5Query: () => toFts5Query,
3774
+ toggleSessionLogEnabled: () => toggleSessionLogEnabled,
3680
3775
  toggleShowThinkingUi: () => toggleShowThinkingUi,
3681
3776
  toggleTool: () => toggleTool,
3682
3777
  touchBookmark: () => touchBookmark,
@@ -10359,11 +10454,11 @@ var init_evolve = __esm({
10359
10454
  const body = JSON.parse(await readBody(req));
10360
10455
  const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
10361
10456
  const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
10362
- const { join: join34 } = await import("path");
10457
+ const { join: join35 } = await import("path");
10363
10458
  const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
10364
10459
  const chatId = body.chatId || (process.env.ALLOWED_CHAT_ID ?? "").split(",")[0]?.trim() || "default";
10365
- const soulPath = join34(home, "identity/SOUL.md");
10366
- const userPath = join34(home, "identity/USER.md");
10460
+ const soulPath = join35(home, "identity/SOUL.md");
10461
+ const userPath = join35(home, "identity/USER.md");
10367
10462
  const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
10368
10463
  const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
10369
10464
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
@@ -10853,6 +10948,7 @@ var init_detect = __esm({
10853
10948
  var agent_exports = {};
10854
10949
  __export(agent_exports, {
10855
10950
  FIRST_RESPONSE_TIMEOUT_ERROR: () => FIRST_RESPONSE_TIMEOUT_ERROR,
10951
+ FREE_SLOTS_EXHAUSTED: () => FREE_SLOTS_EXHAUSTED,
10856
10952
  askAgent: () => askAgent,
10857
10953
  getInFlightMessage: () => getInFlightMessage,
10858
10954
  isChatBusy: () => isChatBusy,
@@ -11167,9 +11263,15 @@ Partial output: ${accumulatedText.slice(-500)}`;
11167
11263
  });
11168
11264
  });
11169
11265
  }
11170
- async function spawnWithSlotRotation(chatId, adapter, baseConfig, configWithSession, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, opts, onSlotRotation) {
11171
- const slots = getEligibleBackendSlots(adapter.id);
11266
+ async function spawnWithSlotRotation(chatId, adapter, baseConfig, configWithSession, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, rotationMode, allowPaid, opts, onSlotRotation) {
11267
+ const effectiveAllowPaid = rotationMode === "keys" ? true : allowPaid;
11268
+ const slots = getEligibleBackendSlots(adapter.id, rotationMode, effectiveAllowPaid);
11172
11269
  if (slots.length === 0) {
11270
+ const allSlots = getBackendSlots(adapter.id).filter((s) => s.enabled);
11271
+ const paidSlots = allSlots.filter((s) => s.slotType === "api_key");
11272
+ if (!effectiveAllowPaid && paidSlots.length > 0) {
11273
+ throw new Error(`${FREE_SLOTS_EXHAUSTED}|${adapter.id}|${paidSlots.length}`);
11274
+ }
11173
11275
  return spawnQuery(adapter, configWithSession, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, opts);
11174
11276
  }
11175
11277
  const maxAttempts = slots.length;
@@ -11201,7 +11303,7 @@ async function spawnWithSlotRotation(chatId, adapter, baseConfig, configWithSess
11201
11303
  clearSession(chatId);
11202
11304
  } catch {
11203
11305
  }
11204
- const nextSlot = getEligibleBackendSlots(adapter.id)[0];
11306
+ const nextSlot = getEligibleBackendSlots(adapter.id, rotationMode, effectiveAllowPaid)[0];
11205
11307
  if (nextSlot && onSlotRotation) {
11206
11308
  const nextLabel = nextSlot.label || `slot-${nextSlot.id}`;
11207
11309
  onSlotRotation(slotLabel, nextLabel);
@@ -11212,11 +11314,18 @@ async function spawnWithSlotRotation(chatId, adapter, baseConfig, configWithSess
11212
11314
  throw err;
11213
11315
  }
11214
11316
  }
11317
+ if (!effectiveAllowPaid) {
11318
+ const paidSlots = getBackendSlots(adapter.id).filter((s) => s.enabled && s.slotType === "api_key");
11319
+ if (paidSlots.length > 0) {
11320
+ throw new Error(`${FREE_SLOTS_EXHAUSTED}|${adapter.id}|${paidSlots.length}`);
11321
+ }
11322
+ }
11215
11323
  throw lastError ?? new Error(`All ${adapter.id} credential slots exhausted`);
11216
11324
  }
11217
11325
  async function spawnGeminiWithRotation(chatId, adapter, baseConfig, configWithSession, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, rotationMode, opts, onSlotRotation, parentChatId, onModelDowngrade) {
11218
11326
  const geminiAdapter = adapter;
11219
- const slots = getEligibleGeminiSlots(rotationMode);
11327
+ const effectiveAllowPaid = rotationMode === "keys" ? true : getAllowPaidSlots(chatId, "gemini");
11328
+ const slots = getEligibleGeminiSlots(rotationMode, effectiveAllowPaid);
11220
11329
  if (slots.length === 0) {
11221
11330
  return spawnQuery(adapter, configWithSession, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, opts);
11222
11331
  }
@@ -11295,7 +11404,7 @@ async function spawnGeminiWithRotation(chatId, adapter, baseConfig, configWithSe
11295
11404
  clearSession(chatId);
11296
11405
  } catch {
11297
11406
  }
11298
- const nextSlot = getEligibleGeminiSlots(rotationMode)[0];
11407
+ const nextSlot = getEligibleGeminiSlots(rotationMode, effectiveAllowPaid)[0];
11299
11408
  if (nextSlot && onSlotRotation) {
11300
11409
  const nextLabel = nextSlot.label || `slot-${nextSlot.id}`;
11301
11410
  onSlotRotation(slotLabel, nextLabel);
@@ -11380,17 +11489,19 @@ async function askAgentImpl(chatId, userMessage, opts) {
11380
11489
  };
11381
11490
  const resolvedModel = model2 ?? adapter.defaultModel;
11382
11491
  let result = { resultText: "", sessionId: void 0, input: 0, output: 0, cacheRead: 0, sawToolEvents: false, sawResultEvent: false };
11383
- const rotationMode = adapter.id === "gemini" ? getGeminiRotationMode() : "off";
11384
- const useGeminiRotation = rotationMode !== "off" && getEligibleGeminiSlots(rotationMode).length > 0;
11385
- const useBackendRotation = adapter.id !== "gemini" && getEligibleBackendSlots(adapter.id).length > 0;
11492
+ const geminiRotationMode = adapter.id === "gemini" ? getGeminiRotationMode() : "off";
11493
+ const backendRotationMode = adapter.id !== "gemini" ? getBackendRotationMode(adapter.id) : "off";
11494
+ const allowPaid = getAllowPaidSlots(chatId, adapter.id);
11495
+ const useGeminiRotation = geminiRotationMode !== "off" && getEligibleGeminiSlots(geminiRotationMode, allowPaid).length > 0;
11496
+ const useBackendRotation = adapter.id !== "gemini" && (backendRotationMode !== "off" || getBackendSlots(adapter.id).filter((s) => s.enabled).length > 0);
11386
11497
  try {
11387
11498
  if (useGeminiRotation) {
11388
11499
  const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
11389
11500
  const downgradeCb = onModelDowngrade ? (from, to, reason) => onModelDowngrade(chatId, from, to, reason) : void 0;
11390
- result = await spawnGeminiWithRotation(chatId, adapter, baseConfig, configWithSession, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, rotationMode, spawnOpts, rotationCb, settingsSourceChatId, downgradeCb);
11501
+ result = await spawnGeminiWithRotation(chatId, adapter, baseConfig, configWithSession, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, geminiRotationMode, spawnOpts, rotationCb, settingsSourceChatId, downgradeCb);
11391
11502
  } else if (useBackendRotation) {
11392
11503
  const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
11393
- result = await spawnWithSlotRotation(chatId, adapter, baseConfig, configWithSession, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, spawnOpts, rotationCb);
11504
+ result = await spawnWithSlotRotation(chatId, adapter, baseConfig, configWithSession, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, backendRotationMode, allowPaid, spawnOpts, rotationCb);
11394
11505
  } else {
11395
11506
  const slotSpawnOpts = (() => {
11396
11507
  if (adapter.id !== "gemini") return spawnOpts;
@@ -11441,10 +11552,10 @@ async function askAgentImpl(chatId, userMessage, opts) {
11441
11552
  if (useGeminiRotation) {
11442
11553
  const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
11443
11554
  const downgradeCb = onModelDowngrade ? (from, to, reason) => onModelDowngrade(chatId, from, to, reason) : void 0;
11444
- result = await spawnGeminiWithRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, rotationMode, spawnOpts, rotationCb, settingsSourceChatId, downgradeCb);
11555
+ result = await spawnGeminiWithRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, geminiRotationMode, spawnOpts, rotationCb, settingsSourceChatId, downgradeCb);
11445
11556
  } else if (useBackendRotation) {
11446
11557
  const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
11447
- result = await spawnWithSlotRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, spawnOpts, rotationCb);
11558
+ result = await spawnWithSlotRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, backendRotationMode, allowPaid, spawnOpts, rotationCb);
11448
11559
  } else {
11449
11560
  const retryOpts = (() => {
11450
11561
  if (adapter.id !== "gemini") return spawnOpts;
@@ -11464,10 +11575,10 @@ async function askAgentImpl(chatId, userMessage, opts) {
11464
11575
  if (useGeminiRotation) {
11465
11576
  const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
11466
11577
  const downgradeCb = onModelDowngrade ? (from, to, reason) => onModelDowngrade(chatId, from, to, reason) : void 0;
11467
- result = await spawnGeminiWithRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, rotationMode, spawnOpts, rotationCb, settingsSourceChatId, downgradeCb);
11578
+ result = await spawnGeminiWithRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, geminiRotationMode, spawnOpts, rotationCb, settingsSourceChatId, downgradeCb);
11468
11579
  } else if (useBackendRotation) {
11469
11580
  const rotationCb = onSlotRotation ? (from, to) => onSlotRotation(chatId, from, to) : void 0;
11470
- result = await spawnWithSlotRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, spawnOpts, rotationCb);
11581
+ result = await spawnWithSlotRotation(chatId, adapter, baseConfig, baseConfig, resolvedModel, cancelState, thinkingLevel, timeoutMs, maxTurns, backendRotationMode, allowPaid, spawnOpts, rotationCb);
11471
11582
  } else {
11472
11583
  const retryOpts = (() => {
11473
11584
  if (adapter.id !== "gemini") return spawnOpts;
@@ -11582,7 +11693,7 @@ function injectMcpConfig(adapterId, args, mcpConfigPath) {
11582
11693
  if (!flag) return args;
11583
11694
  return [...args, ...flag, mcpConfigPath];
11584
11695
  }
11585
- var activeChats, chatLocks, SPAWN_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_ERROR, GEMINI_FALLBACK_CHAIN, GEMINI_DOWNGRADE_MODELS, MCP_CONFIG_FLAG;
11696
+ var activeChats, chatLocks, SPAWN_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_ERROR, FREE_SLOTS_EXHAUSTED, GEMINI_FALLBACK_CHAIN, GEMINI_DOWNGRADE_MODELS, MCP_CONFIG_FLAG;
11586
11697
  var init_agent = __esm({
11587
11698
  "src/agent.ts"() {
11588
11699
  "use strict";
@@ -11608,6 +11719,7 @@ var init_agent = __esm({
11608
11719
  SPAWN_TIMEOUT_MS = 10 * 60 * 1e3;
11609
11720
  FIRST_RESPONSE_TIMEOUT_MS = parseInt(process.env.GEMINI_FIRST_RESPONSE_TIMEOUT_MS ?? "30000", 10);
11610
11721
  FIRST_RESPONSE_TIMEOUT_ERROR = "FIRST_RESPONSE_TIMEOUT";
11722
+ FREE_SLOTS_EXHAUSTED = "FREE_SLOTS_EXHAUSTED";
11611
11723
  GEMINI_FALLBACK_CHAIN = {
11612
11724
  "gemini-3.1-pro-preview": "gemini-2.5-pro",
11613
11725
  "gemini-2.5-pro": "gemini-3.1-flash-preview"
@@ -13400,18 +13512,18 @@ function formatToolStart(toolName, input, level) {
13400
13512
  return `\u{1F527} ${toolName}${cmd ? `: ${cmd}` : path ? `: ${path}` : query ? `: ${query}` : ""}`;
13401
13513
  }
13402
13514
  }
13403
- const inputStr = JSON.stringify(input, null, 2).slice(0, 600);
13515
+ const inputStr = JSON.stringify(input, null, 2).slice(0, 300);
13404
13516
  return `\u{1F527} ${toolName}:
13405
13517
  \`\`\`json
13406
13518
  ${inputStr}
13407
13519
  \`\`\``;
13408
13520
  }
13409
13521
  function formatToolResult(toolName, result) {
13410
- const trimmed = result.trim().slice(0, 400);
13522
+ const trimmed = result.trim().slice(0, 250);
13411
13523
  if (!trimmed) return "";
13412
13524
  const firstLine = trimmed.split("\n")[0] ?? "";
13413
13525
  const isError = /error|failed|exception/i.test(firstLine);
13414
- return isError ? `\u274C ${firstLine.slice(0, 120)}` : `\u{1F4E4} Result:
13526
+ return isError ? `\u274C ${firstLine.slice(0, 120)}` : `\u{1F4EC} Result:
13415
13527
  \`\`\`
13416
13528
  ${trimmed}
13417
13529
  \`\`\``;
@@ -13971,6 +14083,17 @@ var init_image_gen = __esm({
13971
14083
  });
13972
14084
 
13973
14085
  // src/router/response.ts
14086
+ var response_exports = {};
14087
+ __export(response_exports, {
14088
+ ensureReaction: () => ensureReaction,
14089
+ handleResponseExhaustion: () => handleResponseExhaustion,
14090
+ makeToolActionCallback: () => makeToolActionCallback,
14091
+ pendingFallbackMessages: () => pendingFallbackMessages,
14092
+ processFileSends: () => processFileSends2,
14093
+ processImageGenerations: () => processImageGenerations,
14094
+ processReaction: () => processReaction,
14095
+ sendResponse: () => sendResponse
14096
+ });
13974
14097
  import { readFile as readFile3 } from "fs/promises";
13975
14098
  function makeToolActionCallback(chatId, channel, level) {
13976
14099
  return async (toolName, input, result) => {
@@ -16478,13 +16601,13 @@ async function handleEvolveCallback(chatId, data, channel) {
16478
16601
  const { getReflectionStatus: getReflectionStatus2, setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16479
16602
  const current = getReflectionStatus2(getDb(), chatId);
16480
16603
  if (current === "frozen") {
16481
- const { readFileSync: readFileSync26, existsSync: existsSync54 } = await import("fs");
16482
- const { join: join34 } = await import("path");
16604
+ const { readFileSync: readFileSync27, existsSync: existsSync56 } = await import("fs");
16605
+ const { join: join35 } = await import("path");
16483
16606
  const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
16484
- const soulPath = join34(CC_CLAW_HOME3, "identity/SOUL.md");
16485
- const userPath = join34(CC_CLAW_HOME3, "identity/USER.md");
16486
- const soul = existsSync54(soulPath) ? readFileSync26(soulPath, "utf-8") : "";
16487
- const user = existsSync54(userPath) ? readFileSync26(userPath, "utf-8") : "";
16607
+ const soulPath = join35(CC_CLAW_HOME3, "identity/SOUL.md");
16608
+ const userPath = join35(CC_CLAW_HOME3, "identity/USER.md");
16609
+ const soul = existsSync56(soulPath) ? readFileSync27(soulPath, "utf-8") : "";
16610
+ const user = existsSync56(userPath) ? readFileSync27(userPath, "utf-8") : "";
16488
16611
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
16489
16612
  const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
16490
16613
  logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
@@ -17888,6 +18011,7 @@ Tap to toggle:`,
17888
18011
  const exchangeCount = getMessagePairCount(chatId);
17889
18012
  const summarized = await summarizeSession(chatId);
17890
18013
  clearSession(chatId);
18014
+ clearChatPaidSlots(chatId);
17891
18015
  setSessionStartedAt(chatId);
17892
18016
  logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: "New session started", detail: { field: "session", action: "reset", summarized } });
17893
18017
  if (typeof channel.sendKeyboard === "function" && oldSessionId) {
@@ -18208,6 +18332,7 @@ Add with: <code>cc-claw ${slotBackend} add-key</code>`, { parseMode: "html" });
18208
18332
  break;
18209
18333
  }
18210
18334
  if (typeof channel.sendKeyboard === "function") {
18335
+ const currentMode = getBackendRotationMode(slotBackend);
18211
18336
  const pinnedSlotId = getChatBackendSlotId(chatId, slotBackend);
18212
18337
  const slotButtons = slots.filter((s) => s.enabled).map((s) => {
18213
18338
  const label2 = s.label || `slot-${s.id}`;
@@ -18220,8 +18345,15 @@ Add with: <code>cc-claw ${slotBackend} add-key</code>`, { parseMode: "html" });
18220
18345
  rows.push(slotButtons.slice(i, i + 2));
18221
18346
  }
18222
18347
  rows.push([{ label: "\u{1F504} Auto (rotation)", data: `bslot:${slotBackend}:auto` }]);
18223
- await channel.sendKeyboard(chatId, `${slotDisplayName} Accounts:`, rows);
18348
+ const modeLabels = { off: "Off", all: "All", accounts: "\u{1F468}\u{1F3FD}\u200D\u{1F4BB} Only", keys: "\u{1F511} Only" };
18349
+ const modeButtons = ["off", "all", "accounts", "keys"].map((m) => ({
18350
+ label: `${m === currentMode ? "\u2713 " : ""}${modeLabels[m]}`,
18351
+ data: `brotation:${slotBackend}:${m}`
18352
+ }));
18353
+ rows.push(modeButtons);
18354
+ await channel.sendKeyboard(chatId, `${slotDisplayName} Accounts & Rotation:`, rows);
18224
18355
  } else {
18356
+ const currentMode = getBackendRotationMode(slotBackend);
18225
18357
  const list = slots.filter((s) => s.enabled).map((s) => {
18226
18358
  const icon = s.slotType === "oauth" ? "\u{1F468}\u{1F3FD}\u200D\u{1F4BB}" : "\u{1F511}";
18227
18359
  return `${icon} ${s.label || `slot-${s.id}`} (#${s.id})`;
@@ -18229,6 +18361,7 @@ Add with: <code>cc-claw ${slotBackend} add-key</code>`, { parseMode: "html" });
18229
18361
  await channel.sendText(chatId, `${slotDisplayName} Slots:
18230
18362
  ${list}
18231
18363
 
18364
+ Rotation mode: ${currentMode}
18232
18365
  Use: /${command} <name> to pin`, { parseMode: "plain" });
18233
18366
  }
18234
18367
  break;
@@ -18395,8 +18528,8 @@ ${lines.join("\n")}`, { parseMode: "plain" });
18395
18528
  if (arg.startsWith("/") || arg.startsWith("~")) {
18396
18529
  const resolvedPath = arg.startsWith("~") ? arg.replace("~", process.env.HOME ?? "") : arg;
18397
18530
  setCwd(chatId, resolvedPath);
18398
- const basename3 = resolvedPath.split("/").filter(Boolean).pop();
18399
- if (basename3) upsertBookmark(chatId, basename3, resolvedPath, false);
18531
+ const basename4 = resolvedPath.split("/").filter(Boolean).pop();
18532
+ if (basename4) upsertBookmark(chatId, basename4, resolvedPath, false);
18400
18533
  logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Working directory set to ${resolvedPath}`, detail: { field: "cwd", value: resolvedPath } });
18401
18534
  await sendCwdSessionChoice(chatId, resolvedPath, channel);
18402
18535
  return;
@@ -18572,7 +18705,9 @@ Use /model to pick a model with \u26A1 thinking support.`, { parseMode: "plain"
18572
18705
  chatId,
18573
18706
  `\u{1F4AD} Thinking Level \u2014 ${shortModelName(currentModel)}
18574
18707
  Current: ${capitalize(currentLevel)}
18575
- Show thinking tokens: ${showThinkingUi ? "On" : "Off"}${adapter.id === "gemini" ? "\n\n\u26A0\uFE0F Gemini CLI doesn't stream thinking tokens" : ""}`,
18708
+ Show thinking tokens: ${showThinkingUi ? "On" : "Off"}${adapter.id !== "claude" ? `
18709
+
18710
+ \u26A0\uFE0F ${adapter.displayName} CLI doesn't stream thinking tokens` : ""}`,
18576
18711
  buttons
18577
18712
  );
18578
18713
  } else {
@@ -18584,6 +18719,37 @@ Set via callback (keyboard required).`, { parseMode: "plain" });
18584
18719
  }
18585
18720
  break;
18586
18721
  }
18722
+ case "debug": {
18723
+ const { getSessionLogEnabled: getSessionLogEnabled2, toggleSessionLogEnabled: toggleSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
18724
+ const current = getSessionLogEnabled2(chatId);
18725
+ if (commandArgs === "on" || commandArgs === "off") {
18726
+ const { setSessionLogEnabled: setSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
18727
+ const value = commandArgs === "on";
18728
+ setSessionLogEnabled2(chatId, value);
18729
+ await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${value ? "ON" : "OFF"}
18730
+
18731
+ ${value ? "Full tool inputs/results will be saved to ~/.cc-claw/logs/sessions/\nUse 'cc-claw logs session list' or 'cc-claw logs session tail' to inspect." : "Session logs disabled."}`, { parseMode: "plain" });
18732
+ } else if (typeof channel.sendKeyboard === "function") {
18733
+ await channel.sendKeyboard(
18734
+ chatId,
18735
+ `\u{1F52C} Session Debug Logging
18736
+
18737
+ Records full, untruncated tool inputs and results to disk for debugging.
18738
+ Logs: ~/.cc-claw/logs/sessions/
18739
+ Retention: ${process.env.SESSION_LOG_RETENTION_DAYS ?? "7"} day(s)
18740
+
18741
+ Currently: ${current ? "ON" : "OFF"}`,
18742
+ [[
18743
+ { label: current ? "\u2713 ON" : "ON", data: "debug_log:on", ...current ? { style: "primary" } : {} },
18744
+ { label: !current ? "\u2713 OFF" : "OFF", data: "debug_log:off", ...!current ? { style: "primary" } : {} }
18745
+ ]]
18746
+ );
18747
+ } else {
18748
+ const next = toggleSessionLogEnabled2(chatId);
18749
+ await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${next ? "ON" : "OFF"}`, { parseMode: "plain" });
18750
+ }
18751
+ break;
18752
+ }
18587
18753
  case "imagine":
18588
18754
  case "image": {
18589
18755
  if (!commandArgs) {
@@ -19494,11 +19660,19 @@ Select thinking/effort level:`,
19494
19660
  backendId = getAdapterForChat(chatId).id;
19495
19661
  } catch {
19496
19662
  }
19497
- msg = backendId === "gemini" ? "\u{1F4AD} Thinking tokens enabled \u2014 but Gemini CLI doesn't stream them." : "\u{1F4AD} Thinking tokens will now stream live in the status message.";
19663
+ msg = backendId && backendId !== "claude" ? `\u{1F4AD} Thinking tokens enabled \u2014 but ${backendId.charAt(0).toUpperCase() + backendId.slice(1)} CLI doesn't stream them.` : "\u{1F4AD} Thinking tokens will now stream live in the status message.";
19498
19664
  } else {
19499
19665
  msg = "\u{1F4AD} Thinking tokens hidden. Toggle on again via /thinking.";
19500
19666
  }
19501
19667
  await channel.sendText(chatId, msg, { parseMode: "plain" });
19668
+ } else if (data.startsWith("debug_log:")) {
19669
+ const value = data.slice(10) === "on";
19670
+ const { setSessionLogEnabled: setSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
19671
+ setSessionLogEnabled2(chatId, value);
19672
+ logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Session debug log ${value ? "enabled" : "disabled"}`, detail: { field: "session_log", value: String(value) } });
19673
+ await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${value ? "ON" : "OFF"}
19674
+
19675
+ ${value ? "Full tool inputs/results will be saved to ~/.cc-claw/logs/sessions/" : "Session logs disabled."}`, { parseMode: "plain" });
19502
19676
  } else if (data.startsWith("summarizer:")) {
19503
19677
  const rest = data.slice(11);
19504
19678
  if (rest === "auto") {
@@ -19878,6 +20052,32 @@ Result: ${task.result.slice(0, 500)}` : ""
19878
20052
  const modeLabels = { off: "Off", all: "All", accounts: "\u{1F468}\u{1F3FD}\u200D\u{1F4BB} Accounts only", keys: "\u{1F511} Keys only" };
19879
20053
  await channel.sendText(chatId, `Rotation mode set to <b>${modeLabels[mode]}</b>.`, { parseMode: "html" });
19880
20054
  return;
20055
+ } else if (data.startsWith("brotation:")) {
20056
+ const parts = data.split(":");
20057
+ const backend2 = parts[1];
20058
+ const mode = parts[2];
20059
+ const validModes = ["off", "all", "accounts", "keys"];
20060
+ if (!validModes.includes(mode)) return;
20061
+ const displayName = backend2.charAt(0).toUpperCase() + backend2.slice(1);
20062
+ const slots = getBackendSlots(backend2);
20063
+ if (mode === "accounts") {
20064
+ const oauthSlots = slots.filter((s) => s.enabled && s.slotType === "oauth");
20065
+ if (oauthSlots.length === 0) {
20066
+ await channel.sendText(chatId, `\u26A0\uFE0F No ${displayName} OAuth accounts configured. Add one with <code>cc-claw ${backend2} add-account</code> or choose a different mode.`, { parseMode: "html" });
20067
+ return;
20068
+ }
20069
+ } else if (mode === "keys") {
20070
+ const keySlots = slots.filter((s) => s.enabled && s.slotType === "api_key");
20071
+ if (keySlots.length === 0) {
20072
+ await channel.sendText(chatId, `\u26A0\uFE0F No ${displayName} API keys configured. Add one with <code>cc-claw ${backend2} add-key</code> or choose a different mode.`, { parseMode: "html" });
20073
+ return;
20074
+ }
20075
+ }
20076
+ setBackendRotationMode(backend2, mode);
20077
+ clearSession(chatId);
20078
+ const modeLabelMap = { off: "Off", all: "All", accounts: "\u{1F468}\u{1F3FD}\u200D\u{1F4BB} Accounts only", keys: "\u{1F511} Keys only" };
20079
+ await channel.sendText(chatId, `${displayName} rotation mode set to <b>${modeLabelMap[mode]}</b>.`, { parseMode: "html" });
20080
+ return;
19881
20081
  } else if (data.startsWith("gslot:")) {
19882
20082
  const val = data.split(":")[1];
19883
20083
  if (val === "auto") {
@@ -19952,6 +20152,37 @@ ${rotationNote}`, { parseMode: "html" });
19952
20152
  }
19953
20153
  }
19954
20154
  return;
20155
+ } else if (data.startsWith("paidslot:")) {
20156
+ const parts = data.split(":");
20157
+ const action = parts[1];
20158
+ const backend2 = parts[2];
20159
+ const displayName = backend2.charAt(0).toUpperCase() + backend2.slice(1);
20160
+ if (action === "approve") {
20161
+ setAllowPaidSlots(chatId, backend2);
20162
+ await channel.sendText(chatId, `\u2705 Paid API key usage approved for ${displayName} (this session). Retrying\u2026`, { parseMode: "html" });
20163
+ const { pendingFallbackMessages: pendingFallbackMessages3 } = await Promise.resolve().then(() => (init_response(), response_exports));
20164
+ const pending = pendingFallbackMessages3.get(chatId);
20165
+ if (pending) {
20166
+ pendingFallbackMessages3.delete(chatId);
20167
+ const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router(), router_exports));
20168
+ await handleMessage2(pending.msg, pending.channel);
20169
+ }
20170
+ } else if (action === "deny") {
20171
+ const { pendingFallbackMessages: pendingFallbackMessages3 } = await Promise.resolve().then(() => (init_response(), response_exports));
20172
+ pendingFallbackMessages3.delete(chatId);
20173
+ const otherBackends = (await Promise.resolve().then(() => (init_backends(), backends_exports))).getAvailableAdapters().filter((a) => a.id !== backend2);
20174
+ if (typeof channel.sendKeyboard === "function" && otherBackends.length > 0) {
20175
+ const buttons = otherBackends.map((a) => ({
20176
+ label: `\u{1F504} ${a.displayName}`,
20177
+ data: `backend:${a.id}`,
20178
+ style: "primary"
20179
+ }));
20180
+ await channel.sendKeyboard(chatId, `Switch to another backend?`, [buttons]);
20181
+ } else {
20182
+ await channel.sendText(chatId, `Paid usage denied. Try again later or switch backend manually.`, { parseMode: "plain" });
20183
+ }
20184
+ }
20185
+ return;
19955
20186
  } else if (data.startsWith("shell:")) {
19956
20187
  const parts = data.split(":");
19957
20188
  const action = parts[1];
@@ -20417,6 +20648,206 @@ var init_callbacks = __esm({
20417
20648
  }
20418
20649
  });
20419
20650
 
20651
+ // src/router/session-log.ts
20652
+ var session_log_exports2 = {};
20653
+ __export(session_log_exports2, {
20654
+ SessionLogFile: () => SessionLogFile,
20655
+ cleanupSessionLogs: () => cleanupSessionLogs,
20656
+ getRetentionDays: () => getRetentionDays,
20657
+ listSessionLogs: () => listSessionLogs,
20658
+ startSessionLogCleanupTimer: () => startSessionLogCleanupTimer,
20659
+ tailSessionLog: () => tailSessionLog
20660
+ });
20661
+ import { existsSync as existsSync23, mkdirSync as mkdirSync9, appendFileSync, readdirSync as readdirSync12, unlinkSync as unlinkSync6, statSync as statSync7, createReadStream } from "fs";
20662
+ import { join as join24, basename as basename3 } from "path";
20663
+ import { createInterface as createInterface6 } from "readline";
20664
+ function getRetentionDays() {
20665
+ const env = process.env.SESSION_LOG_RETENTION_DAYS;
20666
+ if (env) {
20667
+ const n = parseInt(env, 10);
20668
+ if (!isNaN(n) && n > 0) return n;
20669
+ }
20670
+ return DEFAULT_RETENTION_DAYS;
20671
+ }
20672
+ function cleanupSessionLogs(retentionDays) {
20673
+ const days = retentionDays ?? getRetentionDays();
20674
+ if (!existsSync23(SESSION_LOGS_PATH)) return 0;
20675
+ const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
20676
+ let cleaned = 0;
20677
+ try {
20678
+ for (const file of readdirSync12(SESSION_LOGS_PATH)) {
20679
+ if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
20680
+ const filePath = join24(SESSION_LOGS_PATH, file);
20681
+ try {
20682
+ const { mtimeMs } = statSync7(filePath);
20683
+ if (mtimeMs < cutoff) {
20684
+ unlinkSync6(filePath);
20685
+ cleaned++;
20686
+ }
20687
+ } catch {
20688
+ }
20689
+ }
20690
+ } catch (err) {
20691
+ log(`[session-log] Cleanup failed: ${err}`);
20692
+ }
20693
+ if (cleaned > 0) {
20694
+ log(`[session-log] Cleaned ${cleaned} session log(s) older than ${days} day(s)`);
20695
+ }
20696
+ return cleaned;
20697
+ }
20698
+ function startSessionLogCleanupTimer() {
20699
+ const timer = setInterval(() => {
20700
+ cleanupSessionLogs();
20701
+ }, 24 * 60 * 60 * 1e3);
20702
+ timer.unref();
20703
+ return timer;
20704
+ }
20705
+ function listSessionLogs() {
20706
+ if (!existsSync23(SESSION_LOGS_PATH)) return [];
20707
+ const logs = [];
20708
+ for (const file of readdirSync12(SESSION_LOGS_PATH)) {
20709
+ if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
20710
+ const filePath = join24(SESSION_LOGS_PATH, file);
20711
+ try {
20712
+ const stat4 = statSync7(filePath);
20713
+ const match = file.match(/^session-(.+?)-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})\.log$/);
20714
+ logs.push({
20715
+ filename: file,
20716
+ filePath,
20717
+ chatId: match?.[1] ?? "unknown",
20718
+ timestamp: match?.[2]?.replace(/-/g, (m, i) => i > 9 ? ":" : m) ?? "unknown",
20719
+ sizeBytes: stat4.size,
20720
+ modifiedAt: stat4.mtime
20721
+ });
20722
+ } catch {
20723
+ }
20724
+ }
20725
+ logs.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
20726
+ return logs;
20727
+ }
20728
+ async function* tailSessionLog(filePath, lines = 50) {
20729
+ if (!existsSync23(filePath)) {
20730
+ yield `File not found: ${filePath}`;
20731
+ return;
20732
+ }
20733
+ const allLines = [];
20734
+ const rl2 = createInterface6({
20735
+ input: createReadStream(filePath, { encoding: "utf-8" }),
20736
+ crlfDelay: Infinity
20737
+ });
20738
+ for await (const line of rl2) {
20739
+ allLines.push(line);
20740
+ }
20741
+ const start = Math.max(0, allLines.length - lines);
20742
+ for (let i = start; i < allLines.length; i++) {
20743
+ yield allLines[i];
20744
+ }
20745
+ }
20746
+ var DEFAULT_RETENTION_DAYS, SessionLogFile;
20747
+ var init_session_log2 = __esm({
20748
+ "src/router/session-log.ts"() {
20749
+ "use strict";
20750
+ init_paths();
20751
+ init_log();
20752
+ DEFAULT_RETENTION_DAYS = 7;
20753
+ SessionLogFile = class {
20754
+ constructor(chatId, backend2, model2) {
20755
+ this.backend = backend2;
20756
+ this.model = model2;
20757
+ if (!existsSync23(SESSION_LOGS_PATH)) {
20758
+ mkdirSync9(SESSION_LOGS_PATH, { recursive: true });
20759
+ }
20760
+ const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
20761
+ const sanitizedChatId = chatId.replace(/[^a-zA-Z0-9_-]/g, "_");
20762
+ this.filePath = join24(SESSION_LOGS_PATH, `session-${sanitizedChatId}-${ts2}.log`);
20763
+ const header2 = [
20764
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
20765
+ `CC-Claw Agent Session \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
20766
+ `Chat: ${chatId} | Backend: ${backend2} | Model: ${model2}`,
20767
+ "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
20768
+ ""
20769
+ ].join("\n");
20770
+ appendFileSync(this.filePath, header2 + "\n", "utf-8");
20771
+ }
20772
+ filePath;
20773
+ startTime = Date.now();
20774
+ closed = false;
20775
+ /** Log a tool start with full, untruncated input. */
20776
+ logToolStart(toolName, input) {
20777
+ if (this.closed) return;
20778
+ const ts2 = this.timestamp();
20779
+ const inputStr = JSON.stringify(input, null, 2);
20780
+ const entry = `[${ts2}] TOOL_START ${toolName}
20781
+ ${inputStr}
20782
+
20783
+ `;
20784
+ this.append(entry);
20785
+ }
20786
+ /** Log a tool end with full, untruncated result. */
20787
+ logToolEnd(toolName, result) {
20788
+ if (this.closed) return;
20789
+ const ts2 = this.timestamp();
20790
+ const preview = result.length > 5e3 ? `(${result.length} chars)
20791
+ ${result.slice(0, 5e3)}\u2026[truncated]` : result;
20792
+ const entry = `[${ts2}] TOOL_END ${toolName}
20793
+ ${preview}
20794
+
20795
+ `;
20796
+ this.append(entry);
20797
+ }
20798
+ /** Log thinking tokens with full text. */
20799
+ logThinking(text) {
20800
+ if (this.closed) return;
20801
+ const ts2 = this.timestamp();
20802
+ const entry = `[${ts2}] THINKING
20803
+ ${text}
20804
+
20805
+ `;
20806
+ this.append(entry);
20807
+ }
20808
+ /** Log informational entry. */
20809
+ logInfo(text) {
20810
+ if (this.closed) return;
20811
+ const ts2 = this.timestamp();
20812
+ const entry = `[${ts2}] INFO ${text}
20813
+
20814
+ `;
20815
+ this.append(entry);
20816
+ }
20817
+ /** Finalize the session log with elapsed time and token counts. */
20818
+ finalize(elapsedMs, usage2) {
20819
+ if (this.closed) return;
20820
+ this.closed = true;
20821
+ const ts2 = this.timestamp();
20822
+ const elapsed = (elapsedMs / 1e3).toFixed(1);
20823
+ const usageStr = usage2 ? ` | input=${usage2.input} output=${usage2.output}${usage2.cacheRead ? ` cacheRead=${usage2.cacheRead}` : ""}` : "";
20824
+ const entry = `[${ts2}] FINALIZED \u2014 ${elapsed}s elapsed${usageStr}
20825
+ `;
20826
+ this.append(entry);
20827
+ }
20828
+ /** Get the file path for display/reference. */
20829
+ getFilePath() {
20830
+ return this.filePath;
20831
+ }
20832
+ /** Get just the filename (for compact display). */
20833
+ getFilename() {
20834
+ return basename3(this.filePath);
20835
+ }
20836
+ // ── Internal ──────────────────────────────────────────────────────
20837
+ timestamp() {
20838
+ return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
20839
+ }
20840
+ append(text) {
20841
+ try {
20842
+ appendFileSync(this.filePath, text, "utf-8");
20843
+ } catch (err) {
20844
+ log(`[session-log] Write failed: ${err}`);
20845
+ }
20846
+ }
20847
+ };
20848
+ }
20849
+ });
20850
+
20420
20851
  // src/router/live-status.ts
20421
20852
  var live_status_exports = {};
20422
20853
  __export(live_status_exports, {
@@ -20439,22 +20870,20 @@ function renderEntry(e) {
20439
20870
  }
20440
20871
  return e.text;
20441
20872
  }
20442
- function renderEntries(entries, modelLabel, elapsedMs) {
20873
+ function renderEntries(entries, modelLabel, elapsedMs, trimmed) {
20443
20874
  const elapsedSec = (elapsedMs / 1e3).toFixed(1);
20444
- const lines = [`\u23F3 ${modelLabel} \xB7 ${elapsedSec}s`, ""];
20445
- for (const e of entries) lines.push(renderEntry(e));
20446
- return lines.join("\n");
20447
- }
20448
- function renderFinal(entries, modelLabel, elapsedSec) {
20449
- const lines = [`\u2705 ${modelLabel} \xB7 ${elapsedSec}s`, ""];
20875
+ const lines = [`\u23F3 ${modelLabel} \xB7 ${elapsedSec}s`];
20876
+ if (trimmed) lines[0] += " (\u2026)";
20877
+ lines.push("");
20450
20878
  for (const e of entries) lines.push(renderEntry(e));
20451
- if (lines.length === 2) return `\u2705 ${modelLabel} \xB7 ${elapsedSec}s`;
20452
20879
  return lines.join("\n");
20453
20880
  }
20454
- function renderFrozen(entries, modelLabel, elapsedSec) {
20455
- const lines = [`\u{1F4CE} ${modelLabel} \xB7 ${elapsedSec}s`, ""];
20881
+ function renderFinal(entries, modelLabel, elapsedSec, trimmed) {
20882
+ const lines = [`\u2705 ${modelLabel} \xB7 ${elapsedSec}s`];
20883
+ if (trimmed) lines[0] += " (\u2026)";
20884
+ if (entries.length === 0) return lines[0];
20885
+ lines.push("");
20456
20886
  for (const e of entries) lines.push(renderEntry(e));
20457
- if (lines.length === 2) return `\u{1F4CE} ${modelLabel} \xB7 ${elapsedSec}s`;
20458
20887
  return lines.join("\n");
20459
20888
  }
20460
20889
  function makeLiveStatus(chatId, channel, modelLabel, verboseLevel, showThinking) {
@@ -20468,16 +20897,16 @@ function makeLiveStatus(chatId, channel, modelLabel, verboseLevel, showThinking)
20468
20897
  };
20469
20898
  return { liveStatus, toolCb };
20470
20899
  }
20471
- var FLUSH_INTERVAL_MS, MAX_ENTRIES, MAX_THINKING_CHARS, SPILLOVER_THRESHOLD, LiveStatusMessage;
20900
+ var FLUSH_INTERVAL_MS, MAX_THINKING_CHARS, TRIM_THRESHOLD, MAX_ENTRIES, LiveStatusMessage;
20472
20901
  var init_live_status = __esm({
20473
20902
  "src/router/live-status.ts"() {
20474
20903
  "use strict";
20475
20904
  init_log();
20476
20905
  init_helpers();
20477
20906
  FLUSH_INTERVAL_MS = 1e3;
20478
- MAX_ENTRIES = 50;
20479
20907
  MAX_THINKING_CHARS = 800;
20480
- SPILLOVER_THRESHOLD = 3800;
20908
+ TRIM_THRESHOLD = 3500;
20909
+ MAX_ENTRIES = 200;
20481
20910
  LiveStatusMessage = class {
20482
20911
  constructor(chatId, channel, modelLabel, verboseLevel, showThinking = false) {
20483
20912
  this.chatId = chatId;
@@ -20492,11 +20921,10 @@ var init_live_status = __esm({
20492
20921
  flushTimer = null;
20493
20922
  lastRendered = "";
20494
20923
  finalized = false;
20495
- /**
20496
- * Entries already frozen in previous spillover messages.
20497
- * Tracked so we only render NEW entries in the current message.
20498
- */
20499
- frozenEntryCount = 0;
20924
+ /** Earliest time the next flush is allowed (set after 429 backoff) */
20925
+ nextFlushAllowedAt = 0;
20926
+ /** Tracks whether entries have been trimmed at least once (for display hint). */
20927
+ hasTrimmed = false;
20500
20928
  /** Send the initial status message. Must be called before adding entries. */
20501
20929
  async init() {
20502
20930
  if (!this.channel.sendTextReturningId) return;
@@ -20555,8 +20983,8 @@ var init_live_status = __esm({
20555
20983
  }
20556
20984
  if (!this.messageId || !this.channel.editText) return;
20557
20985
  const elapsedSec = (elapsedMs / 1e3).toFixed(1);
20558
- const currentEntries = dedupThinking(this.entries.slice(this.frozenEntryCount));
20559
- const body = renderFinal(currentEntries, this.modelLabel, elapsedSec);
20986
+ const deduped = dedupThinking(this.entries);
20987
+ const body = renderFinal(deduped, this.modelLabel, elapsedSec, this.hasTrimmed);
20560
20988
  try {
20561
20989
  await this.channel.editText(this.chatId, this.messageId, body, "plain");
20562
20990
  } catch (err) {
@@ -20570,52 +20998,47 @@ var init_live_status = __esm({
20570
20998
  // ── Internal ──────────────────────────────────────────────────────────
20571
20999
  async flush() {
20572
21000
  if (this.finalized || !this.messageId || !this.channel.editText) return;
20573
- const currentEntries = dedupThinking(this.entries.slice(this.frozenEntryCount));
20574
- const body = renderEntries(currentEntries, this.modelLabel, Date.now() - this.startTime);
20575
- if (body.length > SPILLOVER_THRESHOLD && currentEntries.length > 1) {
20576
- await this.spillover();
20577
- return;
20578
- }
21001
+ if (Date.now() < this.nextFlushAllowedAt) return;
21002
+ const deduped = dedupThinking(this.entries);
21003
+ const body = renderEntries(deduped, this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
20579
21004
  if (body === this.lastRendered) return;
20580
21005
  this.lastRendered = body;
20581
21006
  try {
20582
21007
  await this.channel.editText(this.chatId, this.messageId, body, "plain");
20583
21008
  } catch (err) {
20584
- log(`[live-status] flush edit failed: ${err}`);
21009
+ this.handleRateLimit(err);
20585
21010
  }
20586
21011
  }
20587
21012
  /**
20588
- * Freeze the current message and start a new continuation message.
20589
- * The frozen message keeps its content (with 📎 prefix) nothing is lost.
21013
+ * Trim entries from the BEGINNING when the rendered body exceeds the threshold.
21014
+ * This is the core of the single-message pattern: always show the most recent
21015
+ * activity, drop the oldest entries that scroll past the limit.
20590
21016
  */
20591
- async spillover() {
20592
- if (!this.channel.editText || !this.channel.sendTextReturningId || !this.messageId) return;
20593
- const elapsedSec = ((Date.now() - this.startTime) / 1e3).toFixed(1);
20594
- const currentEntries = dedupThinking(this.entries.slice(this.frozenEntryCount));
20595
- const frozenBody = renderFrozen(currentEntries, this.modelLabel, elapsedSec);
20596
- try {
20597
- await this.channel.editText(this.chatId, this.messageId, frozenBody, "plain");
20598
- } catch (err) {
20599
- log(`[live-status] spillover freeze failed: ${err}`);
21017
+ trimEntries() {
21018
+ if (this.entries.length > MAX_ENTRIES) {
21019
+ this.entries = this.entries.slice(this.entries.length - MAX_ENTRIES);
21020
+ this.hasTrimmed = true;
20600
21021
  }
20601
- this.frozenEntryCount = this.entries.length;
20602
- try {
20603
- const initial = `\u23F3 ${this.modelLabel} \xB7 ${elapsedSec}s (continued)`;
20604
- const newId = await this.channel.sendTextReturningId(this.chatId, initial, "plain") ?? null;
20605
- if (newId) {
20606
- this.messageId = newId;
20607
- this.lastRendered = "";
20608
- }
20609
- } catch (err) {
20610
- log(`[live-status] spillover new message failed: ${err}`);
21022
+ let rendered = renderEntries(dedupThinking(this.entries), this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
21023
+ while (rendered.length > TRIM_THRESHOLD && this.entries.length > 3) {
21024
+ this.entries.shift();
21025
+ this.hasTrimmed = true;
21026
+ rendered = renderEntries(dedupThinking(this.entries), this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
20611
21027
  }
20612
21028
  }
20613
- trimEntries() {
20614
- if (this.entries.length > MAX_ENTRIES + this.frozenEntryCount) {
20615
- const keep = this.entries.slice(0, this.frozenEntryCount);
20616
- const current = this.entries.slice(this.frozenEntryCount);
20617
- const trimmed = current.slice(current.length - MAX_ENTRIES);
20618
- this.entries = [...keep, ...trimmed];
21029
+ /**
21030
+ * Handle Telegram 429 rate-limit errors by backing off.
21031
+ * Parses the "retry after N" hint and sets a cooldown.
21032
+ */
21033
+ handleRateLimit(err) {
21034
+ const msg = String(err);
21035
+ const match = msg.match(/retry after (\d+)/i);
21036
+ if (match) {
21037
+ const retrySec = parseInt(match[1], 10) || 3;
21038
+ this.nextFlushAllowedAt = Date.now() + retrySec * 1e3;
21039
+ log(`[live-status] 429 rate-limited, backing off ${retrySec}s`);
21040
+ } else {
21041
+ log(`[live-status] edit failed: ${msg}`);
20619
21042
  }
20620
21043
  }
20621
21044
  };
@@ -20955,16 +21378,40 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
20955
21378
  const needsLiveStatus = tVerbose !== "off" || showThinkingUi;
20956
21379
  let liveStatus = null;
20957
21380
  let tToolCb;
21381
+ const { getSessionLogEnabled: getSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
21382
+ const { SessionLogFile: SessionLogFile2 } = await Promise.resolve().then(() => (init_session_log2(), session_log_exports2));
21383
+ let sessionLog = null;
21384
+ if (getSessionLogEnabled2(chatId)) {
21385
+ sessionLog = new SessionLogFile2(chatId, adapter.id, model2 ?? adapter.defaultModel);
21386
+ }
20958
21387
  if (needsLiveStatus) {
20959
21388
  const { makeLiveStatus: makeLiveStatus2 } = await Promise.resolve().then(() => (init_live_status(), live_status_exports));
20960
21389
  const effectiveVerbose = tVerbose === "off" ? "normal" : tVerbose;
20961
21390
  const ls = makeLiveStatus2(chatId, channel, modelLabel, effectiveVerbose, showThinkingUi);
20962
21391
  liveStatus = ls.liveStatus;
20963
- tToolCb = tVerbose !== "off" ? ls.toolCb : void 0;
21392
+ const baseCb = tVerbose !== "off" ? ls.toolCb : void 0;
21393
+ tToolCb = async (toolName, input, result) => {
21394
+ if (baseCb) await baseCb(toolName, input, result);
21395
+ if (sessionLog) {
21396
+ if (result === void 0) {
21397
+ sessionLog.logToolStart(toolName, input);
21398
+ } else {
21399
+ sessionLog.logToolEnd(toolName, result);
21400
+ }
21401
+ }
21402
+ };
20964
21403
  await liveStatus.init();
20965
- if (showThinkingUi && adapter.id === "gemini") {
20966
- liveStatus.addInfo("\u{1F4AD} Thinking display not available for Gemini");
21404
+ if (showThinkingUi && adapter.id !== "claude") {
21405
+ liveStatus.addInfo(`\u{1F4AD} Thinking display not available for ${adapter.displayName}`);
20967
21406
  }
21407
+ } else if (sessionLog) {
21408
+ tToolCb = async (toolName, input, result) => {
21409
+ if (result === void 0) {
21410
+ sessionLog.logToolStart(toolName, input);
21411
+ } else {
21412
+ sessionLog.logToolEnd(toolName, result);
21413
+ }
21414
+ };
20968
21415
  }
20969
21416
  const sigT0 = Date.now();
20970
21417
  const response = await askAgent(chatId, cleanText || text, {
@@ -20975,7 +21422,10 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
20975
21422
  bootstrapTier,
20976
21423
  maxTurns,
20977
21424
  agentMode: effectiveAgentMode,
20978
- onThinking: liveStatus ? (chunk) => liveStatus.addThinking(chunk) : void 0,
21425
+ onThinking: liveStatus || sessionLog ? (chunk) => {
21426
+ if (liveStatus) liveStatus.addThinking(chunk);
21427
+ if (sessionLog) sessionLog.logThinking(chunk);
21428
+ } : void 0,
20979
21429
  onSubagentActivity: (backendId2, info) => {
20980
21430
  observedSubagents.add(info.name);
20981
21431
  try {
@@ -21015,6 +21465,7 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
21015
21465
  liveStatus.addThinking(response.thinkingText.trim());
21016
21466
  }
21017
21467
  if (liveStatus) await liveStatus.finalize(elapsedMs);
21468
+ if (sessionLog) sessionLog.finalize(elapsedMs, response.usage);
21018
21469
  if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, model2, void 0, response.usage.contextSize);
21019
21470
  let responseText = response.text;
21020
21471
  const sigEnabled = getModelSignature(chatId);
@@ -21105,6 +21556,33 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
21105
21556
  }
21106
21557
  return;
21107
21558
  }
21559
+ if (errMsg.startsWith(FREE_SLOTS_EXHAUSTED)) {
21560
+ const parts = errMsg.split("|");
21561
+ const backend2 = parts[1] ?? "unknown";
21562
+ const paidCount = parts[2] ?? "?";
21563
+ const displayName = backend2.charAt(0).toUpperCase() + backend2.slice(1);
21564
+ const { pendingFallbackMessages: pendingFallbackMessages3 } = await Promise.resolve().then(() => (init_response(), response_exports));
21565
+ pendingFallbackMessages3.set(chatId, { msg, channel, agentMode: effectiveAgentMode });
21566
+ if (typeof channel.sendKeyboard === "function") {
21567
+ await channel.sendKeyboard(
21568
+ chatId,
21569
+ `\u26A0\uFE0F All free ${displayName} accounts are exhausted.
21570
+
21571
+ ${paidCount} paid API key slot(s) available. Using them will incur API costs.
21572
+
21573
+ Approve paid usage for this session?`,
21574
+ [
21575
+ [
21576
+ { label: "\u2705 Approve (this session)", data: `paidslot:approve:${backend2}`, style: "success" },
21577
+ { label: "\u274C No, switch backend", data: `paidslot:deny:${backend2}`, style: "danger" }
21578
+ ]
21579
+ ]
21580
+ );
21581
+ } else {
21582
+ await channel.sendText(chatId, `\u26A0\uFE0F All free ${displayName} accounts exhausted. ${paidCount} paid API key slot(s) available but not approved. Switch backend or approve paid usage.`, { parseMode: "plain" });
21583
+ }
21584
+ return;
21585
+ }
21108
21586
  const errorClass = classifyError(err);
21109
21587
  if (errorClass === "exhausted") {
21110
21588
  if (await handleResponseExhaustion(errMsg, chatId, msg, channel)) return;
@@ -21448,6 +21926,10 @@ async function runWithRetry(job, model2, runId, t0) {
21448
21926
  onToolAction = makeToolActionCallback2(chatId, channel, vLevel);
21449
21927
  }
21450
21928
  }
21929
+ if (job.allowPaidSlots) {
21930
+ const cronBackend = currentBackend;
21931
+ setAllowPaidSlots(chatId, cronBackend);
21932
+ }
21451
21933
  const response = await askAgent(chatId, job.description, {
21452
21934
  model: currentModel,
21453
21935
  backend: currentBackend,
@@ -21456,6 +21938,9 @@ async function runWithRetry(job, model2, runId, t0) {
21456
21938
  permMode: job.sessionType === "main" ? getMode(job.chatId) : "yolo",
21457
21939
  onToolAction
21458
21940
  });
21941
+ if (job.allowPaidSlots) {
21942
+ clearChatPaidSlots(chatId);
21943
+ }
21459
21944
  if (isFallback) {
21460
21945
  response.text = `[Fallback: ran on ${currentBackend}:${currentModel}]
21461
21946
 
@@ -21465,8 +21950,13 @@ ${response.text}`;
21465
21950
  } catch (err) {
21466
21951
  lastError = err;
21467
21952
  const errorClass = classifyError(err);
21953
+ const errMsg = errorMessage(err);
21954
+ if (typeof errMsg === "string" && errMsg.startsWith(FREE_SLOTS_EXHAUSTED)) {
21955
+ log(`[scheduler] Job #${job.id} backend ${currentBackend} free slots exhausted (paid not approved): ${errMsg}`);
21956
+ break;
21957
+ }
21468
21958
  if (errorClass === "exhausted") {
21469
- log(`[scheduler] Job #${job.id} backend ${currentBackend} exhausted: ${errorMessage(err)}`);
21959
+ log(`[scheduler] Job #${job.id} backend ${currentBackend} exhausted: ${errMsg}`);
21470
21960
  break;
21471
21961
  }
21472
21962
  if (errorClass === "permanent" || attempt >= MAX_RETRIES) {
@@ -21523,7 +22013,7 @@ var init_cron = __esm({
21523
22013
  });
21524
22014
 
21525
22015
  // src/agents/runners/wrap-backend.ts
21526
- import { join as join24 } from "path";
22016
+ import { join as join25 } from "path";
21527
22017
  function buildMcpCommands(backendId) {
21528
22018
  const exe = backendId === "cursor" ? "agent" : backendId;
21529
22019
  return {
@@ -21617,7 +22107,7 @@ function wrapBackendAdapter(adapter) {
21617
22107
  const configPath = writeMcpConfigFile(server);
21618
22108
  return ["--mcp-config", configPath];
21619
22109
  },
21620
- getSkillPath: () => join24(SKILLS_PATH, `agent-${adapter.id}.md`)
22110
+ getSkillPath: () => join25(SKILLS_PATH, `agent-${adapter.id}.md`)
21621
22111
  };
21622
22112
  }
21623
22113
  var BACKEND_CAPABILITIES;
@@ -21668,18 +22158,18 @@ var init_wrap_backend = __esm({
21668
22158
  });
21669
22159
 
21670
22160
  // src/agents/runners/config-loader.ts
21671
- import { readFileSync as readFileSync14, readdirSync as readdirSync12, existsSync as existsSync23, mkdirSync as mkdirSync9, watchFile, unwatchFile } from "fs";
21672
- import { join as join25 } from "path";
22161
+ import { readFileSync as readFileSync14, readdirSync as readdirSync13, existsSync as existsSync24, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
22162
+ import { join as join26 } from "path";
21673
22163
  import { execFileSync as execFileSync2 } from "child_process";
21674
22164
  function resolveExecutable(config2) {
21675
- if (existsSync23(config2.executable)) return config2.executable;
22165
+ if (existsSync24(config2.executable)) return config2.executable;
21676
22166
  try {
21677
22167
  return execFileSync2("which", [config2.executable], { encoding: "utf-8" }).trim();
21678
22168
  } catch {
21679
22169
  }
21680
22170
  for (const fallback of config2.executableFallbacks ?? []) {
21681
22171
  const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
21682
- if (existsSync23(resolved)) return resolved;
22172
+ if (existsSync24(resolved)) return resolved;
21683
22173
  }
21684
22174
  return config2.executable;
21685
22175
  }
@@ -21805,7 +22295,7 @@ function configToRunner(config2) {
21805
22295
  prepareMcpInjection() {
21806
22296
  return [];
21807
22297
  },
21808
- getSkillPath: () => join25(SKILLS_PATH, `agent-${config2.id}.md`)
22298
+ getSkillPath: () => join26(SKILLS_PATH, `agent-${config2.id}.md`)
21809
22299
  };
21810
22300
  }
21811
22301
  function loadRunnerConfig(filePath) {
@@ -21818,14 +22308,14 @@ function loadRunnerConfig(filePath) {
21818
22308
  }
21819
22309
  }
21820
22310
  function loadAllRunnerConfigs() {
21821
- if (!existsSync23(RUNNERS_PATH)) {
21822
- mkdirSync9(RUNNERS_PATH, { recursive: true });
22311
+ if (!existsSync24(RUNNERS_PATH)) {
22312
+ mkdirSync10(RUNNERS_PATH, { recursive: true });
21823
22313
  return [];
21824
22314
  }
21825
- const files = readdirSync12(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
22315
+ const files = readdirSync13(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
21826
22316
  const configs = [];
21827
22317
  for (const file of files) {
21828
- const config2 = loadRunnerConfig(join25(RUNNERS_PATH, file));
22318
+ const config2 = loadRunnerConfig(join26(RUNNERS_PATH, file));
21829
22319
  if (config2) configs.push(config2);
21830
22320
  }
21831
22321
  return configs;
@@ -21846,16 +22336,16 @@ function registerConfigRunners() {
21846
22336
  return count;
21847
22337
  }
21848
22338
  function watchRunnerConfigs(onChange) {
21849
- if (!existsSync23(RUNNERS_PATH)) return;
22339
+ if (!existsSync24(RUNNERS_PATH)) return;
21850
22340
  for (const prev of watchedFiles) {
21851
- if (!existsSync23(prev)) {
22341
+ if (!existsSync24(prev)) {
21852
22342
  unwatchFile(prev);
21853
22343
  watchedFiles.delete(prev);
21854
22344
  }
21855
22345
  }
21856
- const files = readdirSync12(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
22346
+ const files = readdirSync13(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
21857
22347
  for (const file of files) {
21858
- const fullPath = join25(RUNNERS_PATH, file);
22348
+ const fullPath = join26(RUNNERS_PATH, file);
21859
22349
  if (watchedFiles.has(fullPath)) continue;
21860
22350
  watchedFiles.add(fullPath);
21861
22351
  watchFile(fullPath, { interval: 5e3 }, () => {
@@ -22256,6 +22746,7 @@ var init_telegram2 = __esm({
22256
22746
  { command: "mode", description: "Execution gate (approved/yolo)" },
22257
22747
  { command: "tools", description: "Configure which tools the agent can use" },
22258
22748
  { command: "verbose", description: "Tool visibility (off/normal/verbose)" },
22749
+ { command: "debug", description: "Toggle session debug logging (full tool I/O)" },
22259
22750
  { command: "cwd", description: "Set or show working directory" },
22260
22751
  // Memory
22261
22752
  { command: "memory", description: "List stored memories" },
@@ -22702,19 +23193,19 @@ var init_telegram2 = __esm({
22702
23193
  });
22703
23194
 
22704
23195
  // src/skills/bootstrap.ts
22705
- import { existsSync as existsSync24 } from "fs";
23196
+ import { existsSync as existsSync25 } from "fs";
22706
23197
  import { readdir as readdir6, readFile as readFile8, writeFile as writeFile5, copyFile } from "fs/promises";
22707
- import { join as join26, dirname as dirname5 } from "path";
23198
+ import { join as join27, dirname as dirname5 } from "path";
22708
23199
  import { fileURLToPath as fileURLToPath2 } from "url";
22709
23200
  async function copyAgentManifestSkills() {
22710
- if (!existsSync24(PKG_SKILLS)) return;
23201
+ if (!existsSync25(PKG_SKILLS)) return;
22711
23202
  try {
22712
23203
  const entries = await readdir6(PKG_SKILLS, { withFileTypes: true });
22713
23204
  for (const entry of entries) {
22714
23205
  if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
22715
- const src = join26(PKG_SKILLS, entry.name);
22716
- const dest = join26(SKILLS_PATH, entry.name);
22717
- if (existsSync24(dest)) continue;
23206
+ const src = join27(PKG_SKILLS, entry.name);
23207
+ const dest = join27(SKILLS_PATH, entry.name);
23208
+ if (existsSync25(dest)) continue;
22718
23209
  await copyFile(src, dest);
22719
23210
  log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
22720
23211
  }
@@ -22724,8 +23215,8 @@ async function copyAgentManifestSkills() {
22724
23215
  }
22725
23216
  async function bootstrapSkills() {
22726
23217
  await copyAgentManifestSkills();
22727
- const usmDir = join26(SKILLS_PATH, USM_DIR_NAME);
22728
- if (existsSync24(usmDir)) return;
23218
+ const usmDir = join27(SKILLS_PATH, USM_DIR_NAME);
23219
+ if (existsSync25(usmDir)) return;
22729
23220
  try {
22730
23221
  const entries = await readdir6(SKILLS_PATH);
22731
23222
  const dirs = entries.filter((e) => !e.startsWith("."));
@@ -22747,8 +23238,8 @@ async function bootstrapSkills() {
22747
23238
  }
22748
23239
  }
22749
23240
  async function patchUsmForCcClaw(usmDir) {
22750
- const skillPath = join26(usmDir, "SKILL.md");
22751
- if (!existsSync24(skillPath)) return;
23241
+ const skillPath = join27(usmDir, "SKILL.md");
23242
+ if (!existsSync25(skillPath)) return;
22752
23243
  try {
22753
23244
  let content = await readFile8(skillPath, "utf-8");
22754
23245
  let patched = false;
@@ -22793,8 +23284,8 @@ var init_bootstrap = __esm({
22793
23284
  USM_REPO = "jacob-bd/universal-skills-manager";
22794
23285
  USM_DIR_NAME = "universal-skills-manager";
22795
23286
  CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
22796
- PKG_ROOT = join26(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
22797
- PKG_SKILLS = join26(PKG_ROOT, "skills");
23287
+ PKG_ROOT = join27(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
23288
+ PKG_SKILLS = join27(PKG_ROOT, "skills");
22798
23289
  }
22799
23290
  });
22800
23291
 
@@ -23016,13 +23507,13 @@ __export(ai_skill_exports, {
23016
23507
  generateAiSkill: () => generateAiSkill,
23017
23508
  installAiSkill: () => installAiSkill
23018
23509
  });
23019
- import { existsSync as existsSync25, writeFileSync as writeFileSync8, mkdirSync as mkdirSync10 } from "fs";
23020
- import { join as join27 } from "path";
23510
+ import { existsSync as existsSync26, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
23511
+ import { join as join28 } from "path";
23021
23512
  import { homedir as homedir9 } from "os";
23022
23513
  function generateAiSkill() {
23023
23514
  const version = VERSION;
23024
23515
  let systemState = "";
23025
- if (existsSync25(DB_PATH)) {
23516
+ if (existsSync26(DB_PATH)) {
23026
23517
  try {
23027
23518
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
23028
23519
  const readDb = openDatabaseReadOnly2();
@@ -23110,6 +23601,7 @@ Use the CC-Claw CLI when you need to:
23110
23601
  - \`/model_signature\` \u2014 Show/hide model name on responses
23111
23602
  - \`/agents mode\` \u2014 Agent mode (auto/native/claw)
23112
23603
  - \`/voice_config\` \u2014 Voice provider settings
23604
+ - \`/debug\` \u2014 Toggle per-chat session debug logging (full tool I/O to disk)
23113
23605
 
23114
23606
  **Memory:**
23115
23607
  - \`/remember <text>\` \u2014 Save a memory
@@ -23152,6 +23644,16 @@ cc-claw logs --error # Show error log
23152
23644
  cc-claw logs --lines 50 # Show last N lines
23153
23645
  \`\`\`
23154
23646
 
23647
+ ### Session Debug Logs
23648
+ \`\`\`bash
23649
+ cc-claw session-logs list # List all session debug logs
23650
+ cc-claw session-logs tail # Tail latest session log
23651
+ cc-claw session-logs tail -f # Follow latest log (like tail -f)
23652
+ cc-claw session-logs tail --file <name> # Tail a specific log file
23653
+ cc-claw session-logs clean # Remove old session logs
23654
+ cc-claw session-logs clean --days 3 # Remove logs older than 3 days
23655
+ \`\`\`
23656
+
23155
23657
  ### Backend & Model
23156
23658
  \`\`\`bash
23157
23659
  cc-claw backend list --json # Available backends
@@ -23426,10 +23928,10 @@ function installAiSkill() {
23426
23928
  const failed = [];
23427
23929
  for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
23428
23930
  for (const dir of dirs) {
23429
- const skillDir = join27(dir, "cc-claw-cli");
23430
- const skillPath = join27(skillDir, "SKILL.md");
23931
+ const skillDir = join28(dir, "cc-claw-cli");
23932
+ const skillPath = join28(skillDir, "SKILL.md");
23431
23933
  try {
23432
- mkdirSync10(skillDir, { recursive: true });
23934
+ mkdirSync11(skillDir, { recursive: true });
23433
23935
  writeFileSync8(skillPath, skill, "utf-8");
23434
23936
  installed.push(skillPath);
23435
23937
  } catch {
@@ -23446,11 +23948,11 @@ var init_ai_skill = __esm({
23446
23948
  init_paths();
23447
23949
  init_version();
23448
23950
  BACKEND_SKILL_DIRS2 = {
23449
- "cc-claw": [join27(homedir9(), ".cc-claw", "workspace", "skills")],
23450
- claude: [join27(homedir9(), ".claude", "skills")],
23451
- gemini: [join27(homedir9(), ".gemini", "skills")],
23452
- codex: [join27(homedir9(), ".agents", "skills")],
23453
- cursor: [join27(homedir9(), ".cursor", "skills"), join27(homedir9(), ".cursor", "skills-cursor")]
23951
+ "cc-claw": [join28(homedir9(), ".cc-claw", "workspace", "skills")],
23952
+ claude: [join28(homedir9(), ".claude", "skills")],
23953
+ gemini: [join28(homedir9(), ".gemini", "skills")],
23954
+ codex: [join28(homedir9(), ".agents", "skills")],
23955
+ cursor: [join28(homedir9(), ".cursor", "skills"), join28(homedir9(), ".cursor", "skills-cursor")]
23454
23956
  };
23455
23957
  }
23456
23958
  });
@@ -23460,21 +23962,21 @@ var index_exports = {};
23460
23962
  __export(index_exports, {
23461
23963
  main: () => main
23462
23964
  });
23463
- import { mkdirSync as mkdirSync11, existsSync as existsSync26, renameSync as renameSync2, statSync as statSync7, readFileSync as readFileSync16 } from "fs";
23464
- import { join as join28 } from "path";
23965
+ import { mkdirSync as mkdirSync12, existsSync as existsSync27, renameSync as renameSync2, statSync as statSync8, readFileSync as readFileSync16 } from "fs";
23966
+ import { join as join29 } from "path";
23465
23967
  import dotenv from "dotenv";
23466
23968
  function migrateLayout() {
23467
23969
  const moves = [
23468
- [join28(CC_CLAW_HOME, "cc-claw.db"), join28(DATA_PATH, "cc-claw.db")],
23469
- [join28(CC_CLAW_HOME, "cc-claw.db-shm"), join28(DATA_PATH, "cc-claw.db-shm")],
23470
- [join28(CC_CLAW_HOME, "cc-claw.db-wal"), join28(DATA_PATH, "cc-claw.db-wal")],
23471
- [join28(CC_CLAW_HOME, "cc-claw.log"), join28(LOGS_PATH, "cc-claw.log")],
23472
- [join28(CC_CLAW_HOME, "cc-claw.log.1"), join28(LOGS_PATH, "cc-claw.log.1")],
23473
- [join28(CC_CLAW_HOME, "cc-claw.error.log"), join28(LOGS_PATH, "cc-claw.error.log")],
23474
- [join28(CC_CLAW_HOME, "cc-claw.error.log.1"), join28(LOGS_PATH, "cc-claw.error.log.1")]
23970
+ [join29(CC_CLAW_HOME, "cc-claw.db"), join29(DATA_PATH, "cc-claw.db")],
23971
+ [join29(CC_CLAW_HOME, "cc-claw.db-shm"), join29(DATA_PATH, "cc-claw.db-shm")],
23972
+ [join29(CC_CLAW_HOME, "cc-claw.db-wal"), join29(DATA_PATH, "cc-claw.db-wal")],
23973
+ [join29(CC_CLAW_HOME, "cc-claw.log"), join29(LOGS_PATH, "cc-claw.log")],
23974
+ [join29(CC_CLAW_HOME, "cc-claw.log.1"), join29(LOGS_PATH, "cc-claw.log.1")],
23975
+ [join29(CC_CLAW_HOME, "cc-claw.error.log"), join29(LOGS_PATH, "cc-claw.error.log")],
23976
+ [join29(CC_CLAW_HOME, "cc-claw.error.log.1"), join29(LOGS_PATH, "cc-claw.error.log.1")]
23475
23977
  ];
23476
23978
  for (const [from, to] of moves) {
23477
- if (existsSync26(from) && !existsSync26(to)) {
23979
+ if (existsSync27(from) && !existsSync27(to)) {
23478
23980
  try {
23479
23981
  renameSync2(from, to);
23480
23982
  } catch {
@@ -23485,7 +23987,7 @@ function migrateLayout() {
23485
23987
  function rotateLogs() {
23486
23988
  for (const file of [LOG_PATH, ERROR_LOG_PATH]) {
23487
23989
  try {
23488
- const { size } = statSync7(file);
23990
+ const { size } = statSync8(file);
23489
23991
  if (size > LOG_MAX_BYTES) {
23490
23992
  const archivePath = `${file}.1`;
23491
23993
  try {
@@ -23508,6 +24010,7 @@ async function main() {
23508
24010
  }
23509
24011
  log(`[cc-claw] Starting v${version}`);
23510
24012
  initDatabase();
24013
+ clearAllPaidSlots();
23511
24014
  pruneMessageLog(30, 2e3);
23512
24015
  bootstrapBuiltinMcps(getDb());
23513
24016
  try {
@@ -23619,11 +24122,11 @@ async function main() {
23619
24122
  bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
23620
24123
  try {
23621
24124
  const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
23622
- const { writeFileSync: writeFileSync13, mkdirSync: mkdirSync18 } = await import("fs");
23623
- const { join: join34 } = await import("path");
23624
- const skillDir = join34(SKILLS_PATH, "cc-claw-cli");
23625
- mkdirSync18(skillDir, { recursive: true });
23626
- writeFileSync13(join34(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
24125
+ const { writeFileSync: writeFileSync13, mkdirSync: mkdirSync19 } = await import("fs");
24126
+ const { join: join35 } = await import("path");
24127
+ const skillDir = join35(SKILLS_PATH, "cc-claw-cli");
24128
+ mkdirSync19(skillDir, { recursive: true });
24129
+ writeFileSync13(join35(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
23627
24130
  log("[cc-claw] AI skill updated");
23628
24131
  } catch {
23629
24132
  }
@@ -23643,6 +24146,12 @@ async function main() {
23643
24146
  cleanupOldMedia().catch(() => {
23644
24147
  });
23645
24148
  pruneImageCache();
24149
+ try {
24150
+ const { cleanupSessionLogs: cleanupSessionLogs2, startSessionLogCleanupTimer: startSessionLogCleanupTimer2 } = await Promise.resolve().then(() => (init_session_log2(), session_log_exports2));
24151
+ cleanupSessionLogs2();
24152
+ startSessionLogCleanupTimer2();
24153
+ } catch {
24154
+ }
23646
24155
  log("[cc-claw] Ready!");
23647
24156
  const shutdown = async (signal) => {
23648
24157
  log(`[cc-claw] Received ${signal}, shutting down...`);
@@ -23695,11 +24204,11 @@ var init_index = __esm({
23695
24204
  init_bootstrap2();
23696
24205
  init_health3();
23697
24206
  init_image_gen();
23698
- for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
23699
- if (!existsSync26(dir)) mkdirSync11(dir, { recursive: true });
24207
+ for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SESSION_LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
24208
+ if (!existsSync27(dir)) mkdirSync12(dir, { recursive: true });
23700
24209
  }
23701
24210
  migrateLayout();
23702
- if (existsSync26(ENV_PATH)) {
24211
+ if (existsSync27(ENV_PATH)) {
23703
24212
  dotenv.config({ path: ENV_PATH });
23704
24213
  } else {
23705
24214
  console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
@@ -23720,12 +24229,12 @@ __export(api_client_exports, {
23720
24229
  apiPost: () => apiPost,
23721
24230
  isDaemonRunning: () => isDaemonRunning
23722
24231
  });
23723
- import { readFileSync as readFileSync17, existsSync as existsSync27 } from "fs";
24232
+ import { readFileSync as readFileSync17, existsSync as existsSync28 } from "fs";
23724
24233
  import { request as httpRequest, Agent } from "http";
23725
24234
  function getToken() {
23726
24235
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
23727
24236
  try {
23728
- if (existsSync27(TOKEN_PATH)) return readFileSync17(TOKEN_PATH, "utf-8").trim();
24237
+ if (existsSync28(TOKEN_PATH)) return readFileSync17(TOKEN_PATH, "utf-8").trim();
23729
24238
  } catch {
23730
24239
  }
23731
24240
  return null;
@@ -23824,10 +24333,10 @@ __export(service_exports, {
23824
24333
  serviceStatus: () => serviceStatus,
23825
24334
  uninstallService: () => uninstallService
23826
24335
  });
23827
- import { existsSync as existsSync28, mkdirSync as mkdirSync12, writeFileSync as writeFileSync9, unlinkSync as unlinkSync6 } from "fs";
24336
+ import { existsSync as existsSync29, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, unlinkSync as unlinkSync7 } from "fs";
23828
24337
  import { execFileSync as execFileSync3, execSync as execSync6 } from "child_process";
23829
24338
  import { homedir as homedir10, platform } from "os";
23830
- import { join as join29, dirname as dirname6 } from "path";
24339
+ import { join as join30, dirname as dirname6 } from "path";
23831
24340
  function xmlEscape(s) {
23832
24341
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
23833
24342
  }
@@ -23836,7 +24345,7 @@ function resolveExecutable2(name) {
23836
24345
  return execFileSync3("which", [name], { encoding: "utf-8" }).trim();
23837
24346
  } catch {
23838
24347
  const fallback = process.argv[1];
23839
- if (fallback && existsSync28(fallback)) return fallback;
24348
+ if (fallback && existsSync29(fallback)) return fallback;
23840
24349
  throw new Error(`Cannot find '${name}' executable. Install globally: npm install -g cc-claw`);
23841
24350
  }
23842
24351
  }
@@ -23845,14 +24354,14 @@ function getPathDirs() {
23845
24354
  const home = homedir10();
23846
24355
  const dirs = /* @__PURE__ */ new Set([
23847
24356
  nodeBin,
23848
- join29(home, ".local", "bin"),
24357
+ join30(home, ".local", "bin"),
23849
24358
  "/usr/local/bin",
23850
24359
  "/usr/bin",
23851
24360
  "/bin"
23852
24361
  ]);
23853
24362
  try {
23854
24363
  const prefix = execSync6("npm config get prefix", { encoding: "utf-8" }).trim();
23855
- if (prefix) dirs.add(join29(prefix, "bin"));
24364
+ if (prefix) dirs.add(join30(prefix, "bin"));
23856
24365
  } catch {
23857
24366
  }
23858
24367
  return [...dirs].join(":");
@@ -23911,9 +24420,9 @@ function generatePlist() {
23911
24420
  }
23912
24421
  function installMacOS() {
23913
24422
  const agentsDir = dirname6(PLIST_PATH);
23914
- if (!existsSync28(agentsDir)) mkdirSync12(agentsDir, { recursive: true });
23915
- if (!existsSync28(LOGS_PATH)) mkdirSync12(LOGS_PATH, { recursive: true });
23916
- if (existsSync28(PLIST_PATH)) {
24423
+ if (!existsSync29(agentsDir)) mkdirSync13(agentsDir, { recursive: true });
24424
+ if (!existsSync29(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
24425
+ if (existsSync29(PLIST_PATH)) {
23917
24426
  try {
23918
24427
  execFileSync3("launchctl", ["unload", PLIST_PATH]);
23919
24428
  } catch {
@@ -23925,7 +24434,7 @@ function installMacOS() {
23925
24434
  console.log(" Service loaded and starting.");
23926
24435
  }
23927
24436
  function uninstallMacOS() {
23928
- if (!existsSync28(PLIST_PATH)) {
24437
+ if (!existsSync29(PLIST_PATH)) {
23929
24438
  console.log(" No service found to uninstall.");
23930
24439
  return;
23931
24440
  }
@@ -23933,7 +24442,7 @@ function uninstallMacOS() {
23933
24442
  execFileSync3("launchctl", ["unload", PLIST_PATH]);
23934
24443
  } catch {
23935
24444
  }
23936
- unlinkSync6(PLIST_PATH);
24445
+ unlinkSync7(PLIST_PATH);
23937
24446
  console.log(" Service uninstalled.");
23938
24447
  }
23939
24448
  function formatUptime(seconds) {
@@ -24000,8 +24509,8 @@ WantedBy=default.target
24000
24509
  `;
24001
24510
  }
24002
24511
  function installLinux() {
24003
- if (!existsSync28(SYSTEMD_DIR)) mkdirSync12(SYSTEMD_DIR, { recursive: true });
24004
- if (!existsSync28(LOGS_PATH)) mkdirSync12(LOGS_PATH, { recursive: true });
24512
+ if (!existsSync29(SYSTEMD_DIR)) mkdirSync13(SYSTEMD_DIR, { recursive: true });
24513
+ if (!existsSync29(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
24005
24514
  writeFileSync9(UNIT_PATH, generateUnit());
24006
24515
  console.log(` Installed: ${UNIT_PATH}`);
24007
24516
  execFileSync3("systemctl", ["--user", "daemon-reload"]);
@@ -24010,7 +24519,7 @@ function installLinux() {
24010
24519
  console.log(" Service enabled and started.");
24011
24520
  }
24012
24521
  function uninstallLinux() {
24013
- if (!existsSync28(UNIT_PATH)) {
24522
+ if (!existsSync29(UNIT_PATH)) {
24014
24523
  console.log(" No service found to uninstall.");
24015
24524
  return;
24016
24525
  }
@@ -24022,7 +24531,7 @@ function uninstallLinux() {
24022
24531
  execFileSync3("systemctl", ["--user", "disable", "cc-claw"]);
24023
24532
  } catch {
24024
24533
  }
24025
- unlinkSync6(UNIT_PATH);
24534
+ unlinkSync7(UNIT_PATH);
24026
24535
  execFileSync3("systemctl", ["--user", "daemon-reload"]);
24027
24536
  console.log(" Service uninstalled.");
24028
24537
  }
@@ -24035,7 +24544,7 @@ function statusLinux() {
24035
24544
  }
24036
24545
  }
24037
24546
  function installService() {
24038
- if (!existsSync28(join29(CC_CLAW_HOME, ".env"))) {
24547
+ if (!existsSync29(join30(CC_CLAW_HOME, ".env"))) {
24039
24548
  console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
24040
24549
  console.error(" Run 'cc-claw setup' before installing the service.");
24041
24550
  process.exitCode = 1;
@@ -24064,9 +24573,9 @@ var init_service = __esm({
24064
24573
  "use strict";
24065
24574
  init_paths();
24066
24575
  PLIST_LABEL = "com.cc-claw";
24067
- PLIST_PATH = join29(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
24068
- SYSTEMD_DIR = join29(homedir10(), ".config", "systemd", "user");
24069
- UNIT_PATH = join29(SYSTEMD_DIR, "cc-claw.service");
24576
+ PLIST_PATH = join30(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
24577
+ SYSTEMD_DIR = join30(homedir10(), ".config", "systemd", "user");
24578
+ UNIT_PATH = join30(SYSTEMD_DIR, "cc-claw.service");
24070
24579
  }
24071
24580
  });
24072
24581
 
@@ -24263,7 +24772,7 @@ var status_exports = {};
24263
24772
  __export(status_exports, {
24264
24773
  statusCommand: () => statusCommand
24265
24774
  });
24266
- import { existsSync as existsSync29, statSync as statSync8 } from "fs";
24775
+ import { existsSync as existsSync30, statSync as statSync9 } from "fs";
24267
24776
  async function statusCommand(globalOpts, localOpts) {
24268
24777
  try {
24269
24778
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -24303,7 +24812,7 @@ async function statusCommand(globalOpts, localOpts) {
24303
24812
  const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
24304
24813
  const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
24305
24814
  const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
24306
- const dbStat = existsSync29(DB_PATH) ? statSync8(DB_PATH) : null;
24815
+ const dbStat = existsSync30(DB_PATH) ? statSync9(DB_PATH) : null;
24307
24816
  let daemonRunning = false;
24308
24817
  let daemonInfo = {};
24309
24818
  try {
@@ -24392,12 +24901,12 @@ var doctor_exports = {};
24392
24901
  __export(doctor_exports, {
24393
24902
  doctorCommand: () => doctorCommand
24394
24903
  });
24395
- import { existsSync as existsSync30, statSync as statSync9, accessSync, constants } from "fs";
24904
+ import { existsSync as existsSync31, statSync as statSync10, accessSync, constants } from "fs";
24396
24905
  import { execFileSync as execFileSync4 } from "child_process";
24397
24906
  async function doctorCommand(globalOpts, localOpts) {
24398
24907
  const checks = [];
24399
- if (existsSync30(DB_PATH)) {
24400
- const size = statSync9(DB_PATH).size;
24908
+ if (existsSync31(DB_PATH)) {
24909
+ const size = statSync10(DB_PATH).size;
24401
24910
  checks.push({ name: "Database", status: "ok", message: `${DB_PATH} (${(size / 1024).toFixed(0)}KB)` });
24402
24911
  try {
24403
24912
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -24426,7 +24935,7 @@ async function doctorCommand(globalOpts, localOpts) {
24426
24935
  } else {
24427
24936
  checks.push({ name: "Database", status: "error", message: `Not found at ${DB_PATH}`, fix: "cc-claw setup" });
24428
24937
  }
24429
- if (existsSync30(ENV_PATH)) {
24938
+ if (existsSync31(ENV_PATH)) {
24430
24939
  checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
24431
24940
  } else {
24432
24941
  checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
@@ -24481,7 +24990,7 @@ async function doctorCommand(globalOpts, localOpts) {
24481
24990
  } catch {
24482
24991
  }
24483
24992
  const tokenPath = `${DATA_PATH}/api-token`;
24484
- if (existsSync30(tokenPath)) {
24993
+ if (existsSync31(tokenPath)) {
24485
24994
  try {
24486
24995
  accessSync(tokenPath, constants.R_OK);
24487
24996
  checks.push({ name: "API token", status: "ok", message: "token file readable" });
@@ -24506,10 +25015,10 @@ async function doctorCommand(globalOpts, localOpts) {
24506
25015
  }
24507
25016
  } catch {
24508
25017
  }
24509
- if (existsSync30(ERROR_LOG_PATH)) {
25018
+ if (existsSync31(ERROR_LOG_PATH)) {
24510
25019
  try {
24511
- const { readFileSync: readFileSync26 } = await import("fs");
24512
- const logContent = readFileSync26(ERROR_LOG_PATH, "utf-8");
25020
+ const { readFileSync: readFileSync27 } = await import("fs");
25021
+ const logContent = readFileSync27(ERROR_LOG_PATH, "utf-8");
24513
25022
  const recentLines = logContent.split("\n").filter(Boolean).slice(-100);
24514
25023
  const last24h = Date.now() - 864e5;
24515
25024
  const recentErrors = recentLines.filter((line) => {
@@ -24632,10 +25141,10 @@ var logs_exports = {};
24632
25141
  __export(logs_exports, {
24633
25142
  logsCommand: () => logsCommand
24634
25143
  });
24635
- import { existsSync as existsSync31, readFileSync as readFileSync20, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
25144
+ import { existsSync as existsSync32, readFileSync as readFileSync20, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
24636
25145
  async function logsCommand(opts) {
24637
25146
  const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
24638
- if (!existsSync31(logFile)) {
25147
+ if (!existsSync32(logFile)) {
24639
25148
  outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
24640
25149
  process.exit(1);
24641
25150
  }
@@ -24675,6 +25184,105 @@ var init_logs = __esm({
24675
25184
  }
24676
25185
  });
24677
25186
 
25187
+ // src/cli/commands/session-logs.ts
25188
+ var session_logs_exports = {};
25189
+ __export(session_logs_exports, {
25190
+ sessionLogsClean: () => sessionLogsClean,
25191
+ sessionLogsList: () => sessionLogsList,
25192
+ sessionLogsTail: () => sessionLogsTail
25193
+ });
25194
+ import { readFileSync as readFileSync21, watchFile as watchFile3, unwatchFile as unwatchFile3 } from "fs";
25195
+ async function sessionLogsList(opts) {
25196
+ const logs = listSessionLogs();
25197
+ if (logs.length === 0) {
25198
+ console.log(muted(" No session debug logs found."));
25199
+ console.log(muted(` Enable via /debug in Telegram, then logs will appear in ${SESSION_LOGS_PATH}`));
25200
+ return;
25201
+ }
25202
+ if (opts.json) {
25203
+ console.log(JSON.stringify(logs.map((l) => ({
25204
+ filename: l.filename,
25205
+ chatId: l.chatId,
25206
+ timestamp: l.timestamp,
25207
+ sizeBytes: l.sizeBytes,
25208
+ modifiedAt: l.modifiedAt.toISOString()
25209
+ })), null, 2));
25210
+ return;
25211
+ }
25212
+ console.log(muted(` \u2500\u2500 Session Debug Logs (${logs.length}) \u2500\u2500
25213
+ `));
25214
+ console.log(` ${"Filename".padEnd(55)} ${"Size".padStart(8)} Chat ID`);
25215
+ console.log(` ${"\u2500".repeat(55)} ${"\u2500".repeat(8)} ${"\u2500".repeat(15)}`);
25216
+ for (const log5 of logs) {
25217
+ const size = log5.sizeBytes < 1024 ? `${log5.sizeBytes}B` : log5.sizeBytes < 1024 * 1024 ? `${(log5.sizeBytes / 1024).toFixed(1)}K` : `${(log5.sizeBytes / 1024 / 1024).toFixed(1)}M`;
25218
+ console.log(` ${log5.filename.padEnd(55)} ${size.padStart(8)} ${log5.chatId}`);
25219
+ }
25220
+ console.log(muted(`
25221
+ Path: ${SESSION_LOGS_PATH}`));
25222
+ console.log(muted(` Retention: ${getRetentionDays()} day(s) (set SESSION_LOG_RETENTION_DAYS to change)`));
25223
+ }
25224
+ async function sessionLogsTail(opts) {
25225
+ const logs = listSessionLogs();
25226
+ if (logs.length === 0) {
25227
+ outputError("NO_LOGS", "No session debug logs found. Enable via /debug in Telegram.");
25228
+ return;
25229
+ }
25230
+ let targetPath;
25231
+ if (opts.file) {
25232
+ const match = logs.find((l) => l.filename.includes(opts.file));
25233
+ if (!match) {
25234
+ outputError("NOT_FOUND", `No session log matching "${opts.file}". Use 'cc-claw logs session list' to see available logs.`);
25235
+ return;
25236
+ }
25237
+ targetPath = match.filePath;
25238
+ } else {
25239
+ targetPath = logs[0].filePath;
25240
+ }
25241
+ const lineCount = parseInt(opts.lines ?? "50", 10);
25242
+ console.log(muted(` \u2500\u2500 ${targetPath} (last ${lineCount} lines) \u2500\u2500
25243
+ `));
25244
+ for await (const line of tailSessionLog(targetPath, lineCount)) {
25245
+ console.log(line);
25246
+ }
25247
+ if (opts.follow) {
25248
+ console.log(muted("\n Following... (Ctrl+C to stop)\n"));
25249
+ let lastLength = 0;
25250
+ try {
25251
+ lastLength = readFileSync21(targetPath, "utf-8").length;
25252
+ } catch {
25253
+ }
25254
+ watchFile3(targetPath, { interval: 500 }, () => {
25255
+ try {
25256
+ const content = readFileSync21(targetPath, "utf-8");
25257
+ if (content.length > lastLength) {
25258
+ process.stdout.write(content.slice(lastLength));
25259
+ lastLength = content.length;
25260
+ }
25261
+ } catch {
25262
+ }
25263
+ });
25264
+ process.on("SIGINT", () => {
25265
+ unwatchFile3(targetPath);
25266
+ process.exit(0);
25267
+ });
25268
+ await new Promise(() => {
25269
+ });
25270
+ }
25271
+ }
25272
+ async function sessionLogsClean(opts) {
25273
+ const days = opts.days ? parseInt(opts.days, 10) : void 0;
25274
+ const cleaned = cleanupSessionLogs(days);
25275
+ console.log(success(`Cleaned ${cleaned} session log(s) older than ${days ?? getRetentionDays()} day(s).`));
25276
+ }
25277
+ var init_session_logs = __esm({
25278
+ "src/cli/commands/session-logs.ts"() {
25279
+ "use strict";
25280
+ init_session_log2();
25281
+ init_paths();
25282
+ init_format2();
25283
+ }
25284
+ });
25285
+
24678
25286
  // src/cli/commands/gemini.ts
24679
25287
  var gemini_exports = {};
24680
25288
  __export(gemini_exports, {
@@ -24687,11 +25295,11 @@ __export(gemini_exports, {
24687
25295
  geminiReorder: () => geminiReorder,
24688
25296
  geminiRotation: () => geminiRotation
24689
25297
  });
24690
- import { existsSync as existsSync32, mkdirSync as mkdirSync13, writeFileSync as writeFileSync10, readFileSync as readFileSync21, chmodSync } from "fs";
24691
- import { join as join30 } from "path";
24692
- import { createInterface as createInterface6 } from "readline";
25298
+ import { existsSync as existsSync34, mkdirSync as mkdirSync14, writeFileSync as writeFileSync10, readFileSync as readFileSync22, chmodSync } from "fs";
25299
+ import { join as join31 } from "path";
25300
+ import { createInterface as createInterface7 } from "readline";
24693
25301
  function requireDb() {
24694
- if (!existsSync32(DB_PATH)) {
25302
+ if (!existsSync34(DB_PATH)) {
24695
25303
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
24696
25304
  process.exit(1);
24697
25305
  }
@@ -24716,9 +25324,9 @@ async function resolveSlotId(idOrLabel) {
24716
25324
  function resolveOAuthEmail(configHome) {
24717
25325
  if (!configHome) return null;
24718
25326
  try {
24719
- const accountsPath = join30(configHome, ".gemini", "google_accounts.json");
24720
- if (!existsSync32(accountsPath)) return null;
24721
- const accounts = JSON.parse(readFileSync21(accountsPath, "utf-8"));
25327
+ const accountsPath = join31(configHome, ".gemini", "google_accounts.json");
25328
+ if (!existsSync34(accountsPath)) return null;
25329
+ const accounts = JSON.parse(readFileSync22(accountsPath, "utf-8"));
24722
25330
  return accounts.active || null;
24723
25331
  } catch {
24724
25332
  return null;
@@ -24762,7 +25370,7 @@ async function geminiList(globalOpts) {
24762
25370
  }
24763
25371
  async function geminiAddKey(globalOpts, opts) {
24764
25372
  await requireWriteDb();
24765
- const rl2 = createInterface6({ input: process.stdin, output: process.stdout });
25373
+ const rl2 = createInterface7({ input: process.stdin, output: process.stdout });
24766
25374
  const ask2 = (q) => new Promise((r) => rl2.question(q, r));
24767
25375
  const key = await ask2("Paste your Gemini API key: ");
24768
25376
  rl2.close();
@@ -24800,14 +25408,14 @@ async function geminiAddKey(globalOpts, opts) {
24800
25408
  }
24801
25409
  async function geminiAddAccount(globalOpts, opts) {
24802
25410
  await requireWriteDb();
24803
- const slotsDir = join30(CC_CLAW_HOME, "gemini-slots");
24804
- if (!existsSync32(slotsDir)) mkdirSync13(slotsDir, { recursive: true });
25411
+ const slotsDir = join31(CC_CLAW_HOME, "gemini-slots");
25412
+ if (!existsSync34(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
24805
25413
  const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24806
25414
  const tempId = Date.now();
24807
- const slotDir = join30(slotsDir, `slot-${tempId}`);
24808
- mkdirSync13(slotDir, { recursive: true, mode: 448 });
24809
- mkdirSync13(join30(slotDir, ".gemini"), { recursive: true });
24810
- writeFileSync10(join30(slotDir, ".gemini", "settings.json"), JSON.stringify({
25415
+ const slotDir = join31(slotsDir, `slot-${tempId}`);
25416
+ mkdirSync14(slotDir, { recursive: true, mode: 448 });
25417
+ mkdirSync14(join31(slotDir, ".gemini"), { recursive: true });
25418
+ writeFileSync10(join31(slotDir, ".gemini", "settings.json"), JSON.stringify({
24811
25419
  security: { auth: { selectedType: "oauth-personal" } }
24812
25420
  }, null, 2));
24813
25421
  console.log("");
@@ -24824,8 +25432,8 @@ async function geminiAddAccount(globalOpts, opts) {
24824
25432
  });
24825
25433
  } catch {
24826
25434
  }
24827
- const oauthPath = join30(slotDir, ".gemini", "oauth_creds.json");
24828
- if (!existsSync32(oauthPath)) {
25435
+ const oauthPath = join31(slotDir, ".gemini", "oauth_creds.json");
25436
+ if (!existsSync34(oauthPath)) {
24829
25437
  console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
24830
25438
  console.log(" The slot directory is preserved at: " + slotDir);
24831
25439
  console.log(" Re-run: cc-claw gemini add-account\n");
@@ -24833,7 +25441,7 @@ async function geminiAddAccount(globalOpts, opts) {
24833
25441
  }
24834
25442
  let accountEmail = "unknown";
24835
25443
  try {
24836
- const accounts = JSON.parse(__require("fs").readFileSync(join30(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
25444
+ const accounts = JSON.parse(__require("fs").readFileSync(join31(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
24837
25445
  accountEmail = accounts.active || accountEmail;
24838
25446
  } catch {
24839
25447
  }
@@ -24952,11 +25560,11 @@ __export(backend_cmd_factory_exports, {
24952
25560
  makeReorder: () => makeReorder,
24953
25561
  registerBackendSlotCommands: () => registerBackendSlotCommands
24954
25562
  });
24955
- import { existsSync as existsSync33, mkdirSync as mkdirSync14, readFileSync as readFileSync22 } from "fs";
24956
- import { join as join31 } from "path";
24957
- import { createInterface as createInterface7 } from "readline";
25563
+ import { existsSync as existsSync35, mkdirSync as mkdirSync15, readFileSync as readFileSync23 } from "fs";
25564
+ import { join as join32 } from "path";
25565
+ import { createInterface as createInterface8 } from "readline";
24958
25566
  function requireDb2() {
24959
- if (!existsSync33(DB_PATH)) {
25567
+ if (!existsSync35(DB_PATH)) {
24960
25568
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
24961
25569
  process.exit(1);
24962
25570
  }
@@ -25015,7 +25623,7 @@ Add one with: cc-claw ${backend2} add-account or cc-claw ${backend2} add-key`)
25015
25623
  function makeAddKey(backend2, displayName) {
25016
25624
  return async function addKey(_globalOpts, opts) {
25017
25625
  await requireWriteDb2();
25018
- const rl2 = createInterface7({ input: process.stdin, output: process.stdout });
25626
+ const rl2 = createInterface8({ input: process.stdin, output: process.stdout });
25019
25627
  const ask2 = (q) => new Promise((r) => rl2.question(q, r));
25020
25628
  const key = await ask2(`Paste your ${displayName} API key: `);
25021
25629
  rl2.close();
@@ -25045,11 +25653,11 @@ function makeAddAccount(backend2, displayName) {
25045
25653
  process.exit(1);
25046
25654
  }
25047
25655
  await requireWriteDb2();
25048
- const slotsDir = join31(CC_CLAW_HOME, config2.slotsSubdir);
25049
- if (!existsSync33(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
25656
+ const slotsDir = join32(CC_CLAW_HOME, config2.slotsSubdir);
25657
+ if (!existsSync35(slotsDir)) mkdirSync15(slotsDir, { recursive: true });
25050
25658
  const tempId = Date.now();
25051
- const slotDir = join31(slotsDir, `slot-${tempId}`);
25052
- mkdirSync14(slotDir, { recursive: true, mode: 448 });
25659
+ const slotDir = join32(slotsDir, `slot-${tempId}`);
25660
+ mkdirSync15(slotDir, { recursive: true, mode: 448 });
25053
25661
  if (config2.preSetup) config2.preSetup(slotDir);
25054
25662
  console.log("");
25055
25663
  console.log(` Opening ${displayName} CLI for sign-in...`);
@@ -25217,22 +25825,22 @@ var init_backend_cmd_factory = __esm({
25217
25825
  envValue: (slotDir) => slotDir,
25218
25826
  envOverrides: { ANTHROPIC_API_KEY: void 0 },
25219
25827
  preSetup: (slotDir) => {
25220
- mkdirSync14(join31(slotDir, ".claude"), { recursive: true });
25828
+ mkdirSync15(join32(slotDir, ".claude"), { recursive: true });
25221
25829
  },
25222
25830
  verifyCredentials: (slotDir) => {
25223
- const claudeJson = join31(slotDir, ".claude.json");
25224
- const claudeJsonNested = join31(slotDir, ".claude", ".claude.json");
25225
- if (existsSync33(claudeJson)) {
25831
+ const claudeJson = join32(slotDir, ".claude.json");
25832
+ const claudeJsonNested = join32(slotDir, ".claude", ".claude.json");
25833
+ if (existsSync35(claudeJson)) {
25226
25834
  try {
25227
- const data = JSON.parse(readFileSync22(claudeJson, "utf-8"));
25835
+ const data = JSON.parse(readFileSync23(claudeJson, "utf-8"));
25228
25836
  return Boolean(data.oauthAccount);
25229
25837
  } catch {
25230
25838
  return false;
25231
25839
  }
25232
25840
  }
25233
- if (existsSync33(claudeJsonNested)) {
25841
+ if (existsSync35(claudeJsonNested)) {
25234
25842
  try {
25235
- const data = JSON.parse(readFileSync22(claudeJsonNested, "utf-8"));
25843
+ const data = JSON.parse(readFileSync23(claudeJsonNested, "utf-8"));
25236
25844
  return Boolean(data.oauthAccount);
25237
25845
  } catch {
25238
25846
  return false;
@@ -25253,9 +25861,9 @@ var init_backend_cmd_factory = __esm({
25253
25861
  } catch {
25254
25862
  }
25255
25863
  try {
25256
- const claudeJson = join31(slotDir, ".claude.json");
25257
- if (existsSync33(claudeJson)) {
25258
- const data = JSON.parse(readFileSync22(claudeJson, "utf-8"));
25864
+ const claudeJson = join32(slotDir, ".claude.json");
25865
+ if (existsSync35(claudeJson)) {
25866
+ const data = JSON.parse(readFileSync23(claudeJson, "utf-8"));
25259
25867
  if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
25260
25868
  }
25261
25869
  } catch {
@@ -25270,11 +25878,11 @@ var init_backend_cmd_factory = __esm({
25270
25878
  envValue: (slotDir) => slotDir,
25271
25879
  envOverrides: { OPENAI_API_KEY: void 0 },
25272
25880
  verifyCredentials: (slotDir) => {
25273
- return existsSync33(join31(slotDir, "auth.json"));
25881
+ return existsSync35(join32(slotDir, "auth.json"));
25274
25882
  },
25275
25883
  extractLabel: (slotDir) => {
25276
25884
  try {
25277
- const authData = JSON.parse(readFileSync22(join31(slotDir, "auth.json"), "utf-8"));
25885
+ const authData = JSON.parse(readFileSync23(join32(slotDir, "auth.json"), "utf-8"));
25278
25886
  if (authData.email) return authData.email;
25279
25887
  if (authData.account_name) return authData.account_name;
25280
25888
  if (authData.user?.email) return authData.user.email;
@@ -25294,12 +25902,12 @@ __export(backend_exports, {
25294
25902
  backendList: () => backendList,
25295
25903
  backendSet: () => backendSet
25296
25904
  });
25297
- import { existsSync as existsSync34 } from "fs";
25905
+ import { existsSync as existsSync36 } from "fs";
25298
25906
  async function backendList(globalOpts) {
25299
25907
  const { getAvailableAdapters: getAvailableAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
25300
25908
  const chatId = resolveChatId(globalOpts);
25301
25909
  let activeBackend = null;
25302
- if (existsSync34(DB_PATH)) {
25910
+ if (existsSync36(DB_PATH)) {
25303
25911
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
25304
25912
  const readDb = openDatabaseReadOnly2();
25305
25913
  try {
@@ -25330,7 +25938,7 @@ async function backendList(globalOpts) {
25330
25938
  }
25331
25939
  async function backendGet(globalOpts) {
25332
25940
  const chatId = resolveChatId(globalOpts);
25333
- if (!existsSync34(DB_PATH)) {
25941
+ if (!existsSync36(DB_PATH)) {
25334
25942
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
25335
25943
  process.exit(1);
25336
25944
  }
@@ -25374,13 +25982,13 @@ __export(model_exports, {
25374
25982
  modelList: () => modelList,
25375
25983
  modelSet: () => modelSet
25376
25984
  });
25377
- import { existsSync as existsSync35 } from "fs";
25985
+ import { existsSync as existsSync37 } from "fs";
25378
25986
  async function modelList(globalOpts) {
25379
25987
  const chatId = resolveChatId(globalOpts);
25380
25988
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
25381
25989
  const { getAdapter: getAdapter4, getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
25382
25990
  let backendId = "claude";
25383
- if (existsSync35(DB_PATH)) {
25991
+ if (existsSync37(DB_PATH)) {
25384
25992
  const readDb = openDatabaseReadOnly2();
25385
25993
  try {
25386
25994
  const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
@@ -25413,7 +26021,7 @@ async function modelList(globalOpts) {
25413
26021
  }
25414
26022
  async function modelGet(globalOpts) {
25415
26023
  const chatId = resolveChatId(globalOpts);
25416
- if (!existsSync35(DB_PATH)) {
26024
+ if (!existsSync37(DB_PATH)) {
25417
26025
  outputError("DB_NOT_FOUND", "Database not found.");
25418
26026
  process.exit(1);
25419
26027
  }
@@ -25457,9 +26065,9 @@ __export(memory_exports2, {
25457
26065
  memoryList: () => memoryList,
25458
26066
  memorySearch: () => memorySearch
25459
26067
  });
25460
- import { existsSync as existsSync36 } from "fs";
26068
+ import { existsSync as existsSync38 } from "fs";
25461
26069
  async function memoryList(globalOpts) {
25462
- if (!existsSync36(DB_PATH)) {
26070
+ if (!existsSync38(DB_PATH)) {
25463
26071
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
25464
26072
  process.exit(1);
25465
26073
  }
@@ -25483,7 +26091,7 @@ async function memoryList(globalOpts) {
25483
26091
  });
25484
26092
  }
25485
26093
  async function memorySearch(globalOpts, query) {
25486
- if (!existsSync36(DB_PATH)) {
26094
+ if (!existsSync38(DB_PATH)) {
25487
26095
  outputError("DB_NOT_FOUND", "Database not found.");
25488
26096
  process.exit(1);
25489
26097
  }
@@ -25505,7 +26113,7 @@ async function memorySearch(globalOpts, query) {
25505
26113
  });
25506
26114
  }
25507
26115
  async function memoryHistory(globalOpts, opts) {
25508
- if (!existsSync36(DB_PATH)) {
26116
+ if (!existsSync38(DB_PATH)) {
25509
26117
  outputError("DB_NOT_FOUND", "Database not found.");
25510
26118
  process.exit(1);
25511
26119
  }
@@ -25553,7 +26161,7 @@ __export(cron_exports2, {
25553
26161
  cronList: () => cronList,
25554
26162
  cronRuns: () => cronRuns
25555
26163
  });
25556
- import { existsSync as existsSync37 } from "fs";
26164
+ import { existsSync as existsSync39 } from "fs";
25557
26165
  function parseFallbacks(raw) {
25558
26166
  return raw.slice(0, 3).map((f) => {
25559
26167
  const [backend2, ...rest] = f.split(":");
@@ -25574,7 +26182,7 @@ function parseAndValidateTimeout(raw) {
25574
26182
  return val;
25575
26183
  }
25576
26184
  async function cronList(globalOpts) {
25577
- if (!existsSync37(DB_PATH)) {
26185
+ if (!existsSync39(DB_PATH)) {
25578
26186
  outputError("DB_NOT_FOUND", "Database not found.");
25579
26187
  process.exit(1);
25580
26188
  }
@@ -25612,7 +26220,7 @@ async function cronList(globalOpts) {
25612
26220
  });
25613
26221
  }
25614
26222
  async function cronHealth(globalOpts) {
25615
- if (!existsSync37(DB_PATH)) {
26223
+ if (!existsSync39(DB_PATH)) {
25616
26224
  outputError("DB_NOT_FOUND", "Database not found.");
25617
26225
  process.exit(1);
25618
26226
  }
@@ -25771,7 +26379,7 @@ async function cronEdit(globalOpts, id, opts) {
25771
26379
  }
25772
26380
  }
25773
26381
  async function cronRuns(globalOpts, jobId, opts) {
25774
- if (!existsSync37(DB_PATH)) {
26382
+ if (!existsSync39(DB_PATH)) {
25775
26383
  outputError("DB_NOT_FOUND", "Database not found.");
25776
26384
  process.exit(1);
25777
26385
  }
@@ -25818,9 +26426,9 @@ __export(agents_exports, {
25818
26426
  runnersList: () => runnersList,
25819
26427
  tasksList: () => tasksList
25820
26428
  });
25821
- import { existsSync as existsSync38 } from "fs";
26429
+ import { existsSync as existsSync40 } from "fs";
25822
26430
  async function agentsList(globalOpts) {
25823
- if (!existsSync38(DB_PATH)) {
26431
+ if (!existsSync40(DB_PATH)) {
25824
26432
  outputError("DB_NOT_FOUND", "Database not found.");
25825
26433
  process.exit(1);
25826
26434
  }
@@ -25851,7 +26459,7 @@ async function agentsList(globalOpts) {
25851
26459
  });
25852
26460
  }
25853
26461
  async function tasksList(globalOpts) {
25854
- if (!existsSync38(DB_PATH)) {
26462
+ if (!existsSync40(DB_PATH)) {
25855
26463
  outputError("DB_NOT_FOUND", "Database not found.");
25856
26464
  process.exit(1);
25857
26465
  }
@@ -25979,18 +26587,18 @@ __export(db_exports, {
25979
26587
  dbPath: () => dbPath,
25980
26588
  dbStats: () => dbStats
25981
26589
  });
25982
- import { existsSync as existsSync39, statSync as statSync10, copyFileSync as copyFileSync3, mkdirSync as mkdirSync15 } from "fs";
26590
+ import { existsSync as existsSync41, statSync as statSync11, copyFileSync as copyFileSync3, mkdirSync as mkdirSync16 } from "fs";
25983
26591
  import { dirname as dirname7 } from "path";
25984
26592
  async function dbStats(globalOpts) {
25985
- if (!existsSync39(DB_PATH)) {
26593
+ if (!existsSync41(DB_PATH)) {
25986
26594
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
25987
26595
  process.exit(1);
25988
26596
  }
25989
26597
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
25990
26598
  const readDb = openDatabaseReadOnly2();
25991
- const mainSize = statSync10(DB_PATH).size;
26599
+ const mainSize = statSync11(DB_PATH).size;
25992
26600
  const walPath = DB_PATH + "-wal";
25993
- const walSize = existsSync39(walPath) ? statSync10(walPath).size : 0;
26601
+ const walSize = existsSync41(walPath) ? statSync11(walPath).size : 0;
25994
26602
  const tableNames = readDb.prepare(
25995
26603
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
25996
26604
  ).all();
@@ -26024,17 +26632,17 @@ async function dbPath(globalOpts) {
26024
26632
  output({ path: DB_PATH }, (d) => d.path);
26025
26633
  }
26026
26634
  async function dbBackup(globalOpts, destPath) {
26027
- if (!existsSync39(DB_PATH)) {
26635
+ if (!existsSync41(DB_PATH)) {
26028
26636
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
26029
26637
  process.exit(1);
26030
26638
  }
26031
26639
  const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
26032
26640
  try {
26033
- mkdirSync15(dirname7(dest), { recursive: true });
26641
+ mkdirSync16(dirname7(dest), { recursive: true });
26034
26642
  copyFileSync3(DB_PATH, dest);
26035
26643
  const walPath = DB_PATH + "-wal";
26036
- if (existsSync39(walPath)) copyFileSync3(walPath, dest + "-wal");
26037
- output({ path: dest, sizeBytes: statSync10(dest).size }, (d) => {
26644
+ if (existsSync41(walPath)) copyFileSync3(walPath, dest + "-wal");
26645
+ output({ path: dest, sizeBytes: statSync11(dest).size }, (d) => {
26038
26646
  const b = d;
26039
26647
  return `
26040
26648
  ${success("Backup created:")} ${b.path} (${(b.sizeBytes / 1024).toFixed(0)}KB)
@@ -26062,9 +26670,9 @@ __export(usage_exports, {
26062
26670
  usageCost: () => usageCost,
26063
26671
  usageTokens: () => usageTokens
26064
26672
  });
26065
- import { existsSync as existsSync40 } from "fs";
26673
+ import { existsSync as existsSync42 } from "fs";
26066
26674
  function ensureDb() {
26067
- if (!existsSync40(DB_PATH)) {
26675
+ if (!existsSync42(DB_PATH)) {
26068
26676
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
26069
26677
  process.exit(1);
26070
26678
  }
@@ -26254,9 +26862,9 @@ __export(config_exports2, {
26254
26862
  configList: () => configList,
26255
26863
  configSet: () => configSet
26256
26864
  });
26257
- import { existsSync as existsSync41, readFileSync as readFileSync23 } from "fs";
26865
+ import { existsSync as existsSync43, readFileSync as readFileSync24 } from "fs";
26258
26866
  async function configList(globalOpts) {
26259
- if (!existsSync41(DB_PATH)) {
26867
+ if (!existsSync43(DB_PATH)) {
26260
26868
  outputError("DB_NOT_FOUND", "Database not found.");
26261
26869
  process.exit(1);
26262
26870
  }
@@ -26290,7 +26898,7 @@ async function configGet(globalOpts, key) {
26290
26898
  outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
26291
26899
  process.exit(1);
26292
26900
  }
26293
- if (!existsSync41(DB_PATH)) {
26901
+ if (!existsSync43(DB_PATH)) {
26294
26902
  outputError("DB_NOT_FOUND", "Database not found.");
26295
26903
  process.exit(1);
26296
26904
  }
@@ -26336,11 +26944,11 @@ async function configSet(globalOpts, key, value) {
26336
26944
  }
26337
26945
  }
26338
26946
  async function configEnv(_globalOpts) {
26339
- if (!existsSync41(ENV_PATH)) {
26947
+ if (!existsSync43(ENV_PATH)) {
26340
26948
  outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
26341
26949
  process.exit(1);
26342
26950
  }
26343
- const content = readFileSync23(ENV_PATH, "utf-8");
26951
+ const content = readFileSync24(ENV_PATH, "utf-8");
26344
26952
  const entries = {};
26345
26953
  const secretPatterns = /TOKEN|KEY|SECRET|PASSWORD|CREDENTIALS/i;
26346
26954
  for (const line of content.split("\n")) {
@@ -26390,9 +26998,9 @@ __export(session_exports, {
26390
26998
  sessionGet: () => sessionGet,
26391
26999
  sessionNew: () => sessionNew
26392
27000
  });
26393
- import { existsSync as existsSync42 } from "fs";
27001
+ import { existsSync as existsSync44 } from "fs";
26394
27002
  async function sessionGet(globalOpts) {
26395
- if (!existsSync42(DB_PATH)) {
27003
+ if (!existsSync44(DB_PATH)) {
26396
27004
  outputError("DB_NOT_FOUND", "Database not found.");
26397
27005
  process.exit(1);
26398
27006
  }
@@ -26453,9 +27061,9 @@ __export(permissions_exports, {
26453
27061
  verboseGet: () => verboseGet,
26454
27062
  verboseSet: () => verboseSet
26455
27063
  });
26456
- import { existsSync as existsSync43 } from "fs";
27064
+ import { existsSync as existsSync45 } from "fs";
26457
27065
  function ensureDb2() {
26458
- if (!existsSync43(DB_PATH)) {
27066
+ if (!existsSync45(DB_PATH)) {
26459
27067
  outputError("DB_NOT_FOUND", "Database not found.");
26460
27068
  process.exit(1);
26461
27069
  }
@@ -26602,9 +27210,9 @@ __export(cwd_exports, {
26602
27210
  cwdGet: () => cwdGet,
26603
27211
  cwdSet: () => cwdSet
26604
27212
  });
26605
- import { existsSync as existsSync44 } from "fs";
27213
+ import { existsSync as existsSync46 } from "fs";
26606
27214
  async function cwdGet(globalOpts) {
26607
- if (!existsSync44(DB_PATH)) {
27215
+ if (!existsSync46(DB_PATH)) {
26608
27216
  outputError("DB_NOT_FOUND", "Database not found.");
26609
27217
  process.exit(1);
26610
27218
  }
@@ -26666,9 +27274,9 @@ __export(voice_exports, {
26666
27274
  voiceGet: () => voiceGet,
26667
27275
  voiceSet: () => voiceSet
26668
27276
  });
26669
- import { existsSync as existsSync45 } from "fs";
27277
+ import { existsSync as existsSync47 } from "fs";
26670
27278
  async function voiceGet(globalOpts) {
26671
- if (!existsSync45(DB_PATH)) {
27279
+ if (!existsSync47(DB_PATH)) {
26672
27280
  outputError("DB_NOT_FOUND", "Database not found.");
26673
27281
  process.exit(1);
26674
27282
  }
@@ -26717,9 +27325,9 @@ __export(heartbeat_exports, {
26717
27325
  heartbeatGet: () => heartbeatGet,
26718
27326
  heartbeatSet: () => heartbeatSet
26719
27327
  });
26720
- import { existsSync as existsSync46 } from "fs";
27328
+ import { existsSync as existsSync48 } from "fs";
26721
27329
  async function heartbeatGet(globalOpts) {
26722
- if (!existsSync46(DB_PATH)) {
27330
+ if (!existsSync48(DB_PATH)) {
26723
27331
  outputError("DB_NOT_FOUND", "Database not found.");
26724
27332
  process.exit(1);
26725
27333
  }
@@ -26828,9 +27436,9 @@ __export(summarizer_exports, {
26828
27436
  summarizerGet: () => summarizerGet,
26829
27437
  summarizerSet: () => summarizerSet
26830
27438
  });
26831
- import { existsSync as existsSync47 } from "fs";
27439
+ import { existsSync as existsSync49 } from "fs";
26832
27440
  async function summarizerGet(globalOpts) {
26833
- if (!existsSync47(DB_PATH)) {
27441
+ if (!existsSync49(DB_PATH)) {
26834
27442
  outputError("DB_NOT_FOUND", "Database not found.");
26835
27443
  process.exit(1);
26836
27444
  }
@@ -26874,9 +27482,9 @@ __export(thinking_exports, {
26874
27482
  thinkingGet: () => thinkingGet,
26875
27483
  thinkingSet: () => thinkingSet
26876
27484
  });
26877
- import { existsSync as existsSync48 } from "fs";
27485
+ import { existsSync as existsSync50 } from "fs";
26878
27486
  async function thinkingGet(globalOpts) {
26879
- if (!existsSync48(DB_PATH)) {
27487
+ if (!existsSync50(DB_PATH)) {
26880
27488
  outputError("DB_NOT_FOUND", "Database not found.");
26881
27489
  process.exit(1);
26882
27490
  }
@@ -26920,9 +27528,9 @@ __export(chats_exports, {
26920
27528
  chatsList: () => chatsList,
26921
27529
  chatsRemoveAlias: () => chatsRemoveAlias
26922
27530
  });
26923
- import { existsSync as existsSync49 } from "fs";
27531
+ import { existsSync as existsSync51 } from "fs";
26924
27532
  async function chatsList(_globalOpts) {
26925
- if (!existsSync49(DB_PATH)) {
27533
+ if (!existsSync51(DB_PATH)) {
26926
27534
  outputError("DB_NOT_FOUND", "Database not found.");
26927
27535
  process.exit(1);
26928
27536
  }
@@ -27050,9 +27658,9 @@ var mcps_exports2 = {};
27050
27658
  __export(mcps_exports2, {
27051
27659
  mcpsList: () => mcpsList
27052
27660
  });
27053
- import { existsSync as existsSync50 } from "fs";
27661
+ import { existsSync as existsSync52 } from "fs";
27054
27662
  async function mcpsList(_globalOpts) {
27055
- if (!existsSync50(DB_PATH)) {
27663
+ if (!existsSync52(DB_PATH)) {
27056
27664
  outputError("DB_NOT_FOUND", "Database not found.");
27057
27665
  process.exit(1);
27058
27666
  }
@@ -27089,11 +27697,11 @@ __export(chat_exports2, {
27089
27697
  chatSend: () => chatSend
27090
27698
  });
27091
27699
  import { request as httpRequest2 } from "http";
27092
- import { readFileSync as readFileSync24, existsSync as existsSync51 } from "fs";
27700
+ import { readFileSync as readFileSync25, existsSync as existsSync53 } from "fs";
27093
27701
  function getToken2() {
27094
27702
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
27095
27703
  try {
27096
- if (existsSync51(TOKEN_PATH2)) return readFileSync24(TOKEN_PATH2, "utf-8").trim();
27704
+ if (existsSync53(TOKEN_PATH2)) return readFileSync25(TOKEN_PATH2, "utf-8").trim();
27097
27705
  } catch {
27098
27706
  }
27099
27707
  return null;
@@ -27230,7 +27838,7 @@ var tui_exports = {};
27230
27838
  __export(tui_exports, {
27231
27839
  tuiCommand: () => tuiCommand
27232
27840
  });
27233
- import { createInterface as createInterface8 } from "readline";
27841
+ import { createInterface as createInterface9 } from "readline";
27234
27842
  import pc2 from "picocolors";
27235
27843
  async function tuiCommand(globalOpts, cmdOpts) {
27236
27844
  const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
@@ -27240,7 +27848,7 @@ async function tuiCommand(globalOpts, cmdOpts) {
27240
27848
  }
27241
27849
  const chatId = resolveChatId(globalOpts);
27242
27850
  const { chatSend: chatSend2 } = await Promise.resolve().then(() => (init_chat2(), chat_exports2));
27243
- const rl2 = createInterface8({
27851
+ const rl2 = createInterface9({
27244
27852
  input: process.stdin,
27245
27853
  output: process.stdout,
27246
27854
  prompt: pc2.cyan("you > "),
@@ -27372,8 +27980,8 @@ var completion_exports = {};
27372
27980
  __export(completion_exports, {
27373
27981
  completionCommand: () => completionCommand
27374
27982
  });
27375
- import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync16 } from "fs";
27376
- import { join as join32 } from "path";
27983
+ import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync17 } from "fs";
27984
+ import { join as join33 } from "path";
27377
27985
  import { homedir as homedir11 } from "os";
27378
27986
  async function completionCommand(opts) {
27379
27987
  const shell = opts.shell ?? detectShell();
@@ -27389,10 +27997,10 @@ async function completionCommand(opts) {
27389
27997
  process.exit(1);
27390
27998
  }
27391
27999
  if (opts.install) {
27392
- const dir = join32(homedir11(), ".config", "cc-claw", "completions");
27393
- mkdirSync16(dir, { recursive: true });
28000
+ const dir = join33(homedir11(), ".config", "cc-claw", "completions");
28001
+ mkdirSync17(dir, { recursive: true });
27394
28002
  const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
27395
- const filepath = join32(dir, filename);
28003
+ const filepath = join33(dir, filename);
27396
28004
  writeFileSync11(filepath, script, "utf-8");
27397
28005
  console.log(`\u2713 Completion script written to ${filepath}
27398
28006
  `);
@@ -27563,9 +28171,9 @@ __export(evolve_exports2, {
27563
28171
  evolveStatus: () => evolveStatus,
27564
28172
  evolveUndo: () => evolveUndo
27565
28173
  });
27566
- import { existsSync as existsSync52 } from "fs";
28174
+ import { existsSync as existsSync54 } from "fs";
27567
28175
  function ensureDb3() {
27568
- if (!existsSync52(DB_PATH)) {
28176
+ if (!existsSync54(DB_PATH)) {
27569
28177
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
27570
28178
  process.exit(1);
27571
28179
  }
@@ -28039,10 +28647,10 @@ var init_optimize2 = __esm({
28039
28647
 
28040
28648
  // src/setup.ts
28041
28649
  var setup_exports = {};
28042
- import { existsSync as existsSync53, writeFileSync as writeFileSync12, readFileSync as readFileSync25, copyFileSync as copyFileSync4, mkdirSync as mkdirSync17, statSync as statSync11 } from "fs";
28650
+ import { existsSync as existsSync55, writeFileSync as writeFileSync12, readFileSync as readFileSync26, copyFileSync as copyFileSync4, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
28043
28651
  import { execFileSync as execFileSync5 } from "child_process";
28044
- import { createInterface as createInterface9 } from "readline";
28045
- import { join as join33 } from "path";
28652
+ import { createInterface as createInterface10 } from "readline";
28653
+ import { join as join34 } from "path";
28046
28654
  function divider2() {
28047
28655
  console.log(dim("\u2500".repeat(55)));
28048
28656
  }
@@ -28117,22 +28725,22 @@ async function setup() {
28117
28725
  }
28118
28726
  console.log("");
28119
28727
  for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
28120
- if (!existsSync53(dir)) mkdirSync17(dir, { recursive: true });
28728
+ if (!existsSync55(dir)) mkdirSync18(dir, { recursive: true });
28121
28729
  }
28122
28730
  const env = {};
28123
- const envSource = existsSync53(ENV_PATH) ? ENV_PATH : existsSync53(".env") ? ".env" : null;
28731
+ const envSource = existsSync55(ENV_PATH) ? ENV_PATH : existsSync55(".env") ? ".env" : null;
28124
28732
  if (envSource) {
28125
28733
  console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
28126
28734
  console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
28127
- const existing = readFileSync25(envSource, "utf-8");
28735
+ const existing = readFileSync26(envSource, "utf-8");
28128
28736
  for (const line of existing.split("\n")) {
28129
28737
  const match = line.match(/^([^#=]+)=(.*)$/);
28130
28738
  if (match) env[match[1].trim()] = match[2].trim();
28131
28739
  }
28132
28740
  }
28133
- const cwdDb = join33(process.cwd(), "cc-claw.db");
28134
- if (existsSync53(cwdDb) && !existsSync53(DB_PATH)) {
28135
- const { size } = statSync11(cwdDb);
28741
+ const cwdDb = join34(process.cwd(), "cc-claw.db");
28742
+ if (existsSync55(cwdDb) && !existsSync55(DB_PATH)) {
28743
+ const { size } = statSync12(cwdDb);
28136
28744
  console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
28137
28745
  const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
28138
28746
  if (migrate) {
@@ -28404,7 +29012,7 @@ var init_setup = __esm({
28404
29012
  "src/setup.ts"() {
28405
29013
  "use strict";
28406
29014
  init_paths();
28407
- rl = createInterface9({ input: process.stdin, output: process.stdout });
29015
+ rl = createInterface10({ input: process.stdin, output: process.stdout });
28408
29016
  ask = (q) => new Promise((resolve) => rl.question(q, resolve));
28409
29017
  bold = (s) => `\x1B[1m${s}\x1B[0m`;
28410
29018
  green = (s) => `\x1B[32m${s}\x1B[0m`;
@@ -28473,6 +29081,19 @@ program.command("logs").description("Tail daemon logs").option("-f, --follow", "
28473
29081
  const { logsCommand: logsCommand2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
28474
29082
  await logsCommand2(opts);
28475
29083
  });
29084
+ var sessionLogs = program.command("session-logs").description("Manage session debug logs (enable via /debug in Telegram)");
29085
+ sessionLogs.command("list").description("List all session debug logs").action(async () => {
29086
+ const { sessionLogsList: sessionLogsList2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
29087
+ await sessionLogsList2(program.opts());
29088
+ });
29089
+ sessionLogs.command("tail").description("Tail latest (or specific) session log").option("-f, --follow", "Follow mode (like tail -f)").option("--file <name>", "Specific log file (partial match)").option("--lines <n>", "Number of lines", "50").action(async (opts) => {
29090
+ const { sessionLogsTail: sessionLogsTail2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
29091
+ await sessionLogsTail2(opts);
29092
+ });
29093
+ sessionLogs.command("clean").description("Remove old session logs").option("--days <n>", "Remove logs older than N days").action(async (opts) => {
29094
+ const { sessionLogsClean: sessionLogsClean2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
29095
+ await sessionLogsClean2(opts);
29096
+ });
28476
29097
  var gemini = program.command("gemini").description("Manage Gemini credential slots for rotation");
28477
29098
  gemini.command("list").description("Show all configured Gemini credential slots").action(async () => {
28478
29099
  const { geminiList: geminiList2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));