@sideboard-ai/core 0.1.197 → 0.1.199

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/{abletime-JINF5KJV.js → abletime-3CSCNAXU.js} +2 -2
  2. package/dist/{abletime-HR6P4GJH.js → abletime-H74RNIKV.js} +2 -2
  3. package/dist/agents/cursor-runner.cjs +49 -45
  4. package/dist/agents/cursor-runner.js +5 -3
  5. package/dist/{agents-IVDCAG7T.js → agents-AVH44CBS.js} +27 -5
  6. package/dist/{agents-BGT5DUGU.js → agents-BOYOK56K.js} +26 -4
  7. package/dist/{app-settings-J775CYOO.js → app-settings-FMTDH5RD.js} +3 -1
  8. package/dist/{app-settings-5KHVKJKO.js → app-settings-MMPLJHWF.js} +3 -1
  9. package/dist/{chunk-S5GLSRLP.js → chunk-2IQ6W47G.js} +10 -0
  10. package/dist/{chunk-HZTHWU6A.js → chunk-BLOKJY4U.js} +2 -2
  11. package/dist/{chunk-E37JHCO3.js → chunk-CA7PWMQ7.js} +1 -1
  12. package/dist/{chunk-NLHFAMC2.js → chunk-CQ5R3VPP.js} +15 -1
  13. package/dist/{chunk-ZG7RONNQ.js → chunk-CTABTALL.js} +22 -21
  14. package/dist/{chunk-PQBRCBIE.js → chunk-DU2ICKLA.js} +382 -6
  15. package/dist/{chunk-S4QCBBXS.js → chunk-DU4ID3DA.js} +1 -1
  16. package/dist/{chunk-AH6WIBLY.js → chunk-HQKGK4KO.js} +10 -0
  17. package/dist/{chunk-N5JBG3BF.js → chunk-KI4YI72Y.js} +371 -6
  18. package/dist/{chunk-SIIDQV2B.js → chunk-PPVN3APP.js} +24 -23
  19. package/dist/{chunk-KTHRWHA3.js → chunk-PTAMHXBT.js} +1 -1
  20. package/dist/{chunk-DP4TKAMZ.js → chunk-QFABSE3Q.js} +1 -1
  21. package/dist/{chunk-6YTI2HBG.js → chunk-S4EEYOSU.js} +2 -2
  22. package/dist/{coordinator-prompt-IX66YUJ2.js → coordinator-prompt-LB3GA3U4.js} +3 -3
  23. package/dist/{coordinator-prompt-LYKS3YNG.js → coordinator-prompt-ROWPLVQ3.js} +3 -3
  24. package/dist/{global-workspace-SNJ2Z6SL.js → global-workspace-C5XKWCRH.js} +3 -3
  25. package/dist/{global-workspace-4QX6UEOY.js → global-workspace-V2A4YKZ6.js} +3 -3
  26. package/dist/index.cjs +688 -262
  27. package/dist/index.d.cts +78 -1
  28. package/dist/index.d.ts +78 -1
  29. package/dist/index.js +33 -9
  30. package/dist/mcp/run-stdio.cjs +317 -258
  31. package/dist/mcp/run-stdio.js +8 -8
  32. package/dist/{orchestrator-SANGGLQV.js → orchestrator-AJGDZEAS.js} +5 -5
  33. package/dist/{orchestrator-HB4LZ2AA.js → orchestrator-NCGYNVYN.js} +6 -6
  34. package/dist/{workspaces-URMUVGAQ.js → workspaces-GWEKIS3B.js} +3 -3
  35. package/dist/{workspaces-UTOYGBYB.js → workspaces-WIRJQ6HA.js} +3 -3
  36. package/dist/{worktree-RM6UWNGZ.js → worktree-QA4J75FI.js} +2 -2
  37. package/dist/{worktree-R43JOR4V.js → worktree-UI5WJC3A.js} +2 -2
  38. package/package.json +1 -1
@@ -781,6 +781,9 @@ function normalizeAdvanced(raw) {
781
781
  if (typeof source.showCost === "boolean") {
782
782
  out.showCost = source.showCost;
783
783
  }
784
+ if (typeof source.confirmClaudeUsageOverLimit === "boolean") {
785
+ out.confirmClaudeUsageOverLimit = source.confirmClaudeUsageOverLimit;
786
+ }
784
787
  if (typeof source.autoArchiveOnMerge === "boolean") {
785
788
  out.autoArchiveOnMerge = source.autoArchiveOnMerge;
786
789
  }
@@ -1656,6 +1659,9 @@ function updateAdvancedSettings(patch) {
1656
1659
  if (typeof patch.showCost === "boolean") {
1657
1660
  advanced.showCost = patch.showCost;
1658
1661
  }
1662
+ if (typeof patch.confirmClaudeUsageOverLimit === "boolean") {
1663
+ advanced.confirmClaudeUsageOverLimit = patch.confirmClaudeUsageOverLimit;
1664
+ }
1659
1665
  if (typeof patch.autoArchiveOnMerge === "boolean") {
1660
1666
  advanced.autoArchiveOnMerge = patch.autoArchiveOnMerge;
1661
1667
  }
@@ -1718,6 +1724,9 @@ function cowboyModeEnabled(settings = loadAppSettings()) {
1718
1724
  function showCostEnabled(settings = loadAppSettings()) {
1719
1725
  return Boolean(settings.advanced.showCost);
1720
1726
  }
1727
+ function confirmClaudeUsageOverLimitEnabled(settings = loadAppSettings()) {
1728
+ return Boolean(settings.advanced.confirmClaudeUsageOverLimit);
1729
+ }
1721
1730
  function autoArchiveOnMergeEnabled(settings = loadAppSettings()) {
1722
1731
  return Boolean(settings.advanced.autoArchiveOnMerge);
1723
1732
  }
@@ -1917,6 +1926,7 @@ export {
1917
1926
  deleteBranchOnPurgeEnabled,
1918
1927
  cowboyModeEnabled,
1919
1928
  showCostEnabled,
1929
+ confirmClaudeUsageOverLimitEnabled,
1920
1930
  autoArchiveOnMergeEnabled,
1921
1931
  autoCleanupOrphansEnabled,
1922
1932
  orchestrationQuotaOnLimit,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  isOrchestratorThread
3
- } from "./chunk-HZTHWU6A.js";
3
+ } from "./chunk-BLOKJY4U.js";
4
4
  import {
5
5
  codexUnattendedGitConfigArgs,
6
6
  mergeAgentGitAuthEnv,
7
7
  resolveAgentGitAuthEnv,
8
8
  resolveCodexGitWritableRoots
9
- } from "./chunk-S4QCBBXS.js";
9
+ } from "./chunk-DU4ID3DA.js";
10
10
  import {
11
11
  applyConnectedTeamToCli,
12
12
  brightsyMcpServerName,
@@ -25,11 +25,12 @@ import {
25
25
  formatUnknownDetail,
26
26
  isAsarPath,
27
27
  looksLikeAgentFailureMessage,
28
+ looksLikeBrightsyEmptyCompletion,
28
29
  packagedCursorRunnerPath,
29
30
  packagedMcpStdioPath,
30
31
  parseCursorRunnerLine,
31
32
  resolveNodeLaunch
32
- } from "./chunk-NLHFAMC2.js";
33
+ } from "./chunk-CQ5R3VPP.js";
33
34
  import {
34
35
  claudeChromeEnabled,
35
36
  isAbleTimeConnected,
@@ -37,7 +38,7 @@ import {
37
38
  loadAppSettings,
38
39
  resolveAgentExecutable,
39
40
  resolveClaudeExecutable
40
- } from "./chunk-S5GLSRLP.js";
41
+ } from "./chunk-2IQ6W47G.js";
41
42
  import {
42
43
  isElectronLikeCommand,
43
44
  unwrapStrippedElectronLaunch
@@ -268,6 +269,12 @@ function parseBrightsyCliLine(line) {
268
269
  try {
269
270
  const obj = JSON.parse(trimmed);
270
271
  if (obj.type === "text" && typeof obj.text === "string") {
272
+ if (looksLikeBrightsyEmptyCompletion(obj.text)) {
273
+ return [
274
+ { type: "stderr", data: obj.text },
275
+ { type: "stdout", data: `Error: ${obj.text}` }
276
+ ];
277
+ }
271
278
  return { type: "stdout", data: obj.text };
272
279
  }
273
280
  if (obj.type === "thinking" && typeof obj.text === "string") {
@@ -311,7 +318,7 @@ function parseBrightsyCliLine(line) {
311
318
  if (trimmed.startsWith("{") && /"type"\s*:\s*"(tool_use|tool_result|tool|text|thinking|usage|done|error)"/.test(trimmed)) {
312
319
  return null;
313
320
  }
314
- if (/error|failed|unauthorized|quota|limit|not logged in/i.test(trimmed)) {
321
+ if (looksLikeBrightsyEmptyCompletion(trimmed) || /error|failed|unauthorized|quota|limit|not logged in/i.test(trimmed)) {
315
322
  return [
316
323
  { type: "stderr", data: trimmed },
317
324
  { type: "stdout", data: `Error: ${trimmed}` }
@@ -320,6 +327,12 @@ function parseBrightsyCliLine(line) {
320
327
  return { type: "stdout", data: line };
321
328
  }
322
329
  }
330
+ function adjustBrightsyTurnExit(exitCode, assistantText) {
331
+ if (looksLikeBrightsyEmptyCompletion(assistantText) && (exitCode === 0 || exitCode == null)) {
332
+ return 2;
333
+ }
334
+ return exitCode;
335
+ }
323
336
  async function fetchTeamChatTargets(team) {
324
337
  const endpoint = (team.endpoint || "https://brightsy.ai").replace(/\/$/, "");
325
338
  let agents = [
@@ -1921,7 +1934,7 @@ var claudeAdapter = {
1921
1934
  );
1922
1935
  }
1923
1936
  const mode = permissionMode(thread);
1924
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-4QX6UEOY.js");
1937
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-V2A4YKZ6.js");
1925
1938
  const isOrchestrator = isOrchestratorThread2(thread);
1926
1939
  const injectedServers = await buildInjectedMcpServers({
1927
1940
  includeSideboard: true,
@@ -3414,6 +3427,346 @@ function resolveQuotaFallbackAgent(current, preferred) {
3414
3427
  return ordered.find((a) => a !== current) ?? (current === "cursor" ? "codex" : "cursor");
3415
3428
  }
3416
3429
 
3430
+ // src/agents/claude-usage.ts
3431
+ var WINDOW_META = {
3432
+ five_hour: {
3433
+ label: "5-hour session",
3434
+ shortLabel: "5h",
3435
+ detail: "Rolling 5-hour limit across all models"
3436
+ },
3437
+ seven_day: {
3438
+ label: "Weekly",
3439
+ shortLabel: "wk",
3440
+ detail: "7-day cap across all models"
3441
+ },
3442
+ seven_day_opus: {
3443
+ label: "Opus",
3444
+ shortLabel: "Opus",
3445
+ detail: "Weekly Opus-only cap"
3446
+ },
3447
+ seven_day_sonnet: {
3448
+ label: "Sonnet",
3449
+ shortLabel: "Sonnet",
3450
+ detail: "Weekly Sonnet-only cap"
3451
+ }
3452
+ };
3453
+ var WINDOW_ORDER = [
3454
+ "five_hour",
3455
+ "seven_day",
3456
+ "seven_day_opus",
3457
+ "seven_day_sonnet"
3458
+ ];
3459
+ function parseClaudeResetsAt(value) {
3460
+ if (typeof value === "number" && Number.isFinite(value)) {
3461
+ const ms = value > 1e12 ? value : value * 1e3;
3462
+ const d = new Date(ms);
3463
+ return Number.isNaN(d.getTime()) ? null : d.toISOString();
3464
+ }
3465
+ if (typeof value === "string") {
3466
+ const trimmed = value.trim();
3467
+ if (!trimmed) return null;
3468
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
3469
+ return parseClaudeResetsAt(Number(trimmed));
3470
+ }
3471
+ const d = new Date(trimmed);
3472
+ return Number.isNaN(d.getTime()) ? null : d.toISOString();
3473
+ }
3474
+ return null;
3475
+ }
3476
+ function parseClaudeUtilization(value) {
3477
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
3478
+ return Math.max(0, Math.min(100, value));
3479
+ }
3480
+ function windowFromRaw(id, raw) {
3481
+ if (!raw || typeof raw !== "object") return null;
3482
+ const row = raw;
3483
+ const used = parseClaudeUtilization(row.utilization ?? row.used_percentage);
3484
+ if (used == null) return null;
3485
+ const meta = WINDOW_META[id];
3486
+ return {
3487
+ id,
3488
+ label: meta.label,
3489
+ shortLabel: meta.shortLabel,
3490
+ detail: meta.detail,
3491
+ usedPercent: used,
3492
+ remainingPercent: Math.max(0, Math.min(100, 100 - used)),
3493
+ resetsAt: parseClaudeResetsAt(row.resets_at)
3494
+ };
3495
+ }
3496
+ function extraUsageFromRaw(raw) {
3497
+ if (!raw || typeof raw !== "object") return void 0;
3498
+ const row = raw;
3499
+ const enabled = row.is_enabled === true || row.enabled === true;
3500
+ if (!enabled && row.is_enabled !== false && row.enabled !== false) return void 0;
3501
+ const usedCredits = numberOrUndef(row.used_credits ?? row.used);
3502
+ const monthlyLimit = numberOrUndef(row.monthly_limit);
3503
+ const usedPercent = parseClaudeUtilization(row.utilization) ?? void 0;
3504
+ return {
3505
+ enabled,
3506
+ ...usedCredits != null ? { usedCredits } : {},
3507
+ ...monthlyLimit != null ? { monthlyLimit } : {},
3508
+ ...usedPercent != null ? { usedPercent } : {}
3509
+ };
3510
+ }
3511
+ function numberOrUndef(value) {
3512
+ if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
3513
+ return value;
3514
+ }
3515
+ function parseClaudeUsagePayload(raw, fetchedAt = (/* @__PURE__ */ new Date()).toISOString()) {
3516
+ if (!raw || typeof raw !== "object") return null;
3517
+ const obj = raw;
3518
+ const source = obj.rate_limits && typeof obj.rate_limits === "object" ? obj.rate_limits : obj;
3519
+ const windows = [];
3520
+ for (const id of WINDOW_ORDER) {
3521
+ const parsed = windowFromRaw(id, source[id]);
3522
+ if (parsed) windows.push(parsed);
3523
+ }
3524
+ if (windows.length === 0) return null;
3525
+ const extra = extraUsageFromRaw(obj.extra_usage ?? source.extra_usage);
3526
+ return {
3527
+ windows,
3528
+ ...extra ? { extraUsage: extra } : {},
3529
+ fetchedAt
3530
+ };
3531
+ }
3532
+ function hottestClaudeWindow(usage) {
3533
+ if (usage.windows.length === 0) return null;
3534
+ return usage.windows.reduce((a, b) => b.usedPercent > a.usedPercent ? b : a);
3535
+ }
3536
+ function formatClaudeUsageReset(resetsAt, now = /* @__PURE__ */ new Date()) {
3537
+ if (!resetsAt) return "";
3538
+ const at = new Date(resetsAt);
3539
+ if (Number.isNaN(at.getTime())) return "";
3540
+ const ms = at.getTime() - now.getTime();
3541
+ if (ms <= 0) return "resets soon";
3542
+ const minutes = Math.round(ms / 6e4);
3543
+ if (minutes < 60) return `resets in ${Math.max(1, minutes)}m`;
3544
+ const hours = Math.round(minutes / 60);
3545
+ if (hours < 36) return `resets in ${hours}h`;
3546
+ try {
3547
+ return `resets ${at.toLocaleString(void 0, {
3548
+ weekday: "short",
3549
+ hour: "numeric",
3550
+ minute: "2-digit"
3551
+ })}`;
3552
+ } catch {
3553
+ return `resets ${at.toISOString()}`;
3554
+ }
3555
+ }
3556
+ function formatClaudeUsageResetClock(resetsAt) {
3557
+ if (!resetsAt) return "";
3558
+ const at = new Date(resetsAt);
3559
+ if (Number.isNaN(at.getTime())) return "";
3560
+ try {
3561
+ return at.toLocaleString(void 0, {
3562
+ weekday: "short",
3563
+ month: "short",
3564
+ day: "numeric",
3565
+ hour: "numeric",
3566
+ minute: "2-digit"
3567
+ });
3568
+ } catch {
3569
+ return at.toISOString();
3570
+ }
3571
+ }
3572
+ function formatClaudeUsageFetchedAt(fetchedAt, now = /* @__PURE__ */ new Date()) {
3573
+ const at = new Date(fetchedAt);
3574
+ if (Number.isNaN(at.getTime())) return "";
3575
+ const minutes = Math.max(0, Math.round((now.getTime() - at.getTime()) / 6e4));
3576
+ if (minutes < 1) return "Updated just now";
3577
+ if (minutes < 60) return `Updated ${minutes}m ago`;
3578
+ const hours = Math.round(minutes / 60);
3579
+ if (hours < 36) return `Updated ${hours}h ago`;
3580
+ return `Updated ${formatClaudeUsageResetClock(fetchedAt)}`;
3581
+ }
3582
+ function formatClaudeExtraUsageDetail(extra) {
3583
+ if (!extra.enabled) return "Extra usage off";
3584
+ const bits = ["Extra usage on"];
3585
+ if (extra.usedCredits != null && extra.monthlyLimit != null) {
3586
+ bits.push(`${extra.usedCredits} / ${extra.monthlyLimit} credits this month`);
3587
+ } else if (extra.usedCredits != null) {
3588
+ bits.push(`${extra.usedCredits} credits used`);
3589
+ }
3590
+ if (extra.usedPercent != null) {
3591
+ bits.push(`${Math.round(extra.usedPercent)}% of extra pool`);
3592
+ }
3593
+ return bits.join(" \xB7 ");
3594
+ }
3595
+ function formatClaudeUsageWindowLine(window, now = /* @__PURE__ */ new Date()) {
3596
+ const reset = formatClaudeUsageReset(window.resetsAt, now);
3597
+ const clock = formatClaudeUsageResetClock(window.resetsAt);
3598
+ const left = `${Math.round(window.remainingPercent)}% left`;
3599
+ const used = `${Math.round(window.usedPercent)}% used`;
3600
+ const resetBit = reset ? clock && !reset.includes(clock) ? `${reset} (${clock})` : reset : "";
3601
+ return resetBit ? `${window.label} \u2014 ${window.detail}. ${left} \xB7 ${used} \xB7 ${resetBit}` : `${window.label} \u2014 ${window.detail}. ${left} \xB7 ${used}`;
3602
+ }
3603
+ function formatClaudeUsageTooltip(usage, now = /* @__PURE__ */ new Date()) {
3604
+ const lines = [
3605
+ "Claude Code plan",
3606
+ ...usage.windows.map((w) => formatClaudeUsageWindowLine(w, now))
3607
+ ];
3608
+ if (usage.extraUsage) {
3609
+ lines.push(formatClaudeExtraUsageDetail(usage.extraUsage));
3610
+ }
3611
+ const fetched = formatClaudeUsageFetchedAt(usage.fetchedAt, now);
3612
+ if (fetched) lines.push(fetched);
3613
+ return lines.join("\n");
3614
+ }
3615
+ function formatClaudeUsageCompact(window) {
3616
+ return `${window.shortLabel} ${Math.round(window.remainingPercent)}%`;
3617
+ }
3618
+ function claudeUsageWindowOverLimit(window) {
3619
+ return window.remainingPercent <= 0 || window.usedPercent >= 100;
3620
+ }
3621
+ function claudeUsageOverLimitWindows(usage) {
3622
+ if (!usage) return [];
3623
+ return usage.windows.filter(claudeUsageWindowOverLimit);
3624
+ }
3625
+ function formatClaudeUsageOverLimitConfirm(windows, now = /* @__PURE__ */ new Date()) {
3626
+ if (windows.length === 0) return "";
3627
+ const parts = windows.map((w) => {
3628
+ const reset = formatClaudeUsageReset(w.resetsAt, now);
3629
+ return reset ? `${w.label} (${reset})` : w.label;
3630
+ });
3631
+ const list = parts.join(", ");
3632
+ const verb = windows.length === 1 ? "is" : "are";
3633
+ return `Claude Code ${list} ${verb} at or over the plan limit. Send this message anyway?`;
3634
+ }
3635
+
3636
+ // src/agents/claude-usage-client.ts
3637
+ import { existsSync as existsSync9, readFileSync as readFileSync4 } from "fs";
3638
+ import { homedir as homedir4 } from "os";
3639
+ import { join as join6 } from "path";
3640
+ var CLAUDE_OAUTH_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
3641
+ var CLAUDE_USAGE_TTL_MS = 9e4;
3642
+ var CLAUDE_USAGE_ERROR_TTL_MS = 5 * 6e4;
3643
+ var CLAUDE_USAGE_STALE_OK_MS = 30 * 6e4;
3644
+ var KEYCHAIN_SERVICES = ["Claude Code-credentials", "Claude Code"];
3645
+ var cache = null;
3646
+ var errorUntil = 0;
3647
+ var inflight = null;
3648
+ var lastGood = null;
3649
+ var claudeVersion = null;
3650
+ function accessTokenFromCredentialsJson(raw) {
3651
+ const trimmed = raw.trim();
3652
+ if (!trimmed) return null;
3653
+ if (trimmed.startsWith("sk-ant-")) {
3654
+ const token = trimmed.split(/\s+/)[0];
3655
+ return token || null;
3656
+ }
3657
+ try {
3658
+ const parsed = JSON.parse(trimmed);
3659
+ const oauth = parsed.claudeAiOauth && typeof parsed.claudeAiOauth === "object" ? parsed.claudeAiOauth : parsed;
3660
+ const token = oauth.accessToken ?? oauth.access_token;
3661
+ return typeof token === "string" && token.trim() ? token.trim() : null;
3662
+ } catch {
3663
+ return null;
3664
+ }
3665
+ }
3666
+ function claudeCredentialsPath() {
3667
+ const root = process.env.CLAUDE_CONFIG_DIR?.trim() || join6(homedir4(), ".claude");
3668
+ return join6(root, ".credentials.json");
3669
+ }
3670
+ async function readFileAccessToken() {
3671
+ const path = claudeCredentialsPath();
3672
+ if (!existsSync9(path)) return null;
3673
+ try {
3674
+ return accessTokenFromCredentialsJson(readFileSync4(path, "utf8"));
3675
+ } catch {
3676
+ return null;
3677
+ }
3678
+ }
3679
+ async function readKeychainAccessToken() {
3680
+ if (process.platform !== "darwin") return null;
3681
+ for (const service of KEYCHAIN_SERVICES) {
3682
+ const result = await run("security", ["find-generic-password", "-s", service, "-w"], {
3683
+ reject: false,
3684
+ timeoutMs: 4e3
3685
+ });
3686
+ if (result.exitCode !== 0 || !result.stdout.trim()) continue;
3687
+ const token = accessTokenFromCredentialsJson(result.stdout);
3688
+ if (token) return token;
3689
+ }
3690
+ return null;
3691
+ }
3692
+ async function readClaudeAccessToken() {
3693
+ const envToken = process.env.CLAUDE_CODE_OAUTH_TOKEN?.trim();
3694
+ if (envToken) return envToken;
3695
+ const fromFile = await readFileAccessToken();
3696
+ if (fromFile) return fromFile;
3697
+ return readKeychainAccessToken();
3698
+ }
3699
+ async function resolveClaudeUserAgent() {
3700
+ if (claudeVersion) return `claude-code/${claudeVersion}`;
3701
+ try {
3702
+ const claude = resolveClaudeExecutable();
3703
+ const result = await run(claude, ["--version"], { reject: false, timeoutMs: 4e3 });
3704
+ const match = `${result.stdout}
3705
+ ${result.stderr}`.match(/(\d+\.\d+\.\d+)/);
3706
+ claudeVersion = match?.[1] ?? "2.1.80";
3707
+ } catch {
3708
+ claudeVersion = "2.1.80";
3709
+ }
3710
+ return `claude-code/${claudeVersion}`;
3711
+ }
3712
+ function staleOk(now) {
3713
+ if (!lastGood) return null;
3714
+ if (now - lastGood.at > CLAUDE_USAGE_STALE_OK_MS) return null;
3715
+ return lastGood.value;
3716
+ }
3717
+ async function getClaudePlanUsage(opts = {}) {
3718
+ const now = opts.now ?? Date.now();
3719
+ if (!opts.force) {
3720
+ if (cache && now - cache.at < CLAUDE_USAGE_TTL_MS) return cache.value;
3721
+ if (now < errorUntil) return staleOk(now);
3722
+ }
3723
+ if (inflight) return inflight;
3724
+ inflight = (async () => {
3725
+ try {
3726
+ const token = await (opts.readAccessToken ?? readClaudeAccessToken)();
3727
+ if (!token) {
3728
+ cache = { at: now, value: null };
3729
+ return null;
3730
+ }
3731
+ const fetchFn = opts.fetch ?? globalThis.fetch;
3732
+ const userAgent = opts.userAgent ?? await resolveClaudeUserAgent();
3733
+ const ac = new AbortController();
3734
+ const timer = setTimeout(() => ac.abort(), 8e3);
3735
+ let res;
3736
+ try {
3737
+ res = await fetchFn(CLAUDE_OAUTH_USAGE_URL, {
3738
+ headers: {
3739
+ Authorization: `Bearer ${token}`,
3740
+ "anthropic-beta": "oauth-2025-04-20",
3741
+ "User-Agent": userAgent
3742
+ },
3743
+ signal: ac.signal
3744
+ });
3745
+ } finally {
3746
+ clearTimeout(timer);
3747
+ }
3748
+ if (res.status === 401 || res.status === 403) {
3749
+ cache = { at: now, value: null };
3750
+ return null;
3751
+ }
3752
+ if (!res.ok) {
3753
+ errorUntil = now + CLAUDE_USAGE_ERROR_TTL_MS;
3754
+ return staleOk(now);
3755
+ }
3756
+ const usage = parseClaudeUsagePayload(await res.json(), new Date(now).toISOString());
3757
+ cache = { at: now, value: usage };
3758
+ if (usage) lastGood = { at: now, value: usage };
3759
+ return usage;
3760
+ } catch {
3761
+ errorUntil = now + CLAUDE_USAGE_ERROR_TTL_MS;
3762
+ return staleOk(now);
3763
+ } finally {
3764
+ inflight = null;
3765
+ }
3766
+ })();
3767
+ return inflight;
3768
+ }
3769
+
3417
3770
  // src/agents/install.ts
3418
3771
  var SETUP = {
3419
3772
  claude: {
@@ -3678,6 +4031,7 @@ export {
3678
4031
  countCacheControlBlocks,
3679
4032
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
3680
4033
  parseBrightsyCliLine,
4034
+ adjustBrightsyTurnExit,
3681
4035
  listBrightsyChatTargets,
3682
4036
  brightsyAdapter,
3683
4037
  parseMcpList,
@@ -3744,6 +4098,17 @@ export {
3744
4098
  isSessionQuotaLimit,
3745
4099
  parseSessionQuotaResetAt,
3746
4100
  resolveQuotaFallbackAgent,
4101
+ parseClaudeUsagePayload,
4102
+ hottestClaudeWindow,
4103
+ formatClaudeUsageReset,
4104
+ formatClaudeUsageResetClock,
4105
+ formatClaudeUsageFetchedAt,
4106
+ formatClaudeExtraUsageDetail,
4107
+ formatClaudeUsageTooltip,
4108
+ formatClaudeUsageCompact,
4109
+ claudeUsageOverLimitWindows,
4110
+ formatClaudeUsageOverLimitConfirm,
4111
+ getClaudePlanUsage,
3747
4112
  getAgentSetupInfo,
3748
4113
  listAgentSetupInfo,
3749
4114
  resolveLoginCommand,
@@ -5,6 +5,7 @@ import {
5
5
  } from "./chunk-DJU54RYW.js";
6
6
  import {
7
7
  PLAN_MODE_INSTRUCTION,
8
+ adjustBrightsyTurnExit,
8
9
  allAdapters,
9
10
  applyAgentEvent,
10
11
  applyTurnUsage,
@@ -24,7 +25,7 @@ import {
24
25
  stripBrightsyNdjsonNoise,
25
26
  sumUsageList,
26
27
  toolDescription
27
- } from "./chunk-N5JBG3BF.js";
28
+ } from "./chunk-KI4YI72Y.js";
28
29
  import {
29
30
  SLACK_REPLY_FORMATTING,
30
31
  addWorkspace,
@@ -47,7 +48,7 @@ import {
47
48
  stageAbsolutePathsAsAttachments,
48
49
  stageBuffersAsAttachments,
49
50
  syncWorkspacesFromThreads
50
- } from "./chunk-HZTHWU6A.js";
51
+ } from "./chunk-BLOKJY4U.js";
51
52
  import {
52
53
  addPrStackLayer,
53
54
  allocateTeamName,
@@ -97,7 +98,7 @@ import {
97
98
  worktreeDisplayLabelForGroup,
98
99
  worktreeNameFromPath,
99
100
  worktreeSlugForTicket
100
- } from "./chunk-S4QCBBXS.js";
101
+ } from "./chunk-DU4ID3DA.js";
101
102
  import {
102
103
  ATTACHMENTS_DIR,
103
104
  DETACHED_JOBS_DIR,
@@ -128,7 +129,7 @@ import {
128
129
  shouldRetryFailedAgentTurn,
129
130
  summarizeTurnStderr,
130
131
  turnFailChatText
131
- } from "./chunk-NLHFAMC2.js";
132
+ } from "./chunk-CQ5R3VPP.js";
132
133
  import {
133
134
  assertOrchestratorCapableAgent,
134
135
  childEnvWithAppSettings,
@@ -153,7 +154,7 @@ import {
153
154
  saveAppSettings,
154
155
  updateAdvancedSettings,
155
156
  writeSecureJson
156
- } from "./chunk-S5GLSRLP.js";
157
+ } from "./chunk-2IQ6W47G.js";
157
158
  import {
158
159
  stripNestedElectronEnv
159
160
  } from "./chunk-4TR3HZFT.js";
@@ -472,7 +473,7 @@ async function continueSourceThread(threadId, prompt) {
472
473
  await continueOnReply(threadId, prompt);
473
474
  return;
474
475
  }
475
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-HB4LZ2AA.js");
476
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-NCGYNVYN.js");
476
477
  await getOrchestrator2().send(threadId, prompt);
477
478
  } catch {
478
479
  }
@@ -806,9 +807,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
806
807
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
807
808
  );
808
809
  }
809
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-4QX6UEOY.js");
810
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-V2A4YKZ6.js");
810
811
  if (isGlobalThread2(thread)) {
811
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-IX66YUJ2.js");
812
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-LB3GA3U4.js");
812
813
  ensureGlobalCoordinatorCwd2(
813
814
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
814
815
  );
@@ -904,11 +905,11 @@ async function spawnAgentTurn(thread, input, onEvent) {
904
905
  consume(child.stderr, "stderr");
905
906
  const done = child.then((result) => {
906
907
  outbound.flush();
907
- const exitCode = result.exitCode ?? null;
908
- onEvent({ type: "exit", data: exitCode });
909
908
  const finalized = finalizeParts(parts);
910
909
  const rawText = assistantText.trim() || partsToAssistantText(finalized);
911
910
  const text = thread.agent === "brightsy" ? stripBrightsyNdjsonNoise(rawText) : rawText;
911
+ const exitCode = thread.agent === "brightsy" ? adjustBrightsyTurnExit(result.exitCode ?? null, text) : result.exitCode ?? null;
912
+ onEvent({ type: "exit", data: exitCode });
912
913
  return { exitCode, sessionId, assistantText: text, parts: finalized, usage };
913
914
  });
914
915
  return {
@@ -3727,7 +3728,7 @@ async function createThread(input, _onSetupLine) {
3727
3728
  });
3728
3729
  await requireAgent(resolved.agent);
3729
3730
  if (input.cowboy) {
3730
- const { cowboyModeEnabled } = await import("./app-settings-5KHVKJKO.js");
3731
+ const { cowboyModeEnabled } = await import("./app-settings-MMPLJHWF.js");
3731
3732
  if (!cowboyModeEnabled()) {
3732
3733
  throw new Error(
3733
3734
  "Cowboy mode is off. Enable it in Settings \u2192 Advanced."
@@ -3785,7 +3786,7 @@ async function createThread(input, _onSetupLine) {
3785
3786
  let sourceIsFork = false;
3786
3787
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
3787
3788
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
3788
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-JINF5KJV.js");
3789
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-3CSCNAXU.js");
3789
3790
  const task = await ensureAbleTimeTask({
3790
3791
  title: title?.trim() || "Untitled work",
3791
3792
  description: input.prompt?.trim() || void 0
@@ -3887,7 +3888,7 @@ async function createThread(input, _onSetupLine) {
3887
3888
  return readThread(thread.id) ?? thread;
3888
3889
  }
3889
3890
  async function listLinearIssues(agent, repoPath) {
3890
- const { getAdapter: getAdapter2 } = await import("./agents-IVDCAG7T.js");
3891
+ const { getAdapter: getAdapter2 } = await import("./agents-AVH44CBS.js");
3891
3892
  await requireAgent(agent, { requireLinear: true });
3892
3893
  const adapter = getAdapter2(agent);
3893
3894
  if (!adapter.listLinearIssues) {
@@ -4309,7 +4310,7 @@ async function adoptThread(input) {
4309
4310
  messages: input.messages ?? []
4310
4311
  });
4311
4312
  writeThread(thread);
4312
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-URMUVGAQ.js");
4313
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-GWEKIS3B.js");
4313
4314
  await ensureWorkspace2(repoPath);
4314
4315
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-X54WSOXM.js");
4315
4316
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -6893,7 +6894,7 @@ function formatScheduledPrompt(name, prompt) {
6893
6894
  ${prompt}`;
6894
6895
  }
6895
6896
  async function defaultDeps() {
6896
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-HB4LZ2AA.js");
6897
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-NCGYNVYN.js");
6897
6898
  const orch = getOrchestrator2();
6898
6899
  return {
6899
6900
  findThread: (id) => findThreadByRef(id),
@@ -7168,7 +7169,7 @@ var Orchestrator = class {
7168
7169
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
7169
7170
  });
7170
7171
  }
7171
- const { autoCleanupOrphansEnabled } = await import("./app-settings-5KHVKJKO.js");
7172
+ const { autoCleanupOrphansEnabled } = await import("./app-settings-MMPLJHWF.js");
7172
7173
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
7173
7174
  await cleanupOrphanWorktrees({ repoPaths });
7174
7175
  }
@@ -7447,7 +7448,7 @@ var Orchestrator = class {
7447
7448
  }
7448
7449
  await setup;
7449
7450
  if (skipSetup) return;
7450
- const { autoRunAfterSetupEnabled } = await import("./app-settings-5KHVKJKO.js");
7451
+ const { autoRunAfterSetupEnabled } = await import("./app-settings-MMPLJHWF.js");
7451
7452
  if (autoRunAfterSetupEnabled()) {
7452
7453
  try {
7453
7454
  await this.startDev(threadId);
@@ -7771,7 +7772,7 @@ var Orchestrator = class {
7771
7772
  }
7772
7773
  const isBrightsy = fresh.agent === "brightsy";
7773
7774
  const isOrchestration = isOrchestratorThread(fresh);
7774
- const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-5KHVKJKO.js");
7775
+ const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-MMPLJHWF.js");
7775
7776
  const gitAuthMode = getGithubGitAuthMode();
7776
7777
  const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
7777
7778
  githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
@@ -8756,7 +8757,7 @@ var Orchestrator = class {
8756
8757
  updateThread(thread.id, { title: meta.title });
8757
8758
  }
8758
8759
  }
8759
- const { autoArchiveOnMergeEnabled } = await import("./app-settings-5KHVKJKO.js");
8760
+ const { autoArchiveOnMergeEnabled } = await import("./app-settings-MMPLJHWF.js");
8760
8761
  const latest = this.requireThread(thread.id);
8761
8762
  if (!shouldAutoArchiveOnPrMerge({
8762
8763
  previousPrState: prevState || null,
@@ -9048,7 +9049,7 @@ var Orchestrator = class {
9048
9049
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
9049
9050
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
9050
9051
  try {
9051
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-URMUVGAQ.js");
9052
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-GWEKIS3B.js");
9052
9053
  await ensureWorkspace2(thread.repoPath);
9053
9054
  } catch {
9054
9055
  }
@@ -9075,7 +9076,7 @@ var Orchestrator = class {
9075
9076
  await runArchiveScript(thread.repoPath, thread.worktreePath);
9076
9077
  } catch {
9077
9078
  }
9078
- const { deleteBranchOnPurgeEnabled } = await import("./app-settings-5KHVKJKO.js");
9079
+ const { deleteBranchOnPurgeEnabled } = await import("./app-settings-MMPLJHWF.js");
9079
9080
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
9080
9081
  await removeWorktree(thread.repoPath, thread.worktreePath, {
9081
9082
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -9102,7 +9103,7 @@ var Orchestrator = class {
9102
9103
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
9103
9104
  );
9104
9105
  }
9105
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-RM6UWNGZ.js");
9106
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-QA4J75FI.js");
9106
9107
  const slug = thread.worktreePath.split("/").pop();
9107
9108
  const dest = thread.worktreePath;
9108
9109
  await withRepoGitLock(thread.repoPath, async () => {
@@ -9212,7 +9213,7 @@ async function startOrchestration(opts) {
9212
9213
  sourceRef: "default",
9213
9214
  ...createOpts
9214
9215
  }).catch(async () => {
9215
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-RM6UWNGZ.js");
9216
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-QA4J75FI.js");
9216
9217
  const repo = await resolveRepoRoot2(repoPath);
9217
9218
  const def = await resolveDefaultBranch2(repo);
9218
9219
  return orch.createThread({