claude-threads 1.6.3 → 1.7.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.
package/dist/index.js CHANGED
@@ -11880,7 +11880,7 @@ import * as fs from "fs/promises";
11880
11880
  import { homedir as homedir4 } from "os";
11881
11881
  async function execGit(args, cwd) {
11882
11882
  const cmd = `git ${args.join(" ")}`;
11883
- log7.debug(`Executing: ${cmd}`);
11883
+ log8.debug(`Executing: ${cmd}`);
11884
11884
  return new Promise((resolve3, reject) => {
11885
11885
  const proc = crossSpawn("git", args, { cwd });
11886
11886
  let stdout = "";
@@ -11893,15 +11893,15 @@ async function execGit(args, cwd) {
11893
11893
  });
11894
11894
  proc.on("close", (code) => {
11895
11895
  if (code === 0) {
11896
- log7.debug(`${cmd} → success`);
11896
+ log8.debug(`${cmd} → success`);
11897
11897
  resolve3(stdout.trim());
11898
11898
  } else {
11899
- log7.debug(`${cmd} → failed (code=${code}): ${stderr.substring(0, 100) || stdout.substring(0, 100)}`);
11899
+ log8.debug(`${cmd} → failed (code=${code}): ${stderr.substring(0, 100) || stdout.substring(0, 100)}`);
11900
11900
  reject(new Error(`git ${args.join(" ")} failed: ${stderr || stdout}`));
11901
11901
  }
11902
11902
  });
11903
11903
  proc.on("error", (err) => {
11904
- log7.warn(`${cmd} → error: ${err}`);
11904
+ log8.warn(`${cmd} → error: ${err}`);
11905
11905
  reject(err);
11906
11906
  });
11907
11907
  });
@@ -11911,7 +11911,7 @@ async function isGitRepository(dir) {
11911
11911
  await execGit(["rev-parse", "--git-dir"], dir);
11912
11912
  return true;
11913
11913
  } catch (err) {
11914
- log7.debug(`Not a git repository: ${dir} (${err})`);
11914
+ log8.debug(`Not a git repository: ${dir} (${err})`);
11915
11915
  return false;
11916
11916
  }
11917
11917
  }
@@ -12046,7 +12046,7 @@ async function detectWorktreeInfo(workingDir) {
12046
12046
  const branchOutput = await execGit(["rev-parse", "--abbrev-ref", "HEAD"], workingDir);
12047
12047
  const branch = branchOutput?.trim();
12048
12048
  if (!branch) {
12049
- log7.debug(`Could not detect branch for worktree at ${workingDir}`);
12049
+ log8.debug(`Could not detect branch for worktree at ${workingDir}`);
12050
12050
  return null;
12051
12051
  }
12052
12052
  const gitDirOutput = await execGit(["rev-parse", "--git-common-dir"], workingDir);
@@ -12058,45 +12058,45 @@ async function detectWorktreeInfo(workingDir) {
12058
12058
  repoRoot = repoRoot.slice(0, -4);
12059
12059
  }
12060
12060
  }
12061
- log7.debug(`Detected worktree: path=${workingDir}, branch=${branch}, repoRoot=${repoRoot}`);
12061
+ log8.debug(`Detected worktree: path=${workingDir}, branch=${branch}, repoRoot=${repoRoot}`);
12062
12062
  return {
12063
12063
  worktreePath: workingDir,
12064
12064
  branch,
12065
12065
  repoRoot: repoRoot || workingDir
12066
12066
  };
12067
12067
  } catch (err) {
12068
- log7.debug(`Failed to detect worktree info for ${workingDir}: ${err}`);
12068
+ log8.debug(`Failed to detect worktree info for ${workingDir}: ${err}`);
12069
12069
  return null;
12070
12070
  }
12071
12071
  }
12072
12072
  async function createWorktree(repoRoot, branch, targetDir) {
12073
- log7.info(`Creating worktree for branch '${branch}' at ${targetDir}`);
12073
+ log8.info(`Creating worktree for branch '${branch}' at ${targetDir}`);
12074
12074
  const parentDir = path.dirname(targetDir);
12075
- log7.debug(`Creating parent directory: ${parentDir}`);
12075
+ log8.debug(`Creating parent directory: ${parentDir}`);
12076
12076
  await fs.mkdir(parentDir, { recursive: true });
12077
12077
  const exists = await branchExists(repoRoot, branch);
12078
12078
  if (exists) {
12079
- log7.debug(`Branch '${branch}' exists, adding worktree`);
12079
+ log8.debug(`Branch '${branch}' exists, adding worktree`);
12080
12080
  await execGit(["worktree", "add", targetDir, branch], repoRoot);
12081
12081
  } else {
12082
- log7.debug(`Branch '${branch}' does not exist, creating with worktree`);
12082
+ log8.debug(`Branch '${branch}' does not exist, creating with worktree`);
12083
12083
  await execGit(["worktree", "add", "-b", branch, targetDir], repoRoot);
12084
12084
  }
12085
- log7.info(`Worktree created successfully: ${targetDir}`);
12085
+ log8.info(`Worktree created successfully: ${targetDir}`);
12086
12086
  return targetDir;
12087
12087
  }
12088
12088
  async function removeWorktree(repoRoot, worktreePath) {
12089
- log7.info(`Removing worktree: ${worktreePath}`);
12089
+ log8.info(`Removing worktree: ${worktreePath}`);
12090
12090
  try {
12091
12091
  await execGit(["worktree", "remove", worktreePath], repoRoot);
12092
- log7.debug("Worktree removed cleanly");
12092
+ log8.debug("Worktree removed cleanly");
12093
12093
  } catch (err) {
12094
- log7.debug(`Clean remove failed (${err}), trying force remove`);
12094
+ log8.debug(`Clean remove failed (${err}), trying force remove`);
12095
12095
  await execGit(["worktree", "remove", "--force", worktreePath], repoRoot);
12096
12096
  }
12097
- log7.debug("Pruning stale worktree references");
12097
+ log8.debug("Pruning stale worktree references");
12098
12098
  await execGit(["worktree", "prune"], repoRoot);
12099
- log7.info("Worktree removed and pruned successfully");
12099
+ log8.info("Worktree removed and pruned successfully");
12100
12100
  }
12101
12101
  async function findWorktreeByBranch(repoRoot, branch) {
12102
12102
  const worktrees = await listWorktrees(repoRoot);
@@ -12137,14 +12137,14 @@ async function writeMetadataStore(store) {
12137
12137
  await fs.writeFile(METADATA_STORE_PATH, JSON.stringify(store, null, 2), { encoding: "utf-8", mode: 384 });
12138
12138
  await fs.chmod(METADATA_STORE_PATH, 384);
12139
12139
  } catch (err) {
12140
- log7.warn(`Failed to write worktree metadata store: ${err}`);
12140
+ log8.warn(`Failed to write worktree metadata store: ${err}`);
12141
12141
  }
12142
12142
  }
12143
12143
  async function writeWorktreeMetadata(worktreePath, metadata) {
12144
12144
  const store = await readMetadataStore();
12145
12145
  store[worktreePath] = metadata;
12146
12146
  await writeMetadataStore(store);
12147
- log7.debug(`Wrote worktree metadata for: ${worktreePath}`);
12147
+ log8.debug(`Wrote worktree metadata for: ${worktreePath}`);
12148
12148
  }
12149
12149
  async function readWorktreeMetadata(worktreePath) {
12150
12150
  const store = await readMetadataStore();
@@ -12167,14 +12167,14 @@ async function removeWorktreeMetadata(worktreePath) {
12167
12167
  if (store[worktreePath]) {
12168
12168
  delete store[worktreePath];
12169
12169
  await writeMetadataStore(store);
12170
- log7.debug(`Removed worktree metadata for: ${worktreePath}`);
12170
+ log8.debug(`Removed worktree metadata for: ${worktreePath}`);
12171
12171
  }
12172
12172
  }
12173
- var log7, WORKTREES_DIR, METADATA_STORE_PATH;
12173
+ var log8, WORKTREES_DIR, METADATA_STORE_PATH;
12174
12174
  var init_worktree = __esm(() => {
12175
12175
  init_spawn();
12176
12176
  init_logger();
12177
- log7 = createLogger("git-wt");
12177
+ log8 = createLogger("git-wt");
12178
12178
  WORKTREES_DIR = path.join(homedir4(), ".claude-threads", "worktrees");
12179
12179
  METADATA_STORE_PATH = path.join(homedir4(), ".claude-threads", "worktree-metadata.json");
12180
12180
  });
@@ -19514,7 +19514,7 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
19514
19514
  return hook.checkDCE ? true : false;
19515
19515
  }
19516
19516
  function setIsStrictModeForDevtools(newIsStrictMode) {
19517
- typeof log30 === "function" && unstable_setDisableYieldValue2(newIsStrictMode);
19517
+ typeof log31 === "function" && unstable_setDisableYieldValue2(newIsStrictMode);
19518
19518
  if (injectedHook && typeof injectedHook.setStrictMode === "function")
19519
19519
  try {
19520
19520
  injectedHook.setStrictMode(rendererID, newIsStrictMode);
@@ -27598,7 +27598,7 @@ Check the render method of %s.`, getComponentNameFromFiber(current) || "Unknown"
27598
27598
  var fiberStack = [];
27599
27599
  var index$jscomp$0 = -1, emptyContextObject = {};
27600
27600
  Object.freeze(emptyContextObject);
27601
- var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback, log$1 = Math.log, LN2 = Math.LN2, nextTransitionUpdateLane = 256, nextTransitionDeferredLane = 262144, nextRetryLane = 4194304, scheduleCallback$3 = Scheduler.unstable_scheduleCallback, cancelCallback$1 = Scheduler.unstable_cancelCallback, shouldYield = Scheduler.unstable_shouldYield, requestPaint = Scheduler.unstable_requestPaint, now$1 = Scheduler.unstable_now, ImmediatePriority = Scheduler.unstable_ImmediatePriority, UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, NormalPriority$1 = Scheduler.unstable_NormalPriority, IdlePriority = Scheduler.unstable_IdlePriority, log30 = Scheduler.log, unstable_setDisableYieldValue2 = Scheduler.unstable_setDisableYieldValue, rendererID = null, injectedHook = null, hasLoggedError = false, isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined", lastResetTime = 0;
27601
+ var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback, log$1 = Math.log, LN2 = Math.LN2, nextTransitionUpdateLane = 256, nextTransitionDeferredLane = 262144, nextRetryLane = 4194304, scheduleCallback$3 = Scheduler.unstable_scheduleCallback, cancelCallback$1 = Scheduler.unstable_cancelCallback, shouldYield = Scheduler.unstable_shouldYield, requestPaint = Scheduler.unstable_requestPaint, now$1 = Scheduler.unstable_now, ImmediatePriority = Scheduler.unstable_ImmediatePriority, UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, NormalPriority$1 = Scheduler.unstable_NormalPriority, IdlePriority = Scheduler.unstable_IdlePriority, log31 = Scheduler.log, unstable_setDisableYieldValue2 = Scheduler.unstable_setDisableYieldValue, rendererID = null, injectedHook = null, hasLoggedError = false, isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined", lastResetTime = 0;
27602
27602
  if (typeof performance === "object" && typeof performance.now === "function") {
27603
27603
  var localPerformance = performance;
27604
27604
  var getCurrentTime = function() {
@@ -53546,6 +53546,104 @@ class SessionStore {
53546
53546
  chmodSync2(this.sessionsFile, 384);
53547
53547
  }
53548
53548
  }
53549
+ // src/claude/account-pool.ts
53550
+ init_logger();
53551
+ var log6 = createLogger("account-pool");
53552
+
53553
+ class AccountPool {
53554
+ accounts;
53555
+ byId;
53556
+ activeCounts = new Map;
53557
+ coolingUntil = new Map;
53558
+ roundRobinIndex = 0;
53559
+ constructor(accounts) {
53560
+ this.accounts = (accounts ?? []).filter((acc) => {
53561
+ const hasAuth = !!acc.home || !!acc.apiKey;
53562
+ if (!hasAuth) {
53563
+ log6.warn(`Claude account ${acc.id} has neither home nor apiKey — ignoring`);
53564
+ return false;
53565
+ }
53566
+ if (acc.home && acc.apiKey) {
53567
+ log6.warn(`Claude account ${acc.id} has both home and apiKey set — must choose one; ignoring`);
53568
+ return false;
53569
+ }
53570
+ return true;
53571
+ });
53572
+ this.byId = new Map(this.accounts.map((acc) => [acc.id, acc]));
53573
+ for (const acc of this.accounts) {
53574
+ this.activeCounts.set(acc.id, 0);
53575
+ }
53576
+ }
53577
+ get isEmpty() {
53578
+ return this.accounts.length === 0;
53579
+ }
53580
+ get size() {
53581
+ return this.accounts.length;
53582
+ }
53583
+ acquire(preferredId) {
53584
+ if (this.isEmpty)
53585
+ return null;
53586
+ if (preferredId) {
53587
+ const preferred = this.byId.get(preferredId);
53588
+ if (preferred) {
53589
+ this.incrementActive(preferred.id);
53590
+ return preferred;
53591
+ }
53592
+ log6.warn(`Preferred account "${preferredId}" not in pool — falling back to round-robin`);
53593
+ }
53594
+ const now = Date.now();
53595
+ const n = this.accounts.length;
53596
+ for (let i2 = 0;i2 < n; i2++) {
53597
+ const idx = (this.roundRobinIndex + i2) % n;
53598
+ const candidate = this.accounts[idx];
53599
+ const cooling = this.coolingUntil.get(candidate.id) ?? 0;
53600
+ if (cooling <= now) {
53601
+ this.roundRobinIndex = (idx + 1) % n;
53602
+ this.incrementActive(candidate.id);
53603
+ return candidate;
53604
+ }
53605
+ }
53606
+ log6.warn(`All ${n} accounts are in rate-limit cooldown`);
53607
+ return null;
53608
+ }
53609
+ release(accountId) {
53610
+ const current = this.activeCounts.get(accountId);
53611
+ if (current === undefined)
53612
+ return;
53613
+ this.activeCounts.set(accountId, Math.max(0, current - 1));
53614
+ }
53615
+ markCooling(accountId, untilEpochMs) {
53616
+ if (!this.byId.has(accountId)) {
53617
+ log6.warn(`markCooling called for unknown account "${accountId}"`);
53618
+ return;
53619
+ }
53620
+ const existing = this.coolingUntil.get(accountId) ?? 0;
53621
+ if (untilEpochMs > existing) {
53622
+ this.coolingUntil.set(accountId, untilEpochMs);
53623
+ const minutes = Math.ceil((untilEpochMs - Date.now()) / 60000);
53624
+ log6.info(`Account "${accountId}" cooling for ~${minutes}min`);
53625
+ }
53626
+ }
53627
+ get(accountId) {
53628
+ return this.byId.get(accountId);
53629
+ }
53630
+ status() {
53631
+ const now = Date.now();
53632
+ return this.accounts.map((acc) => {
53633
+ const cooling = this.coolingUntil.get(acc.id) ?? 0;
53634
+ return {
53635
+ id: acc.id,
53636
+ displayName: acc.displayName ?? acc.id,
53637
+ activeSessions: this.activeCounts.get(acc.id) ?? 0,
53638
+ coolingUntil: cooling > now ? cooling : null
53639
+ };
53640
+ });
53641
+ }
53642
+ incrementActive(accountId) {
53643
+ this.activeCounts.set(accountId, (this.activeCounts.get(accountId) ?? 0) + 1);
53644
+ }
53645
+ }
53646
+
53549
53647
  // src/session/manager.ts
53550
53648
  init_emoji();
53551
53649
 
@@ -53560,7 +53658,7 @@ init_logger();
53560
53658
  import { existsSync as existsSync6, mkdirSync as mkdirSync3, appendFileSync, readdirSync, statSync, unlinkSync, rmdirSync, readFileSync as readFileSync5, chmodSync as chmodSync3 } from "fs";
53561
53659
  import { homedir as homedir3 } from "os";
53562
53660
  import { join as join4, dirname as dirname4 } from "path";
53563
- var log6 = createLogger("thread-log");
53661
+ var log7 = createLogger("thread-log");
53564
53662
  var LOGS_BASE_DIR = join4(homedir3(), ".claude-threads", "logs");
53565
53663
 
53566
53664
  class ThreadLoggerImpl {
@@ -53590,7 +53688,7 @@ class ThreadLoggerImpl {
53590
53688
  this.flushTimer = setInterval(() => {
53591
53689
  this.flushSync();
53592
53690
  }, this.flushIntervalMs);
53593
- log6.debug(`Thread logger initialized: ${this.logPath}`);
53691
+ log7.debug(`Thread logger initialized: ${this.logPath}`);
53594
53692
  }
53595
53693
  }
53596
53694
  isEnabled() {
@@ -53704,7 +53802,7 @@ class ThreadLoggerImpl {
53704
53802
  this.flushTimer = null;
53705
53803
  }
53706
53804
  this.flushSync();
53707
- log6.debug(`Thread logger closed: ${this.logPath}`);
53805
+ log7.debug(`Thread logger closed: ${this.logPath}`);
53708
53806
  }
53709
53807
  addEntry(entry) {
53710
53808
  this.buffer.push(entry);
@@ -53726,7 +53824,7 @@ class ThreadLoggerImpl {
53726
53824
  }
53727
53825
  this.buffer = [];
53728
53826
  } catch (err) {
53729
- log6.error(`Failed to flush thread log: ${err}`);
53827
+ log7.error(`Failed to flush thread log: ${err}`);
53730
53828
  }
53731
53829
  }
53732
53830
  }
@@ -53777,25 +53875,25 @@ function cleanupOldLogs(retentionDays = 30) {
53777
53875
  if (fileStat.mtimeMs < cutoffMs) {
53778
53876
  unlinkSync(filePath);
53779
53877
  deletedCount++;
53780
- log6.debug(`Deleted old log file: ${filePath}`);
53878
+ log7.debug(`Deleted old log file: ${filePath}`);
53781
53879
  }
53782
53880
  } catch (err) {
53783
- log6.warn(`Failed to check/delete log file ${filePath}: ${err}`);
53881
+ log7.warn(`Failed to check/delete log file ${filePath}: ${err}`);
53784
53882
  }
53785
53883
  }
53786
53884
  try {
53787
53885
  const remaining = readdirSync(platformDir);
53788
53886
  if (remaining.length === 0) {
53789
53887
  rmdirSync(platformDir);
53790
- log6.debug(`Removed empty platform log directory: ${platformDir}`);
53888
+ log7.debug(`Removed empty platform log directory: ${platformDir}`);
53791
53889
  }
53792
53890
  } catch {}
53793
53891
  }
53794
53892
  if (deletedCount > 0) {
53795
- log6.info(`Cleaned up ${deletedCount} old log file(s)`);
53893
+ log7.info(`Cleaned up ${deletedCount} old log file(s)`);
53796
53894
  }
53797
53895
  } catch (err) {
53798
- log6.error(`Failed to clean up old logs: ${err}`);
53896
+ log7.error(`Failed to clean up old logs: ${err}`);
53799
53897
  }
53800
53898
  return deletedCount;
53801
53899
  }
@@ -53804,16 +53902,16 @@ function getLogFilePath(platformId, sessionId) {
53804
53902
  }
53805
53903
  function readRecentLogEntries(platformId, sessionId, maxLines = 50) {
53806
53904
  const logPath = getLogFilePath(platformId, sessionId);
53807
- log6.debug(`Reading log entries from: ${logPath}`);
53905
+ log7.debug(`Reading log entries from: ${logPath}`);
53808
53906
  if (!existsSync6(logPath)) {
53809
- log6.debug(`Log file does not exist: ${logPath}`);
53907
+ log7.debug(`Log file does not exist: ${logPath}`);
53810
53908
  return [];
53811
53909
  }
53812
53910
  try {
53813
53911
  const content = readFileSync5(logPath, "utf8");
53814
53912
  const lines = content.trim().split(`
53815
53913
  `);
53816
- log6.debug(`Log file has ${lines.length} lines`);
53914
+ log7.debug(`Log file has ${lines.length} lines`);
53817
53915
  const recentLines = lines.slice(-maxLines);
53818
53916
  const entries = [];
53819
53917
  for (const line of recentLines) {
@@ -53823,17 +53921,17 @@ function readRecentLogEntries(platformId, sessionId, maxLines = 50) {
53823
53921
  entries.push(JSON.parse(line));
53824
53922
  } catch {}
53825
53923
  }
53826
- log6.debug(`Parsed ${entries.length} log entries`);
53924
+ log7.debug(`Parsed ${entries.length} log entries`);
53827
53925
  return entries;
53828
53926
  } catch (err) {
53829
- log6.error(`Failed to read log file: ${err}`);
53927
+ log7.error(`Failed to read log file: ${err}`);
53830
53928
  return [];
53831
53929
  }
53832
53930
  }
53833
53931
 
53834
53932
  // src/cleanup/scheduler.ts
53835
53933
  init_worktree();
53836
- var log8 = createLogger("cleanup");
53934
+ var log9 = createLogger("cleanup");
53837
53935
  var DEFAULT_CLEANUP_INTERVAL_MS = 60 * 60 * 1000;
53838
53936
  var MAX_WORKTREE_AGE_MS = 24 * 60 * 60 * 1000;
53839
53937
 
@@ -53856,17 +53954,17 @@ class CleanupScheduler {
53856
53954
  }
53857
53955
  start() {
53858
53956
  if (this.isRunning) {
53859
- log8.debug("Cleanup scheduler already running");
53957
+ log9.debug("Cleanup scheduler already running");
53860
53958
  return;
53861
53959
  }
53862
53960
  this.isRunning = true;
53863
- log8.info(`Cleanup scheduler started (interval: ${Math.round(this.intervalMs / 60000)}min)`);
53961
+ log9.info(`Cleanup scheduler started (interval: ${Math.round(this.intervalMs / 60000)}min)`);
53864
53962
  this.runCleanup().catch((err) => {
53865
- log8.warn(`Initial cleanup failed: ${err}`);
53963
+ log9.warn(`Initial cleanup failed: ${err}`);
53866
53964
  });
53867
53965
  this.timer = setInterval(() => {
53868
53966
  this.runCleanup().catch((err) => {
53869
- log8.warn(`Periodic cleanup failed: ${err}`);
53967
+ log9.warn(`Periodic cleanup failed: ${err}`);
53870
53968
  });
53871
53969
  }, this.intervalMs);
53872
53970
  }
@@ -53876,11 +53974,11 @@ class CleanupScheduler {
53876
53974
  this.timer = null;
53877
53975
  }
53878
53976
  this.isRunning = false;
53879
- log8.debug("Cleanup scheduler stopped");
53977
+ log9.debug("Cleanup scheduler stopped");
53880
53978
  }
53881
53979
  async runCleanup() {
53882
53980
  const startTime = Date.now();
53883
- log8.debug("Running background cleanup...");
53981
+ log9.debug("Running background cleanup...");
53884
53982
  const stats = {
53885
53983
  logsDeleted: 0,
53886
53984
  worktreesCleaned: 0,
@@ -53906,9 +54004,9 @@ class CleanupScheduler {
53906
54004
  const elapsed = Date.now() - startTime;
53907
54005
  const totalCleaned = stats.logsDeleted + stats.worktreesCleaned + stats.metadataCleaned;
53908
54006
  if (totalCleaned > 0 || stats.errors.length > 0) {
53909
- log8.info(`Cleanup completed in ${elapsed}ms: ` + `${stats.logsDeleted} logs, ${stats.worktreesCleaned} worktrees, ${stats.metadataCleaned} metadata` + (stats.errors.length > 0 ? ` (${stats.errors.length} errors)` : ""));
54007
+ log9.info(`Cleanup completed in ${elapsed}ms: ` + `${stats.logsDeleted} logs, ${stats.worktreesCleaned} worktrees, ${stats.metadataCleaned} metadata` + (stats.errors.length > 0 ? ` (${stats.errors.length} errors)` : ""));
53910
54008
  } else {
53911
- log8.debug(`Cleanup completed in ${elapsed}ms (nothing to clean)`);
54009
+ log9.debug(`Cleanup completed in ${elapsed}ms (nothing to clean)`);
53912
54010
  }
53913
54011
  return stats;
53914
54012
  }
@@ -53921,7 +54019,7 @@ class CleanupScheduler {
53921
54019
  const deleted = cleanupOldLogs(this.logRetentionDays);
53922
54020
  resolve3(deleted);
53923
54021
  } catch (err) {
53924
- log8.warn(`Log cleanup error: ${err}`);
54022
+ log9.warn(`Log cleanup error: ${err}`);
53925
54023
  resolve3(0);
53926
54024
  }
53927
54025
  });
@@ -53930,7 +54028,7 @@ class CleanupScheduler {
53930
54028
  const worktreesDir = getWorktreesDir();
53931
54029
  const result = { cleaned: 0, metadata: 0 };
53932
54030
  if (!existsSync7(worktreesDir)) {
53933
- log8.debug("No worktrees directory exists, nothing to clean");
54031
+ log9.debug("No worktrees directory exists, nothing to clean");
53934
54032
  return result;
53935
54033
  }
53936
54034
  const persisted = this.sessionStore.load();
@@ -53948,7 +54046,7 @@ class CleanupScheduler {
53948
54046
  continue;
53949
54047
  const worktreePath = join6(worktreesDir, entry.name);
53950
54048
  if (activeWorktrees.has(worktreePath)) {
53951
- log8.debug(`Worktree in use by persisted session, skipping: ${entry.name}`);
54049
+ log9.debug(`Worktree in use by persisted session, skipping: ${entry.name}`);
53952
54050
  continue;
53953
54051
  }
53954
54052
  const meta = await readWorktreeMetadata(worktreePath);
@@ -53958,7 +54056,7 @@ class CleanupScheduler {
53958
54056
  const lastActivity = new Date(meta.lastActivityAt).getTime();
53959
54057
  const age = now - lastActivity;
53960
54058
  if (meta.sessionId && age < this.maxWorktreeAgeMs) {
53961
- log8.debug(`Worktree has active session (${Math.round(age / 60000)}min old), skipping: ${entry.name}`);
54059
+ log9.debug(`Worktree has active session (${Math.round(age / 60000)}min old), skipping: ${entry.name}`);
53962
54060
  continue;
53963
54061
  }
53964
54062
  const merged = age >= this.maxWorktreeAgeMs ? await isBranchMerged(meta.repoRoot, meta.branch).catch(() => false) : false;
@@ -53969,7 +54067,7 @@ class CleanupScheduler {
53969
54067
  shouldCleanup = true;
53970
54068
  cleanupReason = `inactive for ${Math.round(age / 3600000)}h`;
53971
54069
  } else {
53972
- log8.debug(`Worktree recent (${Math.round(age / 60000)}min old), skipping: ${entry.name}`);
54070
+ log9.debug(`Worktree recent (${Math.round(age / 60000)}min old), skipping: ${entry.name}`);
53973
54071
  continue;
53974
54072
  }
53975
54073
  } else {
@@ -53978,7 +54076,7 @@ class CleanupScheduler {
53978
54076
  }
53979
54077
  if (!shouldCleanup)
53980
54078
  continue;
53981
- log8.info(`Cleaning worktree (${cleanupReason}): ${entry.name}`);
54079
+ log9.info(`Cleaning worktree (${cleanupReason}): ${entry.name}`);
53982
54080
  try {
53983
54081
  if (meta?.repoRoot) {
53984
54082
  await removeWorktree(meta.repoRoot, worktreePath);
@@ -53989,19 +54087,19 @@ class CleanupScheduler {
53989
54087
  await removeWorktreeMetadata(worktreePath);
53990
54088
  result.metadata++;
53991
54089
  } catch (err) {
53992
- log8.warn(`Failed to clean orphaned worktree ${entry.name}: ${err}`);
54090
+ log9.warn(`Failed to clean orphaned worktree ${entry.name}: ${err}`);
53993
54091
  try {
53994
54092
  await rm(worktreePath, { recursive: true, force: true });
53995
54093
  result.cleaned++;
53996
54094
  await removeWorktreeMetadata(worktreePath);
53997
54095
  result.metadata++;
53998
54096
  } catch (rmErr) {
53999
- log8.error(`Failed to force remove worktree ${entry.name}: ${rmErr}`);
54097
+ log9.error(`Failed to force remove worktree ${entry.name}: ${rmErr}`);
54000
54098
  }
54001
54099
  }
54002
54100
  }
54003
54101
  } catch (err) {
54004
- log8.warn(`Failed to scan worktrees directory: ${err}`);
54102
+ log9.warn(`Failed to scan worktrees directory: ${err}`);
54005
54103
  }
54006
54104
  return result;
54007
54105
  }
@@ -54078,7 +54176,70 @@ import { fileURLToPath as fileURLToPath3 } from "url";
54078
54176
  import { existsSync as existsSync8, readFileSync as readFileSync6, watchFile, unwatchFile, unlinkSync as unlinkSync2, statSync as statSync2, readdirSync as readdirSync2 } from "fs";
54079
54177
  import { tmpdir } from "os";
54080
54178
  import { join as join7 } from "path";
54081
- var log9 = createLogger("claude");
54179
+
54180
+ // src/claude/rate-limit-detector.ts
54181
+ var RATE_LIMIT_PHRASES = [
54182
+ /usage limit reached/i,
54183
+ /rate[_\s-]?limit[_\s-]?error/i,
54184
+ /you have hit the rate limit/i,
54185
+ /quota (has been )?exceeded/i,
54186
+ /\b429\b.*(rate|limit|quota)/i
54187
+ ];
54188
+ var DEFAULT_COOLDOWN_MS = 60 * 60 * 1000;
54189
+ function detectRateLimit(text, now = Date.now()) {
54190
+ if (!text)
54191
+ return { detected: false };
54192
+ let matched;
54193
+ for (const phrase of RATE_LIMIT_PHRASES) {
54194
+ const m = text.match(phrase);
54195
+ if (m) {
54196
+ matched = m[0];
54197
+ break;
54198
+ }
54199
+ }
54200
+ if (!matched)
54201
+ return { detected: false };
54202
+ const resetAtEpochMs = extractResetAt(text, now);
54203
+ return { detected: true, matched, resetAtEpochMs };
54204
+ }
54205
+ function cooldownDeadline(hit, now = Date.now()) {
54206
+ if (!hit.detected)
54207
+ return now;
54208
+ return hit.resetAtEpochMs ?? now + DEFAULT_COOLDOWN_MS;
54209
+ }
54210
+ function extractResetAt(text, now) {
54211
+ const relative = text.match(/(?:retry[_\s-]?after|resets?\s+in)\s+(\d+)\s*(second|minute|hour|day)s?/i);
54212
+ if (relative) {
54213
+ const value = parseInt(relative[1], 10);
54214
+ const unit = relative[2].toLowerCase();
54215
+ const unitMs = {
54216
+ second: 1000,
54217
+ minute: 60000,
54218
+ hour: 3600000,
54219
+ day: 86400000
54220
+ };
54221
+ return now + value * unitMs[unit];
54222
+ }
54223
+ const unix = text.match(/\breset(?:_at)?\b\s*["']?\s*[:=]\s*(\d{10,13})/);
54224
+ if (unix) {
54225
+ const raw = parseInt(unix[1], 10);
54226
+ return unix[1].length === 13 ? raw : raw * 1000;
54227
+ }
54228
+ const clock = text.match(/resets?\s+at\s+(\d{1,2}):(\d{2})\s*(utc|gmt)?/i);
54229
+ if (clock) {
54230
+ const hh = parseInt(clock[1], 10);
54231
+ const mm = parseInt(clock[2], 10);
54232
+ if (hh < 24 && mm < 60) {
54233
+ const reference = new Date(now);
54234
+ const target = new Date(Date.UTC(reference.getUTCFullYear(), reference.getUTCMonth(), reference.getUTCDate(), hh, mm)).getTime();
54235
+ return target > now ? target : target + 86400000;
54236
+ }
54237
+ }
54238
+ return;
54239
+ }
54240
+
54241
+ // src/claude/cli.ts
54242
+ var log10 = createLogger("claude");
54082
54243
  function cleanupBrowserBridgeSockets() {
54083
54244
  try {
54084
54245
  const tempDir = tmpdir();
@@ -54090,15 +54251,23 @@ function cleanupBrowserBridgeSockets() {
54090
54251
  const stats = statSync2(filePath);
54091
54252
  if (stats.isSocket()) {
54092
54253
  unlinkSync2(filePath);
54093
- log9.debug(`Removed stale browser bridge socket: ${file}`);
54254
+ log10.debug(`Removed stale browser bridge socket: ${file}`);
54094
54255
  }
54095
54256
  } catch {}
54096
54257
  }
54097
54258
  }
54098
54259
  } catch (err) {
54099
- log9.debug(`Browser bridge cleanup failed: ${err}`);
54260
+ log10.debug(`Browser bridge cleanup failed: ${err}`);
54100
54261
  }
54101
54262
  }
54263
+ function isErrorResultEvent(event) {
54264
+ const ev = event;
54265
+ if (typeof ev.subtype === "string" && ev.subtype.startsWith("error"))
54266
+ return true;
54267
+ if (ev.is_error === true)
54268
+ return true;
54269
+ return false;
54270
+ }
54102
54271
 
54103
54272
  class ClaudeCli extends EventEmitter2 {
54104
54273
  process = null;
@@ -54108,6 +54277,7 @@ class ClaudeCli extends EventEmitter2 {
54108
54277
  statusFilePath = null;
54109
54278
  lastStatusData = null;
54110
54279
  stderrBuffer = "";
54280
+ lastEmittedRateLimitDeadline = 0;
54111
54281
  log;
54112
54282
  constructor(options2) {
54113
54283
  super();
@@ -54159,6 +54329,7 @@ class ClaudeCli extends EventEmitter2 {
54159
54329
  if (this.process)
54160
54330
  throw new Error("Already running");
54161
54331
  this.stderrBuffer = "";
54332
+ this.lastEmittedRateLimitDeadline = 0;
54162
54333
  cleanupBrowserBridgeSockets();
54163
54334
  const claudePath = getClaudePath();
54164
54335
  const args = [
@@ -54228,9 +54399,13 @@ class ClaudeCli extends EventEmitter2 {
54228
54399
  args.push("--settings", JSON.stringify(statusLineSettings));
54229
54400
  }
54230
54401
  this.log.debug(`Starting: ${claudePath} ${args.slice(0, 5).join(" ")}...`);
54402
+ const childEnv = this.buildChildEnv();
54403
+ if (this.options.account) {
54404
+ this.log.debug(`Spawning under Claude account "${this.options.account.id}"`);
54405
+ }
54231
54406
  this.process = crossSpawn(claudePath, args, {
54232
54407
  cwd: this.options.workingDir,
54233
- env: process.env,
54408
+ env: childEnv,
54234
54409
  stdio: ["pipe", "pipe", "pipe"]
54235
54410
  });
54236
54411
  this.log.debug(`Claude process spawned: pid=${this.process.pid}`);
@@ -54244,6 +54419,7 @@ class ClaudeCli extends EventEmitter2 {
54244
54419
  this.stderrBuffer = this.stderrBuffer.slice(-10240);
54245
54420
  }
54246
54421
  this.log.debug(`stderr: ${text.trim()}`);
54422
+ this.maybeEmitRateLimit(text);
54247
54423
  });
54248
54424
  this.process.on("error", (err) => {
54249
54425
  this.log.error(`Claude error: ${err}`);
@@ -54298,9 +54474,24 @@ class ClaudeCli extends EventEmitter2 {
54298
54474
  try {
54299
54475
  const event = JSON.parse(trimmed);
54300
54476
  this.emit("event", event);
54477
+ if (event.type === "result" && isErrorResultEvent(event)) {
54478
+ this.maybeEmitRateLimit(trimmed);
54479
+ }
54301
54480
  } catch {}
54302
54481
  }
54303
54482
  }
54483
+ maybeEmitRateLimit(text) {
54484
+ const hit = detectRateLimit(text);
54485
+ if (!hit.detected)
54486
+ return;
54487
+ const newDeadline = cooldownDeadline(hit);
54488
+ const MIN_ADVANCE_MS = 60000;
54489
+ if (newDeadline - this.lastEmittedRateLimitDeadline < MIN_ADVANCE_MS)
54490
+ return;
54491
+ this.lastEmittedRateLimitDeadline = newDeadline;
54492
+ this.log.warn(`Rate limit detected: ${hit.matched ?? "(no match text)"}`);
54493
+ this.emit("rate-limit", hit);
54494
+ }
54304
54495
  isRunning() {
54305
54496
  return this.process !== null;
54306
54497
  }
@@ -54369,6 +54560,22 @@ class ClaudeCli extends EventEmitter2 {
54369
54560
  this.process.kill("SIGINT");
54370
54561
  return true;
54371
54562
  }
54563
+ buildChildEnv() {
54564
+ const account = this.options.account;
54565
+ if (!account)
54566
+ return process.env;
54567
+ const env = { ...process.env };
54568
+ if (account.home) {
54569
+ env.HOME = account.home;
54570
+ env.USERPROFILE = account.home;
54571
+ delete env.ANTHROPIC_API_KEY;
54572
+ delete env.CLAUDE_CODE_OAUTH_TOKEN;
54573
+ } else if (account.apiKey) {
54574
+ env.ANTHROPIC_API_KEY = account.apiKey;
54575
+ delete env.CLAUDE_CODE_OAUTH_TOKEN;
54576
+ }
54577
+ return env;
54578
+ }
54372
54579
  getMcpServerPath() {
54373
54580
  const __filename2 = fileURLToPath3(import.meta.url);
54374
54581
  const __dirname4 = dirname6(__filename2);
@@ -55205,7 +55412,7 @@ import { existsSync as existsSync11 } from "fs";
55205
55412
  // src/utils/keep-alive.ts
55206
55413
  init_logger();
55207
55414
  import { spawn as spawn2 } from "child_process";
55208
- var log10 = createLogger("keepalive");
55415
+ var log11 = createLogger("keepalive");
55209
55416
 
55210
55417
  class KeepAliveManager {
55211
55418
  activeSessionCount = 0;
@@ -55220,7 +55427,7 @@ class KeepAliveManager {
55220
55427
  if (!enabled && this.keepAliveProcess) {
55221
55428
  this.stopKeepAlive();
55222
55429
  }
55223
- log10.debug(`Keep-alive ${enabled ? "enabled" : "disabled"}`);
55430
+ log11.debug(`Keep-alive ${enabled ? "enabled" : "disabled"}`);
55224
55431
  }
55225
55432
  isEnabled() {
55226
55433
  return this.enabled;
@@ -55230,7 +55437,7 @@ class KeepAliveManager {
55230
55437
  }
55231
55438
  sessionStarted() {
55232
55439
  this.activeSessionCount++;
55233
- log10.debug(`Session started (${this.activeSessionCount} active)`);
55440
+ log11.debug(`Session started (${this.activeSessionCount} active)`);
55234
55441
  if (this.activeSessionCount === 1) {
55235
55442
  this.startKeepAlive();
55236
55443
  }
@@ -55239,7 +55446,7 @@ class KeepAliveManager {
55239
55446
  if (this.activeSessionCount > 0) {
55240
55447
  this.activeSessionCount--;
55241
55448
  }
55242
- log10.debug(`Session ended (${this.activeSessionCount} active)`);
55449
+ log11.debug(`Session ended (${this.activeSessionCount} active)`);
55243
55450
  if (this.activeSessionCount === 0) {
55244
55451
  this.stopKeepAlive();
55245
55452
  }
@@ -55253,11 +55460,11 @@ class KeepAliveManager {
55253
55460
  }
55254
55461
  startKeepAlive() {
55255
55462
  if (!this.enabled) {
55256
- log10.debug("Keep-alive disabled, skipping");
55463
+ log11.debug("Keep-alive disabled, skipping");
55257
55464
  return;
55258
55465
  }
55259
55466
  if (this.keepAliveProcess) {
55260
- log10.debug("Keep-alive already running");
55467
+ log11.debug("Keep-alive already running");
55261
55468
  return;
55262
55469
  }
55263
55470
  switch (this.platform) {
@@ -55271,12 +55478,12 @@ class KeepAliveManager {
55271
55478
  this.startWindowsKeepAlive();
55272
55479
  break;
55273
55480
  default:
55274
- log10.warn(`Keep-alive not supported on ${this.platform}`);
55481
+ log11.warn(`Keep-alive not supported on ${this.platform}`);
55275
55482
  }
55276
55483
  }
55277
55484
  stopKeepAlive() {
55278
55485
  if (this.keepAliveProcess) {
55279
- log10.debug("Stopping keep-alive");
55486
+ log11.debug("Stopping keep-alive");
55280
55487
  this.keepAliveProcess.kill();
55281
55488
  this.keepAliveProcess = null;
55282
55489
  }
@@ -55288,18 +55495,18 @@ class KeepAliveManager {
55288
55495
  detached: false
55289
55496
  });
55290
55497
  this.keepAliveProcess.on("error", (err) => {
55291
- log10.error(`Failed to start caffeinate: ${err.message}`);
55498
+ log11.error(`Failed to start caffeinate: ${err.message}`);
55292
55499
  this.keepAliveProcess = null;
55293
55500
  });
55294
55501
  this.keepAliveProcess.on("exit", (code) => {
55295
55502
  if (code !== null && code !== 0 && this.activeSessionCount > 0) {
55296
- log10.debug(`caffeinate exited with code ${code}`);
55503
+ log11.debug(`caffeinate exited with code ${code}`);
55297
55504
  }
55298
55505
  this.keepAliveProcess = null;
55299
55506
  });
55300
- log10.info("Sleep prevention active (caffeinate)");
55507
+ log11.info("Sleep prevention active (caffeinate)");
55301
55508
  } catch (err) {
55302
- log10.error(`Failed to start caffeinate: ${err}`);
55509
+ log11.error(`Failed to start caffeinate: ${err}`);
55303
55510
  }
55304
55511
  }
55305
55512
  startLinuxKeepAlive() {
@@ -55315,19 +55522,19 @@ class KeepAliveManager {
55315
55522
  detached: false
55316
55523
  });
55317
55524
  this.keepAliveProcess.on("error", (err) => {
55318
- log10.debug(`systemd-inhibit not available: ${err.message}`);
55525
+ log11.debug(`systemd-inhibit not available: ${err.message}`);
55319
55526
  this.keepAliveProcess = null;
55320
55527
  this.startLinuxKeepAliveFallback();
55321
55528
  });
55322
55529
  this.keepAliveProcess.on("exit", (code) => {
55323
55530
  if (code !== null && code !== 0 && this.activeSessionCount > 0) {
55324
- log10.debug(`systemd-inhibit exited with code ${code}`);
55531
+ log11.debug(`systemd-inhibit exited with code ${code}`);
55325
55532
  }
55326
55533
  this.keepAliveProcess = null;
55327
55534
  });
55328
- log10.info("Sleep prevention active (systemd-inhibit)");
55535
+ log11.info("Sleep prevention active (systemd-inhibit)");
55329
55536
  } catch (err) {
55330
- log10.debug(`Failed to start systemd-inhibit: ${err}`);
55537
+ log11.debug(`Failed to start systemd-inhibit: ${err}`);
55331
55538
  this.startLinuxKeepAliveFallback();
55332
55539
  }
55333
55540
  }
@@ -55341,15 +55548,15 @@ class KeepAliveManager {
55341
55548
  detached: false
55342
55549
  });
55343
55550
  this.keepAliveProcess.on("error", (err) => {
55344
- log10.warn(`Linux keep-alive fallback not available: ${err.message}`);
55551
+ log11.warn(`Linux keep-alive fallback not available: ${err.message}`);
55345
55552
  this.keepAliveProcess = null;
55346
55553
  });
55347
55554
  this.keepAliveProcess.on("exit", () => {
55348
55555
  this.keepAliveProcess = null;
55349
55556
  });
55350
- log10.info("Sleep prevention active (xdg-screensaver)");
55557
+ log11.info("Sleep prevention active (xdg-screensaver)");
55351
55558
  } catch (err) {
55352
- log10.warn(`Linux keep-alive not available: ${err}`);
55559
+ log11.warn(`Linux keep-alive not available: ${err}`);
55353
55560
  }
55354
55561
  }
55355
55562
  startWindowsKeepAlive() {
@@ -55374,18 +55581,18 @@ class KeepAliveManager {
55374
55581
  windowsHide: true
55375
55582
  });
55376
55583
  this.keepAliveProcess.on("error", (err) => {
55377
- log10.warn(`Windows keep-alive not available: ${err.message}`);
55584
+ log11.warn(`Windows keep-alive not available: ${err.message}`);
55378
55585
  this.keepAliveProcess = null;
55379
55586
  });
55380
55587
  this.keepAliveProcess.on("exit", (code) => {
55381
55588
  if (code !== null && code !== 0 && this.activeSessionCount > 0) {
55382
- log10.debug(`PowerShell keep-alive exited with code ${code}`);
55589
+ log11.debug(`PowerShell keep-alive exited with code ${code}`);
55383
55590
  }
55384
55591
  this.keepAliveProcess = null;
55385
55592
  });
55386
- log10.info("Sleep prevention active (SetThreadExecutionState)");
55593
+ log11.info("Sleep prevention active (SetThreadExecutionState)");
55387
55594
  } catch (err) {
55388
- log10.warn(`Windows keep-alive not available: ${err}`);
55595
+ log11.warn(`Windows keep-alive not available: ${err}`);
55389
55596
  }
55390
55597
  }
55391
55598
  }
@@ -55393,7 +55600,7 @@ var keepAlive = new KeepAliveManager;
55393
55600
 
55394
55601
  // src/utils/error-handler/index.ts
55395
55602
  init_logger();
55396
- var log11 = createLogger("error");
55603
+ var log12 = createLogger("error");
55397
55604
 
55398
55605
  class SessionError extends Error {
55399
55606
  sessionId;
@@ -55419,19 +55626,19 @@ async function handleError(error, context, severity = "recoverable") {
55419
55626
  const sessionPart = sessionId ? ` (${formatShortId(sessionId)})` : "";
55420
55627
  const logMessage = `${context.action}${sessionPart}: ${message}`;
55421
55628
  if (severity === "recoverable") {
55422
- log11.warn(logMessage);
55629
+ log12.warn(logMessage);
55423
55630
  } else {
55424
- log11.error(logMessage, error instanceof Error ? error : undefined);
55631
+ log12.error(logMessage, error instanceof Error ? error : undefined);
55425
55632
  }
55426
55633
  if (context.details) {
55427
- log11.debugJson("Error details", context.details);
55634
+ log12.debugJson("Error details", context.details);
55428
55635
  }
55429
55636
  if (context.notifyUser && context.session) {
55430
55637
  try {
55431
55638
  const fmt = context.session.platform.getFormatter();
55432
55639
  await context.session.platform.createPost(`⚠️ ${fmt.formatBold("Error")}: ${context.action} failed - ${message}`, context.session.threadId);
55433
55640
  } catch (notifyError) {
55434
- log11.warn(`Could not notify user: ${notifyError}`);
55641
+ log12.warn(`Could not notify user: ${notifyError}`);
55435
55642
  }
55436
55643
  }
55437
55644
  if (severity === "session-fatal" || severity === "system-fatal") {
@@ -55458,7 +55665,7 @@ async function logAndNotify(error, context) {
55458
55665
  }
55459
55666
  function logSilentError(context, error) {
55460
55667
  const message = error instanceof Error ? error.message : String(error);
55461
- log11.debug(`[${context}] Silently caught: ${message}`);
55668
+ log12.debug(`[${context}] Silently caught: ${message}`);
55462
55669
  }
55463
55670
 
55464
55671
  // src/session/lifecycle.ts
@@ -55478,8 +55685,8 @@ function createSessionLog(baseLog) {
55478
55685
  init_logger();
55479
55686
  init_emoji();
55480
55687
  init_worktree();
55481
- var log12 = createLogger("helpers");
55482
- var sessionLog = createSessionLog(log12);
55688
+ var log13 = createLogger("helpers");
55689
+ var sessionLog = createSessionLog(log13);
55483
55690
  var POST_TYPES = {
55484
55691
  info: "",
55485
55692
  success: "✅",
@@ -55563,7 +55770,7 @@ function updateLastMessage(session, post2) {
55563
55770
  // src/claude/quick-query.ts
55564
55771
  init_spawn();
55565
55772
  init_logger();
55566
- var log13 = createLogger("query");
55773
+ var log14 = createLogger("query");
55567
55774
  async function quickQuery(options2) {
55568
55775
  const {
55569
55776
  prompt,
@@ -55579,7 +55786,7 @@ async function quickQuery(options2) {
55579
55786
  args.push("--system-prompt", systemPrompt);
55580
55787
  }
55581
55788
  args.push(prompt);
55582
- log13.debug(`Quick query: model=${model}, timeout=${timeout}ms, prompt="${prompt.substring(0, 50)}..."`);
55789
+ log14.debug(`Quick query: model=${model}, timeout=${timeout}ms, prompt="${prompt.substring(0, 50)}..."`);
55583
55790
  return new Promise((resolve5) => {
55584
55791
  let stdout = "";
55585
55792
  let stderr = "";
@@ -55593,7 +55800,7 @@ async function quickQuery(options2) {
55593
55800
  if (!resolved) {
55594
55801
  resolved = true;
55595
55802
  proc.kill("SIGTERM");
55596
- log13.debug(`Quick query timed out after ${timeout}ms`);
55803
+ log14.debug(`Quick query timed out after ${timeout}ms`);
55597
55804
  resolve5({
55598
55805
  success: false,
55599
55806
  error: "timeout",
@@ -55611,7 +55818,7 @@ async function quickQuery(options2) {
55611
55818
  if (!resolved) {
55612
55819
  resolved = true;
55613
55820
  clearTimeout(timeoutId);
55614
- log13.debug(`Quick query error: ${err.message}`);
55821
+ log14.debug(`Quick query error: ${err.message}`);
55615
55822
  resolve5({
55616
55823
  success: false,
55617
55824
  error: err.message,
@@ -55625,14 +55832,14 @@ async function quickQuery(options2) {
55625
55832
  clearTimeout(timeoutId);
55626
55833
  const durationMs = Date.now() - startTime;
55627
55834
  if (code === 0 && stdout.trim()) {
55628
- log13.debug(`Quick query success: ${durationMs}ms, ${stdout.length} chars`);
55835
+ log14.debug(`Quick query success: ${durationMs}ms, ${stdout.length} chars`);
55629
55836
  resolve5({
55630
55837
  success: true,
55631
55838
  response: stdout.trim(),
55632
55839
  durationMs
55633
55840
  });
55634
55841
  } else {
55635
- log13.debug(`Quick query failed: code=${code}, stderr=${stderr.substring(0, 100)}`);
55842
+ log14.debug(`Quick query failed: code=${code}, stderr=${stderr.substring(0, 100)}`);
55636
55843
  resolve5({
55637
55844
  success: false,
55638
55845
  error: stderr || `exit code ${code}`,
@@ -55647,7 +55854,7 @@ async function quickQuery(options2) {
55647
55854
 
55648
55855
  // src/operations/suggestions/title.ts
55649
55856
  init_logger();
55650
- var log14 = createLogger("title");
55857
+ var log15 = createLogger("title");
55651
55858
  var SUGGESTION_TIMEOUT = 15000;
55652
55859
  var MIN_TITLE_LENGTH = 3;
55653
55860
  var MAX_TITLE_LENGTH = 50;
@@ -55711,32 +55918,32 @@ function parseMetadata(response) {
55711
55918
  const titleMatch = response.match(/TITLE:\s*(.+)/i);
55712
55919
  const descMatch = response.match(/DESC:\s*(.+)/i);
55713
55920
  if (!titleMatch || !descMatch) {
55714
- log14.debug("Failed to parse title/description from response");
55921
+ log15.debug("Failed to parse title/description from response");
55715
55922
  return null;
55716
55923
  }
55717
55924
  let title = titleMatch[1].trim();
55718
55925
  let description = descMatch[1].trim();
55719
55926
  if (title.length < MIN_TITLE_LENGTH) {
55720
- log14.debug(`Title too short: ${title.length} chars`);
55927
+ log15.debug(`Title too short: ${title.length} chars`);
55721
55928
  return null;
55722
55929
  }
55723
55930
  if (title.length > MAX_TITLE_LENGTH) {
55724
- log14.debug(`Title too long (${title.length} chars), truncating`);
55931
+ log15.debug(`Title too long (${title.length} chars), truncating`);
55725
55932
  title = truncateAtWord(title, MAX_TITLE_LENGTH);
55726
55933
  }
55727
55934
  if (description.length < MIN_DESC_LENGTH) {
55728
- log14.debug(`Description too short: ${description.length} chars`);
55935
+ log15.debug(`Description too short: ${description.length} chars`);
55729
55936
  return null;
55730
55937
  }
55731
55938
  if (description.length > MAX_DESC_LENGTH) {
55732
- log14.debug(`Description too long (${description.length} chars), truncating`);
55939
+ log15.debug(`Description too long (${description.length} chars), truncating`);
55733
55940
  description = truncateAtWord(description, MAX_DESC_LENGTH);
55734
55941
  }
55735
55942
  return { title, description };
55736
55943
  }
55737
55944
  async function suggestSessionMetadata(context) {
55738
55945
  const logContext = typeof context === "string" ? context.substring(0, 50) : context.originalTask.substring(0, 50);
55739
- log14.debug(`Suggesting title for: "${logContext}..."`);
55946
+ log15.debug(`Suggesting title for: "${logContext}..."`);
55740
55947
  try {
55741
55948
  const result = await quickQuery({
55742
55949
  prompt: buildTitlePrompt(context),
@@ -55744,23 +55951,23 @@ async function suggestSessionMetadata(context) {
55744
55951
  timeout: SUGGESTION_TIMEOUT
55745
55952
  });
55746
55953
  if (!result.success || !result.response) {
55747
- log14.debug(`Title suggestion failed: ${result.error || "no response"}`);
55954
+ log15.debug(`Title suggestion failed: ${result.error || "no response"}`);
55748
55955
  return null;
55749
55956
  }
55750
55957
  const metadata = parseMetadata(result.response);
55751
55958
  if (metadata) {
55752
- log14.debug(`Got title: "${metadata.title}" (${result.durationMs}ms)`);
55959
+ log15.debug(`Got title: "${metadata.title}" (${result.durationMs}ms)`);
55753
55960
  }
55754
55961
  return metadata;
55755
55962
  } catch (err) {
55756
- log14.debug(`Title suggestion error: ${err}`);
55963
+ log15.debug(`Title suggestion error: ${err}`);
55757
55964
  return null;
55758
55965
  }
55759
55966
  }
55760
55967
 
55761
55968
  // src/operations/suggestions/tag.ts
55762
55969
  init_logger();
55763
- var log15 = createLogger("tags");
55970
+ var log16 = createLogger("tags");
55764
55971
  var SUGGESTION_TIMEOUT2 = 15000;
55765
55972
  var MAX_TAGS = 3;
55766
55973
  var VALID_TAGS = [
@@ -55792,7 +55999,7 @@ function parseTags(response) {
55792
55999
  return [...new Set(tags)].slice(0, MAX_TAGS);
55793
56000
  }
55794
56001
  async function suggestSessionTags(userMessage) {
55795
- log15.debug(`Suggesting tags for: "${userMessage.substring(0, 50)}..."`);
56002
+ log16.debug(`Suggesting tags for: "${userMessage.substring(0, 50)}..."`);
55796
56003
  try {
55797
56004
  const result = await quickQuery({
55798
56005
  prompt: buildTagPrompt(userMessage),
@@ -55800,14 +56007,14 @@ async function suggestSessionTags(userMessage) {
55800
56007
  timeout: SUGGESTION_TIMEOUT2
55801
56008
  });
55802
56009
  if (!result.success || !result.response) {
55803
- log15.debug(`Tag suggestion failed: ${result.error || "no response"}`);
56010
+ log16.debug(`Tag suggestion failed: ${result.error || "no response"}`);
55804
56011
  return [];
55805
56012
  }
55806
56013
  const tags = parseTags(result.response);
55807
- log15.debug(`Got tags: ${tags.join(", ")} (${result.durationMs}ms)`);
56014
+ log16.debug(`Got tags: ${tags.join(", ")} (${result.durationMs}ms)`);
55808
56015
  return tags;
55809
56016
  } catch (err) {
55810
- log15.debug(`Tag suggestion error: ${err}`);
56017
+ log16.debug(`Tag suggestion error: ${err}`);
55811
56018
  return [];
55812
56019
  }
55813
56020
  }
@@ -59349,7 +59556,7 @@ class BugReportExecutor extends BaseExecutor {
59349
59556
  // src/operations/executors/worktree-prompt.ts
59350
59557
  init_emoji();
59351
59558
  init_logger();
59352
- var log16 = createLogger("wt-prompt");
59559
+ var log17 = createLogger("wt-prompt");
59353
59560
  // src/operations/message-manager.ts
59354
59561
  init_logger();
59355
59562
 
@@ -59386,7 +59593,7 @@ var import_yauzl = __toESM(require_yauzl(), 1);
59386
59593
  import { createGunzip } from "zlib";
59387
59594
  import { pipeline } from "stream/promises";
59388
59595
  import { Readable, Writable } from "stream";
59389
- var log17 = createLogger("streaming");
59596
+ var log18 = createLogger("streaming");
59390
59597
  var MAX_PDF_SIZE = 32 * 1024 * 1024;
59391
59598
  var MAX_TEXT_FILE_SIZE = 1 * 1024 * 1024;
59392
59599
  var MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024;
@@ -59512,7 +59719,7 @@ async function processImageFile(file, platform, debug = false) {
59512
59719
  const buffer = await platform.downloadFile(file.id);
59513
59720
  const base64 = buffer.toString("base64");
59514
59721
  if (debug) {
59515
- log17.debug(`Attached image: ${file.name} (${file.mimeType}, ${Math.round(buffer.length / 1024)}KB)`);
59722
+ log18.debug(`Attached image: ${file.name} (${file.mimeType}, ${Math.round(buffer.length / 1024)}KB)`);
59516
59723
  }
59517
59724
  return {
59518
59725
  block: {
@@ -59525,7 +59732,7 @@ async function processImageFile(file, platform, debug = false) {
59525
59732
  }
59526
59733
  };
59527
59734
  } catch (err) {
59528
- log17.error(`Failed to download image ${file.name}: ${err}`);
59735
+ log18.error(`Failed to download image ${file.name}: ${err}`);
59529
59736
  return {
59530
59737
  skipped: {
59531
59738
  name: file.name,
@@ -59556,7 +59763,7 @@ async function processPdfFile(file, platform, debug = false) {
59556
59763
  }
59557
59764
  const base64 = buffer.toString("base64");
59558
59765
  if (debug) {
59559
- log17.debug(`Attached PDF: ${file.name} (${Math.round(buffer.length / 1024)}KB)`);
59766
+ log18.debug(`Attached PDF: ${file.name} (${Math.round(buffer.length / 1024)}KB)`);
59560
59767
  }
59561
59768
  return {
59562
59769
  block: {
@@ -59570,7 +59777,7 @@ async function processPdfFile(file, platform, debug = false) {
59570
59777
  }
59571
59778
  };
59572
59779
  } catch (err) {
59573
- log17.error(`Failed to process PDF ${file.name}: ${err}`);
59780
+ log18.error(`Failed to process PDF ${file.name}: ${err}`);
59574
59781
  return {
59575
59782
  skipped: {
59576
59783
  name: file.name,
@@ -59601,7 +59808,7 @@ async function processTextFile(file, platform, debug = false) {
59601
59808
  }
59602
59809
  const content = buffer.toString("utf-8");
59603
59810
  if (debug) {
59604
- log17.debug(`Attached text file: ${file.name} (${Math.round(buffer.length / 1024)}KB)`);
59811
+ log18.debug(`Attached text file: ${file.name} (${Math.round(buffer.length / 1024)}KB)`);
59605
59812
  }
59606
59813
  const wrappedContent = formatTextFileContent(file.name, content);
59607
59814
  return {
@@ -59611,7 +59818,7 @@ async function processTextFile(file, platform, debug = false) {
59611
59818
  }
59612
59819
  };
59613
59820
  } catch (err) {
59614
- log17.error(`Failed to process text file ${file.name}: ${err}`);
59821
+ log18.error(`Failed to process text file ${file.name}: ${err}`);
59615
59822
  return {
59616
59823
  skipped: {
59617
59824
  name: file.name,
@@ -59669,7 +59876,7 @@ async function processGzipFile(file, platform, debug = false) {
59669
59876
  compressedBuffer = await platform.downloadFile(file.id);
59670
59877
  } catch (err) {
59671
59878
  const errorMessage = err instanceof Error ? err.message : String(err);
59672
- log17.error(`Failed to download gzip file ${file.name}: ${errorMessage}`);
59879
+ log18.error(`Failed to download gzip file ${file.name}: ${errorMessage}`);
59673
59880
  return {
59674
59881
  skipped: {
59675
59882
  name: file.name,
@@ -59679,7 +59886,7 @@ async function processGzipFile(file, platform, debug = false) {
59679
59886
  };
59680
59887
  }
59681
59888
  if (file.size && compressedBuffer.length !== file.size) {
59682
- log17.warn(`Downloaded size mismatch for ${file.name}: expected ${file.size}, got ${compressedBuffer.length}`);
59889
+ log18.warn(`Downloaded size mismatch for ${file.name}: expected ${file.size}, got ${compressedBuffer.length}`);
59683
59890
  }
59684
59891
  let decompressedBuffer;
59685
59892
  try {
@@ -59715,7 +59922,7 @@ async function processGzipFile(file, platform, debug = false) {
59715
59922
  const innerFilename = file.name.toLowerCase().endsWith(".gz") ? file.name.slice(0, -3) : file.name;
59716
59923
  const contentType = detectDecompressedContentType(decompressedBuffer, innerFilename);
59717
59924
  if (debug) {
59718
- log17.debug(`Decompressed ${file.name}: ${Math.round(decompressedBuffer.length / 1024)}KB, detected type: ${contentType}`);
59925
+ log18.debug(`Decompressed ${file.name}: ${Math.round(decompressedBuffer.length / 1024)}KB, detected type: ${contentType}`);
59719
59926
  }
59720
59927
  if (contentType === "pdf") {
59721
59928
  const base64 = decompressedBuffer.toString("base64");
@@ -59750,7 +59957,7 @@ async function processGzipFile(file, platform, debug = false) {
59750
59957
  }
59751
59958
  } catch (err) {
59752
59959
  const errorMessage = err instanceof Error ? err.message : String(err);
59753
- log17.error(`Failed to process gzip file ${file.name}: ${errorMessage}`);
59960
+ log18.error(`Failed to process gzip file ${file.name}: ${errorMessage}`);
59754
59961
  return {
59755
59962
  skipped: {
59756
59963
  name: file.name,
@@ -59802,7 +60009,7 @@ async function processZipFile(file, platform, debug = false) {
59802
60009
  }
59803
60010
  const zipBuffer = await platform.downloadFile(file.id);
59804
60011
  if (debug) {
59805
- log17.debug(`Processing zip file ${file.name}: ${Math.round(zipBuffer.length / 1024)}KB`);
60012
+ log18.debug(`Processing zip file ${file.name}: ${Math.round(zipBuffer.length / 1024)}KB`);
59806
60013
  }
59807
60014
  const zipfile = await new Promise((resolve5, reject) => {
59808
60015
  import_yauzl.default.fromBuffer(zipBuffer, { lazyEntries: true }, (err, zf) => {
@@ -59876,7 +60083,7 @@ async function processZipFile(file, platform, debug = false) {
59876
60083
  const buffer = await extractZipEntry(zipfile2, entry);
59877
60084
  const contentType = detectDecompressedContentType(buffer, entry.fileName);
59878
60085
  if (debug) {
59879
- log17.debug(`Extracted ${entry.fileName}: ${Math.round(buffer.length / 1024)}KB, type: ${contentType}`);
60086
+ log18.debug(`Extracted ${entry.fileName}: ${Math.round(buffer.length / 1024)}KB, type: ${contentType}`);
59880
60087
  }
59881
60088
  if (contentType === "pdf") {
59882
60089
  const base64 = buffer.toString("base64");
@@ -59919,11 +60126,11 @@ async function processZipFile(file, platform, debug = false) {
59919
60126
  });
59920
60127
  zipfile2.close();
59921
60128
  if (debug) {
59922
- log17.debug(`Zip ${file.name}: processed ${processedCount} files, skipped ${skipped.length}`);
60129
+ log18.debug(`Zip ${file.name}: processed ${processedCount} files, skipped ${skipped.length}`);
59923
60130
  }
59924
60131
  return { blocks, skipped };
59925
60132
  } catch (err) {
59926
- log17.error(`Failed to process zip file ${file.name}: ${err}`);
60133
+ log18.error(`Failed to process zip file ${file.name}: ${err}`);
59927
60134
  return {
59928
60135
  blocks: [],
59929
60136
  skipped: [{
@@ -60020,7 +60227,7 @@ async function processFiles(platform, files, debug = false) {
60020
60227
  blocks.push(...zipResult.blocks);
60021
60228
  for (const s of zipResult.skipped) {
60022
60229
  skipped.push(s);
60023
- log17.warn(`Skipped file ${s.name}: ${s.reason}`);
60230
+ log18.warn(`Skipped file ${s.name}: ${s.reason}`);
60024
60231
  }
60025
60232
  continue;
60026
60233
  }
@@ -60054,7 +60261,7 @@ async function processFiles(platform, files, debug = false) {
60054
60261
  }
60055
60262
  if (result.skipped) {
60056
60263
  skipped.push(result.skipped);
60057
- log17.warn(`Skipped file ${result.skipped.name}: ${result.skipped.reason}`);
60264
+ log18.warn(`Skipped file ${result.skipped.name}: ${result.skipped.reason}`);
60058
60265
  }
60059
60266
  }
60060
60267
  return { blocks, skipped };
@@ -60087,7 +60294,7 @@ function stopTyping(session) {
60087
60294
  }
60088
60295
 
60089
60296
  // src/operations/message-manager.ts
60090
- var log18 = createLogger("msg-mgr");
60297
+ var log19 = createLogger("msg-mgr");
60091
60298
 
60092
60299
  class MessageManager {
60093
60300
  platform;
@@ -60175,7 +60382,7 @@ class MessageManager {
60175
60382
  });
60176
60383
  }
60177
60384
  async handleEvent(event) {
60178
- const logger = log18.forSession(this.sessionId);
60385
+ const logger = log19.forSession(this.sessionId);
60179
60386
  const transformCtx = {
60180
60387
  sessionId: this.sessionId,
60181
60388
  formatter: this.platform.getFormatter(),
@@ -60225,7 +60432,7 @@ class MessageManager {
60225
60432
  }
60226
60433
  }
60227
60434
  async executeOperation(op) {
60228
- const logger = log18.forSession(this.sessionId);
60435
+ const logger = log19.forSession(this.sessionId);
60229
60436
  const ctx = this.getExecutorContext();
60230
60437
  try {
60231
60438
  if (isContentOp(op)) {
@@ -60293,7 +60500,7 @@ class MessageManager {
60293
60500
  threadId: this.threadId,
60294
60501
  platform: this.platform,
60295
60502
  formatter: this.platform.getFormatter(),
60296
- logger: log18.forSession(this.sessionId),
60503
+ logger: log19.forSession(this.sessionId),
60297
60504
  postTracker: this.postTracker,
60298
60505
  contentBreaker: this.contentBreaker,
60299
60506
  threadLogger: this.session.threadLogger,
@@ -60504,13 +60711,13 @@ class MessageManager {
60504
60711
  return this.systemExecutor.postSuccess(message, this.getExecutorContext());
60505
60712
  }
60506
60713
  async prepareForUserMessage() {
60507
- const logger = log18.forSession(this.sessionId);
60714
+ const logger = log19.forSession(this.sessionId);
60508
60715
  logger.debug("Preparing for new user message");
60509
60716
  await this.closeCurrentPost();
60510
60717
  await this.bumpTaskList();
60511
60718
  }
60512
60719
  async handleUserMessage(message, files, username, displayName) {
60513
- const logger = log18.forSession(this.sessionId);
60720
+ const logger = log19.forSession(this.sessionId);
60514
60721
  if (!this.session.claude.isRunning()) {
60515
60722
  logger.debug("Claude not running, ignoring user message");
60516
60723
  return false;
@@ -60537,7 +60744,7 @@ class MessageManager {
60537
60744
  return this.session;
60538
60745
  }
60539
60746
  async handleReaction(postId, emoji, user, action) {
60540
- const logger = log18.forSession(this.sessionId);
60747
+ const logger = log19.forSession(this.sessionId);
60541
60748
  const ctx = this.getExecutorContext();
60542
60749
  logger.debug(`Routing reaction: postId=${postId}, emoji=${emoji}, user=${user}, action=${action}`);
60543
60750
  if (await this.questionApprovalExecutor.handleReaction(postId, emoji, user, action, ctx)) {
@@ -60733,7 +60940,7 @@ function formatPullRequestLink(url, formatter) {
60733
60940
  }
60734
60941
 
60735
60942
  // src/operations/sticky-message/handler.ts
60736
- var log19 = createLogger("sticky");
60943
+ var log20 = createLogger("sticky");
60737
60944
  var botStartedAt = new Date;
60738
60945
  function getPendingPrompts(session) {
60739
60946
  const prompts2 = [];
@@ -60808,21 +61015,21 @@ function initialize(store) {
60808
61015
  stickyPostIds.set(platformId, postId);
60809
61016
  }
60810
61017
  if (persistedIds.size > 0) {
60811
- log19.info(`\uD83D\uDCCC Restored ${persistedIds.size} sticky post ID(s) from persistence`);
61018
+ log20.info(`\uD83D\uDCCC Restored ${persistedIds.size} sticky post ID(s) from persistence`);
60812
61019
  }
60813
61020
  }
60814
61021
  function setPlatformPaused(platformId, paused) {
60815
61022
  if (paused) {
60816
61023
  pausedPlatforms.set(platformId, true);
60817
- log19.debug(`Platform ${platformId} marked as paused`);
61024
+ log20.debug(`Platform ${platformId} marked as paused`);
60818
61025
  } else {
60819
61026
  pausedPlatforms.delete(platformId);
60820
- log19.debug(`Platform ${platformId} marked as active`);
61027
+ log20.debug(`Platform ${platformId} marked as active`);
60821
61028
  }
60822
61029
  }
60823
61030
  function setShuttingDown(shuttingDown) {
60824
61031
  isShuttingDown = shuttingDown;
60825
- log19.debug(`Bot shutdown state: ${shuttingDown}`);
61032
+ log20.debug(`Bot shutdown state: ${shuttingDown}`);
60826
61033
  }
60827
61034
  function getTaskContent(session) {
60828
61035
  const taskState = session.messageManager?.getTaskListState();
@@ -60919,6 +61126,13 @@ async function buildStatusBar(sessionCount, config, formatter, platformId) {
60919
61126
  }
60920
61127
  items.push(formatter.formatCode(formatVersionString()));
60921
61128
  items.push(formatter.formatCode(`${sessionCount}/${config.maxSessions} sessions`));
61129
+ if (config.accountPoolStatus && config.accountPoolStatus.length > 0) {
61130
+ const total = config.accountPoolStatus.length;
61131
+ const cooling = config.accountPoolStatus.filter((a) => a.coolingUntil !== null).length;
61132
+ const available = total - cooling;
61133
+ const label = cooling > 0 ? `\uD83D\uDD11 ${available}/${total} accounts (${cooling} cooling)` : `\uD83D\uDD11 ${total} account${total === 1 ? "" : "s"}`;
61134
+ items.push(formatter.formatCode(label));
61135
+ }
60922
61136
  const permMode = config.skipPermissions ? "⚡ Auto" : "\uD83D\uDD10 Interactive";
60923
61137
  items.push(formatter.formatCode(permMode));
60924
61138
  if (config.worktreeMode === "require") {
@@ -61127,12 +61341,12 @@ async function validateLastMessageIds(platform, sessions) {
61127
61341
  try {
61128
61342
  const post2 = await platform.getPost(lastMessageId);
61129
61343
  if (!post2) {
61130
- log19.debug(`lastMessageId ${lastMessageId.substring(0, 8)} for session ${session.sessionId} was deleted, clearing`);
61344
+ log20.debug(`lastMessageId ${lastMessageId.substring(0, 8)} for session ${session.sessionId} was deleted, clearing`);
61131
61345
  session.lastMessageId = undefined;
61132
61346
  session.lastMessageTs = undefined;
61133
61347
  }
61134
61348
  } catch (err) {
61135
- log19.debug(`Failed to validate lastMessageId for session ${session.sessionId}, clearing: ${err}`);
61349
+ log20.debug(`Failed to validate lastMessageId for session ${session.sessionId}, clearing: ${err}`);
61136
61350
  session.lastMessageId = undefined;
61137
61351
  session.lastMessageTs = undefined;
61138
61352
  }
@@ -61141,63 +61355,63 @@ async function validateLastMessageIds(platform, sessions) {
61141
61355
  }
61142
61356
  async function updateStickyMessageImpl(platform, sessions, config) {
61143
61357
  const platformSessions = [...sessions.values()].filter((s) => s.platformId === platform.platformId);
61144
- log19.debug(`updateStickyMessage for ${platform.platformId}, ${platformSessions.length} sessions`);
61358
+ log20.debug(`updateStickyMessage for ${platform.platformId}, ${platformSessions.length} sessions`);
61145
61359
  for (const s of platformSessions) {
61146
- log19.debug(` - ${s.sessionId}: title="${s.sessionTitle}" firstPrompt="${s.firstPrompt?.substring(0, 30)}..."`);
61360
+ log20.debug(` - ${s.sessionId}: title="${s.sessionTitle}" firstPrompt="${s.firstPrompt?.substring(0, 30)}..."`);
61147
61361
  }
61148
61362
  await validateLastMessageIds(platform, platformSessions);
61149
61363
  const formatter = platform.getFormatter();
61150
61364
  const content = await buildStickyMessage(sessions, platform.platformId, config, formatter, (threadId) => platform.getThreadLink(threadId));
61151
61365
  const existingPostId = stickyPostIds.get(platform.platformId);
61152
61366
  const shouldBump = needsBump.get(platform.platformId) ?? false;
61153
- log19.debug(`existingPostId: ${existingPostId || "(none)"}, needsBump: ${shouldBump}`);
61367
+ log20.debug(`existingPostId: ${existingPostId || "(none)"}, needsBump: ${shouldBump}`);
61154
61368
  try {
61155
61369
  if (existingPostId && !shouldBump) {
61156
- log19.debug(`Updating existing post in place...`);
61370
+ log20.debug(`Updating existing post in place...`);
61157
61371
  try {
61158
61372
  await platform.updatePost(existingPostId, content);
61159
61373
  try {
61160
61374
  await platform.pinPost(existingPostId);
61161
- log19.debug(`Re-pinned post`);
61375
+ log20.debug(`Re-pinned post`);
61162
61376
  } catch (pinErr) {
61163
- log19.debug(`Re-pin failed (might already be pinned): ${pinErr}`);
61377
+ log20.debug(`Re-pin failed (might already be pinned): ${pinErr}`);
61164
61378
  }
61165
- log19.debug(`Updated successfully`);
61379
+ log20.debug(`Updated successfully`);
61166
61380
  return;
61167
61381
  } catch (err) {
61168
- log19.debug(`Update failed, will create new: ${err}`);
61382
+ log20.debug(`Update failed, will create new: ${err}`);
61169
61383
  }
61170
61384
  }
61171
61385
  needsBump.set(platform.platformId, false);
61172
61386
  if (existingPostId) {
61173
- log19.debug(`Unpinning and deleting existing post ${existingPostId.substring(0, 8)}...`);
61387
+ log20.debug(`Unpinning and deleting existing post ${existingPostId.substring(0, 8)}...`);
61174
61388
  try {
61175
61389
  await platform.unpinPost(existingPostId);
61176
- log19.debug(`Unpinned successfully`);
61390
+ log20.debug(`Unpinned successfully`);
61177
61391
  } catch (err) {
61178
- log19.debug(`Unpin failed (probably already unpinned): ${err}`);
61392
+ log20.debug(`Unpin failed (probably already unpinned): ${err}`);
61179
61393
  }
61180
61394
  try {
61181
61395
  await platform.deletePost(existingPostId);
61182
- log19.debug(`Deleted successfully`);
61396
+ log20.debug(`Deleted successfully`);
61183
61397
  } catch (err) {
61184
- log19.debug(`Delete failed (probably already deleted): ${err}`);
61398
+ log20.debug(`Delete failed (probably already deleted): ${err}`);
61185
61399
  }
61186
61400
  stickyPostIds.delete(platform.platformId);
61187
61401
  }
61188
- log19.debug(`Creating new post...`);
61402
+ log20.debug(`Creating new post...`);
61189
61403
  const post2 = await platform.createPost(content);
61190
61404
  stickyPostIds.set(platform.platformId, post2.id);
61191
61405
  try {
61192
61406
  await platform.pinPost(post2.id);
61193
- log19.debug(`Pinned post successfully`);
61407
+ log20.debug(`Pinned post successfully`);
61194
61408
  } catch (err) {
61195
- log19.debug(`Failed to pin post: ${err}`);
61409
+ log20.debug(`Failed to pin post: ${err}`);
61196
61410
  }
61197
61411
  if (sessionStore) {
61198
61412
  sessionStore.saveStickyPostId(platform.platformId, post2.id);
61199
61413
  }
61200
- log19.info(`\uD83D\uDCCC Created sticky message for ${platform.platformId}: ${formatShortId(post2.id)}`);
61414
+ log20.info(`\uD83D\uDCCC Created sticky message for ${platform.platformId}: ${formatShortId(post2.id)}`);
61201
61415
  const excludePostIds = new Set;
61202
61416
  if (sessionStore) {
61203
61417
  for (const session of sessionStore.load().values()) {
@@ -61213,10 +61427,10 @@ async function updateStickyMessageImpl(platform, sessions, config) {
61213
61427
  }
61214
61428
  const botUser = await platform.getBotUser();
61215
61429
  cleanupOldStickyMessages(platform, botUser.id, false, excludePostIds).catch((err) => {
61216
- log19.debug(`Background cleanup failed: ${err}`);
61430
+ log20.debug(`Background cleanup failed: ${err}`);
61217
61431
  });
61218
61432
  } catch (err) {
61219
- log19.error(`Failed to update sticky message for ${platform.platformId}`, err instanceof Error ? err : undefined);
61433
+ log20.error(`Failed to update sticky message for ${platform.platformId}`, err instanceof Error ? err : undefined);
61220
61434
  }
61221
61435
  }
61222
61436
  async function updateAllStickyMessages(platforms, sessions, config) {
@@ -61241,7 +61455,7 @@ async function cleanupOldStickyMessages(platform, botUserId, forceRun = false, e
61241
61455
  if (!forceRun) {
61242
61456
  const lastRun = lastCleanupTime.get(platformId) || 0;
61243
61457
  if (now - lastRun < CLEANUP_THROTTLE_MS) {
61244
- log19.debug(`Cleanup throttled for ${platformId} (last run ${Math.round((now - lastRun) / 1000)}s ago)`);
61458
+ log20.debug(`Cleanup throttled for ${platformId} (last run ${Math.round((now - lastRun) / 1000)}s ago)`);
61245
61459
  return;
61246
61460
  }
61247
61461
  }
@@ -61251,31 +61465,31 @@ async function cleanupOldStickyMessages(platform, botUserId, forceRun = false, e
61251
61465
  const pinnedPostIds = await platform.getPinnedPosts();
61252
61466
  const recentPinnedIds = pinnedPostIds.filter((id) => id !== currentStickyId && !excludePostIds?.has(id) && isRecentPost(id));
61253
61467
  if (recentPinnedIds.length === 0) {
61254
- log19.debug(`No recent pinned posts to check (${pinnedPostIds.length} total, current: ${currentStickyId?.substring(0, 8) || "(none)"})`);
61468
+ log20.debug(`No recent pinned posts to check (${pinnedPostIds.length} total, current: ${currentStickyId?.substring(0, 8) || "(none)"})`);
61255
61469
  return;
61256
61470
  }
61257
- log19.debug(`Checking ${recentPinnedIds.length} recent pinned posts (of ${pinnedPostIds.length} total)`);
61471
+ log20.debug(`Checking ${recentPinnedIds.length} recent pinned posts (of ${pinnedPostIds.length} total)`);
61258
61472
  for (const postId of recentPinnedIds) {
61259
61473
  try {
61260
61474
  const post2 = await platform.getPost(postId);
61261
61475
  if (!post2)
61262
61476
  continue;
61263
61477
  if (post2.userId === botUserId) {
61264
- log19.debug(`Cleaning up old sticky: ${postId.substring(0, 8)}...`);
61478
+ log20.debug(`Cleaning up old sticky: ${postId.substring(0, 8)}...`);
61265
61479
  try {
61266
61480
  await platform.unpinPost(postId);
61267
61481
  await platform.deletePost(postId);
61268
- log19.info(`\uD83E\uDDF9 Cleaned up old sticky message: ${postId.substring(0, 8)}...`);
61482
+ log20.info(`\uD83E\uDDF9 Cleaned up old sticky message: ${postId.substring(0, 8)}...`);
61269
61483
  } catch (err) {
61270
- log19.debug(`Failed to cleanup ${postId}: ${err}`);
61484
+ log20.debug(`Failed to cleanup ${postId}: ${err}`);
61271
61485
  }
61272
61486
  }
61273
61487
  } catch (err) {
61274
- log19.debug(`Could not check post ${postId}: ${err}`);
61488
+ log20.debug(`Could not check post ${postId}: ${err}`);
61275
61489
  }
61276
61490
  }
61277
61491
  } catch (err) {
61278
- log19.error(`Failed to cleanup old sticky messages`, err instanceof Error ? err : undefined);
61492
+ log20.error(`Failed to cleanup old sticky messages`, err instanceof Error ? err : undefined);
61279
61493
  }
61280
61494
  }
61281
61495
  // src/operations/bug-report/handler.ts
@@ -65338,8 +65552,16 @@ function getUpdateInfo() {
65338
65552
  init_emoji();
65339
65553
  init_logger();
65340
65554
  init_worktree();
65341
- var log20 = createLogger("commands");
65342
- var sessionLog2 = createSessionLog(log20);
65555
+ var log21 = createLogger("commands");
65556
+ var sessionLog2 = createSessionLog(log21);
65557
+ function sessionAccountOption(session, ctx) {
65558
+ if (!session.claudeAccountId)
65559
+ return;
65560
+ const account = ctx.ops.getClaudeAccount(session.claudeAccountId);
65561
+ if (!account)
65562
+ return;
65563
+ return { id: account.id, home: account.home, apiKey: account.apiKey };
65564
+ }
65343
65565
  async function restartClaudeSession(session, cliOptions, ctx, actionName) {
65344
65566
  ctx.ops.stopTyping(session);
65345
65567
  transitionTo(session, "restarting");
@@ -65348,6 +65570,7 @@ async function restartClaudeSession(session, cliOptions, ctx, actionName) {
65348
65570
  session.claude = new ClaudeCli(cliOptions);
65349
65571
  session.claude.on("event", (e) => ctx.ops.handleEvent(session.sessionId, e));
65350
65572
  session.claude.on("exit", (code) => ctx.ops.handleExit(session.sessionId, code));
65573
+ session.claude.on("rate-limit", (hit) => handleRateLimit(session, hit, ctx));
65351
65574
  try {
65352
65575
  session.claude.start();
65353
65576
  return true;
@@ -65500,7 +65723,8 @@ ${CHAT_PLATFORM_PROMPT}`;
65500
65723
  platformConfig: session.platform.getMcpConfig(),
65501
65724
  appendSystemPrompt,
65502
65725
  logSessionId: session.sessionId,
65503
- permissionTimeoutMs: ctx.config.permissionTimeoutMs
65726
+ permissionTimeoutMs: ctx.config.permissionTimeoutMs,
65727
+ account: sessionAccountOption(session, ctx)
65504
65728
  };
65505
65729
  const success = await restartClaudeSession(session, cliOptions, ctx, "Restart Claude for directory change");
65506
65730
  if (!success)
@@ -65595,7 +65819,8 @@ async function enableInteractivePermissions(session, username, ctx) {
65595
65819
  chrome: ctx.config.chromeEnabled,
65596
65820
  platformConfig: session.platform.getMcpConfig(),
65597
65821
  logSessionId: session.sessionId,
65598
- permissionTimeoutMs: ctx.config.permissionTimeoutMs
65822
+ permissionTimeoutMs: ctx.config.permissionTimeoutMs,
65823
+ account: sessionAccountOption(session, ctx)
65599
65824
  };
65600
65825
  const success = await restartClaudeSession(session, cliOptions, ctx, "Enable interactive permissions");
65601
65826
  if (!success)
@@ -65701,6 +65926,11 @@ async function updateSessionHeader(session, ctx) {
65701
65926
  if (otherParticipants) {
65702
65927
  items.push(["\uD83D\uDC65", "Participants", otherParticipants]);
65703
65928
  }
65929
+ if (session.claudeAccountId) {
65930
+ const account = ctx.ops.getClaudeAccount(session.claudeAccountId);
65931
+ const label = account?.displayName ?? session.claudeAccountId;
65932
+ items.push(["\uD83D\uDD11", "Claude account", formatter.formatCode(label)]);
65933
+ }
65704
65934
  items.push(["\uD83C\uDD94", "Session ID", formatter.formatCode(session.claudeSessionId.substring(0, 8))]);
65705
65935
  const logPath = getLogFilePath(session.platform.platformId, session.claudeSessionId);
65706
65936
  const shortLogPath = logPath.replace(process.env.HOME || "", "~");
@@ -65857,7 +66087,7 @@ init_logger();
65857
66087
  import { exec as exec3 } from "child_process";
65858
66088
  import { promisify as promisify3 } from "util";
65859
66089
  var execAsync2 = promisify3(exec3);
65860
- var log21 = createLogger("branch");
66090
+ var log22 = createLogger("branch");
65861
66091
  var SUGGESTION_TIMEOUT3 = 15000;
65862
66092
  var MAX_SUGGESTIONS = 3;
65863
66093
  async function getCurrentBranch3(workingDir) {
@@ -65906,7 +66136,7 @@ function parseBranchSuggestions(response) {
65906
66136
  return lines.slice(0, MAX_SUGGESTIONS);
65907
66137
  }
65908
66138
  async function suggestBranchNames(workingDir, userMessage) {
65909
- log21.debug(`Suggesting branch names for: "${userMessage.substring(0, 50)}..."`);
66139
+ log22.debug(`Suggesting branch names for: "${userMessage.substring(0, 50)}..."`);
65910
66140
  try {
65911
66141
  const [currentBranch, recentCommits] = await Promise.all([
65912
66142
  getCurrentBranch3(workingDir),
@@ -65920,14 +66150,14 @@ async function suggestBranchNames(workingDir, userMessage) {
65920
66150
  workingDir
65921
66151
  });
65922
66152
  if (!result.success || !result.response) {
65923
- log21.debug(`Branch suggestion failed: ${result.error || "no response"}`);
66153
+ log22.debug(`Branch suggestion failed: ${result.error || "no response"}`);
65924
66154
  return [];
65925
66155
  }
65926
66156
  const suggestions = parseBranchSuggestions(result.response);
65927
- log21.debug(`Got ${suggestions.length} branch suggestions: ${suggestions.join(", ")}`);
66157
+ log22.debug(`Got ${suggestions.length} branch suggestions: ${suggestions.join(", ")}`);
65928
66158
  return suggestions;
65929
66159
  } catch (err) {
65930
- log21.debug(`Branch suggestion error: ${err}`);
66160
+ log22.debug(`Branch suggestion error: ${err}`);
65931
66161
  return [];
65932
66162
  }
65933
66163
  }
@@ -65936,8 +66166,8 @@ async function suggestBranchNames(workingDir, userMessage) {
65936
66166
  init_worktree();
65937
66167
  import { randomUUID as randomUUID3 } from "crypto";
65938
66168
  init_logger();
65939
- var log22 = createLogger("worktree");
65940
- var sessionLog3 = createSessionLog(log22);
66169
+ var log23 = createLogger("worktree");
66170
+ var sessionLog3 = createSessionLog(log23);
65941
66171
  function parseWorktreeError(error) {
65942
66172
  const message = error instanceof Error ? error.message : String(error);
65943
66173
  const lowerMessage = message.toLowerCase();
@@ -66488,8 +66718,8 @@ async function cleanupWorktreeCommand(session, username, hasOtherSessionsUsingWo
66488
66718
  }
66489
66719
  // src/operations/events/handler.ts
66490
66720
  init_logger();
66491
- var log23 = createLogger("events");
66492
- var sessionLog4 = createSessionLog(log23);
66721
+ var log24 = createLogger("events");
66722
+ var sessionLog4 = createSessionLog(log24);
66493
66723
  function detectAndExecuteClaudeCommands(text, session, ctx) {
66494
66724
  const parsed = parseClaudeCommand(text);
66495
66725
  if (parsed && isClaudeAllowedCommand(parsed.command)) {
@@ -66737,8 +66967,8 @@ function createSessionContext(config, state, ops) {
66737
66967
  // src/operations/context-prompt/handler.ts
66738
66968
  init_emoji();
66739
66969
  init_logger();
66740
- var log24 = createLogger("context");
66741
- var sessionLog5 = createSessionLog(log24);
66970
+ var log25 = createLogger("context");
66971
+ var sessionLog5 = createSessionLog(log25);
66742
66972
  var CONTEXT_PROMPT_TIMEOUT_MS = 30000;
66743
66973
  var CONTEXT_OPTIONS = [3, 5, 10];
66744
66974
  var contextPromptTimeouts = new Map;
@@ -66988,11 +67218,16 @@ function formatRelativeTime(date) {
66988
67218
  }
66989
67219
  // src/session/lifecycle.ts
66990
67220
  init_worktree();
66991
- var log25 = createLogger("lifecycle");
66992
- var sessionLog6 = createSessionLog(log25);
67221
+ var log26 = createLogger("lifecycle");
67222
+ var sessionLog6 = createSessionLog(log26);
66993
67223
  function mutableSessions(ctx) {
66994
67224
  return ctx.state.sessions;
66995
67225
  }
67226
+ var pendingStartsCount = 0;
67227
+ function releasePendingStart() {
67228
+ if (pendingStartsCount > 0)
67229
+ pendingStartsCount--;
67230
+ }
66996
67231
  function mutablePostIndex(ctx) {
66997
67232
  return ctx.state.postIndex;
66998
67233
  }
@@ -67037,12 +67272,31 @@ async function cleanupSession(session, ctx, options2 = {}) {
67037
67272
  cleanupPostIndex(ctx, session.threadId);
67038
67273
  }
67039
67274
  keepAlive.sessionEnded();
67275
+ releaseAccountIfHeld(session, ctx);
67276
+ }
67277
+ function releaseAccountIfHeld(session, ctx) {
67278
+ if (session.claudeAccountId) {
67279
+ ctx.ops.releaseClaudeAccount(session.claudeAccountId);
67280
+ session.claudeAccountId = undefined;
67281
+ }
67040
67282
  }
67041
67283
  function removeFromRegistry(session, ctx) {
67042
67284
  ctx.ops.emitSessionRemove(session.sessionId);
67043
67285
  mutableSessions(ctx).delete(session.sessionId);
67044
67286
  cleanupPostIndex(ctx, session.threadId);
67045
67287
  keepAlive.sessionEnded();
67288
+ releaseAccountIfHeld(session, ctx);
67289
+ }
67290
+ function handleRateLimit(session, hit, ctx) {
67291
+ if (!session.claudeAccountId) {
67292
+ sessionLog6(session).warn(`Rate limit hit in single-account mode — cannot reroute`);
67293
+ return;
67294
+ }
67295
+ const deadline = cooldownDeadline(hit);
67296
+ ctx.ops.markClaudeAccountCooling(session.claudeAccountId, deadline);
67297
+ const minutes = Math.max(1, Math.ceil((deadline - Date.now()) / 60000));
67298
+ sessionLog6(session).warn(`Rate limit on account "${session.claudeAccountId}" — cooling for ~${minutes}min`);
67299
+ post(session, "warning", `⚠️ Claude account \`${session.claudeAccountId}\` hit a rate limit. ` + `New sessions will use another account until it resets (~${minutes}min).`);
67046
67300
  }
67047
67301
  function findPersistedByThreadId(persisted, threadId) {
67048
67302
  for (const session of persisted.values()) {
@@ -67306,20 +67560,24 @@ async function startSession(options2, username, displayName, replyToPostId, plat
67306
67560
  if (!platform) {
67307
67561
  throw new Error(`Platform '${platformId}' not found. Call addPlatform() first.`);
67308
67562
  }
67309
- if (ctx.state.sessions.size >= ctx.config.maxSessions) {
67563
+ const activeOrPending = ctx.state.sessions.size + pendingStartsCount;
67564
+ if (activeOrPending >= ctx.config.maxSessions) {
67310
67565
  const formatter2 = platform.getFormatter();
67311
67566
  const tempSession = {
67312
67567
  platform,
67313
67568
  threadId: replyToPostId || "",
67314
67569
  sessionId: "temp"
67315
67570
  };
67316
- await post(tempSession, "warning", `${formatter2.formatBold("Too busy")} - ${ctx.state.sessions.size} sessions active. Please try again later.`);
67571
+ await post(tempSession, "warning", `${formatter2.formatBold("Too busy")} - ${activeOrPending} sessions active. Please try again later.`);
67317
67572
  return;
67318
67573
  }
67574
+ pendingStartsCount++;
67319
67575
  const startFormatter = platform.getFormatter();
67320
67576
  const startPost = await withErrorHandling(() => platform.createPost(startFormatter.formatItalic("Claude Threads session starting..."), replyToPostId), { action: "Create session post" });
67321
- if (!startPost)
67577
+ if (!startPost) {
67578
+ releasePendingStart();
67322
67579
  return;
67580
+ }
67323
67581
  const actualThreadId = replyToPostId || startPost.id;
67324
67582
  const sessionId = ctx.ops.getSessionId(platformId, actualThreadId);
67325
67583
  platform.sendTyping(actualThreadId);
@@ -67334,26 +67592,32 @@ async function startSession(options2, username, displayName, replyToPostId, plat
67334
67592
  const resolvedDir = resolve6(requestedDir);
67335
67593
  if (!existsSync11(resolvedDir)) {
67336
67594
  await platform.updatePost(startPost.id, `❌ Directory does not exist: ${formatter.formatCode(initialOptions.workingDir)}`);
67595
+ releasePendingStart();
67337
67596
  return;
67338
67597
  }
67339
67598
  const { statSync: statSync4 } = await import("fs");
67340
67599
  if (!statSync4(resolvedDir).isDirectory()) {
67341
67600
  await platform.updatePost(startPost.id, `❌ Not a directory: ${formatter.formatCode(initialOptions.workingDir)}`);
67601
+ releasePendingStart();
67342
67602
  return;
67343
67603
  }
67344
67604
  workingDir = resolvedDir;
67345
- log25.info(`Starting session in directory: ${workingDir} (from !cd command)`);
67605
+ log26.info(`Starting session in directory: ${workingDir} (from !cd command)`);
67346
67606
  }
67347
67607
  if (initialOptions?.forceInteractivePermissions) {
67348
67608
  forceInteractivePermissions = true;
67349
67609
  skipPermissions = false;
67350
- log25.info(`Starting session with interactive permissions (from !permissions command)`);
67610
+ log26.info(`Starting session with interactive permissions (from !permissions command)`);
67351
67611
  }
67352
67612
  const sessionContext = buildSessionContext(platform, workingDir);
67353
67613
  const systemPrompt = `${sessionContext}
67354
67614
 
67355
67615
  ${CHAT_PLATFORM_PROMPT}`;
67356
67616
  const platformMcpConfig = platform.getMcpConfig();
67617
+ const claudeAccount = ctx.ops.acquireClaudeAccount();
67618
+ if (claudeAccount) {
67619
+ log26.info(`Session ${sessionId.substring(0, 20)} reserved Claude account "${claudeAccount.id}"`);
67620
+ }
67357
67621
  const cliOptions = {
67358
67622
  workingDir,
67359
67623
  threadId: actualThreadId,
@@ -67364,7 +67628,8 @@ ${CHAT_PLATFORM_PROMPT}`;
67364
67628
  platformConfig: platformMcpConfig,
67365
67629
  appendSystemPrompt: systemPrompt,
67366
67630
  logSessionId: sessionId,
67367
- permissionTimeoutMs: ctx.config.permissionTimeoutMs
67631
+ permissionTimeoutMs: ctx.config.permissionTimeoutMs,
67632
+ account: claudeAccount ? { id: claudeAccount.id, home: claudeAccount.home, apiKey: claudeAccount.apiKey } : undefined
67368
67633
  };
67369
67634
  const claude = new ClaudeCli(cliOptions);
67370
67635
  const session = {
@@ -67373,6 +67638,7 @@ ${CHAT_PLATFORM_PROMPT}`;
67373
67638
  sessionId,
67374
67639
  platform,
67375
67640
  claudeSessionId,
67641
+ claudeAccountId: claudeAccount?.id,
67376
67642
  startedBy: username,
67377
67643
  startedByDisplayName: displayName,
67378
67644
  startedAt: new Date,
@@ -67401,6 +67667,7 @@ ${CHAT_PLATFORM_PROMPT}`;
67401
67667
  workingDir: ctx.config.workingDir
67402
67668
  });
67403
67669
  mutableSessions(ctx).set(sessionId, session);
67670
+ releasePendingStart();
67404
67671
  ctx.ops.registerPost(startPost.id, actualThreadId);
67405
67672
  ctx.ops.emitSessionAdd(session);
67406
67673
  sessionLog6(session).info(`▶ Session started by @${username}`);
@@ -67411,6 +67678,7 @@ ${CHAT_PLATFORM_PROMPT}`;
67411
67678
  ctx.ops.startTyping(session);
67412
67679
  claude.on("event", (e) => ctx.ops.handleEvent(sessionId, e));
67413
67680
  claude.on("exit", (code) => ctx.ops.handleExit(sessionId, code));
67681
+ claude.on("rate-limit", (hit) => handleRateLimit(session, hit, ctx));
67414
67682
  try {
67415
67683
  claude.start();
67416
67684
  } catch (err) {
@@ -67418,6 +67686,7 @@ ${CHAT_PLATFORM_PROMPT}`;
67418
67686
  ctx.ops.stopTyping(session);
67419
67687
  ctx.ops.emitSessionRemove(session.sessionId);
67420
67688
  mutableSessions(ctx).delete(session.sessionId);
67689
+ releaseAccountIfHeld(session, ctx);
67421
67690
  await ctx.ops.updateStickyMessage();
67422
67691
  return;
67423
67692
  }
@@ -67453,28 +67722,28 @@ async function resumeSession(state, ctx) {
67453
67722
  !state.claudeSessionId && "claudeSessionId",
67454
67723
  !state.workingDir && "workingDir"
67455
67724
  ].filter(Boolean).join(", ");
67456
- log25.warn(`Skipping session with missing required fields: ${missing}`);
67725
+ log26.warn(`Skipping session with missing required fields: ${missing}`);
67457
67726
  return;
67458
67727
  }
67459
67728
  const shortId = state.threadId.substring(0, 8);
67460
67729
  const platforms = ctx.state.platforms;
67461
67730
  const platform = platforms.get(state.platformId);
67462
67731
  if (!platform) {
67463
- log25.warn(`Platform ${state.platformId} not registered, skipping resume for ${shortId}...`);
67732
+ log26.warn(`Platform ${state.platformId} not registered, skipping resume for ${shortId}...`);
67464
67733
  return;
67465
67734
  }
67466
67735
  const threadPost = await platform.getPost(state.threadId);
67467
67736
  if (!threadPost) {
67468
- log25.warn(`Thread ${shortId}... deleted, skipping resume`);
67737
+ log26.warn(`Thread ${shortId}... deleted, skipping resume`);
67469
67738
  ctx.state.sessionStore.remove(`${state.platformId}:${state.threadId}`);
67470
67739
  return;
67471
67740
  }
67472
67741
  if (ctx.state.sessions.size >= ctx.config.maxSessions) {
67473
- log25.warn(`Max sessions reached, skipping resume for ${shortId}...`);
67742
+ log26.warn(`Max sessions reached, skipping resume for ${shortId}...`);
67474
67743
  return;
67475
67744
  }
67476
67745
  if (!existsSync11(state.workingDir)) {
67477
- log25.warn(`Working directory ${state.workingDir} no longer exists, skipping resume for ${shortId}...`);
67746
+ log26.warn(`Working directory ${state.workingDir} no longer exists, skipping resume for ${shortId}...`);
67478
67747
  ctx.state.sessionStore.remove(`${state.platformId}:${state.threadId}`);
67479
67748
  const resumeFormatter = platform.getFormatter();
67480
67749
  const tempSession = {
@@ -67496,6 +67765,10 @@ Please start a new session.`), { action: "Post resume failure notification" });
67496
67765
  const appendSystemPrompt = `${sessionContext}
67497
67766
 
67498
67767
  ${CHAT_PLATFORM_PROMPT}`;
67768
+ const claudeAccount = ctx.ops.acquireClaudeAccount(state.claudeAccountId);
67769
+ if (state.claudeAccountId && !claudeAccount) {
67770
+ log26.warn(`Persisted session referenced Claude account "${state.claudeAccountId}" ` + `which is no longer configured — resuming under default env`);
67771
+ }
67499
67772
  const cliOptions = {
67500
67773
  workingDir: state.workingDir,
67501
67774
  threadId: state.threadId,
@@ -67506,7 +67779,8 @@ ${CHAT_PLATFORM_PROMPT}`;
67506
67779
  platformConfig: platformMcpConfig,
67507
67780
  appendSystemPrompt,
67508
67781
  logSessionId: sessionId,
67509
- permissionTimeoutMs: ctx.config.permissionTimeoutMs
67782
+ permissionTimeoutMs: ctx.config.permissionTimeoutMs,
67783
+ account: claudeAccount ? { id: claudeAccount.id, home: claudeAccount.home, apiKey: claudeAccount.apiKey } : undefined
67510
67784
  };
67511
67785
  const claude = new ClaudeCli(cliOptions);
67512
67786
  const session = {
@@ -67515,6 +67789,7 @@ ${CHAT_PLATFORM_PROMPT}`;
67515
67789
  sessionId,
67516
67790
  platform,
67517
67791
  claudeSessionId: state.claudeSessionId,
67792
+ claudeAccountId: claudeAccount?.id,
67518
67793
  startedBy: state.startedBy,
67519
67794
  startedByDisplayName: state.startedByDisplayName,
67520
67795
  startedAt: new Date(state.startedAt),
@@ -67557,7 +67832,7 @@ ${CHAT_PLATFORM_PROMPT}`;
67557
67832
  worktreePath: detected.worktreePath,
67558
67833
  branch: detected.branch
67559
67834
  };
67560
- log25.info(`Auto-detected worktree info for resumed session: branch=${detected.branch}`);
67835
+ log26.info(`Auto-detected worktree info for resumed session: branch=${detected.branch}`);
67561
67836
  }
67562
67837
  }
67563
67838
  session.messageManager = createMessageManager(session, ctx);
@@ -67592,6 +67867,7 @@ ${CHAT_PLATFORM_PROMPT}`;
67592
67867
  keepAlive.sessionStarted();
67593
67868
  claude.on("event", (e) => ctx.ops.handleEvent(sessionId, e));
67594
67869
  claude.on("exit", (code) => ctx.ops.handleExit(sessionId, code));
67870
+ claude.on("rate-limit", (hit) => handleRateLimit(session, hit, ctx));
67595
67871
  try {
67596
67872
  claude.start();
67597
67873
  sessionLog6(session).info(`\uD83D\uDD04 Session resumed (@${state.startedBy})`);
@@ -67612,10 +67888,11 @@ ${sessionFormatter.formatItalic("Reconnected to Claude session. You can continue
67612
67888
  await ctx.ops.updateStickyMessage();
67613
67889
  ctx.ops.persistSession(session);
67614
67890
  } catch (err) {
67615
- log25.error(`Failed to resume session ${shortId}`, err instanceof Error ? err : undefined);
67891
+ log26.error(`Failed to resume session ${shortId}`, err instanceof Error ? err : undefined);
67616
67892
  ctx.ops.emitSessionRemove(sessionId);
67617
67893
  mutableSessions(ctx).delete(sessionId);
67618
67894
  ctx.state.sessionStore.remove(sessionId);
67895
+ releaseAccountIfHeld(session, ctx);
67619
67896
  const failFormatter = session.platform.getFormatter();
67620
67897
  await withErrorHandling(() => post(session, "warning", `${failFormatter.formatBold("Could not resume previous session.")} Starting fresh.
67621
67898
  ${failFormatter.formatItalic("Your previous conversation context is preserved, but Claude needs to re-read it.")}`), { action: "Post resume failure notification", session });
@@ -67651,18 +67928,18 @@ async function resumePausedSession(threadId, message, files, ctx) {
67651
67928
  const persisted = ctx.state.sessionStore.load();
67652
67929
  const state = findPersistedByThreadId(persisted, threadId);
67653
67930
  if (!state) {
67654
- log25.debug(`No persisted session found for ${threadId.substring(0, 8)}...`);
67931
+ log26.debug(`No persisted session found for ${threadId.substring(0, 8)}...`);
67655
67932
  return;
67656
67933
  }
67657
67934
  const shortId = threadId.substring(0, 8);
67658
- log25.info(`\uD83D\uDD04 Resuming paused session ${shortId}... for new message`);
67935
+ log26.info(`\uD83D\uDD04 Resuming paused session ${shortId}... for new message`);
67659
67936
  await resumeSession(state, ctx);
67660
67937
  const session = ctx.ops.findSessionByThreadId(threadId);
67661
67938
  if (session && session.claude.isRunning() && session.messageManager) {
67662
67939
  session.messageCount++;
67663
67940
  await session.messageManager.handleUserMessage(message, files, state.startedBy);
67664
67941
  } else {
67665
- log25.warn(`Failed to resume session ${shortId}..., could not send message`);
67942
+ log26.warn(`Failed to resume session ${shortId}..., could not send message`);
67666
67943
  }
67667
67944
  }
67668
67945
  async function handleExit(sessionId, code, ctx) {
@@ -67670,7 +67947,7 @@ async function handleExit(sessionId, code, ctx) {
67670
67947
  const shortId = sessionId.substring(0, 8);
67671
67948
  sessionLog6(session).debug(`handleExit called code=${code} isShuttingDown=${ctx.state.isShuttingDown}`);
67672
67949
  if (!session) {
67673
- log25.debug(`Session ${shortId}... not found (already cleaned up)`);
67950
+ log26.debug(`Session ${shortId}... not found (already cleaned up)`);
67674
67951
  return;
67675
67952
  }
67676
67953
  if (isSessionRestarting(session)) {
@@ -67863,7 +68140,7 @@ async function cleanupIdleSessions(timeoutMs, warningMs, ctx) {
67863
68140
  }
67864
68141
 
67865
68142
  // src/operations/monitor/handler.ts
67866
- var log26 = createLogger("monitor");
68143
+ var log27 = createLogger("monitor");
67867
68144
  var DEFAULT_INTERVAL_MS = 60 * 1000;
67868
68145
 
67869
68146
  class SessionMonitor {
@@ -67885,14 +68162,14 @@ class SessionMonitor {
67885
68162
  }
67886
68163
  start() {
67887
68164
  if (this.isRunning) {
67888
- log26.debug("Session monitor already running");
68165
+ log27.debug("Session monitor already running");
67889
68166
  return;
67890
68167
  }
67891
68168
  this.isRunning = true;
67892
- log26.debug(`Session monitor started (interval: ${this.intervalMs / 1000}s)`);
68169
+ log27.debug(`Session monitor started (interval: ${this.intervalMs / 1000}s)`);
67893
68170
  this.timer = setInterval(() => {
67894
68171
  this.runCheck().catch((err) => {
67895
- log26.error(`Error during session monitoring: ${err}`);
68172
+ log27.error(`Error during session monitoring: ${err}`);
67896
68173
  });
67897
68174
  }, this.intervalMs);
67898
68175
  }
@@ -67902,7 +68179,7 @@ class SessionMonitor {
67902
68179
  this.timer = null;
67903
68180
  }
67904
68181
  this.isRunning = false;
67905
- log26.debug("Session monitor stopped");
68182
+ log27.debug("Session monitor stopped");
67906
68183
  }
67907
68184
  async runCheck() {
67908
68185
  await cleanupIdleSessions(this.sessionTimeoutMs, this.sessionWarningMs, this.getContext());
@@ -67914,8 +68191,8 @@ class SessionMonitor {
67914
68191
  // src/operations/plugin/handler.ts
67915
68192
  init_spawn();
67916
68193
  init_logger();
67917
- var log27 = createLogger("plugin");
67918
- var sessionLog7 = createSessionLog(log27);
68194
+ var log28 = createLogger("plugin");
68195
+ var sessionLog7 = createSessionLog(log28);
67919
68196
  async function runPluginCommand(args, cwd, timeout2 = 60000) {
67920
68197
  return new Promise((resolve6) => {
67921
68198
  const claudePath = process.env.CLAUDE_PATH || "claude";
@@ -67936,7 +68213,7 @@ async function runPluginCommand(args, cwd, timeout2 = 60000) {
67936
68213
  });
67937
68214
  proc.on("error", (err) => {
67938
68215
  resolve6({ stdout, stderr, exitCode: 1 });
67939
- log27.error(`Plugin command error: ${err.message}`);
68216
+ log28.error(`Plugin command error: ${err.message}`);
67940
68217
  });
67941
68218
  });
67942
68219
  }
@@ -68135,7 +68412,7 @@ class SessionRegistry {
68135
68412
 
68136
68413
  // src/session/manager.ts
68137
68414
  init_logger();
68138
- var log28 = createLogger("manager");
68415
+ var log29 = createLogger("manager");
68139
68416
 
68140
68417
  class SessionManager extends EventEmitter4 {
68141
68418
  platforms = new Map;
@@ -68158,7 +68435,8 @@ class SessionManager extends EventEmitter4 {
68158
68435
  customDescription;
68159
68436
  customFooter;
68160
68437
  autoUpdateManager = null;
68161
- constructor(workingDir, skipPermissions = false, chromeEnabled = false, worktreeMode = "prompt", sessionsPath, threadLogsEnabled = true, threadLogsRetentionDays = 30, limits) {
68438
+ accountPool;
68439
+ constructor(workingDir, skipPermissions = false, chromeEnabled = false, worktreeMode = "prompt", sessionsPath, threadLogsEnabled = true, threadLogsRetentionDays = 30, limits, claudeAccounts) {
68162
68440
  super();
68163
68441
  this.workingDir = workingDir;
68164
68442
  this.skipPermissions = skipPermissions;
@@ -68169,6 +68447,7 @@ class SessionManager extends EventEmitter4 {
68169
68447
  this.limits = resolveLimits(limits);
68170
68448
  this.sessionStore = new SessionStore(sessionsPath);
68171
68449
  this.registry = new SessionRegistry(this.sessionStore);
68450
+ this.accountPool = new AccountPool(claudeAccounts);
68172
68451
  this.sessionMonitor = new SessionMonitor({
68173
68452
  sessionTimeoutMs: this.limits.sessionTimeoutMinutes * 60 * 1000,
68174
68453
  sessionWarningMs: this.limits.sessionWarningMinutes * 60 * 1000,
@@ -68202,7 +68481,7 @@ class SessionManager extends EventEmitter4 {
68202
68481
  markNeedsBump(platformId);
68203
68482
  this.updateStickyMessage();
68204
68483
  });
68205
- log28.info(`\uD83D\uDCE1 Platform "${platformId}" registered`);
68484
+ log29.info(`\uD83D\uDCE1 Platform "${platformId}" registered`);
68206
68485
  }
68207
68486
  removePlatform(platformId) {
68208
68487
  this.platforms.delete(platformId);
@@ -68218,7 +68497,7 @@ class SessionManager extends EventEmitter4 {
68218
68497
  if (users) {
68219
68498
  users.add(sessionId);
68220
68499
  }
68221
- log28.debug(`Registered session ${sessionId.substring(0, 20)} as worktree user for ${worktreePath}`);
68500
+ log29.debug(`Registered session ${sessionId.substring(0, 20)} as worktree user for ${worktreePath}`);
68222
68501
  }
68223
68502
  unregisterWorktreeUser(worktreePath, sessionId) {
68224
68503
  const users = this.worktreeUsers.get(worktreePath);
@@ -68284,7 +68563,12 @@ class SessionManager extends EventEmitter4 {
68284
68563
  offerContextPrompt: (s, q, f, e) => offerContextPrompt(s, q, f, this.getContextPromptHandler(), e),
68285
68564
  emitSessionAdd: (s) => this.emitSessionAdd(s),
68286
68565
  emitSessionUpdate: (sid, u) => this.emitSessionUpdate(sid, u),
68287
- emitSessionRemove: (sid) => this.emitSessionRemove(sid)
68566
+ emitSessionRemove: (sid) => this.emitSessionRemove(sid),
68567
+ acquireClaudeAccount: (preferredId) => this.accountPool.acquire(preferredId),
68568
+ getClaudeAccount: (id) => this.accountPool.get(id),
68569
+ releaseClaudeAccount: (id) => this.accountPool.release(id),
68570
+ markClaudeAccountCooling: (id, untilMs) => this.accountPool.markCooling(id, untilMs),
68571
+ getClaudeAccountPoolStatus: () => this.accountPool.status()
68288
68572
  };
68289
68573
  return createSessionContext(config, state, ops);
68290
68574
  }
@@ -68365,7 +68649,7 @@ class SessionManager extends EventEmitter4 {
68365
68649
  return false;
68366
68650
  }
68367
68651
  const shortId = persistedSession.threadId.substring(0, 8);
68368
- log28.info(`\uD83D\uDD04 Resuming session ${shortId}... via emoji reaction by @${username}`);
68652
+ log29.info(`\uD83D\uDD04 Resuming session ${shortId}... via emoji reaction by @${username}`);
68369
68653
  await resumeSession(persistedSession, this.getContext());
68370
68654
  return true;
68371
68655
  }
@@ -68395,7 +68679,7 @@ class SessionManager extends EventEmitter4 {
68395
68679
  }
68396
68680
  if (session.lastError?.postId === postId && isBugReportEmoji(emojiName)) {
68397
68681
  if (session.startedBy === username || session.platform.isUserAllowed(username) || session.sessionAllowedUsers.has(username)) {
68398
- log28.info(`\uD83D\uDC1B @${username} triggered bug report from error reaction`);
68682
+ log29.info(`\uD83D\uDC1B @${username} triggered bug report from error reaction`);
68399
68683
  await reportBug(session, undefined, username, this.getContext(), session.lastError);
68400
68684
  return;
68401
68685
  }
@@ -68511,7 +68795,8 @@ class SessionManager extends EventEmitter4 {
68511
68795
  sessionTags: session.sessionTags,
68512
68796
  pullRequestUrl: session.pullRequestUrl,
68513
68797
  messageCount: session.messageCount,
68514
- resumeFailCount: session.lifecycle.resumeFailCount
68798
+ resumeFailCount: session.lifecycle.resumeFailCount,
68799
+ claudeAccountId: session.claudeAccountId
68515
68800
  };
68516
68801
  this.sessionStore.save(session.sessionId, state);
68517
68802
  }
@@ -68536,7 +68821,8 @@ class SessionManager extends EventEmitter4 {
68536
68821
  workingDir: this.workingDir,
68537
68822
  debug: this.debug,
68538
68823
  description: this.customDescription,
68539
- footer: this.customFooter
68824
+ footer: this.customFooter,
68825
+ accountPoolStatus: this.accountPool.isEmpty ? undefined : this.accountPool.status()
68540
68826
  });
68541
68827
  }
68542
68828
  async updateAllStickyMessages() {
@@ -68561,11 +68847,11 @@ class SessionManager extends EventEmitter4 {
68561
68847
  }
68562
68848
  }
68563
68849
  if (sessionsToKill.length === 0) {
68564
- log28.info(`No active sessions to pause for platform ${platformId}`);
68850
+ log29.info(`No active sessions to pause for platform ${platformId}`);
68565
68851
  await this.updateStickyMessage();
68566
68852
  return;
68567
68853
  }
68568
- log28.info(`⏸️ Pausing ${sessionsToKill.length} session(s) for platform ${platformId}`);
68854
+ log29.info(`⏸️ Pausing ${sessionsToKill.length} session(s) for platform ${platformId}`);
68569
68855
  for (const session of sessionsToKill) {
68570
68856
  try {
68571
68857
  const fmt = session.platform.getFormatter();
@@ -68581,9 +68867,9 @@ class SessionManager extends EventEmitter4 {
68581
68867
  session.claude.kill();
68582
68868
  this.registry.unregister(session.sessionId);
68583
68869
  this.emitSessionRemove(session.sessionId);
68584
- log28.info(`⏸️ Paused session ${session.threadId.substring(0, 8)}`);
68870
+ log29.info(`⏸️ Paused session ${session.threadId.substring(0, 8)}`);
68585
68871
  } catch (err) {
68586
- log28.warn(`Failed to pause session ${session.threadId}: ${err}`);
68872
+ log29.warn(`Failed to pause session ${session.threadId}: ${err}`);
68587
68873
  }
68588
68874
  }
68589
68875
  for (const session of sessionsToKill) {
@@ -68604,17 +68890,17 @@ class SessionManager extends EventEmitter4 {
68604
68890
  sessionsToResume.push(state);
68605
68891
  }
68606
68892
  if (sessionsToResume.length === 0) {
68607
- log28.info(`No paused sessions to resume for platform ${platformId}`);
68893
+ log29.info(`No paused sessions to resume for platform ${platformId}`);
68608
68894
  await this.updateStickyMessage();
68609
68895
  return;
68610
68896
  }
68611
- log28.info(`▶️ Resuming ${sessionsToResume.length} paused session(s) for platform ${platformId}`);
68897
+ log29.info(`▶️ Resuming ${sessionsToResume.length} paused session(s) for platform ${platformId}`);
68612
68898
  for (const state of sessionsToResume) {
68613
68899
  try {
68614
68900
  await resumeSession(state, this.getContext());
68615
- log28.info(`▶️ Resumed session ${state.threadId.substring(0, 8)}`);
68901
+ log29.info(`▶️ Resumed session ${state.threadId.substring(0, 8)}`);
68616
68902
  } catch (err) {
68617
- log28.warn(`Failed to resume session ${state.threadId}: ${err}`);
68903
+ log29.warn(`Failed to resume session ${state.threadId}: ${err}`);
68618
68904
  }
68619
68905
  }
68620
68906
  await this.updateStickyMessage();
@@ -68626,14 +68912,14 @@ class SessionManager extends EventEmitter4 {
68626
68912
  const sessionTimeoutMs = this.limits.sessionTimeoutMinutes * 60 * 1000;
68627
68913
  const staleIds = this.sessionStore.cleanStale(sessionTimeoutMs * 2);
68628
68914
  if (staleIds.length > 0) {
68629
- log28.info(`\uD83E\uDDF9 Soft-deleted ${staleIds.length} stale session(s) (kept for history)`);
68915
+ log29.info(`\uD83E\uDDF9 Soft-deleted ${staleIds.length} stale session(s) (kept for history)`);
68630
68916
  }
68631
68917
  const removedCount = this.sessionStore.cleanHistory();
68632
68918
  if (removedCount > 0) {
68633
- log28.info(`\uD83D\uDDD1️ Permanently removed ${removedCount} old session(s) from history`);
68919
+ log29.info(`\uD83D\uDDD1️ Permanently removed ${removedCount} old session(s) from history`);
68634
68920
  }
68635
68921
  const persisted = this.sessionStore.load();
68636
- log28.info(`\uD83D\uDCC2 Loaded ${persisted.size} session(s) from persistence`);
68922
+ log29.info(`\uD83D\uDCC2 Loaded ${persisted.size} session(s) from persistence`);
68637
68923
  const excludePostIdsByPlatform = new Map;
68638
68924
  for (const session of persisted.values()) {
68639
68925
  const platformId = session.platformId;
@@ -68653,10 +68939,10 @@ class SessionManager extends EventEmitter4 {
68653
68939
  const excludePostIds = excludePostIdsByPlatform.get(platform.platformId);
68654
68940
  platform.getBotUser().then((botUser) => {
68655
68941
  cleanupOldStickyMessages(platform, botUser.id, true, excludePostIds).catch((err) => {
68656
- log28.warn(`Failed to cleanup old sticky messages for ${platform.platformId}: ${err}`);
68942
+ log29.warn(`Failed to cleanup old sticky messages for ${platform.platformId}: ${err}`);
68657
68943
  });
68658
68944
  }).catch((err) => {
68659
- log28.warn(`Failed to get bot user for cleanup on ${platform.platformId}: ${err}`);
68945
+ log29.warn(`Failed to get bot user for cleanup on ${platform.platformId}: ${err}`);
68660
68946
  });
68661
68947
  }
68662
68948
  if (persisted.size > 0) {
@@ -68670,10 +68956,10 @@ class SessionManager extends EventEmitter4 {
68670
68956
  }
68671
68957
  }
68672
68958
  if (pausedToSkip.length > 0) {
68673
- log28.info(`⏸️ ${pausedToSkip.length} session(s) remain paused (waiting for user message)`);
68959
+ log29.info(`⏸️ ${pausedToSkip.length} session(s) remain paused (waiting for user message)`);
68674
68960
  }
68675
68961
  if (activeToResume.length > 0) {
68676
- log28.info(`\uD83D\uDD04 Attempting to resume ${activeToResume.length} active session(s)...`);
68962
+ log29.info(`\uD83D\uDD04 Attempting to resume ${activeToResume.length} active session(s)...`);
68677
68963
  for (const state of activeToResume) {
68678
68964
  await resumeSession(state, this.getContext());
68679
68965
  }
@@ -69092,7 +69378,7 @@ Mention me to start a session in this worktree.`, threadId);
69092
69378
  const message = messageBuilder(formatter);
69093
69379
  await post(session, "info", message);
69094
69380
  } catch (err) {
69095
- log28.warn(`Failed to broadcast to session ${session.threadId}: ${err}`);
69381
+ log29.warn(`Failed to broadcast to session ${session.threadId}: ${err}`);
69096
69382
  }
69097
69383
  }
69098
69384
  }
@@ -69111,7 +69397,7 @@ Mention me to start a session in this worktree.`, threadId);
69111
69397
  session.messageManager?.setPendingUpdatePrompt({ postId: post2.id });
69112
69398
  this.registerPost(post2.id, session.threadId);
69113
69399
  } catch (err) {
69114
- log28.warn(`Failed to post ask message to ${threadId}: ${err}`);
69400
+ log29.warn(`Failed to post ask message to ${threadId}: ${err}`);
69115
69401
  }
69116
69402
  }
69117
69403
  }
@@ -76706,29 +76992,29 @@ function SessionLog({ logs, maxLines = 20 }) {
76706
76992
  return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
76707
76993
  flexDirection: "column",
76708
76994
  flexShrink: 0,
76709
- children: displayLogs.map((log29) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
76995
+ children: displayLogs.map((log30) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
76710
76996
  flexShrink: 0,
76711
76997
  children: [
76712
76998
  /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
76713
- color: getColorForLevel(log29.level),
76999
+ color: getColorForLevel(log30.level),
76714
77000
  dimColor: true,
76715
77001
  wrap: "truncate",
76716
77002
  children: [
76717
77003
  "[",
76718
- padComponent(log29.component),
77004
+ padComponent(log30.component),
76719
77005
  "]"
76720
77006
  ]
76721
77007
  }, undefined, true, undefined, this),
76722
77008
  /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
76723
- color: getColorForLevel(log29.level),
77009
+ color: getColorForLevel(log30.level),
76724
77010
  wrap: "truncate",
76725
77011
  children: [
76726
77012
  " ",
76727
- log29.message
77013
+ log30.message
76728
77014
  ]
76729
77015
  }, undefined, true, undefined, this)
76730
77016
  ]
76731
- }, log29.id, true, undefined, this))
77017
+ }, log30.id, true, undefined, this))
76732
77018
  }, undefined, false, undefined, this);
76733
77019
  }
76734
77020
  // src/ui/components/Footer.tsx
@@ -77226,7 +77512,7 @@ function LogPanel({ logs, maxLines = 10, focused = false }) {
77226
77512
  const scrollRef = import_react59.default.useRef(null);
77227
77513
  const { stdout } = use_stdout_default();
77228
77514
  const isDebug = process.env.DEBUG === "1";
77229
- const displayLogs = logs.filter((log29) => isDebug || log29.level !== "debug");
77515
+ const displayLogs = logs.filter((log30) => isDebug || log30.level !== "debug");
77230
77516
  const visibleLogs = displayLogs.slice(-Math.max(maxLines * 3, 100));
77231
77517
  import_react59.default.useEffect(() => {
77232
77518
  const handleResize = () => scrollRef.current?.remeasure();
@@ -77266,25 +77552,25 @@ function LogPanel({ logs, maxLines = 10, focused = false }) {
77266
77552
  overflow: "hidden",
77267
77553
  children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(ScrollView, {
77268
77554
  ref: scrollRef,
77269
- children: visibleLogs.map((log29) => /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
77555
+ children: visibleLogs.map((log30) => /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
77270
77556
  children: [
77271
77557
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
77272
77558
  dimColor: true,
77273
77559
  children: [
77274
77560
  "[",
77275
- padComponent2(log29.component),
77561
+ padComponent2(log30.component),
77276
77562
  "]"
77277
77563
  ]
77278
77564
  }, undefined, true, undefined, this),
77279
77565
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
77280
- color: getLevelColor(log29.level),
77566
+ color: getLevelColor(log30.level),
77281
77567
  children: [
77282
77568
  " ",
77283
- log29.message
77569
+ log30.message
77284
77570
  ]
77285
77571
  }, undefined, true, undefined, this)
77286
77572
  ]
77287
- }, log29.id, true, undefined, this))
77573
+ }, log30.id, true, undefined, this))
77288
77574
  }, undefined, false, undefined, this)
77289
77575
  }, undefined, false, undefined, this);
77290
77576
  }
@@ -77801,10 +78087,10 @@ function useAppState(initialConfig) {
77801
78087
  });
77802
78088
  }, []);
77803
78089
  const getLogsForSession = import_react60.useCallback((sessionId) => {
77804
- return state.logs.filter((log29) => log29.sessionId === sessionId);
78090
+ return state.logs.filter((log30) => log30.sessionId === sessionId);
77805
78091
  }, [state.logs]);
77806
78092
  const getGlobalLogs = import_react60.useCallback(() => {
77807
- return state.logs.filter((log29) => !log29.sessionId);
78093
+ return state.logs.filter((log30) => !log30.sessionId);
77808
78094
  }, [state.logs]);
77809
78095
  const togglePlatformEnabled = import_react60.useCallback((platformId) => {
77810
78096
  let newEnabled = false;
@@ -78798,7 +79084,7 @@ import { EventEmitter as EventEmitter9 } from "events";
78798
79084
  // src/auto-update/checker.ts
78799
79085
  init_logger();
78800
79086
  import { EventEmitter as EventEmitter7 } from "events";
78801
- var log29 = createLogger("checker");
79087
+ var log30 = createLogger("checker");
78802
79088
  var PACKAGE_NAME = "claude-threads";
78803
79089
  function compareVersions(a, b) {
78804
79090
  const partsA = a.replace(/^v/, "").split(".").map(Number);
@@ -78821,13 +79107,13 @@ async function fetchLatestVersion() {
78821
79107
  }
78822
79108
  });
78823
79109
  if (!response.ok) {
78824
- log29.warn(`Failed to fetch latest version: HTTP ${response.status}`);
79110
+ log30.warn(`Failed to fetch latest version: HTTP ${response.status}`);
78825
79111
  return null;
78826
79112
  }
78827
79113
  const data = await response.json();
78828
79114
  return data.version ?? null;
78829
79115
  } catch (err) {
78830
- log29.warn(`Failed to fetch latest version: ${err}`);
79116
+ log30.warn(`Failed to fetch latest version: ${err}`);
78831
79117
  return null;
78832
79118
  }
78833
79119
  }
@@ -78844,38 +79130,38 @@ class UpdateChecker extends EventEmitter7 {
78844
79130
  }
78845
79131
  start() {
78846
79132
  if (!this.config.enabled) {
78847
- log29.debug("Auto-update disabled, not starting checker");
79133
+ log30.debug("Auto-update disabled, not starting checker");
78848
79134
  return;
78849
79135
  }
78850
79136
  setTimeout(() => {
78851
79137
  this.check().catch((err) => {
78852
- log29.warn(`Initial update check failed: ${err}`);
79138
+ log30.warn(`Initial update check failed: ${err}`);
78853
79139
  });
78854
79140
  }, 5000);
78855
79141
  const intervalMs = this.config.checkIntervalMinutes * 60 * 1000;
78856
79142
  this.checkInterval = setInterval(() => {
78857
79143
  this.check().catch((err) => {
78858
- log29.warn(`Periodic update check failed: ${err}`);
79144
+ log30.warn(`Periodic update check failed: ${err}`);
78859
79145
  });
78860
79146
  }, intervalMs);
78861
- log29.info(`\uD83D\uDD04 Update checker started (every ${this.config.checkIntervalMinutes} minutes)`);
79147
+ log30.info(`\uD83D\uDD04 Update checker started (every ${this.config.checkIntervalMinutes} minutes)`);
78862
79148
  }
78863
79149
  stop() {
78864
79150
  if (this.checkInterval) {
78865
79151
  clearInterval(this.checkInterval);
78866
79152
  this.checkInterval = null;
78867
79153
  }
78868
- log29.debug("Update checker stopped");
79154
+ log30.debug("Update checker stopped");
78869
79155
  }
78870
79156
  async check() {
78871
79157
  if (this.isChecking) {
78872
- log29.debug("Check already in progress, skipping");
79158
+ log30.debug("Check already in progress, skipping");
78873
79159
  return this.lastUpdateInfo;
78874
79160
  }
78875
79161
  this.isChecking = true;
78876
79162
  this.emit("check:start");
78877
79163
  try {
78878
- log29.debug("Checking for updates...");
79164
+ log30.debug("Checking for updates...");
78879
79165
  const latestVersion2 = await fetchLatestVersion();
78880
79166
  if (!latestVersion2) {
78881
79167
  this.emit("check:complete", false);
@@ -78892,18 +79178,18 @@ class UpdateChecker extends EventEmitter7 {
78892
79178
  detectedAt: new Date
78893
79179
  };
78894
79180
  if (!this.lastUpdateInfo || this.lastUpdateInfo.latestVersion !== latestVersion2) {
78895
- log29.info(`\uD83C\uDD95 Update available: v${currentVersion} → v${latestVersion2}`);
79181
+ log30.info(`\uD83C\uDD95 Update available: v${currentVersion} → v${latestVersion2}`);
78896
79182
  this.lastUpdateInfo = updateInfo;
78897
79183
  this.emit("update", updateInfo);
78898
79184
  }
78899
79185
  this.emit("check:complete", true);
78900
79186
  return updateInfo;
78901
79187
  }
78902
- log29.debug(`Up to date (v${currentVersion})`);
79188
+ log30.debug(`Up to date (v${currentVersion})`);
78903
79189
  this.emit("check:complete", false);
78904
79190
  return null;
78905
79191
  } catch (err) {
78906
- log29.warn(`Update check failed: ${err}`);
79192
+ log30.warn(`Update check failed: ${err}`);
78907
79193
  this.emit("check:error", err);
78908
79194
  return null;
78909
79195
  } finally {
@@ -78974,7 +79260,7 @@ function isInScheduledWindow(window2) {
78974
79260
  }
78975
79261
 
78976
79262
  // src/auto-update/scheduler.ts
78977
- var log30 = createLogger("scheduler");
79263
+ var log31 = createLogger("scheduler");
78978
79264
 
78979
79265
  class UpdateScheduler extends EventEmitter8 {
78980
79266
  config;
@@ -78998,7 +79284,7 @@ class UpdateScheduler extends EventEmitter8 {
78998
79284
  scheduleUpdate(updateInfo) {
78999
79285
  this.pendingUpdate = updateInfo;
79000
79286
  if (this.config.autoRestartMode === "immediate") {
79001
- log30.info("Immediate mode: triggering update now");
79287
+ log31.info("Immediate mode: triggering update now");
79002
79288
  this.emit("ready", updateInfo);
79003
79289
  return;
79004
79290
  }
@@ -79011,19 +79297,19 @@ class UpdateScheduler extends EventEmitter8 {
79011
79297
  this.scheduledRestartAt = null;
79012
79298
  this.askApprovals.clear();
79013
79299
  this.askStartTime = null;
79014
- log30.debug("Update schedule cancelled");
79300
+ log31.debug("Update schedule cancelled");
79015
79301
  }
79016
79302
  deferUpdate(minutes) {
79017
79303
  const deferUntil = new Date(Date.now() + minutes * 60 * 1000);
79018
79304
  this.scheduledRestartAt = null;
79019
79305
  this.idleStartTime = null;
79020
79306
  this.emit("deferred", deferUntil);
79021
- log30.info(`Update deferred until ${deferUntil.toLocaleTimeString()}`);
79307
+ log31.info(`Update deferred until ${deferUntil.toLocaleTimeString()}`);
79022
79308
  return deferUntil;
79023
79309
  }
79024
79310
  recordAskResponse(threadId, approved) {
79025
79311
  this.askApprovals.set(threadId, approved);
79026
- log30.debug(`Thread ${threadId.substring(0, 8)} ${approved ? "approved" : "denied"} update`);
79312
+ log31.debug(`Thread ${threadId.substring(0, 8)} ${approved ? "approved" : "denied"} update`);
79027
79313
  this.checkAskCondition();
79028
79314
  }
79029
79315
  getScheduledRestartAt() {
@@ -79044,7 +79330,7 @@ class UpdateScheduler extends EventEmitter8 {
79044
79330
  return;
79045
79331
  this.checkCondition();
79046
79332
  this.checkTimer = setInterval(() => this.checkCondition(), 1e4);
79047
- log30.debug(`Started checking for ${this.config.autoRestartMode} condition`);
79333
+ log31.debug(`Started checking for ${this.config.autoRestartMode} condition`);
79048
79334
  }
79049
79335
  stopChecking() {
79050
79336
  if (this.checkTimer) {
@@ -79075,17 +79361,17 @@ class UpdateScheduler extends EventEmitter8 {
79075
79361
  if (activity.activeSessionCount === 0) {
79076
79362
  if (!this.idleStartTime) {
79077
79363
  this.idleStartTime = new Date;
79078
- log30.debug("No active sessions, starting idle timer");
79364
+ log31.debug("No active sessions, starting idle timer");
79079
79365
  }
79080
79366
  const idleMs = Date.now() - this.idleStartTime.getTime();
79081
79367
  const requiredMs = this.config.idleTimeoutMinutes * 60 * 1000;
79082
79368
  if (idleMs >= requiredMs) {
79083
- log30.info(`Idle for ${this.config.idleTimeoutMinutes} minutes, triggering update`);
79369
+ log31.info(`Idle for ${this.config.idleTimeoutMinutes} minutes, triggering update`);
79084
79370
  this.triggerCountdown();
79085
79371
  }
79086
79372
  } else {
79087
79373
  if (this.idleStartTime) {
79088
- log30.debug("Sessions became active, resetting idle timer");
79374
+ log31.debug("Sessions became active, resetting idle timer");
79089
79375
  this.idleStartTime = null;
79090
79376
  }
79091
79377
  }
@@ -79096,7 +79382,7 @@ class UpdateScheduler extends EventEmitter8 {
79096
79382
  const quietMs = Date.now() - activity.lastActivityAt.getTime();
79097
79383
  const requiredMs = this.config.quietTimeoutMinutes * 60 * 1000;
79098
79384
  if (quietMs >= requiredMs && !activity.anySessionBusy) {
79099
- log30.info(`Sessions quiet for ${this.config.quietTimeoutMinutes} minutes, triggering update`);
79385
+ log31.info(`Sessions quiet for ${this.config.quietTimeoutMinutes} minutes, triggering update`);
79100
79386
  this.triggerCountdown();
79101
79387
  }
79102
79388
  } else if (activity.activeSessionCount === 0) {
@@ -79106,7 +79392,7 @@ class UpdateScheduler extends EventEmitter8 {
79106
79392
  const idleMs = Date.now() - this.idleStartTime.getTime();
79107
79393
  const requiredMs = this.config.quietTimeoutMinutes * 60 * 1000;
79108
79394
  if (idleMs >= requiredMs) {
79109
- log30.info("No sessions and quiet timeout reached, triggering update");
79395
+ log31.info("No sessions and quiet timeout reached, triggering update");
79110
79396
  this.triggerCountdown();
79111
79397
  }
79112
79398
  }
@@ -79117,13 +79403,13 @@ class UpdateScheduler extends EventEmitter8 {
79117
79403
  }
79118
79404
  const activity = this.getSessionActivity();
79119
79405
  if (activity.activeSessionCount === 0) {
79120
- log30.info("Within scheduled window and no active sessions, triggering update");
79406
+ log31.info("Within scheduled window and no active sessions, triggering update");
79121
79407
  this.triggerCountdown();
79122
79408
  } else if (activity.lastActivityAt) {
79123
79409
  const quietMs = Date.now() - activity.lastActivityAt.getTime();
79124
79410
  const requiredMs = this.config.idleTimeoutMinutes * 60 * 1000;
79125
79411
  if (quietMs >= requiredMs && !activity.anySessionBusy) {
79126
- log30.info("Within scheduled window and sessions quiet, triggering update");
79412
+ log31.info("Within scheduled window and sessions quiet, triggering update");
79127
79413
  this.triggerCountdown();
79128
79414
  }
79129
79415
  }
@@ -79131,14 +79417,14 @@ class UpdateScheduler extends EventEmitter8 {
79131
79417
  checkAskCondition() {
79132
79418
  const threadIds = this.getActiveThreadIds();
79133
79419
  if (threadIds.length === 0) {
79134
- log30.info("No active threads, proceeding with update");
79420
+ log31.info("No active threads, proceeding with update");
79135
79421
  this.triggerCountdown();
79136
79422
  return;
79137
79423
  }
79138
79424
  if (!this.askStartTime && this.pendingUpdate) {
79139
79425
  this.askStartTime = new Date;
79140
79426
  this.postAskMessage(threadIds, this.pendingUpdate.latestVersion).catch((err) => {
79141
- log30.warn(`Failed to post ask message: ${err}`);
79427
+ log31.warn(`Failed to post ask message: ${err}`);
79142
79428
  });
79143
79429
  return;
79144
79430
  }
@@ -79151,12 +79437,12 @@ class UpdateScheduler extends EventEmitter8 {
79151
79437
  denials++;
79152
79438
  }
79153
79439
  if (approvals > threadIds.length / 2) {
79154
- log30.info(`Majority approved (${approvals}/${threadIds.length}), triggering update`);
79440
+ log31.info(`Majority approved (${approvals}/${threadIds.length}), triggering update`);
79155
79441
  this.triggerCountdown();
79156
79442
  return;
79157
79443
  }
79158
79444
  if (denials > threadIds.length / 2) {
79159
- log30.info(`Majority denied (${denials}/${threadIds.length}), deferring update`);
79445
+ log31.info(`Majority denied (${denials}/${threadIds.length}), deferring update`);
79160
79446
  this.deferUpdate(60);
79161
79447
  return;
79162
79448
  }
@@ -79164,7 +79450,7 @@ class UpdateScheduler extends EventEmitter8 {
79164
79450
  const elapsedMs = Date.now() - this.askStartTime.getTime();
79165
79451
  const timeoutMs = this.config.askTimeoutMinutes * 60 * 1000;
79166
79452
  if (elapsedMs >= timeoutMs) {
79167
- log30.info(`Ask timeout reached (${this.config.askTimeoutMinutes} min), triggering update`);
79453
+ log31.info(`Ask timeout reached (${this.config.askTimeoutMinutes} min), triggering update`);
79168
79454
  this.triggerCountdown();
79169
79455
  }
79170
79456
  }
@@ -79184,7 +79470,7 @@ class UpdateScheduler extends EventEmitter8 {
79184
79470
  this.emit("ready", this.pendingUpdate);
79185
79471
  }
79186
79472
  }, 1000);
79187
- log30.info("Update countdown started (60 seconds)");
79473
+ log31.info("Update countdown started (60 seconds)");
79188
79474
  }
79189
79475
  stopCountdown() {
79190
79476
  if (this.countdownTimer) {
@@ -79200,24 +79486,24 @@ import { spawn as spawn4, spawnSync } from "child_process";
79200
79486
  import { existsSync as existsSync13, readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4 } from "fs";
79201
79487
  import { dirname as dirname8, resolve as resolve6 } from "path";
79202
79488
  import { homedir as homedir5 } from "os";
79203
- var log31 = createLogger("installer");
79489
+ var log32 = createLogger("installer");
79204
79490
  function detectPackageManager() {
79205
79491
  const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
79206
79492
  const originalInstaller = detectOriginalInstaller();
79207
79493
  if (originalInstaller) {
79208
- log31.debug(`Detected original installer: ${originalInstaller}`);
79494
+ log32.debug(`Detected original installer: ${originalInstaller}`);
79209
79495
  if (originalInstaller === "bun") {
79210
79496
  const bunCheck2 = spawnSync("bun", ["--version"], { stdio: "ignore" });
79211
79497
  if (bunCheck2.status === 0) {
79212
79498
  return { cmd: "bun", isBun: true };
79213
79499
  }
79214
- log31.warn("Originally installed with bun, but bun not found. Falling back to npm.");
79500
+ log32.warn("Originally installed with bun, but bun not found. Falling back to npm.");
79215
79501
  } else {
79216
79502
  const npmCheck2 = spawnSync(npmCmd, ["--version"], { stdio: "ignore" });
79217
79503
  if (npmCheck2.status === 0) {
79218
79504
  return { cmd: npmCmd, isBun: false };
79219
79505
  }
79220
- log31.warn("Originally installed with npm, but npm not found. Falling back to bun.");
79506
+ log32.warn("Originally installed with npm, but npm not found. Falling back to bun.");
79221
79507
  }
79222
79508
  }
79223
79509
  const bunCheck = spawnSync("bun", ["--version"], { stdio: "ignore" });
@@ -79268,7 +79554,7 @@ function loadUpdateState() {
79268
79554
  return JSON.parse(content);
79269
79555
  }
79270
79556
  } catch (err) {
79271
- log31.warn(`Failed to load update state: ${err}`);
79557
+ log32.warn(`Failed to load update state: ${err}`);
79272
79558
  }
79273
79559
  return {};
79274
79560
  }
@@ -79279,9 +79565,9 @@ function saveUpdateState(state) {
79279
79565
  mkdirSync4(dir, { recursive: true });
79280
79566
  }
79281
79567
  writeFileSync5(STATE_PATH, JSON.stringify(state, null, 2), "utf-8");
79282
- log31.debug("Update state saved");
79568
+ log32.debug("Update state saved");
79283
79569
  } catch (err) {
79284
- log31.warn(`Failed to save update state: ${err}`);
79570
+ log32.warn(`Failed to save update state: ${err}`);
79285
79571
  }
79286
79572
  }
79287
79573
  function clearUpdateState() {
@@ -79290,7 +79576,7 @@ function clearUpdateState() {
79290
79576
  writeFileSync5(STATE_PATH, "{}", "utf-8");
79291
79577
  }
79292
79578
  } catch (err) {
79293
- log31.warn(`Failed to clear update state: ${err}`);
79579
+ log32.warn(`Failed to clear update state: ${err}`);
79294
79580
  }
79295
79581
  }
79296
79582
  function checkJustUpdated() {
@@ -79322,11 +79608,11 @@ function clearRuntimeSettings() {
79322
79608
  }
79323
79609
  }
79324
79610
  async function installVersion(version) {
79325
- log31.info(`\uD83D\uDCE6 Installing ${PACKAGE_NAME2}@${version}...`);
79611
+ log32.info(`\uD83D\uDCE6 Installing ${PACKAGE_NAME2}@${version}...`);
79326
79612
  const pm = detectPackageManager();
79327
79613
  if (!pm) {
79328
79614
  const error = "Neither bun nor npm found in PATH. Cannot install update.";
79329
- log31.error(`❌ ${error}`);
79615
+ log32.error(`❌ ${error}`);
79330
79616
  return { success: false, error };
79331
79617
  }
79332
79618
  saveUpdateState({
@@ -79338,7 +79624,7 @@ async function installVersion(version) {
79338
79624
  return new Promise((resolve7) => {
79339
79625
  const { cmd, isBun: isBun3 } = pm;
79340
79626
  const args = ["install", "-g", `${PACKAGE_NAME2}@${version}`];
79341
- log31.debug(`Using ${isBun3 ? "bun" : "npm"} for installation`);
79627
+ log32.debug(`Using ${isBun3 ? "bun" : "npm"} for installation`);
79342
79628
  const child = spawn4(cmd, args, {
79343
79629
  stdio: ["ignore", "pipe", "pipe"],
79344
79630
  env: {
@@ -79356,7 +79642,7 @@ async function installVersion(version) {
79356
79642
  });
79357
79643
  child.on("close", (code) => {
79358
79644
  if (code === 0) {
79359
- log31.info(`✅ Successfully installed ${PACKAGE_NAME2}@${version}`);
79645
+ log32.info(`✅ Successfully installed ${PACKAGE_NAME2}@${version}`);
79360
79646
  saveUpdateState({
79361
79647
  previousVersion: VERSION,
79362
79648
  targetVersion: version,
@@ -79366,20 +79652,20 @@ async function installVersion(version) {
79366
79652
  resolve7({ success: true });
79367
79653
  } else {
79368
79654
  const errorMsg = stderr || stdout || `Exit code: ${code}`;
79369
- log31.error(`❌ Installation failed: ${errorMsg}`);
79655
+ log32.error(`❌ Installation failed: ${errorMsg}`);
79370
79656
  clearUpdateState();
79371
79657
  resolve7({ success: false, error: errorMsg });
79372
79658
  }
79373
79659
  });
79374
79660
  child.on("error", (err) => {
79375
- log31.error(`❌ Failed to spawn npm: ${err}`);
79661
+ log32.error(`❌ Failed to spawn npm: ${err}`);
79376
79662
  clearUpdateState();
79377
79663
  resolve7({ success: false, error: err.message });
79378
79664
  });
79379
79665
  setTimeout(() => {
79380
79666
  if (child.exitCode === null) {
79381
79667
  child.kill();
79382
- log31.error("❌ Installation timed out");
79668
+ log32.error("❌ Installation timed out");
79383
79669
  clearUpdateState();
79384
79670
  resolve7({ success: false, error: "Installation timed out" });
79385
79671
  }
@@ -79421,7 +79707,7 @@ class UpdateInstaller {
79421
79707
  }
79422
79708
 
79423
79709
  // src/auto-update/manager.ts
79424
- var log32 = createLogger("updater");
79710
+ var log33 = createLogger("updater");
79425
79711
 
79426
79712
  class AutoUpdateManager extends EventEmitter9 {
79427
79713
  config;
@@ -79444,23 +79730,23 @@ class AutoUpdateManager extends EventEmitter9 {
79444
79730
  }
79445
79731
  start() {
79446
79732
  if (!this.config.enabled) {
79447
- log32.info("Auto-update is disabled");
79733
+ log33.info("Auto-update is disabled");
79448
79734
  return;
79449
79735
  }
79450
79736
  const updateResult = this.installer.checkJustUpdated();
79451
79737
  if (updateResult) {
79452
- log32.info(`\uD83C\uDF89 Updated from v${updateResult.previousVersion} to v${updateResult.currentVersion}`);
79738
+ log33.info(`\uD83C\uDF89 Updated from v${updateResult.previousVersion} to v${updateResult.currentVersion}`);
79453
79739
  this.callbacks.broadcastUpdate((fmt) => `\uD83C\uDF89 ${fmt.formatBold("Bot updated")} from v${updateResult.previousVersion} to v${updateResult.currentVersion}`).catch((err) => {
79454
- log32.warn(`Failed to broadcast update notification: ${err}`);
79740
+ log33.warn(`Failed to broadcast update notification: ${err}`);
79455
79741
  });
79456
79742
  }
79457
79743
  this.checker.start();
79458
- log32.info(`\uD83D\uDD04 Auto-update manager started (mode: ${this.config.autoRestartMode})`);
79744
+ log33.info(`\uD83D\uDD04 Auto-update manager started (mode: ${this.config.autoRestartMode})`);
79459
79745
  }
79460
79746
  stop() {
79461
79747
  this.checker.stop();
79462
79748
  this.scheduler.stop();
79463
- log32.debug("Auto-update manager stopped");
79749
+ log33.debug("Auto-update manager stopped");
79464
79750
  }
79465
79751
  getState() {
79466
79752
  return { ...this.state };
@@ -79474,10 +79760,10 @@ class AutoUpdateManager extends EventEmitter9 {
79474
79760
  async forceUpdate() {
79475
79761
  const updateInfo = this.state.updateInfo || await this.checker.check();
79476
79762
  if (!updateInfo) {
79477
- log32.info("No update available");
79763
+ log33.info("No update available");
79478
79764
  return;
79479
79765
  }
79480
- log32.info("Forcing immediate update");
79766
+ log33.info("Forcing immediate update");
79481
79767
  await this.performUpdate(updateInfo);
79482
79768
  }
79483
79769
  deferUpdate(minutes = 60) {
@@ -79532,7 +79818,7 @@ class AutoUpdateManager extends EventEmitter9 {
79532
79818
  await this.callbacks.broadcastUpdate((fmt) => `✅ ${fmt.formatBold("Update installed")} - restarting now. ${fmt.formatItalic("Sessions will resume automatically.")}`).catch(() => {});
79533
79819
  await new Promise((resolve7) => setTimeout(resolve7, 1000));
79534
79820
  await this.callbacks.prepareForRestart();
79535
- log32.info(`\uD83D\uDD04 Restarting for update to v${updateInfo.latestVersion}`);
79821
+ log33.info(`\uD83D\uDD04 Restarting for update to v${updateInfo.latestVersion}`);
79536
79822
  process.stdout.write("\x1B[2J\x1B[H");
79537
79823
  process.stdout.write("\x1B[?25h");
79538
79824
  process.exit(RESTART_EXIT_CODE);
@@ -79827,7 +80113,7 @@ async function startWithoutDaemon() {
79827
80113
  keepAlive.setEnabled(keepAliveEnabled);
79828
80114
  const threadLogsEnabled = config.threadLogs?.enabled ?? true;
79829
80115
  const threadLogsRetentionDays = config.threadLogs?.retentionDays ?? 30;
79830
- const session = new SessionManager(workingDir, initialSkipPermissions, config.chrome, config.worktreeMode, undefined, threadLogsEnabled, threadLogsRetentionDays, config.limits);
80116
+ const session = new SessionManager(workingDir, initialSkipPermissions, config.chrome, config.worktreeMode, undefined, threadLogsEnabled, threadLogsRetentionDays, config.limits, config.claudeAccounts);
79831
80117
  if (config.stickyMessage) {
79832
80118
  session.setStickyMessageCustomization(config.stickyMessage.description, config.stickyMessage.footer);
79833
80119
  }