cc-claw 0.18.0 → 0.18.1

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 +699 -275
  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.1" : (() => {
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
  });
@@ -1749,6 +1751,12 @@ function initSchema(db3) {
1749
1751
  value INTEGER NOT NULL DEFAULT 0
1750
1752
  );
1751
1753
  `);
1754
+ db3.exec(`
1755
+ CREATE TABLE IF NOT EXISTS chat_session_log (
1756
+ chat_id TEXT PRIMARY KEY,
1757
+ value INTEGER NOT NULL DEFAULT 0
1758
+ );
1759
+ `);
1752
1760
  db3.exec(`
1753
1761
  CREATE TABLE IF NOT EXISTS backend_credentials (
1754
1762
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -2456,6 +2464,7 @@ __export(chat_settings_exports, {
2456
2464
  getModel: () => getModel,
2457
2465
  getPendingEscalation: () => getPendingEscalation,
2458
2466
  getRecentBookmarks: () => getRecentBookmarks,
2467
+ getSessionLogEnabled: () => getSessionLogEnabled,
2459
2468
  getShowThinkingUi: () => getShowThinkingUi,
2460
2469
  getSummarizer: () => getSummarizer,
2461
2470
  getThinkingLevel: () => getThinkingLevel,
@@ -2469,11 +2478,13 @@ __export(chat_settings_exports, {
2469
2478
  setExecMode: () => setExecMode,
2470
2479
  setMode: () => setMode,
2471
2480
  setModel: () => setModel,
2481
+ setSessionLogEnabled: () => setSessionLogEnabled,
2472
2482
  setShowThinkingUi: () => setShowThinkingUi,
2473
2483
  setSummarizer: () => setSummarizer,
2474
2484
  setThinkingLevel: () => setThinkingLevel,
2475
2485
  setVerboseLevel: () => setVerboseLevel,
2476
2486
  storePendingEscalation: () => storePendingEscalation,
2487
+ toggleSessionLogEnabled: () => toggleSessionLogEnabled,
2477
2488
  toggleShowThinkingUi: () => toggleShowThinkingUi,
2478
2489
  toggleTool: () => toggleTool,
2479
2490
  touchBookmark: () => touchBookmark,
@@ -2744,6 +2755,25 @@ function setExecMode(chatId, mode) {
2744
2755
  function clearExecMode(chatId) {
2745
2756
  getDb().prepare("DELETE FROM chat_exec_mode WHERE chat_id = ?").run(chatId);
2746
2757
  }
2758
+ function getSessionLogEnabled(chatId) {
2759
+ const row = getDb().prepare(
2760
+ "SELECT value FROM chat_session_log WHERE chat_id = ?"
2761
+ ).get(chatId);
2762
+ return (row?.value ?? 0) === 1;
2763
+ }
2764
+ function setSessionLogEnabled(chatId, enabled) {
2765
+ getDb().prepare(`
2766
+ INSERT INTO chat_session_log (chat_id, value)
2767
+ VALUES (?, ?)
2768
+ ON CONFLICT(chat_id) DO UPDATE SET value = ?
2769
+ `).run(chatId, enabled ? 1 : 0, enabled ? 1 : 0);
2770
+ }
2771
+ function toggleSessionLogEnabled(chatId) {
2772
+ const current = getSessionLogEnabled(chatId);
2773
+ const next = !current;
2774
+ setSessionLogEnabled(chatId, next);
2775
+ return next;
2776
+ }
2747
2777
  var pendingEscalations, ESCALATION_TTL_MS, ALL_TOOLS;
2748
2778
  var init_chat_settings = __esm({
2749
2779
  "src/memory/chat-settings.ts"() {
@@ -3608,6 +3638,7 @@ __export(store_exports5, {
3608
3638
  getRecentMessageLog: () => getRecentMessageLog,
3609
3639
  getResponseStyle: () => getResponseStyle,
3610
3640
  getSessionId: () => getSessionId,
3641
+ getSessionLogEnabled: () => getSessionLogEnabled,
3611
3642
  getSessionStartedAt: () => getSessionStartedAt,
3612
3643
  getSessionSummaries: () => getSessionSummaries,
3613
3644
  getSessionSummariesWithoutEmbeddings: () => getSessionSummariesWithoutEmbeddings,
@@ -3670,6 +3701,7 @@ __export(store_exports5, {
3670
3701
  setModelSignature: () => setModelSignature,
3671
3702
  setResponseStyle: () => setResponseStyle,
3672
3703
  setSessionId: () => setSessionId,
3704
+ setSessionLogEnabled: () => setSessionLogEnabled,
3673
3705
  setSessionStartedAt: () => setSessionStartedAt,
3674
3706
  setShowThinkingUi: () => setShowThinkingUi,
3675
3707
  setSummarizer: () => setSummarizer,
@@ -3677,6 +3709,7 @@ __export(store_exports5, {
3677
3709
  setVerboseLevel: () => setVerboseLevel,
3678
3710
  storePendingEscalation: () => storePendingEscalation,
3679
3711
  toFts5Query: () => toFts5Query,
3712
+ toggleSessionLogEnabled: () => toggleSessionLogEnabled,
3680
3713
  toggleShowThinkingUi: () => toggleShowThinkingUi,
3681
3714
  toggleTool: () => toggleTool,
3682
3715
  touchBookmark: () => touchBookmark,
@@ -10359,11 +10392,11 @@ var init_evolve = __esm({
10359
10392
  const body = JSON.parse(await readBody(req));
10360
10393
  const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
10361
10394
  const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
10362
- const { join: join34 } = await import("path");
10395
+ const { join: join35 } = await import("path");
10363
10396
  const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
10364
10397
  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");
10398
+ const soulPath = join35(home, "identity/SOUL.md");
10399
+ const userPath = join35(home, "identity/USER.md");
10367
10400
  const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
10368
10401
  const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
10369
10402
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
@@ -13400,18 +13433,18 @@ function formatToolStart(toolName, input, level) {
13400
13433
  return `\u{1F527} ${toolName}${cmd ? `: ${cmd}` : path ? `: ${path}` : query ? `: ${query}` : ""}`;
13401
13434
  }
13402
13435
  }
13403
- const inputStr = JSON.stringify(input, null, 2).slice(0, 600);
13436
+ const inputStr = JSON.stringify(input, null, 2).slice(0, 300);
13404
13437
  return `\u{1F527} ${toolName}:
13405
13438
  \`\`\`json
13406
13439
  ${inputStr}
13407
13440
  \`\`\``;
13408
13441
  }
13409
13442
  function formatToolResult(toolName, result) {
13410
- const trimmed = result.trim().slice(0, 400);
13443
+ const trimmed = result.trim().slice(0, 250);
13411
13444
  if (!trimmed) return "";
13412
13445
  const firstLine = trimmed.split("\n")[0] ?? "";
13413
13446
  const isError = /error|failed|exception/i.test(firstLine);
13414
- return isError ? `\u274C ${firstLine.slice(0, 120)}` : `\u{1F4E4} Result:
13447
+ return isError ? `\u274C ${firstLine.slice(0, 120)}` : `\u{1F4EC} Result:
13415
13448
  \`\`\`
13416
13449
  ${trimmed}
13417
13450
  \`\`\``;
@@ -16478,13 +16511,13 @@ async function handleEvolveCallback(chatId, data, channel) {
16478
16511
  const { getReflectionStatus: getReflectionStatus2, setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16479
16512
  const current = getReflectionStatus2(getDb(), chatId);
16480
16513
  if (current === "frozen") {
16481
- const { readFileSync: readFileSync26, existsSync: existsSync54 } = await import("fs");
16482
- const { join: join34 } = await import("path");
16514
+ const { readFileSync: readFileSync27, existsSync: existsSync56 } = await import("fs");
16515
+ const { join: join35 } = await import("path");
16483
16516
  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") : "";
16517
+ const soulPath = join35(CC_CLAW_HOME3, "identity/SOUL.md");
16518
+ const userPath = join35(CC_CLAW_HOME3, "identity/USER.md");
16519
+ const soul = existsSync56(soulPath) ? readFileSync27(soulPath, "utf-8") : "";
16520
+ const user = existsSync56(userPath) ? readFileSync27(userPath, "utf-8") : "";
16488
16521
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
16489
16522
  const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
16490
16523
  logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
@@ -18395,8 +18428,8 @@ ${lines.join("\n")}`, { parseMode: "plain" });
18395
18428
  if (arg.startsWith("/") || arg.startsWith("~")) {
18396
18429
  const resolvedPath = arg.startsWith("~") ? arg.replace("~", process.env.HOME ?? "") : arg;
18397
18430
  setCwd(chatId, resolvedPath);
18398
- const basename3 = resolvedPath.split("/").filter(Boolean).pop();
18399
- if (basename3) upsertBookmark(chatId, basename3, resolvedPath, false);
18431
+ const basename4 = resolvedPath.split("/").filter(Boolean).pop();
18432
+ if (basename4) upsertBookmark(chatId, basename4, resolvedPath, false);
18400
18433
  logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Working directory set to ${resolvedPath}`, detail: { field: "cwd", value: resolvedPath } });
18401
18434
  await sendCwdSessionChoice(chatId, resolvedPath, channel);
18402
18435
  return;
@@ -18572,7 +18605,9 @@ Use /model to pick a model with \u26A1 thinking support.`, { parseMode: "plain"
18572
18605
  chatId,
18573
18606
  `\u{1F4AD} Thinking Level \u2014 ${shortModelName(currentModel)}
18574
18607
  Current: ${capitalize(currentLevel)}
18575
- Show thinking tokens: ${showThinkingUi ? "On" : "Off"}${adapter.id === "gemini" ? "\n\n\u26A0\uFE0F Gemini CLI doesn't stream thinking tokens" : ""}`,
18608
+ Show thinking tokens: ${showThinkingUi ? "On" : "Off"}${adapter.id !== "claude" ? `
18609
+
18610
+ \u26A0\uFE0F ${adapter.displayName} CLI doesn't stream thinking tokens` : ""}`,
18576
18611
  buttons
18577
18612
  );
18578
18613
  } else {
@@ -18584,6 +18619,37 @@ Set via callback (keyboard required).`, { parseMode: "plain" });
18584
18619
  }
18585
18620
  break;
18586
18621
  }
18622
+ case "debug": {
18623
+ const { getSessionLogEnabled: getSessionLogEnabled2, toggleSessionLogEnabled: toggleSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
18624
+ const current = getSessionLogEnabled2(chatId);
18625
+ if (commandArgs === "on" || commandArgs === "off") {
18626
+ const { setSessionLogEnabled: setSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
18627
+ const value = commandArgs === "on";
18628
+ setSessionLogEnabled2(chatId, value);
18629
+ await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${value ? "ON" : "OFF"}
18630
+
18631
+ ${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" });
18632
+ } else if (typeof channel.sendKeyboard === "function") {
18633
+ await channel.sendKeyboard(
18634
+ chatId,
18635
+ `\u{1F52C} Session Debug Logging
18636
+
18637
+ Records full, untruncated tool inputs and results to disk for debugging.
18638
+ Logs: ~/.cc-claw/logs/sessions/
18639
+ Retention: ${process.env.SESSION_LOG_RETENTION_DAYS ?? "7"} day(s)
18640
+
18641
+ Currently: ${current ? "ON" : "OFF"}`,
18642
+ [[
18643
+ { label: current ? "\u2713 ON" : "ON", data: "debug_log:on", ...current ? { style: "primary" } : {} },
18644
+ { label: !current ? "\u2713 OFF" : "OFF", data: "debug_log:off", ...!current ? { style: "primary" } : {} }
18645
+ ]]
18646
+ );
18647
+ } else {
18648
+ const next = toggleSessionLogEnabled2(chatId);
18649
+ await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${next ? "ON" : "OFF"}`, { parseMode: "plain" });
18650
+ }
18651
+ break;
18652
+ }
18587
18653
  case "imagine":
18588
18654
  case "image": {
18589
18655
  if (!commandArgs) {
@@ -19494,11 +19560,19 @@ Select thinking/effort level:`,
19494
19560
  backendId = getAdapterForChat(chatId).id;
19495
19561
  } catch {
19496
19562
  }
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.";
19563
+ 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
19564
  } else {
19499
19565
  msg = "\u{1F4AD} Thinking tokens hidden. Toggle on again via /thinking.";
19500
19566
  }
19501
19567
  await channel.sendText(chatId, msg, { parseMode: "plain" });
19568
+ } else if (data.startsWith("debug_log:")) {
19569
+ const value = data.slice(10) === "on";
19570
+ const { setSessionLogEnabled: setSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
19571
+ setSessionLogEnabled2(chatId, value);
19572
+ logActivity(getDb(), { chatId, source: "telegram", eventType: "config_changed", summary: `Session debug log ${value ? "enabled" : "disabled"}`, detail: { field: "session_log", value: String(value) } });
19573
+ await channel.sendText(chatId, `\u{1F52C} Session debug logging: ${value ? "ON" : "OFF"}
19574
+
19575
+ ${value ? "Full tool inputs/results will be saved to ~/.cc-claw/logs/sessions/" : "Session logs disabled."}`, { parseMode: "plain" });
19502
19576
  } else if (data.startsWith("summarizer:")) {
19503
19577
  const rest = data.slice(11);
19504
19578
  if (rest === "auto") {
@@ -20417,6 +20491,206 @@ var init_callbacks = __esm({
20417
20491
  }
20418
20492
  });
20419
20493
 
20494
+ // src/router/session-log.ts
20495
+ var session_log_exports2 = {};
20496
+ __export(session_log_exports2, {
20497
+ SessionLogFile: () => SessionLogFile,
20498
+ cleanupSessionLogs: () => cleanupSessionLogs,
20499
+ getRetentionDays: () => getRetentionDays,
20500
+ listSessionLogs: () => listSessionLogs,
20501
+ startSessionLogCleanupTimer: () => startSessionLogCleanupTimer,
20502
+ tailSessionLog: () => tailSessionLog
20503
+ });
20504
+ import { existsSync as existsSync23, mkdirSync as mkdirSync9, appendFileSync, readdirSync as readdirSync12, unlinkSync as unlinkSync6, statSync as statSync7, createReadStream } from "fs";
20505
+ import { join as join24, basename as basename3 } from "path";
20506
+ import { createInterface as createInterface6 } from "readline";
20507
+ function getRetentionDays() {
20508
+ const env = process.env.SESSION_LOG_RETENTION_DAYS;
20509
+ if (env) {
20510
+ const n = parseInt(env, 10);
20511
+ if (!isNaN(n) && n > 0) return n;
20512
+ }
20513
+ return DEFAULT_RETENTION_DAYS;
20514
+ }
20515
+ function cleanupSessionLogs(retentionDays) {
20516
+ const days = retentionDays ?? getRetentionDays();
20517
+ if (!existsSync23(SESSION_LOGS_PATH)) return 0;
20518
+ const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
20519
+ let cleaned = 0;
20520
+ try {
20521
+ for (const file of readdirSync12(SESSION_LOGS_PATH)) {
20522
+ if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
20523
+ const filePath = join24(SESSION_LOGS_PATH, file);
20524
+ try {
20525
+ const { mtimeMs } = statSync7(filePath);
20526
+ if (mtimeMs < cutoff) {
20527
+ unlinkSync6(filePath);
20528
+ cleaned++;
20529
+ }
20530
+ } catch {
20531
+ }
20532
+ }
20533
+ } catch (err) {
20534
+ log(`[session-log] Cleanup failed: ${err}`);
20535
+ }
20536
+ if (cleaned > 0) {
20537
+ log(`[session-log] Cleaned ${cleaned} session log(s) older than ${days} day(s)`);
20538
+ }
20539
+ return cleaned;
20540
+ }
20541
+ function startSessionLogCleanupTimer() {
20542
+ const timer = setInterval(() => {
20543
+ cleanupSessionLogs();
20544
+ }, 24 * 60 * 60 * 1e3);
20545
+ timer.unref();
20546
+ return timer;
20547
+ }
20548
+ function listSessionLogs() {
20549
+ if (!existsSync23(SESSION_LOGS_PATH)) return [];
20550
+ const logs = [];
20551
+ for (const file of readdirSync12(SESSION_LOGS_PATH)) {
20552
+ if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
20553
+ const filePath = join24(SESSION_LOGS_PATH, file);
20554
+ try {
20555
+ const stat4 = statSync7(filePath);
20556
+ const match = file.match(/^session-(.+?)-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})\.log$/);
20557
+ logs.push({
20558
+ filename: file,
20559
+ filePath,
20560
+ chatId: match?.[1] ?? "unknown",
20561
+ timestamp: match?.[2]?.replace(/-/g, (m, i) => i > 9 ? ":" : m) ?? "unknown",
20562
+ sizeBytes: stat4.size,
20563
+ modifiedAt: stat4.mtime
20564
+ });
20565
+ } catch {
20566
+ }
20567
+ }
20568
+ logs.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
20569
+ return logs;
20570
+ }
20571
+ async function* tailSessionLog(filePath, lines = 50) {
20572
+ if (!existsSync23(filePath)) {
20573
+ yield `File not found: ${filePath}`;
20574
+ return;
20575
+ }
20576
+ const allLines = [];
20577
+ const rl2 = createInterface6({
20578
+ input: createReadStream(filePath, { encoding: "utf-8" }),
20579
+ crlfDelay: Infinity
20580
+ });
20581
+ for await (const line of rl2) {
20582
+ allLines.push(line);
20583
+ }
20584
+ const start = Math.max(0, allLines.length - lines);
20585
+ for (let i = start; i < allLines.length; i++) {
20586
+ yield allLines[i];
20587
+ }
20588
+ }
20589
+ var DEFAULT_RETENTION_DAYS, SessionLogFile;
20590
+ var init_session_log2 = __esm({
20591
+ "src/router/session-log.ts"() {
20592
+ "use strict";
20593
+ init_paths();
20594
+ init_log();
20595
+ DEFAULT_RETENTION_DAYS = 7;
20596
+ SessionLogFile = class {
20597
+ constructor(chatId, backend2, model2) {
20598
+ this.backend = backend2;
20599
+ this.model = model2;
20600
+ if (!existsSync23(SESSION_LOGS_PATH)) {
20601
+ mkdirSync9(SESSION_LOGS_PATH, { recursive: true });
20602
+ }
20603
+ const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
20604
+ const sanitizedChatId = chatId.replace(/[^a-zA-Z0-9_-]/g, "_");
20605
+ this.filePath = join24(SESSION_LOGS_PATH, `session-${sanitizedChatId}-${ts2}.log`);
20606
+ const header2 = [
20607
+ "\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",
20608
+ `CC-Claw Agent Session \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
20609
+ `Chat: ${chatId} | Backend: ${backend2} | Model: ${model2}`,
20610
+ "\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",
20611
+ ""
20612
+ ].join("\n");
20613
+ appendFileSync(this.filePath, header2 + "\n", "utf-8");
20614
+ }
20615
+ filePath;
20616
+ startTime = Date.now();
20617
+ closed = false;
20618
+ /** Log a tool start with full, untruncated input. */
20619
+ logToolStart(toolName, input) {
20620
+ if (this.closed) return;
20621
+ const ts2 = this.timestamp();
20622
+ const inputStr = JSON.stringify(input, null, 2);
20623
+ const entry = `[${ts2}] TOOL_START ${toolName}
20624
+ ${inputStr}
20625
+
20626
+ `;
20627
+ this.append(entry);
20628
+ }
20629
+ /** Log a tool end with full, untruncated result. */
20630
+ logToolEnd(toolName, result) {
20631
+ if (this.closed) return;
20632
+ const ts2 = this.timestamp();
20633
+ const preview = result.length > 5e3 ? `(${result.length} chars)
20634
+ ${result.slice(0, 5e3)}\u2026[truncated]` : result;
20635
+ const entry = `[${ts2}] TOOL_END ${toolName}
20636
+ ${preview}
20637
+
20638
+ `;
20639
+ this.append(entry);
20640
+ }
20641
+ /** Log thinking tokens with full text. */
20642
+ logThinking(text) {
20643
+ if (this.closed) return;
20644
+ const ts2 = this.timestamp();
20645
+ const entry = `[${ts2}] THINKING
20646
+ ${text}
20647
+
20648
+ `;
20649
+ this.append(entry);
20650
+ }
20651
+ /** Log informational entry. */
20652
+ logInfo(text) {
20653
+ if (this.closed) return;
20654
+ const ts2 = this.timestamp();
20655
+ const entry = `[${ts2}] INFO ${text}
20656
+
20657
+ `;
20658
+ this.append(entry);
20659
+ }
20660
+ /** Finalize the session log with elapsed time and token counts. */
20661
+ finalize(elapsedMs, usage2) {
20662
+ if (this.closed) return;
20663
+ this.closed = true;
20664
+ const ts2 = this.timestamp();
20665
+ const elapsed = (elapsedMs / 1e3).toFixed(1);
20666
+ const usageStr = usage2 ? ` | input=${usage2.input} output=${usage2.output}${usage2.cacheRead ? ` cacheRead=${usage2.cacheRead}` : ""}` : "";
20667
+ const entry = `[${ts2}] FINALIZED \u2014 ${elapsed}s elapsed${usageStr}
20668
+ `;
20669
+ this.append(entry);
20670
+ }
20671
+ /** Get the file path for display/reference. */
20672
+ getFilePath() {
20673
+ return this.filePath;
20674
+ }
20675
+ /** Get just the filename (for compact display). */
20676
+ getFilename() {
20677
+ return basename3(this.filePath);
20678
+ }
20679
+ // ── Internal ──────────────────────────────────────────────────────
20680
+ timestamp() {
20681
+ return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
20682
+ }
20683
+ append(text) {
20684
+ try {
20685
+ appendFileSync(this.filePath, text, "utf-8");
20686
+ } catch (err) {
20687
+ log(`[session-log] Write failed: ${err}`);
20688
+ }
20689
+ }
20690
+ };
20691
+ }
20692
+ });
20693
+
20420
20694
  // src/router/live-status.ts
20421
20695
  var live_status_exports = {};
20422
20696
  __export(live_status_exports, {
@@ -20439,22 +20713,20 @@ function renderEntry(e) {
20439
20713
  }
20440
20714
  return e.text;
20441
20715
  }
20442
- function renderEntries(entries, modelLabel, elapsedMs) {
20716
+ function renderEntries(entries, modelLabel, elapsedMs, trimmed) {
20443
20717
  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`, ""];
20718
+ const lines = [`\u23F3 ${modelLabel} \xB7 ${elapsedSec}s`];
20719
+ if (trimmed) lines[0] += " (\u2026)";
20720
+ lines.push("");
20450
20721
  for (const e of entries) lines.push(renderEntry(e));
20451
- if (lines.length === 2) return `\u2705 ${modelLabel} \xB7 ${elapsedSec}s`;
20452
20722
  return lines.join("\n");
20453
20723
  }
20454
- function renderFrozen(entries, modelLabel, elapsedSec) {
20455
- const lines = [`\u{1F4CE} ${modelLabel} \xB7 ${elapsedSec}s`, ""];
20724
+ function renderFinal(entries, modelLabel, elapsedSec, trimmed) {
20725
+ const lines = [`\u2705 ${modelLabel} \xB7 ${elapsedSec}s`];
20726
+ if (trimmed) lines[0] += " (\u2026)";
20727
+ if (entries.length === 0) return lines[0];
20728
+ lines.push("");
20456
20729
  for (const e of entries) lines.push(renderEntry(e));
20457
- if (lines.length === 2) return `\u{1F4CE} ${modelLabel} \xB7 ${elapsedSec}s`;
20458
20730
  return lines.join("\n");
20459
20731
  }
20460
20732
  function makeLiveStatus(chatId, channel, modelLabel, verboseLevel, showThinking) {
@@ -20468,16 +20740,16 @@ function makeLiveStatus(chatId, channel, modelLabel, verboseLevel, showThinking)
20468
20740
  };
20469
20741
  return { liveStatus, toolCb };
20470
20742
  }
20471
- var FLUSH_INTERVAL_MS, MAX_ENTRIES, MAX_THINKING_CHARS, SPILLOVER_THRESHOLD, LiveStatusMessage;
20743
+ var FLUSH_INTERVAL_MS, MAX_THINKING_CHARS, TRIM_THRESHOLD, MAX_ENTRIES, LiveStatusMessage;
20472
20744
  var init_live_status = __esm({
20473
20745
  "src/router/live-status.ts"() {
20474
20746
  "use strict";
20475
20747
  init_log();
20476
20748
  init_helpers();
20477
20749
  FLUSH_INTERVAL_MS = 1e3;
20478
- MAX_ENTRIES = 50;
20479
20750
  MAX_THINKING_CHARS = 800;
20480
- SPILLOVER_THRESHOLD = 3800;
20751
+ TRIM_THRESHOLD = 3500;
20752
+ MAX_ENTRIES = 200;
20481
20753
  LiveStatusMessage = class {
20482
20754
  constructor(chatId, channel, modelLabel, verboseLevel, showThinking = false) {
20483
20755
  this.chatId = chatId;
@@ -20492,11 +20764,10 @@ var init_live_status = __esm({
20492
20764
  flushTimer = null;
20493
20765
  lastRendered = "";
20494
20766
  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;
20767
+ /** Earliest time the next flush is allowed (set after 429 backoff) */
20768
+ nextFlushAllowedAt = 0;
20769
+ /** Tracks whether entries have been trimmed at least once (for display hint). */
20770
+ hasTrimmed = false;
20500
20771
  /** Send the initial status message. Must be called before adding entries. */
20501
20772
  async init() {
20502
20773
  if (!this.channel.sendTextReturningId) return;
@@ -20555,8 +20826,8 @@ var init_live_status = __esm({
20555
20826
  }
20556
20827
  if (!this.messageId || !this.channel.editText) return;
20557
20828
  const elapsedSec = (elapsedMs / 1e3).toFixed(1);
20558
- const currentEntries = dedupThinking(this.entries.slice(this.frozenEntryCount));
20559
- const body = renderFinal(currentEntries, this.modelLabel, elapsedSec);
20829
+ const deduped = dedupThinking(this.entries);
20830
+ const body = renderFinal(deduped, this.modelLabel, elapsedSec, this.hasTrimmed);
20560
20831
  try {
20561
20832
  await this.channel.editText(this.chatId, this.messageId, body, "plain");
20562
20833
  } catch (err) {
@@ -20570,52 +20841,47 @@ var init_live_status = __esm({
20570
20841
  // ── Internal ──────────────────────────────────────────────────────────
20571
20842
  async flush() {
20572
20843
  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
- }
20844
+ if (Date.now() < this.nextFlushAllowedAt) return;
20845
+ const deduped = dedupThinking(this.entries);
20846
+ const body = renderEntries(deduped, this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
20579
20847
  if (body === this.lastRendered) return;
20580
20848
  this.lastRendered = body;
20581
20849
  try {
20582
20850
  await this.channel.editText(this.chatId, this.messageId, body, "plain");
20583
20851
  } catch (err) {
20584
- log(`[live-status] flush edit failed: ${err}`);
20852
+ this.handleRateLimit(err);
20585
20853
  }
20586
20854
  }
20587
20855
  /**
20588
- * Freeze the current message and start a new continuation message.
20589
- * The frozen message keeps its content (with 📎 prefix) nothing is lost.
20856
+ * Trim entries from the BEGINNING when the rendered body exceeds the threshold.
20857
+ * This is the core of the single-message pattern: always show the most recent
20858
+ * activity, drop the oldest entries that scroll past the limit.
20590
20859
  */
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}`);
20860
+ trimEntries() {
20861
+ if (this.entries.length > MAX_ENTRIES) {
20862
+ this.entries = this.entries.slice(this.entries.length - MAX_ENTRIES);
20863
+ this.hasTrimmed = true;
20600
20864
  }
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}`);
20865
+ let rendered = renderEntries(dedupThinking(this.entries), this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
20866
+ while (rendered.length > TRIM_THRESHOLD && this.entries.length > 3) {
20867
+ this.entries.shift();
20868
+ this.hasTrimmed = true;
20869
+ rendered = renderEntries(dedupThinking(this.entries), this.modelLabel, Date.now() - this.startTime, this.hasTrimmed);
20611
20870
  }
20612
20871
  }
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];
20872
+ /**
20873
+ * Handle Telegram 429 rate-limit errors by backing off.
20874
+ * Parses the "retry after N" hint and sets a cooldown.
20875
+ */
20876
+ handleRateLimit(err) {
20877
+ const msg = String(err);
20878
+ const match = msg.match(/retry after (\d+)/i);
20879
+ if (match) {
20880
+ const retrySec = parseInt(match[1], 10) || 3;
20881
+ this.nextFlushAllowedAt = Date.now() + retrySec * 1e3;
20882
+ log(`[live-status] 429 rate-limited, backing off ${retrySec}s`);
20883
+ } else {
20884
+ log(`[live-status] edit failed: ${msg}`);
20619
20885
  }
20620
20886
  }
20621
20887
  };
@@ -20955,16 +21221,40 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
20955
21221
  const needsLiveStatus = tVerbose !== "off" || showThinkingUi;
20956
21222
  let liveStatus = null;
20957
21223
  let tToolCb;
21224
+ const { getSessionLogEnabled: getSessionLogEnabled2 } = await Promise.resolve().then(() => (init_chat_settings(), chat_settings_exports));
21225
+ const { SessionLogFile: SessionLogFile2 } = await Promise.resolve().then(() => (init_session_log2(), session_log_exports2));
21226
+ let sessionLog = null;
21227
+ if (getSessionLogEnabled2(chatId)) {
21228
+ sessionLog = new SessionLogFile2(chatId, adapter.id, model2 ?? adapter.defaultModel);
21229
+ }
20958
21230
  if (needsLiveStatus) {
20959
21231
  const { makeLiveStatus: makeLiveStatus2 } = await Promise.resolve().then(() => (init_live_status(), live_status_exports));
20960
21232
  const effectiveVerbose = tVerbose === "off" ? "normal" : tVerbose;
20961
21233
  const ls = makeLiveStatus2(chatId, channel, modelLabel, effectiveVerbose, showThinkingUi);
20962
21234
  liveStatus = ls.liveStatus;
20963
- tToolCb = tVerbose !== "off" ? ls.toolCb : void 0;
21235
+ const baseCb = tVerbose !== "off" ? ls.toolCb : void 0;
21236
+ tToolCb = async (toolName, input, result) => {
21237
+ if (baseCb) await baseCb(toolName, input, result);
21238
+ if (sessionLog) {
21239
+ if (result === void 0) {
21240
+ sessionLog.logToolStart(toolName, input);
21241
+ } else {
21242
+ sessionLog.logToolEnd(toolName, result);
21243
+ }
21244
+ }
21245
+ };
20964
21246
  await liveStatus.init();
20965
- if (showThinkingUi && adapter.id === "gemini") {
20966
- liveStatus.addInfo("\u{1F4AD} Thinking display not available for Gemini");
21247
+ if (showThinkingUi && adapter.id !== "claude") {
21248
+ liveStatus.addInfo(`\u{1F4AD} Thinking display not available for ${adapter.displayName}`);
20967
21249
  }
21250
+ } else if (sessionLog) {
21251
+ tToolCb = async (toolName, input, result) => {
21252
+ if (result === void 0) {
21253
+ sessionLog.logToolStart(toolName, input);
21254
+ } else {
21255
+ sessionLog.logToolEnd(toolName, result);
21256
+ }
21257
+ };
20968
21258
  }
20969
21259
  const sigT0 = Date.now();
20970
21260
  const response = await askAgent(chatId, cleanText || text, {
@@ -20975,7 +21265,10 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
20975
21265
  bootstrapTier,
20976
21266
  maxTurns,
20977
21267
  agentMode: effectiveAgentMode,
20978
- onThinking: liveStatus ? (chunk) => liveStatus.addThinking(chunk) : void 0,
21268
+ onThinking: liveStatus || sessionLog ? (chunk) => {
21269
+ if (liveStatus) liveStatus.addThinking(chunk);
21270
+ if (sessionLog) sessionLog.logThinking(chunk);
21271
+ } : void 0,
20979
21272
  onSubagentActivity: (backendId2, info) => {
20980
21273
  observedSubagents.add(info.name);
20981
21274
  try {
@@ -21015,6 +21308,7 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
21015
21308
  liveStatus.addThinking(response.thinkingText.trim());
21016
21309
  }
21017
21310
  if (liveStatus) await liveStatus.finalize(elapsedMs);
21311
+ if (sessionLog) sessionLog.finalize(elapsedMs, response.usage);
21018
21312
  if (response.usage) addUsage(chatId, response.usage.input, response.usage.output, response.usage.cacheRead, model2, void 0, response.usage.contextSize);
21019
21313
  let responseText = response.text;
21020
21314
  const sigEnabled = getModelSignature(chatId);
@@ -21523,7 +21817,7 @@ var init_cron = __esm({
21523
21817
  });
21524
21818
 
21525
21819
  // src/agents/runners/wrap-backend.ts
21526
- import { join as join24 } from "path";
21820
+ import { join as join25 } from "path";
21527
21821
  function buildMcpCommands(backendId) {
21528
21822
  const exe = backendId === "cursor" ? "agent" : backendId;
21529
21823
  return {
@@ -21617,7 +21911,7 @@ function wrapBackendAdapter(adapter) {
21617
21911
  const configPath = writeMcpConfigFile(server);
21618
21912
  return ["--mcp-config", configPath];
21619
21913
  },
21620
- getSkillPath: () => join24(SKILLS_PATH, `agent-${adapter.id}.md`)
21914
+ getSkillPath: () => join25(SKILLS_PATH, `agent-${adapter.id}.md`)
21621
21915
  };
21622
21916
  }
21623
21917
  var BACKEND_CAPABILITIES;
@@ -21668,18 +21962,18 @@ var init_wrap_backend = __esm({
21668
21962
  });
21669
21963
 
21670
21964
  // 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";
21965
+ import { readFileSync as readFileSync14, readdirSync as readdirSync13, existsSync as existsSync24, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
21966
+ import { join as join26 } from "path";
21673
21967
  import { execFileSync as execFileSync2 } from "child_process";
21674
21968
  function resolveExecutable(config2) {
21675
- if (existsSync23(config2.executable)) return config2.executable;
21969
+ if (existsSync24(config2.executable)) return config2.executable;
21676
21970
  try {
21677
21971
  return execFileSync2("which", [config2.executable], { encoding: "utf-8" }).trim();
21678
21972
  } catch {
21679
21973
  }
21680
21974
  for (const fallback of config2.executableFallbacks ?? []) {
21681
21975
  const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
21682
- if (existsSync23(resolved)) return resolved;
21976
+ if (existsSync24(resolved)) return resolved;
21683
21977
  }
21684
21978
  return config2.executable;
21685
21979
  }
@@ -21805,7 +22099,7 @@ function configToRunner(config2) {
21805
22099
  prepareMcpInjection() {
21806
22100
  return [];
21807
22101
  },
21808
- getSkillPath: () => join25(SKILLS_PATH, `agent-${config2.id}.md`)
22102
+ getSkillPath: () => join26(SKILLS_PATH, `agent-${config2.id}.md`)
21809
22103
  };
21810
22104
  }
21811
22105
  function loadRunnerConfig(filePath) {
@@ -21818,14 +22112,14 @@ function loadRunnerConfig(filePath) {
21818
22112
  }
21819
22113
  }
21820
22114
  function loadAllRunnerConfigs() {
21821
- if (!existsSync23(RUNNERS_PATH)) {
21822
- mkdirSync9(RUNNERS_PATH, { recursive: true });
22115
+ if (!existsSync24(RUNNERS_PATH)) {
22116
+ mkdirSync10(RUNNERS_PATH, { recursive: true });
21823
22117
  return [];
21824
22118
  }
21825
- const files = readdirSync12(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
22119
+ const files = readdirSync13(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
21826
22120
  const configs = [];
21827
22121
  for (const file of files) {
21828
- const config2 = loadRunnerConfig(join25(RUNNERS_PATH, file));
22122
+ const config2 = loadRunnerConfig(join26(RUNNERS_PATH, file));
21829
22123
  if (config2) configs.push(config2);
21830
22124
  }
21831
22125
  return configs;
@@ -21846,16 +22140,16 @@ function registerConfigRunners() {
21846
22140
  return count;
21847
22141
  }
21848
22142
  function watchRunnerConfigs(onChange) {
21849
- if (!existsSync23(RUNNERS_PATH)) return;
22143
+ if (!existsSync24(RUNNERS_PATH)) return;
21850
22144
  for (const prev of watchedFiles) {
21851
- if (!existsSync23(prev)) {
22145
+ if (!existsSync24(prev)) {
21852
22146
  unwatchFile(prev);
21853
22147
  watchedFiles.delete(prev);
21854
22148
  }
21855
22149
  }
21856
- const files = readdirSync12(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
22150
+ const files = readdirSync13(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
21857
22151
  for (const file of files) {
21858
- const fullPath = join25(RUNNERS_PATH, file);
22152
+ const fullPath = join26(RUNNERS_PATH, file);
21859
22153
  if (watchedFiles.has(fullPath)) continue;
21860
22154
  watchedFiles.add(fullPath);
21861
22155
  watchFile(fullPath, { interval: 5e3 }, () => {
@@ -22256,6 +22550,7 @@ var init_telegram2 = __esm({
22256
22550
  { command: "mode", description: "Execution gate (approved/yolo)" },
22257
22551
  { command: "tools", description: "Configure which tools the agent can use" },
22258
22552
  { command: "verbose", description: "Tool visibility (off/normal/verbose)" },
22553
+ { command: "debug", description: "Toggle session debug logging (full tool I/O)" },
22259
22554
  { command: "cwd", description: "Set or show working directory" },
22260
22555
  // Memory
22261
22556
  { command: "memory", description: "List stored memories" },
@@ -22702,19 +22997,19 @@ var init_telegram2 = __esm({
22702
22997
  });
22703
22998
 
22704
22999
  // src/skills/bootstrap.ts
22705
- import { existsSync as existsSync24 } from "fs";
23000
+ import { existsSync as existsSync25 } from "fs";
22706
23001
  import { readdir as readdir6, readFile as readFile8, writeFile as writeFile5, copyFile } from "fs/promises";
22707
- import { join as join26, dirname as dirname5 } from "path";
23002
+ import { join as join27, dirname as dirname5 } from "path";
22708
23003
  import { fileURLToPath as fileURLToPath2 } from "url";
22709
23004
  async function copyAgentManifestSkills() {
22710
- if (!existsSync24(PKG_SKILLS)) return;
23005
+ if (!existsSync25(PKG_SKILLS)) return;
22711
23006
  try {
22712
23007
  const entries = await readdir6(PKG_SKILLS, { withFileTypes: true });
22713
23008
  for (const entry of entries) {
22714
23009
  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;
23010
+ const src = join27(PKG_SKILLS, entry.name);
23011
+ const dest = join27(SKILLS_PATH, entry.name);
23012
+ if (existsSync25(dest)) continue;
22718
23013
  await copyFile(src, dest);
22719
23014
  log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
22720
23015
  }
@@ -22724,8 +23019,8 @@ async function copyAgentManifestSkills() {
22724
23019
  }
22725
23020
  async function bootstrapSkills() {
22726
23021
  await copyAgentManifestSkills();
22727
- const usmDir = join26(SKILLS_PATH, USM_DIR_NAME);
22728
- if (existsSync24(usmDir)) return;
23022
+ const usmDir = join27(SKILLS_PATH, USM_DIR_NAME);
23023
+ if (existsSync25(usmDir)) return;
22729
23024
  try {
22730
23025
  const entries = await readdir6(SKILLS_PATH);
22731
23026
  const dirs = entries.filter((e) => !e.startsWith("."));
@@ -22747,8 +23042,8 @@ async function bootstrapSkills() {
22747
23042
  }
22748
23043
  }
22749
23044
  async function patchUsmForCcClaw(usmDir) {
22750
- const skillPath = join26(usmDir, "SKILL.md");
22751
- if (!existsSync24(skillPath)) return;
23045
+ const skillPath = join27(usmDir, "SKILL.md");
23046
+ if (!existsSync25(skillPath)) return;
22752
23047
  try {
22753
23048
  let content = await readFile8(skillPath, "utf-8");
22754
23049
  let patched = false;
@@ -22793,8 +23088,8 @@ var init_bootstrap = __esm({
22793
23088
  USM_REPO = "jacob-bd/universal-skills-manager";
22794
23089
  USM_DIR_NAME = "universal-skills-manager";
22795
23090
  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");
23091
+ PKG_ROOT = join27(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
23092
+ PKG_SKILLS = join27(PKG_ROOT, "skills");
22798
23093
  }
22799
23094
  });
22800
23095
 
@@ -23016,13 +23311,13 @@ __export(ai_skill_exports, {
23016
23311
  generateAiSkill: () => generateAiSkill,
23017
23312
  installAiSkill: () => installAiSkill
23018
23313
  });
23019
- import { existsSync as existsSync25, writeFileSync as writeFileSync8, mkdirSync as mkdirSync10 } from "fs";
23020
- import { join as join27 } from "path";
23314
+ import { existsSync as existsSync26, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
23315
+ import { join as join28 } from "path";
23021
23316
  import { homedir as homedir9 } from "os";
23022
23317
  function generateAiSkill() {
23023
23318
  const version = VERSION;
23024
23319
  let systemState = "";
23025
- if (existsSync25(DB_PATH)) {
23320
+ if (existsSync26(DB_PATH)) {
23026
23321
  try {
23027
23322
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
23028
23323
  const readDb = openDatabaseReadOnly2();
@@ -23110,6 +23405,7 @@ Use the CC-Claw CLI when you need to:
23110
23405
  - \`/model_signature\` \u2014 Show/hide model name on responses
23111
23406
  - \`/agents mode\` \u2014 Agent mode (auto/native/claw)
23112
23407
  - \`/voice_config\` \u2014 Voice provider settings
23408
+ - \`/debug\` \u2014 Toggle per-chat session debug logging (full tool I/O to disk)
23113
23409
 
23114
23410
  **Memory:**
23115
23411
  - \`/remember <text>\` \u2014 Save a memory
@@ -23152,6 +23448,16 @@ cc-claw logs --error # Show error log
23152
23448
  cc-claw logs --lines 50 # Show last N lines
23153
23449
  \`\`\`
23154
23450
 
23451
+ ### Session Debug Logs
23452
+ \`\`\`bash
23453
+ cc-claw session-logs list # List all session debug logs
23454
+ cc-claw session-logs tail # Tail latest session log
23455
+ cc-claw session-logs tail -f # Follow latest log (like tail -f)
23456
+ cc-claw session-logs tail --file <name> # Tail a specific log file
23457
+ cc-claw session-logs clean # Remove old session logs
23458
+ cc-claw session-logs clean --days 3 # Remove logs older than 3 days
23459
+ \`\`\`
23460
+
23155
23461
  ### Backend & Model
23156
23462
  \`\`\`bash
23157
23463
  cc-claw backend list --json # Available backends
@@ -23426,10 +23732,10 @@ function installAiSkill() {
23426
23732
  const failed = [];
23427
23733
  for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
23428
23734
  for (const dir of dirs) {
23429
- const skillDir = join27(dir, "cc-claw-cli");
23430
- const skillPath = join27(skillDir, "SKILL.md");
23735
+ const skillDir = join28(dir, "cc-claw-cli");
23736
+ const skillPath = join28(skillDir, "SKILL.md");
23431
23737
  try {
23432
- mkdirSync10(skillDir, { recursive: true });
23738
+ mkdirSync11(skillDir, { recursive: true });
23433
23739
  writeFileSync8(skillPath, skill, "utf-8");
23434
23740
  installed.push(skillPath);
23435
23741
  } catch {
@@ -23446,11 +23752,11 @@ var init_ai_skill = __esm({
23446
23752
  init_paths();
23447
23753
  init_version();
23448
23754
  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")]
23755
+ "cc-claw": [join28(homedir9(), ".cc-claw", "workspace", "skills")],
23756
+ claude: [join28(homedir9(), ".claude", "skills")],
23757
+ gemini: [join28(homedir9(), ".gemini", "skills")],
23758
+ codex: [join28(homedir9(), ".agents", "skills")],
23759
+ cursor: [join28(homedir9(), ".cursor", "skills"), join28(homedir9(), ".cursor", "skills-cursor")]
23454
23760
  };
23455
23761
  }
23456
23762
  });
@@ -23460,21 +23766,21 @@ var index_exports = {};
23460
23766
  __export(index_exports, {
23461
23767
  main: () => main
23462
23768
  });
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";
23769
+ import { mkdirSync as mkdirSync12, existsSync as existsSync27, renameSync as renameSync2, statSync as statSync8, readFileSync as readFileSync16 } from "fs";
23770
+ import { join as join29 } from "path";
23465
23771
  import dotenv from "dotenv";
23466
23772
  function migrateLayout() {
23467
23773
  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")]
23774
+ [join29(CC_CLAW_HOME, "cc-claw.db"), join29(DATA_PATH, "cc-claw.db")],
23775
+ [join29(CC_CLAW_HOME, "cc-claw.db-shm"), join29(DATA_PATH, "cc-claw.db-shm")],
23776
+ [join29(CC_CLAW_HOME, "cc-claw.db-wal"), join29(DATA_PATH, "cc-claw.db-wal")],
23777
+ [join29(CC_CLAW_HOME, "cc-claw.log"), join29(LOGS_PATH, "cc-claw.log")],
23778
+ [join29(CC_CLAW_HOME, "cc-claw.log.1"), join29(LOGS_PATH, "cc-claw.log.1")],
23779
+ [join29(CC_CLAW_HOME, "cc-claw.error.log"), join29(LOGS_PATH, "cc-claw.error.log")],
23780
+ [join29(CC_CLAW_HOME, "cc-claw.error.log.1"), join29(LOGS_PATH, "cc-claw.error.log.1")]
23475
23781
  ];
23476
23782
  for (const [from, to] of moves) {
23477
- if (existsSync26(from) && !existsSync26(to)) {
23783
+ if (existsSync27(from) && !existsSync27(to)) {
23478
23784
  try {
23479
23785
  renameSync2(from, to);
23480
23786
  } catch {
@@ -23485,7 +23791,7 @@ function migrateLayout() {
23485
23791
  function rotateLogs() {
23486
23792
  for (const file of [LOG_PATH, ERROR_LOG_PATH]) {
23487
23793
  try {
23488
- const { size } = statSync7(file);
23794
+ const { size } = statSync8(file);
23489
23795
  if (size > LOG_MAX_BYTES) {
23490
23796
  const archivePath = `${file}.1`;
23491
23797
  try {
@@ -23619,11 +23925,11 @@ async function main() {
23619
23925
  bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
23620
23926
  try {
23621
23927
  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");
23928
+ const { writeFileSync: writeFileSync13, mkdirSync: mkdirSync19 } = await import("fs");
23929
+ const { join: join35 } = await import("path");
23930
+ const skillDir = join35(SKILLS_PATH, "cc-claw-cli");
23931
+ mkdirSync19(skillDir, { recursive: true });
23932
+ writeFileSync13(join35(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
23627
23933
  log("[cc-claw] AI skill updated");
23628
23934
  } catch {
23629
23935
  }
@@ -23643,6 +23949,12 @@ async function main() {
23643
23949
  cleanupOldMedia().catch(() => {
23644
23950
  });
23645
23951
  pruneImageCache();
23952
+ try {
23953
+ const { cleanupSessionLogs: cleanupSessionLogs2, startSessionLogCleanupTimer: startSessionLogCleanupTimer2 } = await Promise.resolve().then(() => (init_session_log2(), session_log_exports2));
23954
+ cleanupSessionLogs2();
23955
+ startSessionLogCleanupTimer2();
23956
+ } catch {
23957
+ }
23646
23958
  log("[cc-claw] Ready!");
23647
23959
  const shutdown = async (signal) => {
23648
23960
  log(`[cc-claw] Received ${signal}, shutting down...`);
@@ -23695,11 +24007,11 @@ var init_index = __esm({
23695
24007
  init_bootstrap2();
23696
24008
  init_health3();
23697
24009
  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 });
24010
+ for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SESSION_LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
24011
+ if (!existsSync27(dir)) mkdirSync12(dir, { recursive: true });
23700
24012
  }
23701
24013
  migrateLayout();
23702
- if (existsSync26(ENV_PATH)) {
24014
+ if (existsSync27(ENV_PATH)) {
23703
24015
  dotenv.config({ path: ENV_PATH });
23704
24016
  } else {
23705
24017
  console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
@@ -23720,12 +24032,12 @@ __export(api_client_exports, {
23720
24032
  apiPost: () => apiPost,
23721
24033
  isDaemonRunning: () => isDaemonRunning
23722
24034
  });
23723
- import { readFileSync as readFileSync17, existsSync as existsSync27 } from "fs";
24035
+ import { readFileSync as readFileSync17, existsSync as existsSync28 } from "fs";
23724
24036
  import { request as httpRequest, Agent } from "http";
23725
24037
  function getToken() {
23726
24038
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
23727
24039
  try {
23728
- if (existsSync27(TOKEN_PATH)) return readFileSync17(TOKEN_PATH, "utf-8").trim();
24040
+ if (existsSync28(TOKEN_PATH)) return readFileSync17(TOKEN_PATH, "utf-8").trim();
23729
24041
  } catch {
23730
24042
  }
23731
24043
  return null;
@@ -23824,10 +24136,10 @@ __export(service_exports, {
23824
24136
  serviceStatus: () => serviceStatus,
23825
24137
  uninstallService: () => uninstallService
23826
24138
  });
23827
- import { existsSync as existsSync28, mkdirSync as mkdirSync12, writeFileSync as writeFileSync9, unlinkSync as unlinkSync6 } from "fs";
24139
+ import { existsSync as existsSync29, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, unlinkSync as unlinkSync7 } from "fs";
23828
24140
  import { execFileSync as execFileSync3, execSync as execSync6 } from "child_process";
23829
24141
  import { homedir as homedir10, platform } from "os";
23830
- import { join as join29, dirname as dirname6 } from "path";
24142
+ import { join as join30, dirname as dirname6 } from "path";
23831
24143
  function xmlEscape(s) {
23832
24144
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
23833
24145
  }
@@ -23836,7 +24148,7 @@ function resolveExecutable2(name) {
23836
24148
  return execFileSync3("which", [name], { encoding: "utf-8" }).trim();
23837
24149
  } catch {
23838
24150
  const fallback = process.argv[1];
23839
- if (fallback && existsSync28(fallback)) return fallback;
24151
+ if (fallback && existsSync29(fallback)) return fallback;
23840
24152
  throw new Error(`Cannot find '${name}' executable. Install globally: npm install -g cc-claw`);
23841
24153
  }
23842
24154
  }
@@ -23845,14 +24157,14 @@ function getPathDirs() {
23845
24157
  const home = homedir10();
23846
24158
  const dirs = /* @__PURE__ */ new Set([
23847
24159
  nodeBin,
23848
- join29(home, ".local", "bin"),
24160
+ join30(home, ".local", "bin"),
23849
24161
  "/usr/local/bin",
23850
24162
  "/usr/bin",
23851
24163
  "/bin"
23852
24164
  ]);
23853
24165
  try {
23854
24166
  const prefix = execSync6("npm config get prefix", { encoding: "utf-8" }).trim();
23855
- if (prefix) dirs.add(join29(prefix, "bin"));
24167
+ if (prefix) dirs.add(join30(prefix, "bin"));
23856
24168
  } catch {
23857
24169
  }
23858
24170
  return [...dirs].join(":");
@@ -23911,9 +24223,9 @@ function generatePlist() {
23911
24223
  }
23912
24224
  function installMacOS() {
23913
24225
  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)) {
24226
+ if (!existsSync29(agentsDir)) mkdirSync13(agentsDir, { recursive: true });
24227
+ if (!existsSync29(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
24228
+ if (existsSync29(PLIST_PATH)) {
23917
24229
  try {
23918
24230
  execFileSync3("launchctl", ["unload", PLIST_PATH]);
23919
24231
  } catch {
@@ -23925,7 +24237,7 @@ function installMacOS() {
23925
24237
  console.log(" Service loaded and starting.");
23926
24238
  }
23927
24239
  function uninstallMacOS() {
23928
- if (!existsSync28(PLIST_PATH)) {
24240
+ if (!existsSync29(PLIST_PATH)) {
23929
24241
  console.log(" No service found to uninstall.");
23930
24242
  return;
23931
24243
  }
@@ -23933,7 +24245,7 @@ function uninstallMacOS() {
23933
24245
  execFileSync3("launchctl", ["unload", PLIST_PATH]);
23934
24246
  } catch {
23935
24247
  }
23936
- unlinkSync6(PLIST_PATH);
24248
+ unlinkSync7(PLIST_PATH);
23937
24249
  console.log(" Service uninstalled.");
23938
24250
  }
23939
24251
  function formatUptime(seconds) {
@@ -24000,8 +24312,8 @@ WantedBy=default.target
24000
24312
  `;
24001
24313
  }
24002
24314
  function installLinux() {
24003
- if (!existsSync28(SYSTEMD_DIR)) mkdirSync12(SYSTEMD_DIR, { recursive: true });
24004
- if (!existsSync28(LOGS_PATH)) mkdirSync12(LOGS_PATH, { recursive: true });
24315
+ if (!existsSync29(SYSTEMD_DIR)) mkdirSync13(SYSTEMD_DIR, { recursive: true });
24316
+ if (!existsSync29(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
24005
24317
  writeFileSync9(UNIT_PATH, generateUnit());
24006
24318
  console.log(` Installed: ${UNIT_PATH}`);
24007
24319
  execFileSync3("systemctl", ["--user", "daemon-reload"]);
@@ -24010,7 +24322,7 @@ function installLinux() {
24010
24322
  console.log(" Service enabled and started.");
24011
24323
  }
24012
24324
  function uninstallLinux() {
24013
- if (!existsSync28(UNIT_PATH)) {
24325
+ if (!existsSync29(UNIT_PATH)) {
24014
24326
  console.log(" No service found to uninstall.");
24015
24327
  return;
24016
24328
  }
@@ -24022,7 +24334,7 @@ function uninstallLinux() {
24022
24334
  execFileSync3("systemctl", ["--user", "disable", "cc-claw"]);
24023
24335
  } catch {
24024
24336
  }
24025
- unlinkSync6(UNIT_PATH);
24337
+ unlinkSync7(UNIT_PATH);
24026
24338
  execFileSync3("systemctl", ["--user", "daemon-reload"]);
24027
24339
  console.log(" Service uninstalled.");
24028
24340
  }
@@ -24035,7 +24347,7 @@ function statusLinux() {
24035
24347
  }
24036
24348
  }
24037
24349
  function installService() {
24038
- if (!existsSync28(join29(CC_CLAW_HOME, ".env"))) {
24350
+ if (!existsSync29(join30(CC_CLAW_HOME, ".env"))) {
24039
24351
  console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
24040
24352
  console.error(" Run 'cc-claw setup' before installing the service.");
24041
24353
  process.exitCode = 1;
@@ -24064,9 +24376,9 @@ var init_service = __esm({
24064
24376
  "use strict";
24065
24377
  init_paths();
24066
24378
  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");
24379
+ PLIST_PATH = join30(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
24380
+ SYSTEMD_DIR = join30(homedir10(), ".config", "systemd", "user");
24381
+ UNIT_PATH = join30(SYSTEMD_DIR, "cc-claw.service");
24070
24382
  }
24071
24383
  });
24072
24384
 
@@ -24263,7 +24575,7 @@ var status_exports = {};
24263
24575
  __export(status_exports, {
24264
24576
  statusCommand: () => statusCommand
24265
24577
  });
24266
- import { existsSync as existsSync29, statSync as statSync8 } from "fs";
24578
+ import { existsSync as existsSync30, statSync as statSync9 } from "fs";
24267
24579
  async function statusCommand(globalOpts, localOpts) {
24268
24580
  try {
24269
24581
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -24303,7 +24615,7 @@ async function statusCommand(globalOpts, localOpts) {
24303
24615
  const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
24304
24616
  const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
24305
24617
  const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
24306
- const dbStat = existsSync29(DB_PATH) ? statSync8(DB_PATH) : null;
24618
+ const dbStat = existsSync30(DB_PATH) ? statSync9(DB_PATH) : null;
24307
24619
  let daemonRunning = false;
24308
24620
  let daemonInfo = {};
24309
24621
  try {
@@ -24392,12 +24704,12 @@ var doctor_exports = {};
24392
24704
  __export(doctor_exports, {
24393
24705
  doctorCommand: () => doctorCommand
24394
24706
  });
24395
- import { existsSync as existsSync30, statSync as statSync9, accessSync, constants } from "fs";
24707
+ import { existsSync as existsSync31, statSync as statSync10, accessSync, constants } from "fs";
24396
24708
  import { execFileSync as execFileSync4 } from "child_process";
24397
24709
  async function doctorCommand(globalOpts, localOpts) {
24398
24710
  const checks = [];
24399
- if (existsSync30(DB_PATH)) {
24400
- const size = statSync9(DB_PATH).size;
24711
+ if (existsSync31(DB_PATH)) {
24712
+ const size = statSync10(DB_PATH).size;
24401
24713
  checks.push({ name: "Database", status: "ok", message: `${DB_PATH} (${(size / 1024).toFixed(0)}KB)` });
24402
24714
  try {
24403
24715
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -24426,7 +24738,7 @@ async function doctorCommand(globalOpts, localOpts) {
24426
24738
  } else {
24427
24739
  checks.push({ name: "Database", status: "error", message: `Not found at ${DB_PATH}`, fix: "cc-claw setup" });
24428
24740
  }
24429
- if (existsSync30(ENV_PATH)) {
24741
+ if (existsSync31(ENV_PATH)) {
24430
24742
  checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
24431
24743
  } else {
24432
24744
  checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
@@ -24481,7 +24793,7 @@ async function doctorCommand(globalOpts, localOpts) {
24481
24793
  } catch {
24482
24794
  }
24483
24795
  const tokenPath = `${DATA_PATH}/api-token`;
24484
- if (existsSync30(tokenPath)) {
24796
+ if (existsSync31(tokenPath)) {
24485
24797
  try {
24486
24798
  accessSync(tokenPath, constants.R_OK);
24487
24799
  checks.push({ name: "API token", status: "ok", message: "token file readable" });
@@ -24506,10 +24818,10 @@ async function doctorCommand(globalOpts, localOpts) {
24506
24818
  }
24507
24819
  } catch {
24508
24820
  }
24509
- if (existsSync30(ERROR_LOG_PATH)) {
24821
+ if (existsSync31(ERROR_LOG_PATH)) {
24510
24822
  try {
24511
- const { readFileSync: readFileSync26 } = await import("fs");
24512
- const logContent = readFileSync26(ERROR_LOG_PATH, "utf-8");
24823
+ const { readFileSync: readFileSync27 } = await import("fs");
24824
+ const logContent = readFileSync27(ERROR_LOG_PATH, "utf-8");
24513
24825
  const recentLines = logContent.split("\n").filter(Boolean).slice(-100);
24514
24826
  const last24h = Date.now() - 864e5;
24515
24827
  const recentErrors = recentLines.filter((line) => {
@@ -24632,10 +24944,10 @@ var logs_exports = {};
24632
24944
  __export(logs_exports, {
24633
24945
  logsCommand: () => logsCommand
24634
24946
  });
24635
- import { existsSync as existsSync31, readFileSync as readFileSync20, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
24947
+ import { existsSync as existsSync32, readFileSync as readFileSync20, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
24636
24948
  async function logsCommand(opts) {
24637
24949
  const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
24638
- if (!existsSync31(logFile)) {
24950
+ if (!existsSync32(logFile)) {
24639
24951
  outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
24640
24952
  process.exit(1);
24641
24953
  }
@@ -24675,6 +24987,105 @@ var init_logs = __esm({
24675
24987
  }
24676
24988
  });
24677
24989
 
24990
+ // src/cli/commands/session-logs.ts
24991
+ var session_logs_exports = {};
24992
+ __export(session_logs_exports, {
24993
+ sessionLogsClean: () => sessionLogsClean,
24994
+ sessionLogsList: () => sessionLogsList,
24995
+ sessionLogsTail: () => sessionLogsTail
24996
+ });
24997
+ import { readFileSync as readFileSync21, watchFile as watchFile3, unwatchFile as unwatchFile3 } from "fs";
24998
+ async function sessionLogsList(opts) {
24999
+ const logs = listSessionLogs();
25000
+ if (logs.length === 0) {
25001
+ console.log(muted(" No session debug logs found."));
25002
+ console.log(muted(` Enable via /debug in Telegram, then logs will appear in ${SESSION_LOGS_PATH}`));
25003
+ return;
25004
+ }
25005
+ if (opts.json) {
25006
+ console.log(JSON.stringify(logs.map((l) => ({
25007
+ filename: l.filename,
25008
+ chatId: l.chatId,
25009
+ timestamp: l.timestamp,
25010
+ sizeBytes: l.sizeBytes,
25011
+ modifiedAt: l.modifiedAt.toISOString()
25012
+ })), null, 2));
25013
+ return;
25014
+ }
25015
+ console.log(muted(` \u2500\u2500 Session Debug Logs (${logs.length}) \u2500\u2500
25016
+ `));
25017
+ console.log(` ${"Filename".padEnd(55)} ${"Size".padStart(8)} Chat ID`);
25018
+ console.log(` ${"\u2500".repeat(55)} ${"\u2500".repeat(8)} ${"\u2500".repeat(15)}`);
25019
+ for (const log5 of logs) {
25020
+ 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`;
25021
+ console.log(` ${log5.filename.padEnd(55)} ${size.padStart(8)} ${log5.chatId}`);
25022
+ }
25023
+ console.log(muted(`
25024
+ Path: ${SESSION_LOGS_PATH}`));
25025
+ console.log(muted(` Retention: ${getRetentionDays()} day(s) (set SESSION_LOG_RETENTION_DAYS to change)`));
25026
+ }
25027
+ async function sessionLogsTail(opts) {
25028
+ const logs = listSessionLogs();
25029
+ if (logs.length === 0) {
25030
+ outputError("NO_LOGS", "No session debug logs found. Enable via /debug in Telegram.");
25031
+ return;
25032
+ }
25033
+ let targetPath;
25034
+ if (opts.file) {
25035
+ const match = logs.find((l) => l.filename.includes(opts.file));
25036
+ if (!match) {
25037
+ outputError("NOT_FOUND", `No session log matching "${opts.file}". Use 'cc-claw logs session list' to see available logs.`);
25038
+ return;
25039
+ }
25040
+ targetPath = match.filePath;
25041
+ } else {
25042
+ targetPath = logs[0].filePath;
25043
+ }
25044
+ const lineCount = parseInt(opts.lines ?? "50", 10);
25045
+ console.log(muted(` \u2500\u2500 ${targetPath} (last ${lineCount} lines) \u2500\u2500
25046
+ `));
25047
+ for await (const line of tailSessionLog(targetPath, lineCount)) {
25048
+ console.log(line);
25049
+ }
25050
+ if (opts.follow) {
25051
+ console.log(muted("\n Following... (Ctrl+C to stop)\n"));
25052
+ let lastLength = 0;
25053
+ try {
25054
+ lastLength = readFileSync21(targetPath, "utf-8").length;
25055
+ } catch {
25056
+ }
25057
+ watchFile3(targetPath, { interval: 500 }, () => {
25058
+ try {
25059
+ const content = readFileSync21(targetPath, "utf-8");
25060
+ if (content.length > lastLength) {
25061
+ process.stdout.write(content.slice(lastLength));
25062
+ lastLength = content.length;
25063
+ }
25064
+ } catch {
25065
+ }
25066
+ });
25067
+ process.on("SIGINT", () => {
25068
+ unwatchFile3(targetPath);
25069
+ process.exit(0);
25070
+ });
25071
+ await new Promise(() => {
25072
+ });
25073
+ }
25074
+ }
25075
+ async function sessionLogsClean(opts) {
25076
+ const days = opts.days ? parseInt(opts.days, 10) : void 0;
25077
+ const cleaned = cleanupSessionLogs(days);
25078
+ console.log(success(`Cleaned ${cleaned} session log(s) older than ${days ?? getRetentionDays()} day(s).`));
25079
+ }
25080
+ var init_session_logs = __esm({
25081
+ "src/cli/commands/session-logs.ts"() {
25082
+ "use strict";
25083
+ init_session_log2();
25084
+ init_paths();
25085
+ init_format2();
25086
+ }
25087
+ });
25088
+
24678
25089
  // src/cli/commands/gemini.ts
24679
25090
  var gemini_exports = {};
24680
25091
  __export(gemini_exports, {
@@ -24687,11 +25098,11 @@ __export(gemini_exports, {
24687
25098
  geminiReorder: () => geminiReorder,
24688
25099
  geminiRotation: () => geminiRotation
24689
25100
  });
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";
25101
+ import { existsSync as existsSync34, mkdirSync as mkdirSync14, writeFileSync as writeFileSync10, readFileSync as readFileSync22, chmodSync } from "fs";
25102
+ import { join as join31 } from "path";
25103
+ import { createInterface as createInterface7 } from "readline";
24693
25104
  function requireDb() {
24694
- if (!existsSync32(DB_PATH)) {
25105
+ if (!existsSync34(DB_PATH)) {
24695
25106
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
24696
25107
  process.exit(1);
24697
25108
  }
@@ -24716,9 +25127,9 @@ async function resolveSlotId(idOrLabel) {
24716
25127
  function resolveOAuthEmail(configHome) {
24717
25128
  if (!configHome) return null;
24718
25129
  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"));
25130
+ const accountsPath = join31(configHome, ".gemini", "google_accounts.json");
25131
+ if (!existsSync34(accountsPath)) return null;
25132
+ const accounts = JSON.parse(readFileSync22(accountsPath, "utf-8"));
24722
25133
  return accounts.active || null;
24723
25134
  } catch {
24724
25135
  return null;
@@ -24762,7 +25173,7 @@ async function geminiList(globalOpts) {
24762
25173
  }
24763
25174
  async function geminiAddKey(globalOpts, opts) {
24764
25175
  await requireWriteDb();
24765
- const rl2 = createInterface6({ input: process.stdin, output: process.stdout });
25176
+ const rl2 = createInterface7({ input: process.stdin, output: process.stdout });
24766
25177
  const ask2 = (q) => new Promise((r) => rl2.question(q, r));
24767
25178
  const key = await ask2("Paste your Gemini API key: ");
24768
25179
  rl2.close();
@@ -24800,14 +25211,14 @@ async function geminiAddKey(globalOpts, opts) {
24800
25211
  }
24801
25212
  async function geminiAddAccount(globalOpts, opts) {
24802
25213
  await requireWriteDb();
24803
- const slotsDir = join30(CC_CLAW_HOME, "gemini-slots");
24804
- if (!existsSync32(slotsDir)) mkdirSync13(slotsDir, { recursive: true });
25214
+ const slotsDir = join31(CC_CLAW_HOME, "gemini-slots");
25215
+ if (!existsSync34(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
24805
25216
  const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24806
25217
  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({
25218
+ const slotDir = join31(slotsDir, `slot-${tempId}`);
25219
+ mkdirSync14(slotDir, { recursive: true, mode: 448 });
25220
+ mkdirSync14(join31(slotDir, ".gemini"), { recursive: true });
25221
+ writeFileSync10(join31(slotDir, ".gemini", "settings.json"), JSON.stringify({
24811
25222
  security: { auth: { selectedType: "oauth-personal" } }
24812
25223
  }, null, 2));
24813
25224
  console.log("");
@@ -24824,8 +25235,8 @@ async function geminiAddAccount(globalOpts, opts) {
24824
25235
  });
24825
25236
  } catch {
24826
25237
  }
24827
- const oauthPath = join30(slotDir, ".gemini", "oauth_creds.json");
24828
- if (!existsSync32(oauthPath)) {
25238
+ const oauthPath = join31(slotDir, ".gemini", "oauth_creds.json");
25239
+ if (!existsSync34(oauthPath)) {
24829
25240
  console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
24830
25241
  console.log(" The slot directory is preserved at: " + slotDir);
24831
25242
  console.log(" Re-run: cc-claw gemini add-account\n");
@@ -24833,7 +25244,7 @@ async function geminiAddAccount(globalOpts, opts) {
24833
25244
  }
24834
25245
  let accountEmail = "unknown";
24835
25246
  try {
24836
- const accounts = JSON.parse(__require("fs").readFileSync(join30(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
25247
+ const accounts = JSON.parse(__require("fs").readFileSync(join31(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
24837
25248
  accountEmail = accounts.active || accountEmail;
24838
25249
  } catch {
24839
25250
  }
@@ -24952,11 +25363,11 @@ __export(backend_cmd_factory_exports, {
24952
25363
  makeReorder: () => makeReorder,
24953
25364
  registerBackendSlotCommands: () => registerBackendSlotCommands
24954
25365
  });
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";
25366
+ import { existsSync as existsSync35, mkdirSync as mkdirSync15, readFileSync as readFileSync23 } from "fs";
25367
+ import { join as join32 } from "path";
25368
+ import { createInterface as createInterface8 } from "readline";
24958
25369
  function requireDb2() {
24959
- if (!existsSync33(DB_PATH)) {
25370
+ if (!existsSync35(DB_PATH)) {
24960
25371
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
24961
25372
  process.exit(1);
24962
25373
  }
@@ -25015,7 +25426,7 @@ Add one with: cc-claw ${backend2} add-account or cc-claw ${backend2} add-key`)
25015
25426
  function makeAddKey(backend2, displayName) {
25016
25427
  return async function addKey(_globalOpts, opts) {
25017
25428
  await requireWriteDb2();
25018
- const rl2 = createInterface7({ input: process.stdin, output: process.stdout });
25429
+ const rl2 = createInterface8({ input: process.stdin, output: process.stdout });
25019
25430
  const ask2 = (q) => new Promise((r) => rl2.question(q, r));
25020
25431
  const key = await ask2(`Paste your ${displayName} API key: `);
25021
25432
  rl2.close();
@@ -25045,11 +25456,11 @@ function makeAddAccount(backend2, displayName) {
25045
25456
  process.exit(1);
25046
25457
  }
25047
25458
  await requireWriteDb2();
25048
- const slotsDir = join31(CC_CLAW_HOME, config2.slotsSubdir);
25049
- if (!existsSync33(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
25459
+ const slotsDir = join32(CC_CLAW_HOME, config2.slotsSubdir);
25460
+ if (!existsSync35(slotsDir)) mkdirSync15(slotsDir, { recursive: true });
25050
25461
  const tempId = Date.now();
25051
- const slotDir = join31(slotsDir, `slot-${tempId}`);
25052
- mkdirSync14(slotDir, { recursive: true, mode: 448 });
25462
+ const slotDir = join32(slotsDir, `slot-${tempId}`);
25463
+ mkdirSync15(slotDir, { recursive: true, mode: 448 });
25053
25464
  if (config2.preSetup) config2.preSetup(slotDir);
25054
25465
  console.log("");
25055
25466
  console.log(` Opening ${displayName} CLI for sign-in...`);
@@ -25217,22 +25628,22 @@ var init_backend_cmd_factory = __esm({
25217
25628
  envValue: (slotDir) => slotDir,
25218
25629
  envOverrides: { ANTHROPIC_API_KEY: void 0 },
25219
25630
  preSetup: (slotDir) => {
25220
- mkdirSync14(join31(slotDir, ".claude"), { recursive: true });
25631
+ mkdirSync15(join32(slotDir, ".claude"), { recursive: true });
25221
25632
  },
25222
25633
  verifyCredentials: (slotDir) => {
25223
- const claudeJson = join31(slotDir, ".claude.json");
25224
- const claudeJsonNested = join31(slotDir, ".claude", ".claude.json");
25225
- if (existsSync33(claudeJson)) {
25634
+ const claudeJson = join32(slotDir, ".claude.json");
25635
+ const claudeJsonNested = join32(slotDir, ".claude", ".claude.json");
25636
+ if (existsSync35(claudeJson)) {
25226
25637
  try {
25227
- const data = JSON.parse(readFileSync22(claudeJson, "utf-8"));
25638
+ const data = JSON.parse(readFileSync23(claudeJson, "utf-8"));
25228
25639
  return Boolean(data.oauthAccount);
25229
25640
  } catch {
25230
25641
  return false;
25231
25642
  }
25232
25643
  }
25233
- if (existsSync33(claudeJsonNested)) {
25644
+ if (existsSync35(claudeJsonNested)) {
25234
25645
  try {
25235
- const data = JSON.parse(readFileSync22(claudeJsonNested, "utf-8"));
25646
+ const data = JSON.parse(readFileSync23(claudeJsonNested, "utf-8"));
25236
25647
  return Boolean(data.oauthAccount);
25237
25648
  } catch {
25238
25649
  return false;
@@ -25253,9 +25664,9 @@ var init_backend_cmd_factory = __esm({
25253
25664
  } catch {
25254
25665
  }
25255
25666
  try {
25256
- const claudeJson = join31(slotDir, ".claude.json");
25257
- if (existsSync33(claudeJson)) {
25258
- const data = JSON.parse(readFileSync22(claudeJson, "utf-8"));
25667
+ const claudeJson = join32(slotDir, ".claude.json");
25668
+ if (existsSync35(claudeJson)) {
25669
+ const data = JSON.parse(readFileSync23(claudeJson, "utf-8"));
25259
25670
  if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
25260
25671
  }
25261
25672
  } catch {
@@ -25270,11 +25681,11 @@ var init_backend_cmd_factory = __esm({
25270
25681
  envValue: (slotDir) => slotDir,
25271
25682
  envOverrides: { OPENAI_API_KEY: void 0 },
25272
25683
  verifyCredentials: (slotDir) => {
25273
- return existsSync33(join31(slotDir, "auth.json"));
25684
+ return existsSync35(join32(slotDir, "auth.json"));
25274
25685
  },
25275
25686
  extractLabel: (slotDir) => {
25276
25687
  try {
25277
- const authData = JSON.parse(readFileSync22(join31(slotDir, "auth.json"), "utf-8"));
25688
+ const authData = JSON.parse(readFileSync23(join32(slotDir, "auth.json"), "utf-8"));
25278
25689
  if (authData.email) return authData.email;
25279
25690
  if (authData.account_name) return authData.account_name;
25280
25691
  if (authData.user?.email) return authData.user.email;
@@ -25294,12 +25705,12 @@ __export(backend_exports, {
25294
25705
  backendList: () => backendList,
25295
25706
  backendSet: () => backendSet
25296
25707
  });
25297
- import { existsSync as existsSync34 } from "fs";
25708
+ import { existsSync as existsSync36 } from "fs";
25298
25709
  async function backendList(globalOpts) {
25299
25710
  const { getAvailableAdapters: getAvailableAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
25300
25711
  const chatId = resolveChatId(globalOpts);
25301
25712
  let activeBackend = null;
25302
- if (existsSync34(DB_PATH)) {
25713
+ if (existsSync36(DB_PATH)) {
25303
25714
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
25304
25715
  const readDb = openDatabaseReadOnly2();
25305
25716
  try {
@@ -25330,7 +25741,7 @@ async function backendList(globalOpts) {
25330
25741
  }
25331
25742
  async function backendGet(globalOpts) {
25332
25743
  const chatId = resolveChatId(globalOpts);
25333
- if (!existsSync34(DB_PATH)) {
25744
+ if (!existsSync36(DB_PATH)) {
25334
25745
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
25335
25746
  process.exit(1);
25336
25747
  }
@@ -25374,13 +25785,13 @@ __export(model_exports, {
25374
25785
  modelList: () => modelList,
25375
25786
  modelSet: () => modelSet
25376
25787
  });
25377
- import { existsSync as existsSync35 } from "fs";
25788
+ import { existsSync as existsSync37 } from "fs";
25378
25789
  async function modelList(globalOpts) {
25379
25790
  const chatId = resolveChatId(globalOpts);
25380
25791
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
25381
25792
  const { getAdapter: getAdapter4, getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
25382
25793
  let backendId = "claude";
25383
- if (existsSync35(DB_PATH)) {
25794
+ if (existsSync37(DB_PATH)) {
25384
25795
  const readDb = openDatabaseReadOnly2();
25385
25796
  try {
25386
25797
  const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
@@ -25413,7 +25824,7 @@ async function modelList(globalOpts) {
25413
25824
  }
25414
25825
  async function modelGet(globalOpts) {
25415
25826
  const chatId = resolveChatId(globalOpts);
25416
- if (!existsSync35(DB_PATH)) {
25827
+ if (!existsSync37(DB_PATH)) {
25417
25828
  outputError("DB_NOT_FOUND", "Database not found.");
25418
25829
  process.exit(1);
25419
25830
  }
@@ -25457,9 +25868,9 @@ __export(memory_exports2, {
25457
25868
  memoryList: () => memoryList,
25458
25869
  memorySearch: () => memorySearch
25459
25870
  });
25460
- import { existsSync as existsSync36 } from "fs";
25871
+ import { existsSync as existsSync38 } from "fs";
25461
25872
  async function memoryList(globalOpts) {
25462
- if (!existsSync36(DB_PATH)) {
25873
+ if (!existsSync38(DB_PATH)) {
25463
25874
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
25464
25875
  process.exit(1);
25465
25876
  }
@@ -25483,7 +25894,7 @@ async function memoryList(globalOpts) {
25483
25894
  });
25484
25895
  }
25485
25896
  async function memorySearch(globalOpts, query) {
25486
- if (!existsSync36(DB_PATH)) {
25897
+ if (!existsSync38(DB_PATH)) {
25487
25898
  outputError("DB_NOT_FOUND", "Database not found.");
25488
25899
  process.exit(1);
25489
25900
  }
@@ -25505,7 +25916,7 @@ async function memorySearch(globalOpts, query) {
25505
25916
  });
25506
25917
  }
25507
25918
  async function memoryHistory(globalOpts, opts) {
25508
- if (!existsSync36(DB_PATH)) {
25919
+ if (!existsSync38(DB_PATH)) {
25509
25920
  outputError("DB_NOT_FOUND", "Database not found.");
25510
25921
  process.exit(1);
25511
25922
  }
@@ -25553,7 +25964,7 @@ __export(cron_exports2, {
25553
25964
  cronList: () => cronList,
25554
25965
  cronRuns: () => cronRuns
25555
25966
  });
25556
- import { existsSync as existsSync37 } from "fs";
25967
+ import { existsSync as existsSync39 } from "fs";
25557
25968
  function parseFallbacks(raw) {
25558
25969
  return raw.slice(0, 3).map((f) => {
25559
25970
  const [backend2, ...rest] = f.split(":");
@@ -25574,7 +25985,7 @@ function parseAndValidateTimeout(raw) {
25574
25985
  return val;
25575
25986
  }
25576
25987
  async function cronList(globalOpts) {
25577
- if (!existsSync37(DB_PATH)) {
25988
+ if (!existsSync39(DB_PATH)) {
25578
25989
  outputError("DB_NOT_FOUND", "Database not found.");
25579
25990
  process.exit(1);
25580
25991
  }
@@ -25612,7 +26023,7 @@ async function cronList(globalOpts) {
25612
26023
  });
25613
26024
  }
25614
26025
  async function cronHealth(globalOpts) {
25615
- if (!existsSync37(DB_PATH)) {
26026
+ if (!existsSync39(DB_PATH)) {
25616
26027
  outputError("DB_NOT_FOUND", "Database not found.");
25617
26028
  process.exit(1);
25618
26029
  }
@@ -25771,7 +26182,7 @@ async function cronEdit(globalOpts, id, opts) {
25771
26182
  }
25772
26183
  }
25773
26184
  async function cronRuns(globalOpts, jobId, opts) {
25774
- if (!existsSync37(DB_PATH)) {
26185
+ if (!existsSync39(DB_PATH)) {
25775
26186
  outputError("DB_NOT_FOUND", "Database not found.");
25776
26187
  process.exit(1);
25777
26188
  }
@@ -25818,9 +26229,9 @@ __export(agents_exports, {
25818
26229
  runnersList: () => runnersList,
25819
26230
  tasksList: () => tasksList
25820
26231
  });
25821
- import { existsSync as existsSync38 } from "fs";
26232
+ import { existsSync as existsSync40 } from "fs";
25822
26233
  async function agentsList(globalOpts) {
25823
- if (!existsSync38(DB_PATH)) {
26234
+ if (!existsSync40(DB_PATH)) {
25824
26235
  outputError("DB_NOT_FOUND", "Database not found.");
25825
26236
  process.exit(1);
25826
26237
  }
@@ -25851,7 +26262,7 @@ async function agentsList(globalOpts) {
25851
26262
  });
25852
26263
  }
25853
26264
  async function tasksList(globalOpts) {
25854
- if (!existsSync38(DB_PATH)) {
26265
+ if (!existsSync40(DB_PATH)) {
25855
26266
  outputError("DB_NOT_FOUND", "Database not found.");
25856
26267
  process.exit(1);
25857
26268
  }
@@ -25979,18 +26390,18 @@ __export(db_exports, {
25979
26390
  dbPath: () => dbPath,
25980
26391
  dbStats: () => dbStats
25981
26392
  });
25982
- import { existsSync as existsSync39, statSync as statSync10, copyFileSync as copyFileSync3, mkdirSync as mkdirSync15 } from "fs";
26393
+ import { existsSync as existsSync41, statSync as statSync11, copyFileSync as copyFileSync3, mkdirSync as mkdirSync16 } from "fs";
25983
26394
  import { dirname as dirname7 } from "path";
25984
26395
  async function dbStats(globalOpts) {
25985
- if (!existsSync39(DB_PATH)) {
26396
+ if (!existsSync41(DB_PATH)) {
25986
26397
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
25987
26398
  process.exit(1);
25988
26399
  }
25989
26400
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
25990
26401
  const readDb = openDatabaseReadOnly2();
25991
- const mainSize = statSync10(DB_PATH).size;
26402
+ const mainSize = statSync11(DB_PATH).size;
25992
26403
  const walPath = DB_PATH + "-wal";
25993
- const walSize = existsSync39(walPath) ? statSync10(walPath).size : 0;
26404
+ const walSize = existsSync41(walPath) ? statSync11(walPath).size : 0;
25994
26405
  const tableNames = readDb.prepare(
25995
26406
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
25996
26407
  ).all();
@@ -26024,17 +26435,17 @@ async function dbPath(globalOpts) {
26024
26435
  output({ path: DB_PATH }, (d) => d.path);
26025
26436
  }
26026
26437
  async function dbBackup(globalOpts, destPath) {
26027
- if (!existsSync39(DB_PATH)) {
26438
+ if (!existsSync41(DB_PATH)) {
26028
26439
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
26029
26440
  process.exit(1);
26030
26441
  }
26031
26442
  const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
26032
26443
  try {
26033
- mkdirSync15(dirname7(dest), { recursive: true });
26444
+ mkdirSync16(dirname7(dest), { recursive: true });
26034
26445
  copyFileSync3(DB_PATH, dest);
26035
26446
  const walPath = DB_PATH + "-wal";
26036
- if (existsSync39(walPath)) copyFileSync3(walPath, dest + "-wal");
26037
- output({ path: dest, sizeBytes: statSync10(dest).size }, (d) => {
26447
+ if (existsSync41(walPath)) copyFileSync3(walPath, dest + "-wal");
26448
+ output({ path: dest, sizeBytes: statSync11(dest).size }, (d) => {
26038
26449
  const b = d;
26039
26450
  return `
26040
26451
  ${success("Backup created:")} ${b.path} (${(b.sizeBytes / 1024).toFixed(0)}KB)
@@ -26062,9 +26473,9 @@ __export(usage_exports, {
26062
26473
  usageCost: () => usageCost,
26063
26474
  usageTokens: () => usageTokens
26064
26475
  });
26065
- import { existsSync as existsSync40 } from "fs";
26476
+ import { existsSync as existsSync42 } from "fs";
26066
26477
  function ensureDb() {
26067
- if (!existsSync40(DB_PATH)) {
26478
+ if (!existsSync42(DB_PATH)) {
26068
26479
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
26069
26480
  process.exit(1);
26070
26481
  }
@@ -26254,9 +26665,9 @@ __export(config_exports2, {
26254
26665
  configList: () => configList,
26255
26666
  configSet: () => configSet
26256
26667
  });
26257
- import { existsSync as existsSync41, readFileSync as readFileSync23 } from "fs";
26668
+ import { existsSync as existsSync43, readFileSync as readFileSync24 } from "fs";
26258
26669
  async function configList(globalOpts) {
26259
- if (!existsSync41(DB_PATH)) {
26670
+ if (!existsSync43(DB_PATH)) {
26260
26671
  outputError("DB_NOT_FOUND", "Database not found.");
26261
26672
  process.exit(1);
26262
26673
  }
@@ -26290,7 +26701,7 @@ async function configGet(globalOpts, key) {
26290
26701
  outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
26291
26702
  process.exit(1);
26292
26703
  }
26293
- if (!existsSync41(DB_PATH)) {
26704
+ if (!existsSync43(DB_PATH)) {
26294
26705
  outputError("DB_NOT_FOUND", "Database not found.");
26295
26706
  process.exit(1);
26296
26707
  }
@@ -26336,11 +26747,11 @@ async function configSet(globalOpts, key, value) {
26336
26747
  }
26337
26748
  }
26338
26749
  async function configEnv(_globalOpts) {
26339
- if (!existsSync41(ENV_PATH)) {
26750
+ if (!existsSync43(ENV_PATH)) {
26340
26751
  outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
26341
26752
  process.exit(1);
26342
26753
  }
26343
- const content = readFileSync23(ENV_PATH, "utf-8");
26754
+ const content = readFileSync24(ENV_PATH, "utf-8");
26344
26755
  const entries = {};
26345
26756
  const secretPatterns = /TOKEN|KEY|SECRET|PASSWORD|CREDENTIALS/i;
26346
26757
  for (const line of content.split("\n")) {
@@ -26390,9 +26801,9 @@ __export(session_exports, {
26390
26801
  sessionGet: () => sessionGet,
26391
26802
  sessionNew: () => sessionNew
26392
26803
  });
26393
- import { existsSync as existsSync42 } from "fs";
26804
+ import { existsSync as existsSync44 } from "fs";
26394
26805
  async function sessionGet(globalOpts) {
26395
- if (!existsSync42(DB_PATH)) {
26806
+ if (!existsSync44(DB_PATH)) {
26396
26807
  outputError("DB_NOT_FOUND", "Database not found.");
26397
26808
  process.exit(1);
26398
26809
  }
@@ -26453,9 +26864,9 @@ __export(permissions_exports, {
26453
26864
  verboseGet: () => verboseGet,
26454
26865
  verboseSet: () => verboseSet
26455
26866
  });
26456
- import { existsSync as existsSync43 } from "fs";
26867
+ import { existsSync as existsSync45 } from "fs";
26457
26868
  function ensureDb2() {
26458
- if (!existsSync43(DB_PATH)) {
26869
+ if (!existsSync45(DB_PATH)) {
26459
26870
  outputError("DB_NOT_FOUND", "Database not found.");
26460
26871
  process.exit(1);
26461
26872
  }
@@ -26602,9 +27013,9 @@ __export(cwd_exports, {
26602
27013
  cwdGet: () => cwdGet,
26603
27014
  cwdSet: () => cwdSet
26604
27015
  });
26605
- import { existsSync as existsSync44 } from "fs";
27016
+ import { existsSync as existsSync46 } from "fs";
26606
27017
  async function cwdGet(globalOpts) {
26607
- if (!existsSync44(DB_PATH)) {
27018
+ if (!existsSync46(DB_PATH)) {
26608
27019
  outputError("DB_NOT_FOUND", "Database not found.");
26609
27020
  process.exit(1);
26610
27021
  }
@@ -26666,9 +27077,9 @@ __export(voice_exports, {
26666
27077
  voiceGet: () => voiceGet,
26667
27078
  voiceSet: () => voiceSet
26668
27079
  });
26669
- import { existsSync as existsSync45 } from "fs";
27080
+ import { existsSync as existsSync47 } from "fs";
26670
27081
  async function voiceGet(globalOpts) {
26671
- if (!existsSync45(DB_PATH)) {
27082
+ if (!existsSync47(DB_PATH)) {
26672
27083
  outputError("DB_NOT_FOUND", "Database not found.");
26673
27084
  process.exit(1);
26674
27085
  }
@@ -26717,9 +27128,9 @@ __export(heartbeat_exports, {
26717
27128
  heartbeatGet: () => heartbeatGet,
26718
27129
  heartbeatSet: () => heartbeatSet
26719
27130
  });
26720
- import { existsSync as existsSync46 } from "fs";
27131
+ import { existsSync as existsSync48 } from "fs";
26721
27132
  async function heartbeatGet(globalOpts) {
26722
- if (!existsSync46(DB_PATH)) {
27133
+ if (!existsSync48(DB_PATH)) {
26723
27134
  outputError("DB_NOT_FOUND", "Database not found.");
26724
27135
  process.exit(1);
26725
27136
  }
@@ -26828,9 +27239,9 @@ __export(summarizer_exports, {
26828
27239
  summarizerGet: () => summarizerGet,
26829
27240
  summarizerSet: () => summarizerSet
26830
27241
  });
26831
- import { existsSync as existsSync47 } from "fs";
27242
+ import { existsSync as existsSync49 } from "fs";
26832
27243
  async function summarizerGet(globalOpts) {
26833
- if (!existsSync47(DB_PATH)) {
27244
+ if (!existsSync49(DB_PATH)) {
26834
27245
  outputError("DB_NOT_FOUND", "Database not found.");
26835
27246
  process.exit(1);
26836
27247
  }
@@ -26874,9 +27285,9 @@ __export(thinking_exports, {
26874
27285
  thinkingGet: () => thinkingGet,
26875
27286
  thinkingSet: () => thinkingSet
26876
27287
  });
26877
- import { existsSync as existsSync48 } from "fs";
27288
+ import { existsSync as existsSync50 } from "fs";
26878
27289
  async function thinkingGet(globalOpts) {
26879
- if (!existsSync48(DB_PATH)) {
27290
+ if (!existsSync50(DB_PATH)) {
26880
27291
  outputError("DB_NOT_FOUND", "Database not found.");
26881
27292
  process.exit(1);
26882
27293
  }
@@ -26920,9 +27331,9 @@ __export(chats_exports, {
26920
27331
  chatsList: () => chatsList,
26921
27332
  chatsRemoveAlias: () => chatsRemoveAlias
26922
27333
  });
26923
- import { existsSync as existsSync49 } from "fs";
27334
+ import { existsSync as existsSync51 } from "fs";
26924
27335
  async function chatsList(_globalOpts) {
26925
- if (!existsSync49(DB_PATH)) {
27336
+ if (!existsSync51(DB_PATH)) {
26926
27337
  outputError("DB_NOT_FOUND", "Database not found.");
26927
27338
  process.exit(1);
26928
27339
  }
@@ -27050,9 +27461,9 @@ var mcps_exports2 = {};
27050
27461
  __export(mcps_exports2, {
27051
27462
  mcpsList: () => mcpsList
27052
27463
  });
27053
- import { existsSync as existsSync50 } from "fs";
27464
+ import { existsSync as existsSync52 } from "fs";
27054
27465
  async function mcpsList(_globalOpts) {
27055
- if (!existsSync50(DB_PATH)) {
27466
+ if (!existsSync52(DB_PATH)) {
27056
27467
  outputError("DB_NOT_FOUND", "Database not found.");
27057
27468
  process.exit(1);
27058
27469
  }
@@ -27089,11 +27500,11 @@ __export(chat_exports2, {
27089
27500
  chatSend: () => chatSend
27090
27501
  });
27091
27502
  import { request as httpRequest2 } from "http";
27092
- import { readFileSync as readFileSync24, existsSync as existsSync51 } from "fs";
27503
+ import { readFileSync as readFileSync25, existsSync as existsSync53 } from "fs";
27093
27504
  function getToken2() {
27094
27505
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
27095
27506
  try {
27096
- if (existsSync51(TOKEN_PATH2)) return readFileSync24(TOKEN_PATH2, "utf-8").trim();
27507
+ if (existsSync53(TOKEN_PATH2)) return readFileSync25(TOKEN_PATH2, "utf-8").trim();
27097
27508
  } catch {
27098
27509
  }
27099
27510
  return null;
@@ -27230,7 +27641,7 @@ var tui_exports = {};
27230
27641
  __export(tui_exports, {
27231
27642
  tuiCommand: () => tuiCommand
27232
27643
  });
27233
- import { createInterface as createInterface8 } from "readline";
27644
+ import { createInterface as createInterface9 } from "readline";
27234
27645
  import pc2 from "picocolors";
27235
27646
  async function tuiCommand(globalOpts, cmdOpts) {
27236
27647
  const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
@@ -27240,7 +27651,7 @@ async function tuiCommand(globalOpts, cmdOpts) {
27240
27651
  }
27241
27652
  const chatId = resolveChatId(globalOpts);
27242
27653
  const { chatSend: chatSend2 } = await Promise.resolve().then(() => (init_chat2(), chat_exports2));
27243
- const rl2 = createInterface8({
27654
+ const rl2 = createInterface9({
27244
27655
  input: process.stdin,
27245
27656
  output: process.stdout,
27246
27657
  prompt: pc2.cyan("you > "),
@@ -27372,8 +27783,8 @@ var completion_exports = {};
27372
27783
  __export(completion_exports, {
27373
27784
  completionCommand: () => completionCommand
27374
27785
  });
27375
- import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync16 } from "fs";
27376
- import { join as join32 } from "path";
27786
+ import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync17 } from "fs";
27787
+ import { join as join33 } from "path";
27377
27788
  import { homedir as homedir11 } from "os";
27378
27789
  async function completionCommand(opts) {
27379
27790
  const shell = opts.shell ?? detectShell();
@@ -27389,10 +27800,10 @@ async function completionCommand(opts) {
27389
27800
  process.exit(1);
27390
27801
  }
27391
27802
  if (opts.install) {
27392
- const dir = join32(homedir11(), ".config", "cc-claw", "completions");
27393
- mkdirSync16(dir, { recursive: true });
27803
+ const dir = join33(homedir11(), ".config", "cc-claw", "completions");
27804
+ mkdirSync17(dir, { recursive: true });
27394
27805
  const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
27395
- const filepath = join32(dir, filename);
27806
+ const filepath = join33(dir, filename);
27396
27807
  writeFileSync11(filepath, script, "utf-8");
27397
27808
  console.log(`\u2713 Completion script written to ${filepath}
27398
27809
  `);
@@ -27563,9 +27974,9 @@ __export(evolve_exports2, {
27563
27974
  evolveStatus: () => evolveStatus,
27564
27975
  evolveUndo: () => evolveUndo
27565
27976
  });
27566
- import { existsSync as existsSync52 } from "fs";
27977
+ import { existsSync as existsSync54 } from "fs";
27567
27978
  function ensureDb3() {
27568
- if (!existsSync52(DB_PATH)) {
27979
+ if (!existsSync54(DB_PATH)) {
27569
27980
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
27570
27981
  process.exit(1);
27571
27982
  }
@@ -28039,10 +28450,10 @@ var init_optimize2 = __esm({
28039
28450
 
28040
28451
  // src/setup.ts
28041
28452
  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";
28453
+ import { existsSync as existsSync55, writeFileSync as writeFileSync12, readFileSync as readFileSync26, copyFileSync as copyFileSync4, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
28043
28454
  import { execFileSync as execFileSync5 } from "child_process";
28044
- import { createInterface as createInterface9 } from "readline";
28045
- import { join as join33 } from "path";
28455
+ import { createInterface as createInterface10 } from "readline";
28456
+ import { join as join34 } from "path";
28046
28457
  function divider2() {
28047
28458
  console.log(dim("\u2500".repeat(55)));
28048
28459
  }
@@ -28117,22 +28528,22 @@ async function setup() {
28117
28528
  }
28118
28529
  console.log("");
28119
28530
  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 });
28531
+ if (!existsSync55(dir)) mkdirSync18(dir, { recursive: true });
28121
28532
  }
28122
28533
  const env = {};
28123
- const envSource = existsSync53(ENV_PATH) ? ENV_PATH : existsSync53(".env") ? ".env" : null;
28534
+ const envSource = existsSync55(ENV_PATH) ? ENV_PATH : existsSync55(".env") ? ".env" : null;
28124
28535
  if (envSource) {
28125
28536
  console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
28126
28537
  console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
28127
- const existing = readFileSync25(envSource, "utf-8");
28538
+ const existing = readFileSync26(envSource, "utf-8");
28128
28539
  for (const line of existing.split("\n")) {
28129
28540
  const match = line.match(/^([^#=]+)=(.*)$/);
28130
28541
  if (match) env[match[1].trim()] = match[2].trim();
28131
28542
  }
28132
28543
  }
28133
- const cwdDb = join33(process.cwd(), "cc-claw.db");
28134
- if (existsSync53(cwdDb) && !existsSync53(DB_PATH)) {
28135
- const { size } = statSync11(cwdDb);
28544
+ const cwdDb = join34(process.cwd(), "cc-claw.db");
28545
+ if (existsSync55(cwdDb) && !existsSync55(DB_PATH)) {
28546
+ const { size } = statSync12(cwdDb);
28136
28547
  console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
28137
28548
  const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
28138
28549
  if (migrate) {
@@ -28404,7 +28815,7 @@ var init_setup = __esm({
28404
28815
  "src/setup.ts"() {
28405
28816
  "use strict";
28406
28817
  init_paths();
28407
- rl = createInterface9({ input: process.stdin, output: process.stdout });
28818
+ rl = createInterface10({ input: process.stdin, output: process.stdout });
28408
28819
  ask = (q) => new Promise((resolve) => rl.question(q, resolve));
28409
28820
  bold = (s) => `\x1B[1m${s}\x1B[0m`;
28410
28821
  green = (s) => `\x1B[32m${s}\x1B[0m`;
@@ -28473,6 +28884,19 @@ program.command("logs").description("Tail daemon logs").option("-f, --follow", "
28473
28884
  const { logsCommand: logsCommand2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
28474
28885
  await logsCommand2(opts);
28475
28886
  });
28887
+ var sessionLogs = program.command("session-logs").description("Manage session debug logs (enable via /debug in Telegram)");
28888
+ sessionLogs.command("list").description("List all session debug logs").action(async () => {
28889
+ const { sessionLogsList: sessionLogsList2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
28890
+ await sessionLogsList2(program.opts());
28891
+ });
28892
+ 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) => {
28893
+ const { sessionLogsTail: sessionLogsTail2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
28894
+ await sessionLogsTail2(opts);
28895
+ });
28896
+ sessionLogs.command("clean").description("Remove old session logs").option("--days <n>", "Remove logs older than N days").action(async (opts) => {
28897
+ const { sessionLogsClean: sessionLogsClean2 } = await Promise.resolve().then(() => (init_session_logs(), session_logs_exports));
28898
+ await sessionLogsClean2(opts);
28899
+ });
28476
28900
  var gemini = program.command("gemini").description("Manage Gemini credential slots for rotation");
28477
28901
  gemini.command("list").description("Show all configured Gemini credential slots").action(async () => {
28478
28902
  const { geminiList: geminiList2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));