sidekick-agent-hub 0.14.2 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -93,15 +93,19 @@ You can also press `r` in the TUI dashboard to generate a report for the current
93
93
  sidekick status
94
94
  ```
95
95
 
96
- Check Claude API health from status.claude.com. Shows indicator with color coding (green/yellow/red), affected components, and active incident details. Use `--json` for machine-readable output. The dashboard also shows a status indicator in the status bar and Sessions Summary tab when the API is degraded.
96
+ Check API health for both Claude (status.claude.com) and OpenAI (status.openai.com). Shows indicators with color coding (green/yellow/red), affected components, and active incident details. Use `--json` for machine-readable output. The dashboard also shows a status indicator in the status bar and Sessions Summary tab when the API is degraded.
97
97
 
98
- ## Subscription Quota
98
+ ## Quota & Rate Limits
99
99
 
100
100
  ```bash
101
101
  sidekick quota
102
102
  ```
103
103
 
104
- Check Claude Max / Claude Code subscription quota utilization. Shows 5-hour and 7-day windows with color-coded progress bars and reset countdowns.
104
+ Provider-aware quota and rate-limit display. The command auto-detects the active provider:
105
+
106
+ - **Claude Code**: Shows Claude Max subscription quota — 5-hour and 7-day windows with color-coded progress bars, projections, and reset countdowns.
107
+ - **Codex**: Shows rate limits from the latest session's event stream — primary and secondary windows with progress bars and reset countdowns.
108
+ - **OpenCode**: Prints an informational message (no rate-limit data available).
105
109
 
106
110
  ```
107
111
  Subscription Quota
@@ -110,9 +114,9 @@ Subscription Quota
110
114
  7-Day ██████████████████████░░░░░░░░ 72% resets in 4d 6h
111
115
  ```
112
116
 
113
- When quota data is unavailable, `sidekick quota` shows structured auth, rate-limit, network, server, or unexpected-failure messaging instead of a generic raw error. The dashboard Sessions panel also keeps a compact inline quota state for Claude Code instead of hiding quota entirely.
117
+ When quota data is unavailable, `sidekick quota` shows structured auth, rate-limit, network, server, or unexpected-failure messaging instead of a generic raw error. The dashboard Sessions panel also keeps a compact inline quota/rate-limit state visible instead of hiding the section entirely.
114
118
 
115
- Use `--json` for machine-readable output. Requires active Claude Code credentials (read from the system Keychain on macOS, or `~/.claude/.credentials.json` on Linux/Windows). JSON output includes `failureKind`, `httpStatus`, and `retryAfterMs` on unavailable responses.
119
+ Use `--json` for machine-readable output. Use `--provider codex` to explicitly check Codex rate limits. Claude Code requires active credentials (read from the system Keychain on macOS, or `~/.claude/.credentials.json` on Linux/Windows). JSON output includes `failureKind`, `httpStatus`, and `retryAfterMs` on unavailable responses.
116
120
 
117
121
  When multi-account is enabled, `sidekick quota` shows the active account email above the quota bars.
118
122
 
@@ -8899,7 +8899,7 @@ var require_codex = __commonJS({
8899
8899
  return this._wasTruncated;
8900
8900
  }
8901
8901
  };
8902
- var CodexProvider3 = class {
8902
+ var CodexProvider4 = class {
8903
8903
  id = "codex";
8904
8904
  displayName = "Codex CLI";
8905
8905
  db = null;
@@ -9328,7 +9328,7 @@ var require_codex = __commonJS({
9328
9328
  this.lastTokenUsageData = null;
9329
9329
  }
9330
9330
  };
9331
- exports.CodexProvider = CodexProvider3;
9331
+ exports.CodexProvider = CodexProvider4;
9332
9332
  }
9333
9333
  });
9334
9334
 
@@ -11496,7 +11496,7 @@ var require_factory = __commonJS({
11496
11496
  };
11497
11497
  }();
11498
11498
  Object.defineProperty(exports, "__esModule", { value: true });
11499
- exports.createWatcher = createWatcher4;
11499
+ exports.createWatcher = createWatcher5;
11500
11500
  var os5 = __importStar(__require("os"));
11501
11501
  var path7 = __importStar(__require("path"));
11502
11502
  var jsonlWatcher_1 = require_jsonlWatcher();
@@ -11507,7 +11507,7 @@ var require_factory = __commonJS({
11507
11507
  return path7.join(xdg, "opencode");
11508
11508
  return path7.join(os5.homedir(), ".local", "share", "opencode");
11509
11509
  }
11510
- function createWatcher4(options) {
11510
+ function createWatcher5(options) {
11511
11511
  const { provider, workspacePath, sessionId, callbacks } = options;
11512
11512
  const sessions = provider.findAllSessions(workspacePath);
11513
11513
  if (sessions.length === 0) {
@@ -17362,8 +17362,9 @@ var require_providerStatus = __commonJS({
17362
17362
  "use strict";
17363
17363
  Object.defineProperty(exports, "__esModule", { value: true });
17364
17364
  exports.fetchProviderStatus = fetchProviderStatus3;
17365
- var STATUS_URL = "https://status.claude.com/api/v2/status.json";
17366
- var SUMMARY_URL = "https://status.claude.com/api/v2/summary.json";
17365
+ exports.fetchOpenAIStatus = fetchOpenAIStatus3;
17366
+ var CLAUDE_BASE = "https://status.claude.com";
17367
+ var OPENAI_BASE = "https://status.openai.com";
17367
17368
  function fallbackState() {
17368
17369
  return {
17369
17370
  indicator: "none",
@@ -17373,9 +17374,9 @@ var require_providerStatus = __commonJS({
17373
17374
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
17374
17375
  };
17375
17376
  }
17376
- async function fetchProviderStatus3() {
17377
+ async function fetchStatusPage(baseUrl) {
17377
17378
  try {
17378
- const statusRes = await fetch(STATUS_URL);
17379
+ const statusRes = await fetch(`${baseUrl}/api/v2/status.json`);
17379
17380
  if (!statusRes.ok)
17380
17381
  return fallbackState();
17381
17382
  const statusData = await statusRes.json();
@@ -17385,7 +17386,7 @@ var require_providerStatus = __commonJS({
17385
17386
  if (indicator === "none") {
17386
17387
  return { indicator, description, affectedComponents: [], activeIncident: null, updatedAt };
17387
17388
  }
17388
- const summaryRes = await fetch(SUMMARY_URL);
17389
+ const summaryRes = await fetch(`${baseUrl}/api/v2/summary.json`);
17389
17390
  if (!summaryRes.ok) {
17390
17391
  return { indicator, description, affectedComponents: [], activeIncident: null, updatedAt };
17391
17392
  }
@@ -17403,6 +17404,12 @@ var require_providerStatus = __commonJS({
17403
17404
  return fallbackState();
17404
17405
  }
17405
17406
  }
17407
+ async function fetchProviderStatus3() {
17408
+ return fetchStatusPage(CLAUDE_BASE);
17409
+ }
17410
+ async function fetchOpenAIStatus3() {
17411
+ return fetchStatusPage(OPENAI_BASE);
17412
+ }
17406
17413
  }
17407
17414
  });
17408
17415
 
@@ -17413,7 +17420,7 @@ var require_dist = __commonJS({
17413
17420
  Object.defineProperty(exports, "__esModule", { value: true });
17414
17421
  exports.findActiveClaudeSession = exports.discoverSessionDirectory = exports.getClaudeSessionDirectory = exports.encodeClaudeWorkspacePath = exports.detectSessionActivity = exports.extractTaskInfo = exports.scanSubagentDir = exports.normalizeCodexToolInput = exports.normalizeCodexToolName = exports.extractPatchFilePaths = exports.CodexRolloutParser = exports.parseDbPartData = exports.parseDbMessageData = exports.convertOpenCodeMessage = exports.detectPlanModeFromText = exports.normalizeToolInput = exports.normalizeToolName = exports.TRUNCATION_PATTERNS = exports.JsonlParser = exports.CodexProvider = exports.OpenCodeProvider = exports.ClaudeCodeProvider = exports.getAllDetectedProviders = exports.detectProvider = exports.readClaudeCodePlanFiles = exports.getPlanAnalytics = exports.writePlans = exports.getLatestPlan = exports.readPlans = exports.readLatestHandoff = exports.readHistory = exports.readNotes = exports.readDecisions = exports.readTasks = exports.getProjectSlugRaw = exports.getProjectSlug = exports.encodeWorkspacePath = exports.getGlobalDataPath = exports.getProjectDataPath = exports.getConfigDir = exports.MAX_PLANS_PER_PROJECT = exports.PLAN_SCHEMA_VERSION = exports.createEmptyTokenTotals = exports.HISTORICAL_DATA_SCHEMA_VERSION = exports.STALENESS_THRESHOLDS = exports.IMPORTANCE_DECAY_FACTORS = exports.KNOWLEDGE_NOTE_SCHEMA_VERSION = exports.DECISION_LOG_SCHEMA_VERSION = exports.normalizeTaskStatus = exports.TASK_PERSISTENCE_SCHEMA_VERSION = void 0;
17415
17422
  exports.HeatmapTracker = exports.FrequencyTracker = exports.getSnapshotPath = exports.isSnapshotValid = exports.deleteSnapshot = exports.loadSnapshot = exports.saveSnapshot = exports.parseTodoDependencies = exports.EventAggregator = exports.getRandomPhrase = exports.ALL_PHRASES = exports.HIGHLIGHT_CSS = exports.clearHighlightCache = exports.highlightEvent = exports.formatSessionJson = exports.formatSessionMarkdown = exports.formatSessionText = exports.classifyNoise = exports.shouldMergeWithPrevious = exports.classifyFollowEvent = exports.classifyMessage = exports.getSoftNoiseReason = exports.isHardNoiseFollowEvent = exports.isHardNoise = exports.formatToolSummary = exports.toFollowEvents = exports.createWatcher = exports.parseChangelog = exports.extractProposedPlanShared = exports.parsePlanMarkdownShared = exports.PlanExtractor = exports.composeContext = exports.FilterEngine = exports.searchSessions = exports.CodexDatabase = exports.OpenCodeDatabase = exports.discoverDebugLogs = exports.collapseDuplicates = exports.filterByLevel = exports.parseDebugLog = exports.scanSubagentTraces = exports.findAllSessionsWithWorktrees = exports.discoverWorktreeSiblings = exports.resolveWorktreeMainRepo = exports.getAllClaudeProjectFolders = exports.decodeEncodedPath = exports.getMostRecentlyActiveSessionDir = exports.findSubdirectorySessionDirs = exports.findSessionsInDirectory = exports.findAllClaudeSessions = void 0;
17416
- exports.fetchProviderStatus = exports.DEFAULT_CONTEXT_WINDOW = exports.getModelContextWindowSize = exports.describeQuotaFailure = exports.fetchQuota = exports.isMultiAccountEnabled = exports.getActiveAccount = exports.listAccounts = exports.removeAccount = exports.switchToAccount = exports.addCurrentAccount = exports.readActiveClaudeAccount = exports.writeAccountRegistry = exports.readAccountRegistry = exports.getAccountsDir = exports.readClaudeMaxAccessTokenSync = exports.readClaudeMaxCredentials = exports.writeActiveCredentials = exports.readActiveCredentials = exports.openInBrowser = exports.parseTranscript = exports.generateHtmlReport = exports.PatternExtractor = void 0;
17423
+ exports.fetchOpenAIStatus = exports.fetchProviderStatus = exports.DEFAULT_CONTEXT_WINDOW = exports.getModelContextWindowSize = exports.describeQuotaFailure = exports.fetchQuota = exports.isMultiAccountEnabled = exports.getActiveAccount = exports.listAccounts = exports.removeAccount = exports.switchToAccount = exports.addCurrentAccount = exports.readActiveClaudeAccount = exports.writeAccountRegistry = exports.readAccountRegistry = exports.getAccountsDir = exports.readClaudeMaxAccessTokenSync = exports.readClaudeMaxCredentials = exports.writeActiveCredentials = exports.readActiveCredentials = exports.openInBrowser = exports.parseTranscript = exports.generateHtmlReport = exports.PatternExtractor = void 0;
17417
17424
  var taskPersistence_1 = require_taskPersistence();
17418
17425
  Object.defineProperty(exports, "TASK_PERSISTENCE_SCHEMA_VERSION", { enumerable: true, get: function() {
17419
17426
  return taskPersistence_1.TASK_PERSISTENCE_SCHEMA_VERSION;
@@ -17834,6 +17841,9 @@ var require_dist = __commonJS({
17834
17841
  Object.defineProperty(exports, "fetchProviderStatus", { enumerable: true, get: function() {
17835
17842
  return providerStatus_1.fetchProviderStatus;
17836
17843
  } });
17844
+ Object.defineProperty(exports, "fetchOpenAIStatus", { enumerable: true, get: function() {
17845
+ return providerStatus_1.fetchOpenAIStatus;
17846
+ } });
17837
17847
  }
17838
17848
  });
17839
17849
 
@@ -19320,8 +19330,9 @@ var init_DashboardState = __esm({
19320
19330
  _providerName;
19321
19331
  // Quota (external state from OAuth API or Codex rate limits)
19322
19332
  _quota = null;
19323
- // Provider status (external state from status.claude.com)
19333
+ // Provider status (external state from status.claude.com / status.openai.com)
19324
19334
  _providerStatus = null;
19335
+ _openaiStatus = null;
19325
19336
  // Update availability (external state)
19326
19337
  _updateInfo = null;
19327
19338
  // Session ID (for plan persistence)
@@ -19345,6 +19356,7 @@ var init_DashboardState = __esm({
19345
19356
  this._providerName = void 0;
19346
19357
  this._quota = null;
19347
19358
  this._providerStatus = null;
19359
+ this._openaiStatus = null;
19348
19360
  this._updateInfo = null;
19349
19361
  this._sessionId = void 0;
19350
19362
  this._lastKnownCompactionCount = 0;
@@ -19505,10 +19517,14 @@ var init_DashboardState = __esm({
19505
19517
  setQuota(quota) {
19506
19518
  this._quota = quota;
19507
19519
  }
19508
- /** Update provider status from status.claude.com polling. */
19520
+ /** Update Claude provider status from status.claude.com polling. */
19509
19521
  setProviderStatus(status) {
19510
19522
  this._providerStatus = status;
19511
19523
  }
19524
+ /** Update OpenAI provider status from status.openai.com polling. */
19525
+ setOpenAIStatus(status) {
19526
+ this._openaiStatus = status;
19527
+ }
19512
19528
  /** Set update availability info from UpdateCheckService. */
19513
19529
  setUpdateInfo(info) {
19514
19530
  this._updateInfo = info;
@@ -19614,6 +19630,7 @@ var init_DashboardState = __esm({
19614
19630
  compactionEvents,
19615
19631
  quota: this._quota,
19616
19632
  providerStatus: this._providerStatus,
19633
+ openaiStatus: this._openaiStatus,
19617
19634
  eventCount: m.eventCount,
19618
19635
  sessionStartTime: m.sessionStartTime ?? void 0,
19619
19636
  currentModel: m.currentModel ?? void 0,
@@ -19946,16 +19963,22 @@ var init_ProviderStatusService = __esm({
19946
19963
  ProviderStatusService = class {
19947
19964
  _interval = null;
19948
19965
  _cached = null;
19966
+ _cachedOpenAI = null;
19949
19967
  _callback = null;
19950
- /** Register a callback for status updates. */
19968
+ _openAICallback = null;
19969
+ /** Register a callback for Claude status updates. */
19951
19970
  onUpdate(cb) {
19952
19971
  this._callback = cb;
19953
19972
  }
19973
+ /** Register a callback for OpenAI status updates. */
19974
+ onOpenAIUpdate(cb) {
19975
+ this._openAICallback = cb;
19976
+ }
19954
19977
  /** Start polling. Fetches immediately, then every 60s. */
19955
19978
  start() {
19956
19979
  if (this._interval) return;
19957
- this._fetch();
19958
- this._interval = setInterval(() => this._fetch(), REFRESH_MS2);
19980
+ this._fetchAll();
19981
+ this._interval = setInterval(() => this._fetchAll(), REFRESH_MS2);
19959
19982
  }
19960
19983
  /** Stop polling. */
19961
19984
  stop() {
@@ -19964,18 +19987,27 @@ var init_ProviderStatusService = __esm({
19964
19987
  this._interval = null;
19965
19988
  }
19966
19989
  }
19967
- /** Get the last fetched status state. */
19990
+ /** Get the last fetched Claude status state. */
19968
19991
  getCached() {
19969
19992
  return this._cached;
19970
19993
  }
19994
+ /** Get the last fetched OpenAI status state. */
19995
+ getCachedOpenAI() {
19996
+ return this._cachedOpenAI;
19997
+ }
19971
19998
  /** Single fetch — no polling. */
19972
19999
  async fetchOnce() {
19973
20000
  return (0, import_sidekick_shared6.fetchProviderStatus)();
19974
20001
  }
19975
- async _fetch() {
19976
- const state = await (0, import_sidekick_shared6.fetchProviderStatus)();
19977
- this._cached = state;
19978
- this._callback?.(state);
20002
+ async _fetchAll() {
20003
+ const [claude, openai] = await Promise.all([
20004
+ (0, import_sidekick_shared6.fetchProviderStatus)(),
20005
+ (0, import_sidekick_shared6.fetchOpenAIStatus)()
20006
+ ]);
20007
+ this._cached = claude;
20008
+ this._callback?.(claude);
20009
+ this._cachedOpenAI = openai;
20010
+ this._openAICallback?.(openai);
19979
20011
  }
19980
20012
  };
19981
20013
  }
@@ -20012,7 +20044,7 @@ var init_UpdateCheckService = __esm({
20012
20044
  /** Run the update check (one-shot). */
20013
20045
  async check() {
20014
20046
  try {
20015
- const current = "0.14.2";
20047
+ const current = "0.15.2";
20016
20048
  const cached = this.readCache();
20017
20049
  let latest;
20018
20050
  if (cached && Date.now() - cached.checkedAt < CACHE_TTL_MS) {
@@ -21578,9 +21610,10 @@ ${hint}{/grey-fg}`;
21578
21610
  lines.push(` ${modelName.padEnd(20)} {bold}${String(ms.calls).padStart(4)}{/bold}{grey-fg} calls{/grey-fg} {green-fg}$${ms.cost.toFixed(4)}{/green-fg}`);
21579
21611
  }
21580
21612
  }
21613
+ const quotaLabel = m.providerId === "codex" ? "Rate Limits" : "Quota";
21581
21614
  if (m.quota?.available) {
21582
21615
  const q = m.quota;
21583
- lines.push("", sectionHeader("Quota", w2));
21616
+ lines.push("", sectionHeader(quotaLabel, w2));
21584
21617
  const fiveColor = getUtilizationColor(q.fiveHour.utilization);
21585
21618
  const fiveBar = makeColorBar(q.fiveHour.utilization, 18, fiveColor);
21586
21619
  const fiveProj = q.projectedFiveHour != null ? (() => {
@@ -21595,11 +21628,11 @@ ${hint}{/grey-fg}`;
21595
21628
  return ` {grey-fg}\u2192{/grey-fg} {${pc}-fg}${q.projectedSevenDay.toFixed(0)}%{/${pc}-fg}`;
21596
21629
  })() : "";
21597
21630
  lines.push(` {grey-fg}7d{/grey-fg} ${sevenBar} {bold}${q.sevenDay.utilization.toFixed(0)}%{/bold}${sevenProj}`);
21598
- } else if (m.providerId === "claude-code" && m.quota) {
21631
+ } else if ((m.providerId === "claude-code" || m.providerId === "codex") && m.quota) {
21599
21632
  const descriptor = (0, import_sidekick_shared8.describeQuotaFailure)(m.quota);
21600
21633
  if (descriptor) {
21601
21634
  const severityColor = descriptor.severity === "warning" ? "yellow" : descriptor.severity === "info" ? "cyan" : "red";
21602
- lines.push("", sectionHeader("Quota", w2));
21635
+ lines.push("", sectionHeader(quotaLabel, w2));
21603
21636
  lines.push(` {${severityColor}-fg}${descriptor.title}{/${severityColor}-fg}`);
21604
21637
  const failureText = [descriptor.message, descriptor.detail].filter(Boolean).join(" ");
21605
21638
  const quotaTextWidth = Math.max(20, detailWidth() - 4);
@@ -21608,19 +21641,24 @@ ${hint}{/grey-fg}`;
21608
21641
  }
21609
21642
  }
21610
21643
  }
21611
- if (m.providerStatus && m.providerStatus.indicator !== "none") {
21612
- const ps = m.providerStatus;
21613
- const statusColor = ps.indicator === "minor" ? "yellow" : "red";
21614
- lines.push("", sectionHeader("API Status", w2));
21615
- lines.push(` {${statusColor}-fg}\u25CF ${ps.description}{/${statusColor}-fg}`);
21616
- for (const c2 of ps.affectedComponents) {
21617
- const cColor = c2.status.includes("major") ? "red" : "yellow";
21618
- lines.push(` {${cColor}-fg}\u2022{/${cColor}-fg} ${c2.name} {grey-fg}\u2014 ${c2.status.replace(/_/g, " ")}{/grey-fg}`);
21619
- }
21620
- if (ps.activeIncident) {
21621
- lines.push(` {${statusColor}-fg}${ps.activeIncident.name}{/${statusColor}-fg}`);
21622
- if (ps.activeIncident.shortlink) {
21623
- lines.push(` {grey-fg}${ps.activeIncident.shortlink}{/grey-fg}`);
21644
+ const statusEntries = [
21645
+ { label: "Claude API Status", status: m.providerStatus },
21646
+ { label: "OpenAI API Status", status: m.openaiStatus }
21647
+ ];
21648
+ for (const { label, status: ps } of statusEntries) {
21649
+ if (ps && ps.indicator !== "none") {
21650
+ const statusColor = ps.indicator === "minor" ? "yellow" : "red";
21651
+ lines.push("", sectionHeader(label, w2));
21652
+ lines.push(` {${statusColor}-fg}\u25CF ${ps.description}{/${statusColor}-fg}`);
21653
+ for (const c2 of ps.affectedComponents) {
21654
+ const cColor = c2.status.includes("major") ? "red" : "yellow";
21655
+ lines.push(` {${cColor}-fg}\u2022{/${cColor}-fg} ${c2.name} {grey-fg}\u2014 ${c2.status.replace(/_/g, " ")}{/grey-fg}`);
21656
+ }
21657
+ if (ps.activeIncident) {
21658
+ lines.push(` {${statusColor}-fg}${ps.activeIncident.name}{/${statusColor}-fg}`);
21659
+ if (ps.activeIncident.shortlink) {
21660
+ lines.push(` {grey-fg}${ps.activeIncident.shortlink}{/grey-fg}`);
21661
+ }
21624
21662
  }
21625
21663
  }
21626
21664
  }
@@ -60601,19 +60639,22 @@ function StatusBar({
60601
60639
  matchCount,
60602
60640
  totalCount,
60603
60641
  updateInfo,
60604
- providerStatus
60642
+ providerStatus,
60643
+ openaiStatus
60605
60644
  }) {
60606
60645
  const evtLabel = eventCount > 0 ? `${eventCount} events` : "waiting...";
60607
60646
  const permissionColor = permissionMode === "bypassPermissions" ? "red" : permissionMode === "acceptEdits" ? "magenta" : permissionMode === "plan" ? "green" : void 0;
60608
60647
  const permissionLabel = permissionMode === "bypassPermissions" ? "BYPASS" : permissionMode === "acceptEdits" ? "EDITS" : permissionMode === "plan" ? "PLAN" : void 0;
60609
60648
  const statusIndicator = providerStatus && providerStatus.indicator !== "none";
60610
60649
  const statusColor = providerStatus?.indicator === "minor" ? "yellow" : "red";
60650
+ const openaiIndicator = openaiStatus && openaiStatus.indicator !== "none";
60651
+ const openaiColor = openaiStatus?.indicator === "minor" ? "yellow" : "red";
60611
60652
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { height: 1, width: "100%", children: [
60612
60653
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
60613
60654
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: parseBlessedTags(BRAND_INLINE) }),
60614
60655
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { dimColor: true, children: [
60615
60656
  " v",
60616
- "0.14.2"
60657
+ "0.15.2"
60617
60658
  ] }),
60618
60659
  updateInfo && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "yellow", children: [
60619
60660
  " (v",
@@ -60652,10 +60693,22 @@ function StatusBar({
60652
60693
  ] }),
60653
60694
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: statusColor, children: [
60654
60695
  "\u25CF",
60655
- " API ",
60696
+ " Claude ",
60656
60697
  providerStatus.indicator
60657
60698
  ] })
60658
60699
  ] }),
60700
+ openaiIndicator && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
60701
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { dimColor: true, children: [
60702
+ " ",
60703
+ "\u2502",
60704
+ " "
60705
+ ] }),
60706
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: openaiColor, children: [
60707
+ "\u25CF",
60708
+ " OpenAI ",
60709
+ openaiStatus.indicator
60710
+ ] })
60711
+ ] }),
60659
60712
  filterString && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "yellow", children: [
60660
60713
  ' filter: "',
60661
60714
  filterString,
@@ -60991,7 +61044,7 @@ function ChangelogOverlay({ entries, scrollOffset }) {
60991
61044
  " ",
60992
61045
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { bold: true, color: "cyan", children: [
60993
61046
  "Terminal Dashboard v",
60994
- "0.14.2"
61047
+ "0.15.2"
60995
61048
  ] }),
60996
61049
  latestDate ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { color: "gray", children: [
60997
61050
  " \u2014 ",
@@ -61313,7 +61366,7 @@ var init_mouse = __esm({
61313
61366
  var CHANGELOG_default;
61314
61367
  var init_CHANGELOG = __esm({
61315
61368
  "CHANGELOG.md"() {
61316
- CHANGELOG_default = '# Changelog\n\nAll notable changes to the Sidekick Agent Hub CLI will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [0.14.2] - 2026-03-16\n\n### Fixed\n\n- **Quota polling interval**: Reduced quota refresh from every 30 seconds to every 5 minutes to avoid unnecessary API calls\n- **SessionsPanel `detailWidth()` call**: Removed unused parameter from `detailWidth()` in the Sessions panel quota rendering\n\n## [0.14.1] - 2026-03-14\n\n### Fixed\n\n- **Per-model context window sizes**: Dashboard context gauge now shows correct utilization for Claude Opus 4.6 (1M context) and other models with non-200K windows\n\n### Changed\n\n- **Shared model context lookup**: CLI dashboard now uses the centralized `getModelContextWindowSize()` from `sidekick-shared` instead of a local duplicate map\n\n## [0.14.0] - 2026-03-12\n\n### Added\n\n- **`sidekick account` Command**: Manage Claude Code accounts from the terminal \u2014 list saved accounts, add the current account with an optional label, switch to the next or a specific account, and remove accounts. Supports `--json` output for scripting\n- **Quota Account Label**: `sidekick quota` now shows the active account email and label above the quota bars when multi-account is enabled\n- **macOS Keychain Support**: `sidekick account` and `sidekick quota` now read and write credentials via the system Keychain on macOS, fixing account switching and quota checks on Mac\n\n## [0.13.8] - 2026-03-12\n\n### Changed\n\n- **Structured quota failure output**: `sidekick quota` now renders consistent auth, rate-limit, server, network, and unexpected-failure copy from shared quota failure descriptors while preserving `--json` machine-readable output\n- **Dashboard unavailable quota rendering**: The Sessions panel now shows Claude Code quota failures inline instead of hiding the quota section whenever subscription data is unavailable\n- **Quota transition toasts**: The Ink dashboard now fires low-noise toast notifications only when Claude Code quota failure state changes, avoiding repeated alerts every polling interval\n\n## [0.13.7] - 2026-03-11\n\n### Changed\n\n- **npm README sync**: Updated the published CLI package README to reflect current OpenCode monitoring behavior, platform-specific data directories, and the `sqlite3` runtime requirement\n- **README badge cleanup**: Removed the Ask DeepWiki badge from the published CLI package README; the repo root README still keeps it\n\n## [0.13.6] - 2026-03-11\n\n### Changed\n\n- **Refreshed CLI Dashboard Wordmark**: Updated the dashboard wordmark/header styling for a cleaner splash and dashboard identity\n\n### Fixed\n\n- **OpenCode dashboard startup**: OpenCode DB-backed session discovery now resolves projects by worktree, sandboxes, and session directory instead of quietly behaving like no session exists\n- **OpenCode runtime notices**: The CLI now prints an OpenCode-only actionable notice when `opencode.db` exists but `sqlite3` is missing, blocked, or otherwise unusable in the current shell environment\n\n## [0.13.5] - 2026-03-10\n\n### Added\n\n- **`sidekick status` Command**: One-shot Claude API status check with color-coded text output and `--json` mode\n- **Dashboard Status Banner**: Status bar shows a colored `\u25CF API minor/major/critical` indicator when Claude is degraded; Sessions panel Summary tab shows an "API Status" section with affected components and active incident details. Polls every 60s\n\n## [0.13.4] - 2026-03-08\n\n### Fixed\n\n- **Onboarding Phrase Spam**: Splash screen and detail pane motivational phrases memoized \u2014 no longer flicker every render tick (fixes [#13](https://github.com/cesarandreslopez/sidekick-agent-hub/issues/13))\n\n### Changed\n\n- **Simplified Logo**: Replaced 6-line ASCII robot art with compact text header in splash, help, and changelog overlays\n- **Removed Dead Code**: Removed unused `getSplashContent()` and `HELP_HEADER` exports from branding module\n\n## [0.13.3] - 2026-03-04\n\n_No CLI-specific changes in this release._\n\n## [0.13.2] - 2026-03-04\n\n_No CLI-specific changes in this release._\n\n## [0.13.1] - 2026-03-04\n\n### Added\n\n- **`sidekick quota` Command**: One-shot subscription quota check showing 5-hour and 7-day utilization with color-coded progress bars and reset countdowns \u2014 supports `--json` for machine-readable output\n- **Quota Projections**: Elapsed-time projections shown in `sidekick quota` output and TUI dashboard quota section \u2014 displays projected end-of-window utilization next to current value (e.g., `40% \u2192 100%`), included in `--json` output as `projectedFiveHour` / `projectedSevenDay`\n\n## [0.13.0] - 2026-03-03\n\n_No CLI-specific changes in this release._\n\n## [0.12.10] - 2026-03-01\n\n### Added\n\n- **Events Panel** (key 7): Scrollable live event stream with colored type badges (`[USR]`, `[AST]`, `[TOOL]`, `[RES]`), timestamps, and keyword-highlighted summaries; detail tabs for full event JSON and surrounding context\n- **Charts Panel** (key 8): Tool frequency horizontal bars, event type distribution, 60-minute activity heatmap using `\u2591\u2592\u2593\u2588` intensity characters, and pattern analysis with frequency bars and template text\n- **Multi-Mode Filter**: `/` filter overlay now supports four modes \u2014 substring, fuzzy, regex, and date range \u2014 Tab cycles modes, regex mode shows red validation errors\n- **Search Term Highlighting**: Active filter terms highlighted in blue within side list items\n- **Timeline Keyword Coloring**: Event summaries in the Sessions panel Timeline tab now use semantic keyword coloring \u2014 errors red, success green, tool names cyan, file paths magenta\n\n### Removed\n\n- **Search Panel**: Removed redundant Search panel (previously key 7) \u2014 the `/` filter with multi-mode support serves the same purpose\n\n## [0.12.9] - 2026-02-28\n\n### Added\n\n- **Standalone Data Commands**: `sidekick tasks`, `sidekick decisions`, `sidekick notes`, `sidekick stats`, `sidekick handoff` for accessing project data without launching the TUI\n- **`sidekick search <query>`**: Cross-session full-text search from the terminal\n- **`sidekick context`**: Composite output of tasks, decisions, notes, and handoff for piping into other tools\n- **`--list` flag on `sidekick dump`**: Discover available session IDs before requiring `--session <id>`\n- **Search Panel**: Search panel (panel 7) wired into the TUI dashboard\n\n### Changed\n\n- **`taskMerger` utility**: Duplicate `mergeTasks` logic extracted into shared `taskMerger` utility\n- **Model constants**: Hardcoded model IDs extracted to named constants\n\n### Fixed\n\n- **`convention` icon**: Notes panel icon replaced with valid `tip` type\n- **Linux clipboard**: Now supports Wayland (`wl-copy`) and `xsel` fallbacks, with error messages instead of silent failure\n- **`provider.dispose()`**: Added to `dump` and `report` commands (prevents SQLite connection leaks)\n\n## [0.12.8] - 2026-02-28\n\n### Changed\n\n- **Dashboard UI/UX Polish**: Visual overhaul for better hierarchy, consistency, and readability\n - Splash screen and help overlay now display the robot ASCII logo\n - Toast notifications show severity icons (\u2718 error, \u26A0 warning, \u25CF info) with inner padding\n - Focused pane uses double-border for clear focus indication\n - Section dividers (`\u2500\u2500 Title \u2500\u2500\u2500\u2500`) replace bare bold headers in summary, agents, and context attribution\n - Tab bar: active tab underlined in magenta, inactive tabs dimmed, bracket syntax removed\n - Status bar: segmented layout with `\u2502` separators; keys bold, labels dim\n - Summary metrics condensed: elapsed/events/compactions on one line, tokens on one line with cache rate and cost\n - Sparklines display peak metadata annotations\n - Progress bars use blessed color tags for consistent coloring\n - Help overlay uses dot-leader alignment for all keybinding rows\n - Empty state hints per panel (e.g. "Tasks appear as your agent works.")\n - Session picker groups sessions by provider with section headers when multiple providers are present\n\n## [0.12.7] - 2026-02-27\n\n### Added\n\n- **HTML Session Report**: `sidekick report` command generates a self-contained HTML report and opens it in the default browser\n - Options: `--session`, `--output`, `--theme` (dark/light), `--no-open`, `--no-thinking`\n - TUI Dashboard: press `r` to generate and open an HTML report for the current session\n\n## [0.12.6] - 2026-02-26\n\n### Added\n\n- **Session Dump Command**: `sidekick dump` exports session data in text, markdown, or JSON format with `--format`, `--width`, and `--expand` options\n- **Plans Panel Re-enabled**: Plans panel restored in CLI dashboard with plan file discovery from `~/.claude/plans/`\n- **Enhanced Status Bar**: Session info display improved with richer metadata\n\n### Fixed\n\n- **Old snapshot format migration**: Restoring pre-0.12.3 session snapshots no longer shows empty timeline entries\n\n### Changed\n\n- **Phrase library moved to shared**: CLI-specific phrase formatting kept local, all phrase content now from `sidekick-shared`\n\n## [0.12.5] - 2026-02-24\n\n### Fixed\n\n- **Update check too slow to notice new versions**: Reduced npm registry cache TTL from 24 hours to 4 hours so upgrade notices appear sooner after a new release\n\n## [0.12.4] - 2026-02-24\n\n### Fixed\n\n- **Session crash on upgrade**: Fixed `d.timestamp.getTime is not a function` error when restoring tool call data from session snapshots \u2014 `Date` objects were serialized to strings by JSON but not rehydrated on restore, causing the session monitor to crash on first run after upgrading from 0.12.2 to 0.12.3\n\n## [0.12.3] - 2026-02-24\n\n### Added\n\n- **Latest-node indicator**: The most recently added node in tree and boxed mind map views is now marked with a yellow indicator\n- **Plan analytics in mind map**: Tree and boxed views now display plan progress and per-step metrics\n - Tree view: plan header shows completion stats; steps show complexity, duration, tokens, tool calls, and errors in metadata brackets\n - Box view: progress bar with completion percentage; steps show right-aligned metrics; subtitle shows step count and total duration\n- **Cross-provider plan extraction**: Shared `PlanExtractor` now handles Claude Code (EnterPlanMode/ExitPlanMode) and OpenCode (`<proposed_plan>` XML) plans \u2014 previously only Codex plans were shown\n- **Enriched plan data model**: Plan steps include duration, token count, tool call count, and error messages\n- **Phase-grouped plan display**: When a plan has phase structure, tree and boxed views group steps under phase headers with context lines from the original plan markdown\n- **Node type filter**: Press `f` on the Mind Map tab to cycle through node type filters (file, tool, task, subagent, command, plan, knowledge-note) \u2014 non-matching sections render dimmed in grey\n\n### Fixed\n\n- **Kanban board regression**: Subagent and plan-step tasks now correctly appear in the kanban board\n\n### Changed\n\n- **Plans panel temporarily disabled**: The Plans panel in the CLI dashboard is disabled until plan-mode event capture is reliably working end-to-end. Plan nodes in the mind map remain active.\n- `DashboardState` now delegates to shared `EventAggregator` instead of maintaining its own aggregation logic\n\n## [0.12.2] - 2026-02-23\n\n### Added\n\n- **Update notifications**: The dashboard now checks the npm registry for newer versions on startup and shows a yellow banner in the status bar when an update is available (e.g., `v0.13.0 available \u2014 npm i -g sidekick-agent-hub`). Results are cached for 24 hours to avoid repeated network requests.\n\n## [0.12.1] - 2026-02-23\n\n### Fixed\n\n- **VS Code integration**: Fixed exit code 127 when the extension launches the CLI dashboard on systems using nvm or volta (node binary not found when shell init is bypassed)\n\n## [0.12.0] - 2026-02-22\n\n### Added\n\n- **"Open CLI Dashboard" VS Code Integration**: New VS Code command `Sidekick: Open CLI Dashboard` launches the TUI dashboard in an integrated terminal\n - Install the CLI with `npm install -g sidekick-agent-hub`\n\n## [0.11.0] - 2026-02-19\n\n### Added\n\n- **Initial Release**: Full-screen TUI dashboard for monitoring agent sessions from the terminal\n - Ink-based terminal UI with panels for sessions, tasks, kanban, mind map, notes, decisions, search, files, and git diff\n - Multi-provider support: auto-detects Claude Code, OpenCode, and Codex sessions\n - Reads from `~/.config/sidekick/` \u2014 the same data files the VS Code extension writes\n - Usage: `sidekick dashboard [--project <path>] [--provider <id>]`\n';
61369
+ CHANGELOG_default = '# Changelog\n\nAll notable changes to the Sidekick Agent Hub CLI will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [0.15.2] - 2026-03-18\n\n### Fixed\n\n- **CLI help descriptions**: Updated `quota` and `status` command descriptions to reflect provider-aware behavior\n- **`sidekick quota --provider`**: Added local `--provider` option so `sidekick quota --provider codex` works naturally\n\n## [0.15.0] - 2026-03-18\n\n### Added\n\n- **OpenAI status page monitoring**: CLI dashboard now shows OpenAI API status alongside Claude API status\n- **Codex rate limits in dashboard**: Sessions panel displays Codex rate-limit data with "Rate Limits" header instead of "Quota"\n- **Provider-aware `sidekick quota` command**: Detects active provider and shows Codex rate limits, Claude subscription quota, or an informational message for OpenCode\n\n### Fixed\n\n- **QuotaService polling for Codex**: Dashboard no longer starts Claude OAuth quota polling when the active provider is Codex\n\n## [0.14.2] - 2026-03-16\n\n### Fixed\n\n- **Quota polling interval**: Reduced quota refresh from every 30 seconds to every 5 minutes to avoid unnecessary API calls\n- **SessionsPanel `detailWidth()` call**: Removed unused parameter from `detailWidth()` in the Sessions panel quota rendering\n\n## [0.14.1] - 2026-03-14\n\n### Fixed\n\n- **Per-model context window sizes**: Dashboard context gauge now shows correct utilization for Claude Opus 4.6 (1M context) and other models with non-200K windows\n\n### Changed\n\n- **Shared model context lookup**: CLI dashboard now uses the centralized `getModelContextWindowSize()` from `sidekick-shared` instead of a local duplicate map\n\n## [0.14.0] - 2026-03-12\n\n### Added\n\n- **`sidekick account` Command**: Manage Claude Code accounts from the terminal \u2014 list saved accounts, add the current account with an optional label, switch to the next or a specific account, and remove accounts. Supports `--json` output for scripting\n- **Quota Account Label**: `sidekick quota` now shows the active account email and label above the quota bars when multi-account is enabled\n- **macOS Keychain Support**: `sidekick account` and `sidekick quota` now read and write credentials via the system Keychain on macOS, fixing account switching and quota checks on Mac\n\n## [0.13.8] - 2026-03-12\n\n### Changed\n\n- **Structured quota failure output**: `sidekick quota` now renders consistent auth, rate-limit, server, network, and unexpected-failure copy from shared quota failure descriptors while preserving `--json` machine-readable output\n- **Dashboard unavailable quota rendering**: The Sessions panel now shows Claude Code quota failures inline instead of hiding the quota section whenever subscription data is unavailable\n- **Quota transition toasts**: The Ink dashboard now fires low-noise toast notifications only when Claude Code quota failure state changes, avoiding repeated alerts every polling interval\n\n## [0.13.7] - 2026-03-11\n\n### Changed\n\n- **npm README sync**: Updated the published CLI package README to reflect current OpenCode monitoring behavior, platform-specific data directories, and the `sqlite3` runtime requirement\n- **README badge cleanup**: Removed the Ask DeepWiki badge from the published CLI package README; the repo root README still keeps it\n\n## [0.13.6] - 2026-03-11\n\n### Changed\n\n- **Refreshed CLI Dashboard Wordmark**: Updated the dashboard wordmark/header styling for a cleaner splash and dashboard identity\n\n### Fixed\n\n- **OpenCode dashboard startup**: OpenCode DB-backed session discovery now resolves projects by worktree, sandboxes, and session directory instead of quietly behaving like no session exists\n- **OpenCode runtime notices**: The CLI now prints an OpenCode-only actionable notice when `opencode.db` exists but `sqlite3` is missing, blocked, or otherwise unusable in the current shell environment\n\n## [0.13.5] - 2026-03-10\n\n### Added\n\n- **`sidekick status` Command**: One-shot Claude API status check with color-coded text output and `--json` mode\n- **Dashboard Status Banner**: Status bar shows a colored `\u25CF API minor/major/critical` indicator when Claude is degraded; Sessions panel Summary tab shows an "API Status" section with affected components and active incident details. Polls every 60s\n\n## [0.13.4] - 2026-03-08\n\n### Fixed\n\n- **Onboarding Phrase Spam**: Splash screen and detail pane motivational phrases memoized \u2014 no longer flicker every render tick (fixes [#13](https://github.com/cesarandreslopez/sidekick-agent-hub/issues/13))\n\n### Changed\n\n- **Simplified Logo**: Replaced 6-line ASCII robot art with compact text header in splash, help, and changelog overlays\n- **Removed Dead Code**: Removed unused `getSplashContent()` and `HELP_HEADER` exports from branding module\n\n## [0.13.3] - 2026-03-04\n\n_No CLI-specific changes in this release._\n\n## [0.13.2] - 2026-03-04\n\n_No CLI-specific changes in this release._\n\n## [0.13.1] - 2026-03-04\n\n### Added\n\n- **`sidekick quota` Command**: One-shot subscription quota check showing 5-hour and 7-day utilization with color-coded progress bars and reset countdowns \u2014 supports `--json` for machine-readable output\n- **Quota Projections**: Elapsed-time projections shown in `sidekick quota` output and TUI dashboard quota section \u2014 displays projected end-of-window utilization next to current value (e.g., `40% \u2192 100%`), included in `--json` output as `projectedFiveHour` / `projectedSevenDay`\n\n## [0.13.0] - 2026-03-03\n\n_No CLI-specific changes in this release._\n\n## [0.12.10] - 2026-03-01\n\n### Added\n\n- **Events Panel** (key 7): Scrollable live event stream with colored type badges (`[USR]`, `[AST]`, `[TOOL]`, `[RES]`), timestamps, and keyword-highlighted summaries; detail tabs for full event JSON and surrounding context\n- **Charts Panel** (key 8): Tool frequency horizontal bars, event type distribution, 60-minute activity heatmap using `\u2591\u2592\u2593\u2588` intensity characters, and pattern analysis with frequency bars and template text\n- **Multi-Mode Filter**: `/` filter overlay now supports four modes \u2014 substring, fuzzy, regex, and date range \u2014 Tab cycles modes, regex mode shows red validation errors\n- **Search Term Highlighting**: Active filter terms highlighted in blue within side list items\n- **Timeline Keyword Coloring**: Event summaries in the Sessions panel Timeline tab now use semantic keyword coloring \u2014 errors red, success green, tool names cyan, file paths magenta\n\n### Removed\n\n- **Search Panel**: Removed redundant Search panel (previously key 7) \u2014 the `/` filter with multi-mode support serves the same purpose\n\n## [0.12.9] - 2026-02-28\n\n### Added\n\n- **Standalone Data Commands**: `sidekick tasks`, `sidekick decisions`, `sidekick notes`, `sidekick stats`, `sidekick handoff` for accessing project data without launching the TUI\n- **`sidekick search <query>`**: Cross-session full-text search from the terminal\n- **`sidekick context`**: Composite output of tasks, decisions, notes, and handoff for piping into other tools\n- **`--list` flag on `sidekick dump`**: Discover available session IDs before requiring `--session <id>`\n- **Search Panel**: Search panel (panel 7) wired into the TUI dashboard\n\n### Changed\n\n- **`taskMerger` utility**: Duplicate `mergeTasks` logic extracted into shared `taskMerger` utility\n- **Model constants**: Hardcoded model IDs extracted to named constants\n\n### Fixed\n\n- **`convention` icon**: Notes panel icon replaced with valid `tip` type\n- **Linux clipboard**: Now supports Wayland (`wl-copy`) and `xsel` fallbacks, with error messages instead of silent failure\n- **`provider.dispose()`**: Added to `dump` and `report` commands (prevents SQLite connection leaks)\n\n## [0.12.8] - 2026-02-28\n\n### Changed\n\n- **Dashboard UI/UX Polish**: Visual overhaul for better hierarchy, consistency, and readability\n - Splash screen and help overlay now display the robot ASCII logo\n - Toast notifications show severity icons (\u2718 error, \u26A0 warning, \u25CF info) with inner padding\n - Focused pane uses double-border for clear focus indication\n - Section dividers (`\u2500\u2500 Title \u2500\u2500\u2500\u2500`) replace bare bold headers in summary, agents, and context attribution\n - Tab bar: active tab underlined in magenta, inactive tabs dimmed, bracket syntax removed\n - Status bar: segmented layout with `\u2502` separators; keys bold, labels dim\n - Summary metrics condensed: elapsed/events/compactions on one line, tokens on one line with cache rate and cost\n - Sparklines display peak metadata annotations\n - Progress bars use blessed color tags for consistent coloring\n - Help overlay uses dot-leader alignment for all keybinding rows\n - Empty state hints per panel (e.g. "Tasks appear as your agent works.")\n - Session picker groups sessions by provider with section headers when multiple providers are present\n\n## [0.12.7] - 2026-02-27\n\n### Added\n\n- **HTML Session Report**: `sidekick report` command generates a self-contained HTML report and opens it in the default browser\n - Options: `--session`, `--output`, `--theme` (dark/light), `--no-open`, `--no-thinking`\n - TUI Dashboard: press `r` to generate and open an HTML report for the current session\n\n## [0.12.6] - 2026-02-26\n\n### Added\n\n- **Session Dump Command**: `sidekick dump` exports session data in text, markdown, or JSON format with `--format`, `--width`, and `--expand` options\n- **Plans Panel Re-enabled**: Plans panel restored in CLI dashboard with plan file discovery from `~/.claude/plans/`\n- **Enhanced Status Bar**: Session info display improved with richer metadata\n\n### Fixed\n\n- **Old snapshot format migration**: Restoring pre-0.12.3 session snapshots no longer shows empty timeline entries\n\n### Changed\n\n- **Phrase library moved to shared**: CLI-specific phrase formatting kept local, all phrase content now from `sidekick-shared`\n\n## [0.12.5] - 2026-02-24\n\n### Fixed\n\n- **Update check too slow to notice new versions**: Reduced npm registry cache TTL from 24 hours to 4 hours so upgrade notices appear sooner after a new release\n\n## [0.12.4] - 2026-02-24\n\n### Fixed\n\n- **Session crash on upgrade**: Fixed `d.timestamp.getTime is not a function` error when restoring tool call data from session snapshots \u2014 `Date` objects were serialized to strings by JSON but not rehydrated on restore, causing the session monitor to crash on first run after upgrading from 0.12.2 to 0.12.3\n\n## [0.12.3] - 2026-02-24\n\n### Added\n\n- **Latest-node indicator**: The most recently added node in tree and boxed mind map views is now marked with a yellow indicator\n- **Plan analytics in mind map**: Tree and boxed views now display plan progress and per-step metrics\n - Tree view: plan header shows completion stats; steps show complexity, duration, tokens, tool calls, and errors in metadata brackets\n - Box view: progress bar with completion percentage; steps show right-aligned metrics; subtitle shows step count and total duration\n- **Cross-provider plan extraction**: Shared `PlanExtractor` now handles Claude Code (EnterPlanMode/ExitPlanMode) and OpenCode (`<proposed_plan>` XML) plans \u2014 previously only Codex plans were shown\n- **Enriched plan data model**: Plan steps include duration, token count, tool call count, and error messages\n- **Phase-grouped plan display**: When a plan has phase structure, tree and boxed views group steps under phase headers with context lines from the original plan markdown\n- **Node type filter**: Press `f` on the Mind Map tab to cycle through node type filters (file, tool, task, subagent, command, plan, knowledge-note) \u2014 non-matching sections render dimmed in grey\n\n### Fixed\n\n- **Kanban board regression**: Subagent and plan-step tasks now correctly appear in the kanban board\n\n### Changed\n\n- **Plans panel temporarily disabled**: The Plans panel in the CLI dashboard is disabled until plan-mode event capture is reliably working end-to-end. Plan nodes in the mind map remain active.\n- `DashboardState` now delegates to shared `EventAggregator` instead of maintaining its own aggregation logic\n\n## [0.12.2] - 2026-02-23\n\n### Added\n\n- **Update notifications**: The dashboard now checks the npm registry for newer versions on startup and shows a yellow banner in the status bar when an update is available (e.g., `v0.13.0 available \u2014 npm i -g sidekick-agent-hub`). Results are cached for 24 hours to avoid repeated network requests.\n\n## [0.12.1] - 2026-02-23\n\n### Fixed\n\n- **VS Code integration**: Fixed exit code 127 when the extension launches the CLI dashboard on systems using nvm or volta (node binary not found when shell init is bypassed)\n\n## [0.12.0] - 2026-02-22\n\n### Added\n\n- **"Open CLI Dashboard" VS Code Integration**: New VS Code command `Sidekick: Open CLI Dashboard` launches the TUI dashboard in an integrated terminal\n - Install the CLI with `npm install -g sidekick-agent-hub`\n\n## [0.11.0] - 2026-02-19\n\n### Added\n\n- **Initial Release**: Full-screen TUI dashboard for monitoring agent sessions from the terminal\n - Ink-based terminal UI with panels for sessions, tasks, kanban, mind map, notes, decisions, search, files, and git diff\n - Multi-provider support: auto-detects Claude Code, OpenCode, and Codex sessions\n - Reads from `~/.config/sidekick/` \u2014 the same data files the VS Code extension writes\n - Usage: `sidekick dashboard [--project <path>] [--provider <id>]`\n';
61317
61370
  }
61318
61371
  });
61319
61372
 
@@ -61996,7 +62049,8 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
61996
62049
  matchCount: currentItems.length,
61997
62050
  totalCount: panel.getItems(metrics, staticData).length,
61998
62051
  updateInfo: metrics.updateInfo,
61999
- providerStatus: metrics.providerStatus
62052
+ providerStatus: metrics.providerStatus,
62053
+ openaiStatus: metrics.openaiStatus
62000
62054
  }
62001
62055
  ),
62002
62056
  state.overlay === "context-menu" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -62391,6 +62445,10 @@ async function dashboardAction(_opts, cmd) {
62391
62445
  state.setProviderStatus(status);
62392
62446
  scheduleRender();
62393
62447
  });
62448
+ providerStatusService.onOpenAIUpdate((status) => {
62449
+ state.setOpenAIStatus(status);
62450
+ scheduleRender();
62451
+ });
62394
62452
  let stopped = false;
62395
62453
  function cleanup() {
62396
62454
  if (stopped) return;
@@ -62471,7 +62529,9 @@ async function dashboardAction(_opts, cmd) {
62471
62529
  }
62472
62530
  } catch {
62473
62531
  }
62474
- quotaService.start();
62532
+ if (activeProvider.id === "claude-code") {
62533
+ quotaService.start();
62534
+ }
62475
62535
  providerStatusService.start();
62476
62536
  updateCheckService.check();
62477
62537
  scheduleRender();
@@ -63403,7 +63463,28 @@ function formatTimeUntil(isoString) {
63403
63463
  }
63404
63464
  async function quotaAction(_opts, cmd) {
63405
63465
  const globalOpts = cmd.parent.opts();
63466
+ const localOpts = cmd.opts();
63406
63467
  const jsonOutput = !!globalOpts.json;
63468
+ const providerOpts = localOpts.provider ? { provider: localOpts.provider } : globalOpts;
63469
+ const provider = resolveProvider(providerOpts);
63470
+ if (provider.id === "opencode") {
63471
+ provider.dispose();
63472
+ const msg = "OpenCode does not provide rate-limit data.";
63473
+ if (jsonOutput) {
63474
+ process.stdout.write(JSON.stringify({ available: false, error: msg }, null, 2) + "\n");
63475
+ } else {
63476
+ process.stderr.write(source_default.yellow(msg) + "\n");
63477
+ }
63478
+ return;
63479
+ }
63480
+ if (provider.id === "codex") {
63481
+ await codexQuotaAction(provider, globalOpts, jsonOutput);
63482
+ return;
63483
+ }
63484
+ provider.dispose();
63485
+ await claudeQuotaAction(jsonOutput);
63486
+ }
63487
+ async function claudeQuotaAction(jsonOutput) {
63407
63488
  const service = new QuotaService();
63408
63489
  const quota = await service.fetchOnce();
63409
63490
  if (!quota.available) {
@@ -63458,12 +63539,92 @@ async function quotaAction(_opts, cmd) {
63458
63539
  process.stdout.write(` ${source_default.dim("7-Day")} ${makeChalkBar(sevenPct, barWidth)} ${String(sevenPct).padStart(3)}%${sevenProj} ${source_default.dim("resets " + sevenReset)}
63459
63540
  `);
63460
63541
  }
63542
+ async function codexQuotaAction(provider, globalOpts, jsonOutput) {
63543
+ const workspacePath = globalOpts.project || process.cwd();
63544
+ const sessions = provider.findAllSessions(workspacePath);
63545
+ if (sessions.length === 0) {
63546
+ provider.dispose();
63547
+ const msg = "No active Codex session. Rate limits are available only during active sessions.";
63548
+ if (jsonOutput) {
63549
+ process.stdout.write(JSON.stringify({ available: false, error: msg }, null, 2) + "\n");
63550
+ } else {
63551
+ process.stderr.write(source_default.yellow(msg) + "\n");
63552
+ }
63553
+ return;
63554
+ }
63555
+ const captured = { rl: void 0 };
63556
+ try {
63557
+ const result = (0, import_sidekick_shared24.createWatcher)({
63558
+ provider,
63559
+ workspacePath,
63560
+ callbacks: {
63561
+ onEvent: (event) => {
63562
+ if (event.rateLimits) {
63563
+ captured.rl = event.rateLimits;
63564
+ }
63565
+ },
63566
+ onError: () => {
63567
+ }
63568
+ }
63569
+ });
63570
+ result.watcher.start(true);
63571
+ result.watcher.stop();
63572
+ } catch {
63573
+ }
63574
+ provider.dispose();
63575
+ const rateLimits = captured.rl;
63576
+ if (!rateLimits) {
63577
+ const msg = "No rate-limit data found in latest Codex session.";
63578
+ if (jsonOutput) {
63579
+ process.stdout.write(JSON.stringify({ available: false, error: msg }, null, 2) + "\n");
63580
+ } else {
63581
+ process.stderr.write(source_default.yellow(msg) + "\n");
63582
+ }
63583
+ return;
63584
+ }
63585
+ const primary = rateLimits.primary;
63586
+ const secondary = rateLimits.secondary;
63587
+ if (!primary && !secondary) {
63588
+ const msg = "No rate-limit data found in latest Codex session.";
63589
+ if (jsonOutput) {
63590
+ process.stdout.write(JSON.stringify({ available: false, error: msg }, null, 2) + "\n");
63591
+ } else {
63592
+ process.stderr.write(source_default.yellow(msg) + "\n");
63593
+ }
63594
+ return;
63595
+ }
63596
+ const quota = {
63597
+ fiveHour: primary ? { utilization: primary.usedPercent, resetsAt: new Date(primary.resetsAt * 1e3).toISOString() } : { utilization: 0, resetsAt: "" },
63598
+ sevenDay: secondary ? { utilization: secondary.usedPercent, resetsAt: new Date(secondary.resetsAt * 1e3).toISOString() } : { utilization: 0, resetsAt: "" },
63599
+ available: true
63600
+ };
63601
+ if (jsonOutput) {
63602
+ process.stdout.write(JSON.stringify(quota, null, 2) + "\n");
63603
+ return;
63604
+ }
63605
+ const barWidth = 30;
63606
+ const fivePct = Math.round(quota.fiveHour.utilization);
63607
+ const sevenPct = Math.round(quota.sevenDay.utilization);
63608
+ const fiveReset = quota.fiveHour.resetsAt ? formatTimeUntil(quota.fiveHour.resetsAt) : "";
63609
+ const sevenReset = quota.sevenDay.resetsAt ? formatTimeUntil(quota.sevenDay.resetsAt) : "";
63610
+ process.stdout.write(source_default.bold("Rate Limits\n"));
63611
+ process.stdout.write(source_default.dim("\u2500".repeat(50) + "\n"));
63612
+ if (primary) {
63613
+ process.stdout.write(` ${source_default.dim("Primary")} ${makeChalkBar(fivePct, barWidth)} ${String(fivePct).padStart(3)}% ${fiveReset ? source_default.dim("resets " + fiveReset) : ""}
63614
+ `);
63615
+ }
63616
+ if (secondary) {
63617
+ process.stdout.write(` ${source_default.dim("Secondary")} ${makeChalkBar(sevenPct, barWidth - 1)} ${String(sevenPct).padStart(3)}% ${sevenReset ? source_default.dim("resets " + sevenReset) : ""}
63618
+ `);
63619
+ }
63620
+ }
63461
63621
  var import_sidekick_shared24;
63462
63622
  var init_quota = __esm({
63463
63623
  "src/commands/quota.ts"() {
63464
63624
  "use strict";
63465
63625
  init_source();
63466
63626
  import_sidekick_shared24 = __toESM(require_dist(), 1);
63627
+ init_cli();
63467
63628
  init_QuotaService();
63468
63629
  }
63469
63630
  });
@@ -63473,22 +63634,17 @@ var status_exports = {};
63473
63634
  __export(status_exports, {
63474
63635
  statusAction: () => statusAction
63475
63636
  });
63476
- async function statusAction(_opts, cmd) {
63477
- const globalOpts = cmd.parent.opts();
63478
- const jsonOutput = !!globalOpts.json;
63479
- const status = await (0, import_sidekick_shared25.fetchProviderStatus)();
63480
- if (jsonOutput) {
63481
- process.stdout.write(JSON.stringify(status, null, 2) + "\n");
63482
- return;
63483
- }
63637
+ function printStatus(label, statusPageHost, status) {
63484
63638
  const indicatorColor = status.indicator === "none" ? source_default.green : status.indicator === "minor" ? source_default.yellow : source_default.red;
63485
63639
  const indicatorLabel = status.indicator === "none" ? "\u25CF" : status.indicator === "minor" ? "\u25D0" : "\u25CF";
63486
- process.stdout.write(source_default.bold("Claude API Status\n"));
63640
+ process.stdout.write(source_default.bold(`${label}
63641
+ `));
63487
63642
  process.stdout.write(source_default.dim("\u2500".repeat(50) + "\n"));
63488
63643
  process.stdout.write(` ${indicatorColor(indicatorLabel)} ${indicatorColor(status.description || status.indicator)}
63489
63644
  `);
63490
63645
  if (status.description === "Status unavailable") {
63491
- process.stdout.write(source_default.dim(" Could not reach status.claude.com\n"));
63646
+ process.stdout.write(source_default.dim(` Could not reach ${statusPageHost}
63647
+ `));
63492
63648
  return;
63493
63649
  }
63494
63650
  if (status.affectedComponents.length > 0) {
@@ -63513,6 +63669,21 @@ async function statusAction(_opts, cmd) {
63513
63669
  }
63514
63670
  }
63515
63671
  }
63672
+ async function statusAction(_opts, cmd) {
63673
+ const globalOpts = cmd.parent.opts();
63674
+ const jsonOutput = !!globalOpts.json;
63675
+ const [claude, openai] = await Promise.all([
63676
+ (0, import_sidekick_shared25.fetchProviderStatus)(),
63677
+ (0, import_sidekick_shared25.fetchOpenAIStatus)()
63678
+ ]);
63679
+ if (jsonOutput) {
63680
+ process.stdout.write(JSON.stringify({ claude, openai }, null, 2) + "\n");
63681
+ return;
63682
+ }
63683
+ printStatus("Claude API Status", "status.claude.com", claude);
63684
+ process.stdout.write("\n");
63685
+ printStatus("OpenAI API Status", "status.openai.com", openai);
63686
+ }
63516
63687
  var import_sidekick_shared25;
63517
63688
  var init_status = __esm({
63518
63689
  "src/commands/status.ts"() {
@@ -63717,7 +63888,7 @@ var init_cli = __esm({
63717
63888
  import_sidekick_shared28 = __toESM(require_dist(), 1);
63718
63889
  import_sidekick_shared29 = __toESM(require_dist(), 1);
63719
63890
  program2 = new Command();
63720
- program2.name("sidekick").description("Query Sidekick project intelligence from the command line").version("0.14.2").option("--json", "Output as JSON").option("--project <path>", "Override project path (default: cwd)").option("--provider <id>", "Provider: claude-code, opencode, codex, auto (default: auto)");
63891
+ program2.name("sidekick").description("Query Sidekick project intelligence from the command line").version("0.15.2").option("--json", "Output as JSON").option("--project <path>", "Override project path (default: cwd)").option("--provider <id>", "Provider: claude-code, opencode, codex, auto (default: auto)");
63721
63892
  dashCmd = new Command("dashboard").description("Full-screen TUI dashboard with live session metrics").option("--session <id>", "Follow a specific session (default: most recent)").option("--replay", "Replay existing events before streaming new ones").action(async (_opts, cmd) => {
63722
63893
  const { dashboardAction: dashboardAction2 } = await init_dashboard().then(() => dashboard_exports);
63723
63894
  return dashboardAction2(_opts, cmd);
@@ -63764,12 +63935,12 @@ var init_cli = __esm({
63764
63935
  return statsAction2(_opts, cmd);
63765
63936
  });
63766
63937
  program2.addCommand(statsCmd);
63767
- quotaCmd = new Command("quota").description("Show subscription quota utilization (Claude Max / Claude Code)").action(async (_opts, cmd) => {
63938
+ quotaCmd = new Command("quota").description("Show quota or rate-limit utilization (auto-detects provider)").option("--provider <id>", "Provider: claude-code, codex, auto (default: auto)").action(async (_opts, cmd) => {
63768
63939
  const { quotaAction: quotaAction2 } = await Promise.resolve().then(() => (init_quota(), quota_exports));
63769
63940
  return quotaAction2(_opts, cmd);
63770
63941
  });
63771
63942
  program2.addCommand(quotaCmd);
63772
- statusCmd = new Command("status").description("Show Claude API status (from status.claude.com)").action(async (_opts, cmd) => {
63943
+ statusCmd = new Command("status").description("Show API status (Claude and OpenAI)").action(async (_opts, cmd) => {
63773
63944
  const { statusAction: statusAction2 } = await Promise.resolve().then(() => (init_status(), status_exports));
63774
63945
  return statusAction2(_opts, cmd);
63775
63946
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sidekick-agent-hub",
3
- "version": "0.14.2",
3
+ "version": "0.15.2",
4
4
  "description": "Terminal dashboard for monitoring AI coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {