sidekick-agent-hub 0.12.7 → 0.12.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/sidekick-cli.mjs +422 -331
  2. package/package.json +1 -1
@@ -17997,7 +17997,7 @@ var init_UpdateCheckService = __esm({
17997
17997
  /** Run the update check (one-shot). */
17998
17998
  async check() {
17999
17999
  try {
18000
- const current = "0.12.7";
18000
+ const current = "0.12.8";
18001
18001
  const cached = this.readCache();
18002
18002
  let latest;
18003
18003
  if (cached && Date.now() - cached.checkedAt < CACHE_TTL_MS) {
@@ -18102,6 +18102,28 @@ function formatElapsed(startTime) {
18102
18102
  const s = secs % 60;
18103
18103
  return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
18104
18104
  }
18105
+ function sectionHeader(title, width = 40) {
18106
+ const prefix = "\u2500\u2500 ";
18107
+ const suffix = " ";
18108
+ const fillLen = Math.max(0, width - prefix.length - title.length - suffix.length);
18109
+ const fill = "\u2500".repeat(fillLen);
18110
+ return `{grey-fg}${prefix}{/grey-fg}{bold}${title}{/bold}{grey-fg}${suffix}${fill}{/grey-fg}`;
18111
+ }
18112
+ function makeColorBar(percent, width, color = "green") {
18113
+ const clamped = Math.max(0, Math.min(100, percent));
18114
+ const filled = Math.round(clamped / 100 * width);
18115
+ const empty = width - filled;
18116
+ return `{${color}-fg}${"\u2588".repeat(filled)}{/${color}-fg}{grey-fg}${"\u2591".repeat(empty)}{/grey-fg}`;
18117
+ }
18118
+ function makeSparkline(data, maxWidth = 25) {
18119
+ const trimmed = data.slice(-maxWidth);
18120
+ if (trimmed.length === 0) return { spark: "", max: 0, latest: 0 };
18121
+ const max = Math.max(...trimmed, 1);
18122
+ const latest = trimmed[trimmed.length - 1];
18123
+ const chars = [" ", "\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
18124
+ const spark = trimmed.map((v) => chars[Math.min(8, Math.round(v / max * 8))]).join("");
18125
+ return { spark, max, latest };
18126
+ }
18105
18127
  function makeBar(percent, width) {
18106
18128
  const clamped = Math.max(0, Math.min(100, percent));
18107
18129
  const filled = Math.round(clamped / 100 * width);
@@ -19219,7 +19241,7 @@ function renderContextAttribution(attr) {
19219
19241
  const total = categories.reduce((sum, c) => sum + c.tokens, 0);
19220
19242
  if (total === 0) return [];
19221
19243
  const barWidth = 30;
19222
- const lines = ["{bold}Context Attribution{/bold}", ""];
19244
+ const lines = [sectionHeader("Context Attribution", 40), ""];
19223
19245
  let bar = " ";
19224
19246
  for (const cat of categories) {
19225
19247
  if (cat.tokens === 0) continue;
@@ -19251,6 +19273,7 @@ var init_SessionsPanel = __esm({
19251
19273
  id = "sessions";
19252
19274
  title = "Sessions";
19253
19275
  shortcutKey = 1;
19276
+ emptyStateHint = "Start an agent session in another terminal.";
19254
19277
  mindMapView = "tree";
19255
19278
  mindMapFilter = "all";
19256
19279
  diffCache;
@@ -19436,75 +19459,67 @@ ${hint}{/grey-fg}`;
19436
19459
  const t = m.tokens;
19437
19460
  const c = m.context;
19438
19461
  const contextColor = getUtilizationColor(c.percent);
19439
- const barWidth = 30;
19440
- const filled = Math.round(c.percent / 100 * barWidth);
19441
- const empty = barWidth - filled;
19442
- const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
19462
+ const w2 = detailWidth();
19443
19463
  const elapsed = m.sessionStartTime ? formatElapsed(m.sessionStartTime) : "--:--:--";
19444
- const burnData = m.burnRate.length > 0 ? m.burnRate : [0];
19445
- const latest = burnData[burnData.length - 1];
19446
- const max = Math.max(...burnData, 1);
19447
- const chars = [" ", "\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
19448
- const spark = burnData.slice(-25).map((v) => chars[Math.min(8, Math.round(v / max * 8))]).join("");
19449
- const runningAgents = m.subagents.filter((a) => a.status === "running").length;
19450
- const completedAgents = m.subagents.filter((a) => a.status === "completed").length;
19451
- const agentSummary = m.subagents.length > 0 ? `${m.subagents.length} (${runningAgents} running, ${completedAgents} done)` : "0";
19452
19464
  const recentEvent = [...m.timeline].reverse().find(
19453
19465
  (e) => e.type !== "user" && e.type !== "tool_result"
19454
19466
  );
19455
19467
  const recentLine = recentEvent ? (() => {
19456
19468
  const prefix = `[${formatTime(recentEvent.timestamp)}] ${recentEvent.type.padEnd(12)} `;
19457
- const maxSummary = Math.max(20, detailWidth() - prefix.length);
19469
+ const maxSummary = Math.max(20, w2 - prefix.length);
19458
19470
  return `{yellow-fg}${prefix}${truncate(recentEvent.summary || "", maxSummary)}{/yellow-fg}`;
19459
19471
  })() : "{grey-fg}(no events yet){/grey-fg}";
19472
+ const compactionSuffix = m.compactionCount > 0 ? ` {bold}${m.compactionCount}{/bold}{grey-fg} compaction${m.compactionCount !== 1 ? "s" : ""}{/grey-fg}` : "";
19460
19473
  const lines = [
19461
- "{bold}Active Session{/bold}",
19462
- recentLine,
19463
- "",
19464
- `{bold}Elapsed:{/bold} ${elapsed}`,
19465
- `{bold}Provider:{/bold} ${m.providerName || "unknown"}`,
19466
- `{bold}Model:{/bold} ${m.currentModel || "unknown"}`,
19467
- `{bold}Events:{/bold} ${m.eventCount}`,
19468
- `{bold}Compactions:{/bold} ${m.compactionCount}`,
19469
- `{bold}Subagents:{/bold} ${agentSummary}`,
19470
- "",
19471
- "{bold}Tokens{/bold}",
19472
- ` Input: ${fmtNum(t.input)}`,
19473
- ` Output: ${fmtNum(t.output)}`,
19474
- ` Cache Read: ${fmtNum(t.cacheRead)}`,
19475
- ` Cache Write: ${fmtNum(t.cacheWrite)}`,
19476
- ...t.cacheRead + t.input > 0 ? [` Hit Rate: ${(t.cacheRead / (t.cacheRead + t.input) * 100).toFixed(1)}%`] : [],
19477
- ` Cost: {green-fg}$${t.cost.toFixed(4)}{/green-fg}`,
19478
- "",
19479
- "{bold}Context{/bold}",
19480
- ` {${contextColor}-fg}${bar}{/${contextColor}-fg}`,
19481
- ` {bold}${c.percent}%{/bold} ${fmtNum(c.used)} / ${fmtNum(c.limit)}`
19474
+ `{bold}${elapsed}{/bold}{grey-fg} elapsed{/grey-fg} {bold}${m.eventCount}{/bold}{grey-fg} events{/grey-fg}${compactionSuffix}`,
19475
+ `{grey-fg}Provider{/grey-fg} {bold}${m.providerName || "unknown"}{/bold} {grey-fg}Model{/grey-fg} {bold}${m.currentModel || "unknown"}{/bold}`,
19476
+ recentLine
19482
19477
  ];
19483
- if (m.contextTimeline && m.contextTimeline.length > 1) {
19484
- const ctxPoints = m.contextTimeline.slice(-25);
19485
- const ctxMax = Math.max(...ctxPoints.map((p) => p.inputTokens), 1);
19486
- const sparkChars = [" ", "\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
19487
- const ctxSpark = ctxPoints.map((p) => sparkChars[Math.min(8, Math.round(p.inputTokens / ctxMax * 8))]).join("");
19488
- lines.push(` {grey-fg}${ctxSpark}{/grey-fg} history`);
19489
- }
19490
19478
  if (m.permissionMode && m.permissionMode !== "default") {
19491
19479
  const modeColors = { bypassPermissions: "red", acceptEdits: "magenta", plan: "green" };
19492
19480
  const modeLabels = { bypassPermissions: "Bypass Permissions", acceptEdits: "Accept Edits", plan: "Plan Mode" };
19493
19481
  const modeColor = modeColors[m.permissionMode] || "grey";
19494
19482
  const modeLabel = modeLabels[m.permissionMode] || m.permissionMode;
19495
- lines.push("", `{bold}Permission:{/bold} {${modeColor}-fg}${modeLabel}{/${modeColor}-fg}`);
19483
+ lines.push(`{grey-fg}Permission{/grey-fg} {${modeColor}-fg}{bold}${modeLabel}{/bold}{/${modeColor}-fg}`);
19484
+ }
19485
+ if (m.subagents.length > 0) {
19486
+ const runningAgents = m.subagents.filter((a) => a.status === "running").length;
19487
+ const completedAgents = m.subagents.filter((a) => a.status === "completed").length;
19488
+ lines.push(`{grey-fg}Subagents{/grey-fg} {bold}${m.subagents.length}{/bold} ({green-fg}${runningAgents} running{/green-fg}, ${completedAgents} done)`);
19496
19489
  }
19490
+ const cacheRate = t.cacheRead + t.input > 0 ? `{grey-fg}Cache{/grey-fg} {bold}${(t.cacheRead / (t.cacheRead + t.input) * 100).toFixed(1)}%{/bold}` : "";
19491
+ lines.push(
19492
+ "",
19493
+ sectionHeader("Tokens", w2),
19494
+ `{grey-fg}In{/grey-fg} {bold}${fmtNum(t.input)}{/bold} {grey-fg}Out{/grey-fg} {bold}${fmtNum(t.output)}{/bold} ${cacheRate} {green-fg}$${t.cost.toFixed(4)}{/green-fg}`
19495
+ );
19496
+ const contextBar = makeColorBar(c.percent, 30, contextColor);
19497
19497
  lines.push(
19498
19498
  "",
19499
- "{bold}Burn Rate{/bold}",
19500
- ` {cyan-fg}${spark}{/cyan-fg} {bold}${fmtNum(latest)}{/bold} tok/min`
19499
+ sectionHeader("Context", w2),
19500
+ ` ${contextBar} {bold}${c.percent}%{/bold} ${fmtNum(c.used)} / ${fmtNum(c.limit)}`
19501
+ );
19502
+ if (m.contextTimeline && m.contextTimeline.length > 1) {
19503
+ const ctxData = m.contextTimeline.slice(-25).map((p) => p.inputTokens);
19504
+ const ctxSpark = makeSparkline(ctxData);
19505
+ lines.push(` {grey-fg}${ctxSpark.spark}{/grey-fg} {grey-fg}peak ${fmtNum(ctxSpark.max)}{/grey-fg}`);
19506
+ }
19507
+ const burnData = m.burnRate.length > 0 ? m.burnRate : [0];
19508
+ const burnSpark = makeSparkline(burnData);
19509
+ lines.push(
19510
+ "",
19511
+ sectionHeader("Burn Rate", w2),
19512
+ ` {cyan-fg}${burnSpark.spark}{/cyan-fg} {bold}${fmtNum(burnSpark.latest)}{/bold}{grey-fg} tok/min{/grey-fg} {grey-fg}peak ${fmtNum(burnSpark.max)}{/grey-fg}`
19501
19513
  );
19502
19514
  if (m.tasks.length > 0) {
19503
19515
  const completed = m.tasks.filter((t2) => t2.status === "completed").length;
19504
19516
  const active = m.tasks.filter((t2) => t2.status === "in_progress").length;
19505
19517
  const pending = m.tasks.filter((t2) => t2.status === "pending").length;
19506
- lines.push("", "{bold}Tasks{/bold}");
19507
- lines.push(` ${completed}/${m.tasks.length} completed ${active} active ${pending} pending`);
19518
+ lines.push(
19519
+ "",
19520
+ sectionHeader("Tasks", w2),
19521
+ ` {bold}${completed}{/bold}/{m.tasks.length}{grey-fg} completed{/grey-fg} {bold}${active}{/bold}{grey-fg} active{/grey-fg} {bold}${pending}{/bold}{grey-fg} pending{/grey-fg}`
19522
+ );
19508
19523
  }
19509
19524
  const diffStats = this.diffCache?.getStats() ?? /* @__PURE__ */ new Map();
19510
19525
  if (diffStats.size > 0) {
@@ -19513,25 +19528,28 @@ ${hint}{/grey-fg}`;
19513
19528
  totalAdd += s2.additions;
19514
19529
  totalDel += s2.deletions;
19515
19530
  }
19516
- lines.push("", "{bold}File Changes{/bold}");
19517
- lines.push(` ${diffStats.size} files touched {green-fg}+${totalAdd}{/green-fg} {red-fg}-${totalDel}{/red-fg} lines`);
19531
+ lines.push(
19532
+ "",
19533
+ sectionHeader("File Changes", w2),
19534
+ ` {bold}${diffStats.size}{/bold}{grey-fg} files{/grey-fg} {green-fg}+${totalAdd}{/green-fg} {red-fg}-${totalDel}{/red-fg}`
19535
+ );
19518
19536
  }
19519
19537
  if (m.modelStats.length > 0) {
19520
- lines.push("", "{bold}Model Usage{/bold}");
19538
+ lines.push("", sectionHeader("Model Usage", w2));
19521
19539
  for (const ms of m.modelStats) {
19522
19540
  const modelName = ms.model.length > 20 ? ms.model.substring(0, 17) + "..." : ms.model;
19523
- lines.push(` ${modelName.padEnd(20)} ${String(ms.calls).padStart(4)} calls {green-fg}$${ms.cost.toFixed(4)}{/green-fg}`);
19541
+ 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}`);
19524
19542
  }
19525
19543
  }
19526
19544
  if (m.quota?.available) {
19527
19545
  const q = m.quota;
19528
- lines.push("", "{bold}Quota{/bold}");
19546
+ lines.push("", sectionHeader("Quota", w2));
19529
19547
  const fiveColor = getUtilizationColor(q.fiveHour.utilization);
19530
- const fiveBar = makeBar(q.fiveHour.utilization, 18);
19531
- lines.push(` 5h: {${fiveColor}-fg}${fiveBar}{/${fiveColor}-fg} ${q.fiveHour.utilization.toFixed(0)}%`);
19548
+ const fiveBar = makeColorBar(q.fiveHour.utilization, 18, fiveColor);
19549
+ lines.push(` {grey-fg}5h{/grey-fg} ${fiveBar} {bold}${q.fiveHour.utilization.toFixed(0)}%{/bold}`);
19532
19550
  const sevenColor = getUtilizationColor(q.sevenDay.utilization);
19533
- const sevenBar = makeBar(q.sevenDay.utilization, 18);
19534
- lines.push(` 7d: {${sevenColor}-fg}${sevenBar}{/${sevenColor}-fg} ${q.sevenDay.utilization.toFixed(0)}%`);
19551
+ const sevenBar = makeColorBar(q.sevenDay.utilization, 18, sevenColor);
19552
+ lines.push(` {grey-fg}7d{/grey-fg} ${sevenBar} {bold}${q.sevenDay.utilization.toFixed(0)}%{/bold}`);
19535
19553
  }
19536
19554
  const attrLines = renderContextAttribution(m.contextAttribution);
19537
19555
  if (attrLines.length > 0) {
@@ -19540,21 +19558,18 @@ ${hint}{/grey-fg}`;
19540
19558
  return lines.join("\n");
19541
19559
  }
19542
19560
  const s = d.session;
19561
+ const w = detailWidth();
19543
19562
  const totalTokens = s.inputTokens + s.outputTokens;
19544
19563
  return [
19545
- `{bold}${s.date}{/bold}`,
19564
+ `{bold}${s.date}{/bold} {bold}${s.sessionCount}{/bold}{grey-fg} sessions{/grey-fg} {bold}${s.messageCount}{/bold}{grey-fg} messages{/grey-fg}`,
19565
+ `{grey-fg}Tokens{/grey-fg} {bold}${fmtNum(totalTokens)}{/bold} ({grey-fg}In{/grey-fg} ${fmtNum(s.inputTokens)} {grey-fg}Out{/grey-fg} ${fmtNum(s.outputTokens)}) {green-fg}$${s.totalCost.toFixed(4)}{/green-fg}`,
19546
19566
  "",
19547
- `{bold}Sessions:{/bold} ${s.sessionCount}`,
19548
- `{bold}Tokens:{/bold} ${fmtNum(totalTokens)} (${fmtNum(s.inputTokens)} in / ${fmtNum(s.outputTokens)} out)`,
19549
- `{bold}Cost:{/bold} {green-fg}$${s.totalCost.toFixed(4)}{/green-fg}`,
19550
- `{bold}Messages:{/bold} ${s.messageCount}`,
19567
+ sectionHeader("Models", w),
19568
+ ...s.modelUsage.map((u) => ` ${u.model}: {bold}${u.calls}{/bold} calls`),
19551
19569
  "",
19552
- "{bold}Models{/bold}",
19553
- ...s.modelUsage.map((u) => ` ${u.model}: ${u.calls} calls`),
19554
- "",
19555
- "{bold}Tools{/bold}",
19570
+ sectionHeader("Tools", w),
19556
19571
  ...s.toolUsage.sort((a, b) => b.calls - a.calls).slice(0, 10).map(
19557
- (u) => ` ${u.tool.padEnd(16)} ${u.calls} calls`
19572
+ (u) => ` ${u.tool.padEnd(16)} {bold}${u.calls}{/bold} calls`
19558
19573
  )
19559
19574
  ].join("\n");
19560
19575
  }
@@ -19688,10 +19703,10 @@ ${hint}{/grey-fg}`;
19688
19703
  const running = agents.filter((a) => a.status === "running").length;
19689
19704
  const completed = agents.filter((a) => a.status === "completed").length;
19690
19705
  const parallel = agents.filter((a) => a.isParallel).length;
19706
+ const w = detailWidth();
19691
19707
  const lines = [
19692
- "{bold}Subagents{/bold}",
19693
- "",
19694
- ` Total: ${agents.length} Running: {green-fg}${running}{/green-fg} Completed: {cyan-fg}${completed}{/cyan-fg}` + (parallel > 0 ? ` Parallel: {magenta-fg}${parallel}{/magenta-fg}` : ""),
19708
+ sectionHeader("Subagents", w),
19709
+ ` {bold}${agents.length}{/bold}{grey-fg} total{/grey-fg} {green-fg}{bold}${running}{/bold} running{/green-fg} {cyan-fg}{bold}${completed}{/bold} done{/cyan-fg}` + (parallel > 0 ? ` {magenta-fg}{bold}${parallel}{/bold} parallel{/magenta-fg}` : ""),
19695
19710
  ""
19696
19711
  ];
19697
19712
  for (const a of agents) {
@@ -19713,7 +19728,7 @@ ${hint}{/grey-fg}`;
19713
19728
  }
19714
19729
  const subagentTasks = metrics.tasks.filter((t) => t.subagentType);
19715
19730
  if (subagentTasks.length > 0) {
19716
- lines.push("", "{bold}Tasks from Subagents{/bold}", "");
19731
+ lines.push("", sectionHeader("Tasks from Subagents", w), "");
19717
19732
  for (const t of subagentTasks) {
19718
19733
  const statusIcon = t.status === "completed" ? "\u2713" : t.status === "in_progress" ? "\u2192" : "\u25CB";
19719
19734
  const taskPrefix = ` ${statusIcon} ${t.subagentType} #${t.taskId}: `;
@@ -19756,6 +19771,7 @@ var init_TasksPanel = __esm({
19756
19771
  id = "tasks";
19757
19772
  title = "Tasks";
19758
19773
  shortcutKey = 2;
19774
+ emptyStateHint = "Tasks appear as your agent works.";
19759
19775
  detailTabs = [
19760
19776
  { label: "Detail", render: (item, m) => this.renderDetail(item, m) }
19761
19777
  ];
@@ -19851,6 +19867,7 @@ var init_KanbanPanel = __esm({
19851
19867
  id = "kanban";
19852
19868
  title = "Kanban";
19853
19869
  shortcutKey = 3;
19870
+ emptyStateHint = "Task board populates from active sessions.";
19854
19871
  detailTabs = [
19855
19872
  { label: "Board", render: (item, m) => this.renderBoard(item, m) }
19856
19873
  ];
@@ -19966,6 +19983,7 @@ var init_NotesPanel = __esm({
19966
19983
  id = "notes";
19967
19984
  title = "Notes";
19968
19985
  shortcutKey = 4;
19986
+ emptyStateHint = "Knowledge notes saved by your agent appear here.";
19969
19987
  detailTabs = [
19970
19988
  { label: "Content", render: (item) => this.renderContent(item) },
19971
19989
  { label: "Related", render: (item, _m, sd) => this.renderRelated(item, sd) }
@@ -20038,6 +20056,7 @@ var init_DecisionsPanel = __esm({
20038
20056
  id = "decisions";
20039
20057
  title = "Decisions";
20040
20058
  shortcutKey = 5;
20059
+ emptyStateHint = "Decisions logged by your agent show up here.";
20041
20060
  detailTabs = [
20042
20061
  { label: "Detail", render: (item) => this.renderDetail(item) }
20043
20062
  ];
@@ -20123,6 +20142,7 @@ var init_PlansPanel = __esm({
20123
20142
  id = "plans";
20124
20143
  title = "Plans";
20125
20144
  shortcutKey = 6;
20145
+ emptyStateHint = "Plans created by your agent appear here.";
20126
20146
  sourceFilter = "all";
20127
20147
  detailTabs = [
20128
20148
  { label: "Steps", render: (item) => this.renderSteps(item) },
@@ -31205,14 +31225,14 @@ var require_react_reconciler_production = __commonJS({
31205
31225
  }
31206
31226
  var exports2 = {};
31207
31227
  "use strict";
31208
- var React15 = require_react(), Scheduler2 = require_scheduler(), assign = Object.assign, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy");
31228
+ var React16 = require_react(), Scheduler2 = require_scheduler(), assign = Object.assign, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy");
31209
31229
  Symbol.for("react.scope");
31210
31230
  var REACT_ACTIVITY_TYPE = Symbol.for("react.activity");
31211
31231
  Symbol.for("react.legacy_hidden");
31212
31232
  Symbol.for("react.tracing_marker");
31213
31233
  var REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
31214
31234
  Symbol.for("react.view_transition");
31215
- var MAYBE_ITERATOR_SYMBOL = Symbol.iterator, REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), isArrayImpl = Array.isArray, ReactSharedInternals = React15.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, rendererVersion = $$$config.rendererVersion, rendererPackageName = $$$config.rendererPackageName, extraDevToolsConfig = $$$config.extraDevToolsConfig, getPublicInstance = $$$config.getPublicInstance, getRootHostContext = $$$config.getRootHostContext, getChildHostContext = $$$config.getChildHostContext, prepareForCommit = $$$config.prepareForCommit, resetAfterCommit = $$$config.resetAfterCommit, createInstance = $$$config.createInstance;
31235
+ var MAYBE_ITERATOR_SYMBOL = Symbol.iterator, REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), isArrayImpl = Array.isArray, ReactSharedInternals = React16.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, rendererVersion = $$$config.rendererVersion, rendererPackageName = $$$config.rendererPackageName, extraDevToolsConfig = $$$config.extraDevToolsConfig, getPublicInstance = $$$config.getPublicInstance, getRootHostContext = $$$config.getRootHostContext, getChildHostContext = $$$config.getChildHostContext, prepareForCommit = $$$config.prepareForCommit, resetAfterCommit = $$$config.resetAfterCommit, createInstance = $$$config.createInstance;
31216
31236
  $$$config.cloneMutableInstance;
31217
31237
  var appendInitialChild = $$$config.appendInitialChild, finalizeInitialChildren = $$$config.finalizeInitialChildren, shouldSetTextContent = $$$config.shouldSetTextContent, createTextInstance = $$$config.createTextInstance;
31218
31238
  $$$config.cloneMutableTextInstance;
@@ -43805,14 +43825,14 @@ var require_react_reconciler_development = __commonJS({
43805
43825
  }
43806
43826
  var exports2 = {};
43807
43827
  "use strict";
43808
- var React15 = require_react(), Scheduler2 = require_scheduler(), assign = Object.assign, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy");
43828
+ var React16 = require_react(), Scheduler2 = require_scheduler(), assign = Object.assign, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy");
43809
43829
  Symbol.for("react.scope");
43810
43830
  var REACT_ACTIVITY_TYPE = Symbol.for("react.activity");
43811
43831
  Symbol.for("react.legacy_hidden");
43812
43832
  Symbol.for("react.tracing_marker");
43813
43833
  var REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
43814
43834
  Symbol.for("react.view_transition");
43815
- var MAYBE_ITERATOR_SYMBOL = Symbol.iterator, REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), isArrayImpl = Array.isArray, ReactSharedInternals = React15.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, rendererVersion = $$$config.rendererVersion, rendererPackageName = $$$config.rendererPackageName, extraDevToolsConfig = $$$config.extraDevToolsConfig, getPublicInstance = $$$config.getPublicInstance, getRootHostContext = $$$config.getRootHostContext, getChildHostContext = $$$config.getChildHostContext, prepareForCommit = $$$config.prepareForCommit, resetAfterCommit = $$$config.resetAfterCommit, createInstance = $$$config.createInstance;
43835
+ var MAYBE_ITERATOR_SYMBOL = Symbol.iterator, REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), isArrayImpl = Array.isArray, ReactSharedInternals = React16.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, rendererVersion = $$$config.rendererVersion, rendererPackageName = $$$config.rendererPackageName, extraDevToolsConfig = $$$config.extraDevToolsConfig, getPublicInstance = $$$config.getPublicInstance, getRootHostContext = $$$config.getRootHostContext, getChildHostContext = $$$config.getChildHostContext, prepareForCommit = $$$config.prepareForCommit, resetAfterCommit = $$$config.resetAfterCommit, createInstance = $$$config.createInstance;
43816
43836
  $$$config.cloneMutableInstance;
43817
43837
  var appendInitialChild = $$$config.appendInitialChild, finalizeInitialChildren = $$$config.finalizeInitialChildren, shouldSetTextContent = $$$config.shouldSetTextContent, createTextInstance = $$$config.createTextInstance;
43818
43838
  $$$config.cloneMutableTextInstance;
@@ -57472,18 +57492,18 @@ var require_react_jsx_runtime_development = __commonJS({
57472
57492
  function isValidElement(object) {
57473
57493
  return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
57474
57494
  }
57475
- var React15 = require_react(), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React15.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
57495
+ var React16 = require_react(), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React16.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
57476
57496
  return null;
57477
57497
  };
57478
- React15 = {
57498
+ React16 = {
57479
57499
  react_stack_bottom_frame: function(callStackForError) {
57480
57500
  return callStackForError();
57481
57501
  }
57482
57502
  };
57483
57503
  var specialPropKeyWarningShown;
57484
57504
  var didWarnAboutElementRef = {};
57485
- var unknownOwnerDebugStack = React15.react_stack_bottom_frame.bind(
57486
- React15,
57505
+ var unknownOwnerDebugStack = React16.react_stack_bottom_frame.bind(
57506
+ React16,
57487
57507
  UnknownOwner
57488
57508
  )();
57489
57509
  var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
@@ -57528,9 +57548,29 @@ var require_jsx_runtime = __commonJS({
57528
57548
  });
57529
57549
 
57530
57550
  // src/dashboard/ink/SessionPickerInk.tsx
57551
+ function buildGroupedRows(items) {
57552
+ const providerIds = new Set(items.map((it) => it.providerId).filter(Boolean));
57553
+ if (providerIds.size <= 1) return null;
57554
+ const rows = [];
57555
+ const grouped = /* @__PURE__ */ new Map();
57556
+ for (let i = 0; i < items.length; i++) {
57557
+ const pid = items[i].providerId || "unknown";
57558
+ if (!grouped.has(pid)) grouped.set(pid, []);
57559
+ grouped.get(pid).push(i);
57560
+ }
57561
+ for (const [pid, indices] of grouped) {
57562
+ rows.push({ type: "header", providerId: pid });
57563
+ for (const idx of indices) {
57564
+ rows.push({ type: "item", index: idx });
57565
+ }
57566
+ }
57567
+ rows.push({ type: "item", index: items.length });
57568
+ return { rows, selectableCount: items.length + 1 };
57569
+ }
57531
57570
  function SessionPickerInk({ items, onSelect }) {
57532
57571
  const [selectedIndex, setSelectedIndex] = (0, import_react29.useState)(0);
57533
57572
  const { exit } = use_app_default();
57573
+ const grouped = buildGroupedRows(items);
57534
57574
  const totalItems = items.length + 1;
57535
57575
  use_input_default((input, key) => {
57536
57576
  if (input === "q" || key.escape || key.ctrl && input === "c") {
@@ -57556,9 +57596,88 @@ function SessionPickerInk({ items, onSelect }) {
57556
57596
  });
57557
57597
  const rows = process.stdout.rows || 24;
57558
57598
  const viewportHeight = Math.max(5, rows - 15);
57559
- const scrollOffset = Math.max(0, Math.min(selectedIndex - Math.floor(viewportHeight / 2), totalItems - viewportHeight));
57560
- const visibleStart = Math.max(0, scrollOffset);
57561
- const visibleEnd = Math.min(totalItems, visibleStart + viewportHeight);
57599
+ function renderSessionRow(i, isSelected) {
57600
+ if (i === items.length) {
57601
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { inverse: isSelected, children: [
57602
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "yellow", children: "+" }),
57603
+ " Wait for a new session to start..."
57604
+ ] }) }, "wait");
57605
+ }
57606
+ const item = items[i];
57607
+ const dot = item.isActive ? "\u25CF" : "\u25CB";
57608
+ const dotColor = item.isActive ? "green" : "gray";
57609
+ const badge = item.providerId ? PROVIDER_BADGES[item.providerId] : null;
57610
+ const truncLabel = item.label.length > 40 ? item.label.substring(0, 37) + "..." : item.label;
57611
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { inverse: isSelected, children: [
57612
+ badge && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: badge.color, children: [
57613
+ "[",
57614
+ badge.badge,
57615
+ "]"
57616
+ ] }),
57617
+ " ",
57618
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: dotColor, children: dot }),
57619
+ " ",
57620
+ truncLabel.padEnd(40),
57621
+ " ",
57622
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: item.age.padEnd(9) }),
57623
+ " ",
57624
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: item.sessionId }),
57625
+ item.isActive ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "green", children: " LIVE" }) : ""
57626
+ ] }) }, item.sessionPath);
57627
+ }
57628
+ function renderList() {
57629
+ if (grouped) {
57630
+ const allRows = grouped.rows;
57631
+ let selectableIdx = 0;
57632
+ const selectablePositions = [];
57633
+ for (let r = 0; r < allRows.length; r++) {
57634
+ if (allRows[r].type === "item") selectablePositions.push(r);
57635
+ }
57636
+ const selectedVisualPos = selectablePositions[selectedIndex] ?? 0;
57637
+ const scrollOffset2 = Math.max(0, Math.min(selectedVisualPos - Math.floor(viewportHeight / 2), allRows.length - viewportHeight));
57638
+ const visibleStart2 = Math.max(0, scrollOffset2);
57639
+ const visibleEnd2 = Math.min(allRows.length, visibleStart2 + viewportHeight);
57640
+ const elements = [];
57641
+ selectableIdx = 0;
57642
+ for (let r = 0; r < allRows.length; r++) {
57643
+ if (r < visibleStart2 || r >= visibleEnd2) {
57644
+ if (allRows[r].type === "item") selectableIdx++;
57645
+ continue;
57646
+ }
57647
+ const row = allRows[r];
57648
+ if (row.type === "header") {
57649
+ const name = PROVIDER_NAMES[row.providerId] || row.providerId;
57650
+ const badge = PROVIDER_BADGES[row.providerId];
57651
+ elements.push(
57652
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { children: [
57653
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { dimColor: true, children: [
57654
+ "\u2500\u2500",
57655
+ " "
57656
+ ] }),
57657
+ badge && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: badge.color, children: name }),
57658
+ !badge && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: name }),
57659
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { dimColor: true, children: [
57660
+ " ",
57661
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
57662
+ ] })
57663
+ ] }, `hdr-${row.providerId}`)
57664
+ );
57665
+ } else {
57666
+ const isSelected = selectableIdx === selectedIndex;
57667
+ elements.push(renderSessionRow(row.index, isSelected));
57668
+ selectableIdx++;
57669
+ }
57670
+ }
57671
+ return elements;
57672
+ }
57673
+ const scrollOffset = Math.max(0, Math.min(selectedIndex - Math.floor(viewportHeight / 2), totalItems - viewportHeight));
57674
+ const visibleStart = Math.max(0, scrollOffset);
57675
+ const visibleEnd = Math.min(totalItems, visibleStart + viewportHeight);
57676
+ return Array.from({ length: visibleEnd - visibleStart }, (_, vi) => {
57677
+ const i = visibleStart + vi;
57678
+ return renderSessionRow(i, i === selectedIndex);
57679
+ });
57680
+ }
57562
57681
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", width: "100%", height: rows, children: [
57563
57682
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { justifyContent: "center", marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", width: 50, children: [
57564
57683
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, color: "magenta", children: " S I D E K I C K" }),
@@ -57578,37 +57697,7 @@ function SessionPickerInk({ items, onSelect }) {
57578
57697
  items.length,
57579
57698
  ") "
57580
57699
  ] }),
57581
- Array.from({ length: visibleEnd - visibleStart }, (_, vi) => {
57582
- const i = visibleStart + vi;
57583
- const isSelected = i === selectedIndex;
57584
- if (i === items.length) {
57585
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { inverse: isSelected, children: [
57586
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "yellow", children: "+" }),
57587
- " Wait for a new session to start..."
57588
- ] }) }, "wait");
57589
- }
57590
- const item = items[i];
57591
- const dot = item.isActive ? "\u25CF" : "\u25CB";
57592
- const dotColor = item.isActive ? "green" : "gray";
57593
- const badge = item.providerId ? PROVIDER_BADGES[item.providerId] : null;
57594
- const truncLabel = item.label.length > 40 ? item.label.substring(0, 37) + "..." : item.label;
57595
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { inverse: isSelected, children: [
57596
- badge && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: badge.color, children: [
57597
- "[",
57598
- badge.badge,
57599
- "]"
57600
- ] }),
57601
- " ",
57602
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: dotColor, children: dot }),
57603
- " ",
57604
- truncLabel.padEnd(40),
57605
- " ",
57606
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: item.age.padEnd(9) }),
57607
- " ",
57608
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: item.sessionId }),
57609
- item.isActive ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "green", children: " LIVE" }) : ""
57610
- ] }) }, item.sessionPath);
57611
- })
57700
+ renderList()
57612
57701
  ]
57613
57702
  }
57614
57703
  ),
@@ -57618,7 +57707,11 @@ function SessionPickerInk({ items, onSelect }) {
57618
57707
  " ",
57619
57708
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: "Session Picker" }),
57620
57709
  " ",
57621
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, children: "\u2191/\u2193" }),
57710
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { bold: true, children: [
57711
+ "\u2191",
57712
+ "/",
57713
+ "\u2193"
57714
+ ] }),
57622
57715
  " navigate ",
57623
57716
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, children: "Enter" }),
57624
57717
  " select ",
@@ -57658,7 +57751,7 @@ async function showSessionPicker(provider, workspacePath, additionalProviders) {
57658
57751
  }).catch(reject);
57659
57752
  });
57660
57753
  }
57661
- var import_react29, import_jsx_runtime;
57754
+ var import_react29, import_jsx_runtime, PROVIDER_NAMES;
57662
57755
  var init_SessionPickerInk = __esm({
57663
57756
  async "src/dashboard/ink/SessionPickerInk.tsx"() {
57664
57757
  "use strict";
@@ -57666,6 +57759,11 @@ var init_SessionPickerInk = __esm({
57666
57759
  await init_build2();
57667
57760
  init_SessionPickerHelpers();
57668
57761
  import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
57762
+ PROVIDER_NAMES = {
57763
+ "claude-code": "Claude Code",
57764
+ "opencode": "OpenCode",
57765
+ "codex": "Codex"
57766
+ };
57669
57767
  }
57670
57768
  });
57671
57769
 
@@ -57809,27 +57907,27 @@ var init_useWindowedScroll = __esm({
57809
57907
  // src/dashboard/ink/TabBar.tsx
57810
57908
  function TabBar({ panels, activeIndex, layoutMode }) {
57811
57909
  const modeLabel = MODE_LABELS[layoutMode] || layoutMode;
57812
- const modeColor = MODE_COLORS[layoutMode] || "gray";
57813
57910
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { height: 1, width: "100%", children: [
57814
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { flexGrow: 1, children: panels.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { marginRight: 1, children: i === activeIndex ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { bold: true, color: "magenta", children: [
57815
- "[",
57911
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { flexGrow: 1, children: panels.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { marginRight: 1, children: i === activeIndex ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { bold: true, underline: true, color: "magenta", children: [
57816
57912
  p.shortcutKey,
57817
- "] ",
57818
- p.title
57819
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: "gray", children: [
57820
- "[",
57821
- p.shortcutKey,
57822
- "] ",
57913
+ " ",
57823
57914
  p.title
57915
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
57916
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: p.shortcutKey }),
57917
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: "gray", children: [
57918
+ " ",
57919
+ p.title
57920
+ ] })
57824
57921
  ] }) }, p.id)) }),
57825
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: modeColor, children: [
57922
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
57826
57923
  "z: ",
57827
57924
  modeLabel,
57828
- " \u25B8"
57925
+ " ",
57926
+ "\u25B8"
57829
57927
  ] }) })
57830
57928
  ] });
57831
57929
  }
57832
- var import_jsx_runtime2, MODE_LABELS, MODE_COLORS;
57930
+ var import_jsx_runtime2, MODE_LABELS;
57833
57931
  var init_TabBar = __esm({
57834
57932
  async "src/dashboard/ink/TabBar.tsx"() {
57835
57933
  "use strict";
@@ -57840,11 +57938,6 @@ var init_TabBar = __esm({
57840
57938
  expanded: "Expanded",
57841
57939
  "wide-side": "Wide Side"
57842
57940
  };
57843
- MODE_COLORS = {
57844
- normal: "gray",
57845
- expanded: "cyan",
57846
- "wide-side": "yellow"
57847
- };
57848
57941
  }
57849
57942
  });
57850
57943
 
@@ -57955,9 +58048,11 @@ function SideList({
57955
58048
  width,
57956
58049
  viewportHeight,
57957
58050
  panelTitle,
57958
- sessionFilterActive
58051
+ sessionFilterActive,
58052
+ emptyStateHint
57959
58053
  }) {
57960
58054
  const borderColor = focused ? "magenta" : "gray";
58055
+ const borderStyle = focused ? "double" : "single";
57961
58056
  const innerWidth = Math.max(1, width - 3);
57962
58057
  const visibleItems = items.slice(scrollOffset, scrollOffset + viewportHeight);
57963
58058
  const hasMoreAbove = scrollOffset > 0;
@@ -57967,7 +58062,7 @@ function SideList({
57967
58062
  {
57968
58063
  width,
57969
58064
  flexDirection: "column",
57970
- borderStyle: "single",
58065
+ borderStyle,
57971
58066
  borderColor,
57972
58067
  overflow: "hidden",
57973
58068
  children: [
@@ -58001,9 +58096,10 @@ function SideList({
58001
58096
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { color: "gray", children: "Press " }),
58002
58097
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { color: "magenta", bold: true, children: "f" }),
58003
58098
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { color: "gray", children: " to see all" })
58004
- ] }, "empty-hint-2")
58099
+ ] }, "empty-hint-2"),
58100
+ !sessionFilterActive && emptyStateHint && viewportHeight >= 5 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Box_default, { justifyContent: "center", width: innerWidth, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { dimColor: true, children: emptyStateHint }) }, "empty-hint-desc")
58005
58101
  ] }),
58006
- visibleItems.length < viewportHeight && Array.from({ length: Math.max(0, viewportHeight - visibleItems.length - (items.length === 0 && viewportHeight >= 3 ? sessionFilterActive ? 3 : 2 : 0)) }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Box_default, { width: innerWidth, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { children: " " }) }, `empty-${i}`)),
58102
+ visibleItems.length < viewportHeight && Array.from({ length: Math.max(0, viewportHeight - visibleItems.length - (items.length === 0 && viewportHeight >= 3 ? sessionFilterActive ? 3 : !sessionFilterActive && emptyStateHint && viewportHeight >= 5 ? 3 : 2 : 0)) }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Box_default, { width: innerWidth, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { children: " " }) }, `empty-${i}`)),
58007
58103
  hasMoreBelow && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Box_default, { justifyContent: "center", width: innerWidth, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { color: "gray", children: "\u25BC" }) })
58008
58104
  ]
58009
58105
  }
@@ -58054,6 +58150,7 @@ function DetailPane({
58054
58150
  focused
58055
58151
  }) {
58056
58152
  const borderColor = focused ? "magenta" : "gray";
58153
+ const borderStyle = focused ? "double" : "single";
58057
58154
  const lines = content ? content.split("\n") : [];
58058
58155
  const totalLines = lines.length;
58059
58156
  const hasMoreAbove = scrollOffset > 0;
@@ -58067,7 +58164,7 @@ function DetailPane({
58067
58164
  {
58068
58165
  flexDirection: "column",
58069
58166
  flexGrow: 1,
58070
- borderStyle: "single",
58167
+ borderStyle,
58071
58168
  borderColor,
58072
58169
  paddingLeft: 1,
58073
58170
  children: [
@@ -58114,64 +58211,88 @@ function StatusBar({
58114
58211
  const permissionColor = permissionMode === "bypassPermissions" ? "red" : permissionMode === "acceptEdits" ? "magenta" : permissionMode === "plan" ? "green" : void 0;
58115
58212
  const permissionLabel = permissionMode === "bypassPermissions" ? "BYPASS" : permissionMode === "acceptEdits" ? "EDITS" : permissionMode === "plan" ? "PLAN" : void 0;
58116
58213
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { height: 1, width: "100%", children: [
58117
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, color: "magenta", children: "\u26A1 SIDEKICK" }),
58118
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "gray", children: [
58119
- " v",
58120
- "0.12.7"
58121
- ] }),
58122
- updateInfo && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "yellow", children: [
58123
- " (v",
58124
- updateInfo.latest,
58125
- " available \u2014 npm i -g sidekick-agent-hub)"
58126
- ] }),
58127
- providerName && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
58128
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "gray", children: " | " }),
58129
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "cyan", children: providerName })
58130
- ] }),
58131
- permissionMode && permissionMode !== "default" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
58132
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "gray", children: " | " }),
58133
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: permissionColor, children: permissionLabel })
58134
- ] }),
58135
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "gray", children: " | " }),
58136
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: evtLabel }),
58137
- filterString && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "yellow", children: [
58138
- ' filter: "',
58139
- filterString,
58140
- '" (',
58141
- matchCount ?? 0,
58142
- " of ",
58143
- totalCount ?? 0,
58144
- ")"
58214
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
58215
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { bold: true, color: "magenta", children: [
58216
+ "\u26A1",
58217
+ " SIDEKICK"
58218
+ ] }),
58219
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { dimColor: true, children: [
58220
+ " v",
58221
+ "0.12.8"
58222
+ ] }),
58223
+ updateInfo && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "yellow", children: [
58224
+ " (v",
58225
+ updateInfo.latest,
58226
+ ")"
58227
+ ] })
58145
58228
  ] }),
58146
- sessionFilter && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "magenta", children: [
58147
- " ",
58148
- sessionFilter
58229
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { flexGrow: 1, justifyContent: "center", children: [
58230
+ providerName && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
58231
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { dimColor: true, children: [
58232
+ " ",
58233
+ "\u2502",
58234
+ " "
58235
+ ] }),
58236
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "cyan", children: providerName })
58237
+ ] }),
58238
+ permissionMode && permissionMode !== "default" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
58239
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { dimColor: true, children: [
58240
+ " ",
58241
+ "\u2502",
58242
+ " "
58243
+ ] }),
58244
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: permissionColor, children: permissionLabel })
58245
+ ] }),
58246
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { dimColor: true, children: [
58247
+ " ",
58248
+ "\u2502",
58249
+ " "
58250
+ ] }),
58251
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: evtLabel }),
58252
+ filterString && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "yellow", children: [
58253
+ ' filter: "',
58254
+ filterString,
58255
+ '" (',
58256
+ matchCount ?? 0,
58257
+ "/",
58258
+ totalCount ?? 0,
58259
+ ")"
58260
+ ] }),
58261
+ sessionFilter && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "magenta", children: [
58262
+ " ",
58263
+ sessionFilter
58264
+ ] })
58149
58265
  ] }),
58150
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "gray", children: " | " }),
58151
- focusTarget === "side" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
58152
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "\u2191\u2193" }),
58153
- " navigate ",
58154
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "Tab" }),
58155
- " detail ",
58156
- panelHints,
58157
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "/" }),
58158
- " filter ",
58159
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "?" }),
58160
- " help ",
58161
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "q" }),
58162
- " quit"
58163
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
58164
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "j/k" }),
58165
- " scroll ",
58166
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "[]" }),
58167
- " tab ",
58168
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "Tab" }),
58169
- " side ",
58170
- panelHints,
58171
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "?" }),
58172
- " help ",
58173
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "q" }),
58174
- " quit"
58266
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
58267
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { dimColor: true, children: [
58268
+ "\u2502",
58269
+ " "
58270
+ ] }),
58271
+ focusTarget === "side" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
58272
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "\u2191\u2193" }),
58273
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " nav " }),
58274
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "Tab" }),
58275
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " detail " }),
58276
+ panelHints,
58277
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "/" }),
58278
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " filter " }),
58279
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "?" }),
58280
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " help " }),
58281
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "q" }),
58282
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " quit" })
58283
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
58284
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "j/k" }),
58285
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " scroll " }),
58286
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "[]" }),
58287
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " tab " }),
58288
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "Tab" }),
58289
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " side " }),
58290
+ panelHints,
58291
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "?" }),
58292
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " help " }),
58293
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "q" }),
58294
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " quit" })
58295
+ ] })
58175
58296
  ] })
58176
58297
  ] });
58177
58298
  }
@@ -58205,6 +58326,27 @@ var init_useSpinner = __esm({
58205
58326
  }
58206
58327
  });
58207
58328
 
58329
+ // src/dashboard/branding.ts
58330
+ var LOGO_ART, HELP_HEADER;
58331
+ var init_branding = __esm({
58332
+ "src/dashboard/branding.ts"() {
58333
+ "use strict";
58334
+ init_phraseFormatters();
58335
+ LOGO_ART = [
58336
+ " {yellow-fg}\u26A1{/yellow-fg}",
58337
+ " {magenta-fg}\u2502{/magenta-fg}",
58338
+ " {white-fg}</>{/white-fg} {white-fg}\u256D\u2500\u2500\u2534\u2500\u2500\u256E{/white-fg} {bold}{magenta-fg}S I D E K I C K{/magenta-fg}{/bold}",
58339
+ " {white-fg}\u2502{/white-fg} {cyan-fg}\u25CF{/cyan-fg} {cyan-fg}\u25CF{/cyan-fg} {white-fg}\u2502{/white-fg} {bold}Agent Hub{/bold}",
58340
+ " {white-fg}\u2502{/white-fg} {green-fg}\u25E1{/green-fg} {white-fg}\u2502{/white-fg} {grey-fg}Terminal Dashboard{/grey-fg}",
58341
+ " {white-fg}\u2570\u2500\u2500\u2500\u2500\u2500\u256F{/white-fg}"
58342
+ ];
58343
+ HELP_HEADER = [
58344
+ ...LOGO_ART,
58345
+ ""
58346
+ ];
58347
+ }
58348
+ });
58349
+
58208
58350
  // src/dashboard/ink/SplashOverlay.tsx
58209
58351
  function SplashOverlay() {
58210
58352
  const spinner = useSpinner();
@@ -58218,12 +58360,7 @@ function SplashOverlay() {
58218
58360
  paddingY: 1,
58219
58361
  width: 60,
58220
58362
  children: [
58221
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { bold: true, color: "magenta", children: " S I D E K I C K" }),
58222
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { bold: true, children: " Agent Hub" }),
58223
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: "gray", children: [
58224
- " Terminal Dashboard",
58225
- "0.12.7" ? ` v${"0.12.7"}` : ""
58226
- ] }),
58363
+ LOGO_ART.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: parseBlessedTags(line) }, i)),
58227
58364
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: " " }),
58228
58365
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: "gray", children: [
58229
58366
  " ",
@@ -58269,11 +58406,27 @@ var init_SplashOverlay = __esm({
58269
58406
  await init_build2();
58270
58407
  init_useSpinner();
58271
58408
  import_sidekick_shared8 = __toESM(require_dist(), 1);
58409
+ init_branding();
58410
+ await init_parseBlessedTags();
58272
58411
  import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
58273
58412
  }
58274
58413
  });
58275
58414
 
58276
58415
  // src/dashboard/ink/HelpOverlay.tsx
58416
+ function helpRow(key, desc, keyWidth = 14, totalWidth = 54) {
58417
+ const padding = keyWidth - key.length;
58418
+ const dotCount = Math.max(1, totalWidth - keyWidth - desc.length);
58419
+ const dots = "\xB7".repeat(dotCount);
58420
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58421
+ " ",
58422
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: key }),
58423
+ " ".repeat(Math.max(0, padding)),
58424
+ " ",
58425
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { dimColor: true, children: dots }),
58426
+ " ",
58427
+ desc
58428
+ ] });
58429
+ }
58277
58430
  function HelpOverlay({ panels, activePanelIndex }) {
58278
58431
  const panel = panels[activePanelIndex];
58279
58432
  const actions = panel.getActions();
@@ -58288,75 +58441,25 @@ function HelpOverlay({ panels, activePanelIndex }) {
58288
58441
  paddingY: 1,
58289
58442
  width: 60,
58290
58443
  children: [
58291
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, color: "magenta", children: " S I D E K I C K" }),
58292
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: " Agent Hub" }),
58444
+ LOGO_ART.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: parseBlessedTags(line) }, `logo-${i}`)),
58293
58445
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: " " }),
58294
58446
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: " Panels" }),
58295
- panels.map((p) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58296
- " ",
58297
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: p.shortcutKey }),
58298
- " ",
58299
- p.title
58300
- ] }, p.id)),
58447
+ panels.map((p) => helpRow(String(p.shortcutKey), p.title)),
58301
58448
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: " " }),
58302
58449
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: " Navigation" }),
58303
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58304
- " ",
58305
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "Tab" }),
58306
- " Toggle side \u2194 detail focus"
58307
- ] }),
58308
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58309
- " ",
58310
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "j / \u2193" }),
58311
- " Next item (side) / scroll (detail)"
58312
- ] }),
58313
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58314
- " ",
58315
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "k / \u2191" }),
58316
- " Prev item (side) / scroll (detail)"
58317
- ] }),
58318
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58319
- " ",
58320
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "g / G" }),
58321
- " First / last item"
58322
- ] }),
58323
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58324
- " ",
58325
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "Enter" }),
58326
- " Focus detail pane"
58327
- ] }),
58328
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58329
- " ",
58330
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "h / \u2190" }),
58331
- " Return to side"
58332
- ] }),
58333
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58334
- " ",
58335
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "[ / ]" }),
58336
- " Cycle detail tabs"
58337
- ] }),
58338
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58339
- " ",
58340
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "z" }),
58341
- " Cycle layout mode"
58342
- ] }),
58450
+ helpRow("Tab", "Toggle side / detail focus"),
58451
+ helpRow("j / \u2193", "Next item / scroll down"),
58452
+ helpRow("k / \u2191", "Prev item / scroll up"),
58453
+ helpRow("g / G", "First / last item"),
58454
+ helpRow("Enter", "Focus detail pane"),
58455
+ helpRow("h / \u2190", "Return to side"),
58456
+ helpRow("[ / ]", "Cycle detail tabs"),
58457
+ helpRow("z", "Cycle layout mode"),
58343
58458
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: " " }),
58344
58459
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: " Actions" }),
58345
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58346
- " ",
58347
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "x" }),
58348
- " Context menu"
58349
- ] }),
58350
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58351
- " ",
58352
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "/" }),
58353
- " Filter side list"
58354
- ] }),
58355
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58356
- " ",
58357
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "f" }),
58358
- " Toggle session filter"
58359
- ] }),
58460
+ helpRow("x", "Context menu"),
58461
+ helpRow("/", "Filter side list"),
58462
+ helpRow("f", "Toggle session filter"),
58360
58463
  (actions.length > 0 || bindings.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
58361
58464
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: " " }),
58362
58465
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { bold: true, children: [
@@ -58364,55 +58467,28 @@ function HelpOverlay({ panels, activePanelIndex }) {
58364
58467
  panel.title,
58365
58468
  " Actions"
58366
58469
  ] }),
58367
- actions.map((a) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58368
- " ",
58369
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: a.key }),
58370
- " ",
58371
- a.label
58372
- ] }, a.key)),
58373
- bindings.map((b) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58374
- " ",
58375
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: b.keys.join("/") }),
58376
- " ",
58377
- b.label
58378
- ] }, b.keys[0]))
58470
+ actions.map((a) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react33.default.Fragment, { children: helpRow(a.key, a.label) }, a.key)),
58471
+ bindings.map((b) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react33.default.Fragment, { children: helpRow(b.keys.join("/"), b.label) }, b.keys[0]))
58379
58472
  ] }),
58380
58473
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: " " }),
58381
58474
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: " General" }),
58382
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58383
- " ",
58384
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "r" }),
58385
- " Generate HTML report"
58386
- ] }),
58387
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58388
- " ",
58389
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "V" }),
58390
- " Version & changelog"
58391
- ] }),
58392
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58393
- " ",
58394
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "?" }),
58395
- " Toggle this help"
58396
- ] }),
58397
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58398
- " ",
58399
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "Esc" }),
58400
- " Close overlay / clear filter / back"
58401
- ] }),
58402
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
58403
- " ",
58404
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { bold: true, children: "q / Ctrl+C" }),
58405
- " Quit"
58406
- ] })
58475
+ helpRow("r", "Generate HTML report"),
58476
+ helpRow("V", "Version & changelog"),
58477
+ helpRow("?", "Toggle this help"),
58478
+ helpRow("Esc", "Close overlay / clear filter"),
58479
+ helpRow("q / Ctrl+C", "Quit")
58407
58480
  ]
58408
58481
  }
58409
58482
  ) });
58410
58483
  }
58411
- var import_jsx_runtime9;
58484
+ var import_react33, import_jsx_runtime9;
58412
58485
  var init_HelpOverlay = __esm({
58413
58486
  async "src/dashboard/ink/HelpOverlay.tsx"() {
58414
58487
  "use strict";
58488
+ import_react33 = __toESM(require_react(), 1);
58415
58489
  await init_build2();
58490
+ init_branding();
58491
+ await init_parseBlessedTags();
58416
58492
  import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
58417
58493
  }
58418
58494
  });
@@ -58497,7 +58573,7 @@ function ChangelogOverlay({ entries, scrollOffset }) {
58497
58573
  " ",
58498
58574
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { bold: true, color: "cyan", children: [
58499
58575
  "Terminal Dashboard v",
58500
- "0.12.7"
58576
+ "0.12.8"
58501
58577
  ] }),
58502
58578
  latestDate ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { color: "gray", children: [
58503
58579
  " \u2014 ",
@@ -58678,20 +58754,26 @@ var init_TooSmallOverlay = __esm({
58678
58754
  // src/dashboard/ink/ToastNotification.tsx
58679
58755
  function ToastNotification({ toast }) {
58680
58756
  const color = SEVERITY_COLOR[toast.severity] || "cyan";
58757
+ const icon = SEVERITY_ICON[toast.severity] || "\u25CF";
58681
58758
  const truncMsg = toast.message.length > 56 ? toast.message.substring(0, 53) + "..." : toast.message;
58682
58759
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
58683
58760
  Box_default,
58684
58761
  {
58685
58762
  position: "absolute",
58686
- marginLeft: Math.max(0, process.stdout.columns - truncMsg.length - 6),
58763
+ marginLeft: Math.max(0, process.stdout.columns - truncMsg.length - 8),
58687
58764
  marginTop: 0,
58688
58765
  borderStyle: "single",
58689
58766
  borderColor: color,
58690
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color, children: truncMsg })
58767
+ paddingX: 1,
58768
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { color, children: [
58769
+ icon,
58770
+ " ",
58771
+ truncMsg
58772
+ ] })
58691
58773
  }
58692
58774
  );
58693
58775
  }
58694
- var import_jsx_runtime14, SEVERITY_COLOR;
58776
+ var import_jsx_runtime14, SEVERITY_COLOR, SEVERITY_ICON;
58695
58777
  var init_ToastNotification = __esm({
58696
58778
  async "src/dashboard/ink/ToastNotification.tsx"() {
58697
58779
  "use strict";
@@ -58702,6 +58784,14 @@ var init_ToastNotification = __esm({
58702
58784
  warning: "yellow",
58703
58785
  info: "cyan"
58704
58786
  };
58787
+ SEVERITY_ICON = {
58788
+ error: "\u2718",
58789
+ // ✘
58790
+ warning: "\u26A0",
58791
+ // ⚠
58792
+ info: "\u25CF"
58793
+ // ●
58794
+ };
58705
58795
  }
58706
58796
  });
58707
58797
 
@@ -58790,7 +58880,7 @@ function InputSink() {
58790
58880
  return null;
58791
58881
  }
58792
58882
  function MouseProvider({ onMouse, children }) {
58793
- (0, import_react33.useEffect)(() => {
58883
+ (0, import_react34.useEffect)(() => {
58794
58884
  enableMouse();
58795
58885
  const handler = (data) => {
58796
58886
  const event = parseMouseEvent(data);
@@ -58812,11 +58902,11 @@ function MouseProvider({ onMouse, children }) {
58812
58902
  children
58813
58903
  ] });
58814
58904
  }
58815
- var import_react33, import_jsx_runtime15;
58905
+ var import_react34, import_jsx_runtime15;
58816
58906
  var init_MouseProvider = __esm({
58817
58907
  async "src/dashboard/ink/mouse/MouseProvider.tsx"() {
58818
58908
  "use strict";
58819
- import_react33 = __toESM(require_react(), 1);
58909
+ import_react34 = __toESM(require_react(), 1);
58820
58910
  await init_build2();
58821
58911
  init_mouseProtocol();
58822
58912
  init_parseMouseEvent();
@@ -58838,7 +58928,7 @@ var init_mouse = __esm({
58838
58928
  var CHANGELOG_default;
58839
58929
  var init_CHANGELOG = __esm({
58840
58930
  "CHANGELOG.md"() {
58841
- 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.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';
58931
+ 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.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';
58842
58932
  }
58843
58933
  });
58844
58934
 
@@ -58931,20 +59021,20 @@ function reducer(state, action) {
58931
59021
  }
58932
59022
  }
58933
59023
  function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath, onSessionSwitch, onTogglePin, onGenerateReport }) {
58934
- const [state, dispatch] = (0, import_react34.useReducer)(reducer, initialState);
59024
+ const [state, dispatch] = (0, import_react35.useReducer)(reducer, initialState);
58935
59025
  const { exit } = use_app_default();
58936
59026
  const { columns, rows } = useTerminalSize();
58937
- const toastIdRef = (0, import_react34.useRef)(0);
58938
- const lastAlertCountRef = (0, import_react34.useRef)(0);
58939
- const alertsInitRef = (0, import_react34.useRef)(false);
58940
- const prevDetailLineCountRef = (0, import_react34.useRef)(0);
58941
- (0, import_react34.useEffect)(() => {
59027
+ const toastIdRef = (0, import_react35.useRef)(0);
59028
+ const lastAlertCountRef = (0, import_react35.useRef)(0);
59029
+ const alertsInitRef = (0, import_react35.useRef)(false);
59030
+ const prevDetailLineCountRef = (0, import_react35.useRef)(0);
59031
+ (0, import_react35.useEffect)(() => {
58942
59032
  if (!state.hasReceivedEvents && metrics.eventCount > 0) {
58943
59033
  const prefix = (metrics.sessionStartTime || "").substring(0, 8);
58944
59034
  dispatch({ type: "FIRST_EVENT", sessionPrefix: prefix });
58945
59035
  }
58946
59036
  }, [metrics.eventCount, state.hasReceivedEvents, metrics.sessionStartTime]);
58947
- (0, import_react34.useEffect)(() => {
59037
+ (0, import_react35.useEffect)(() => {
58948
59038
  if (!alertsInitRef.current) {
58949
59039
  lastAlertCountRef.current = metrics.eventCount;
58950
59040
  alertsInitRef.current = true;
@@ -58963,7 +59053,7 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
58963
59053
  }
58964
59054
  lastAlertCountRef.current = metrics.eventCount;
58965
59055
  }, [metrics.eventCount, metrics.timeline]);
58966
- const addToast = (0, import_react34.useCallback)((message, severity) => {
59056
+ const addToast = (0, import_react35.useCallback)((message, severity) => {
58967
59057
  const durations = { error: 4e3, warning: 3e3, info: 2e3 };
58968
59058
  const id = ++toastIdRef.current;
58969
59059
  dispatch({
@@ -58987,7 +59077,7 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
58987
59077
  }
58988
59078
  };
58989
59079
  const sideWidth = getSideWidth();
58990
- const getFilteredItems = (0, import_react34.useCallback)(() => {
59080
+ const getFilteredItems = (0, import_react35.useCallback)(() => {
58991
59081
  let items = panel.getItems(metrics, staticData);
58992
59082
  if (state.sessionFilter && ["tasks", "kanban", "notes", "decisions", "plans"].includes(panel.id)) {
58993
59083
  if (panel.id === "kanban") {
@@ -59016,7 +59106,7 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
59016
59106
  totalItems: currentItems.length,
59017
59107
  viewportHeight: sideViewportHeight
59018
59108
  });
59019
- (0, import_react34.useEffect)(() => {
59109
+ (0, import_react35.useEffect)(() => {
59020
59110
  if (sideScroll.selectedIndex !== state.selectedItemIndex) {
59021
59111
  sideScroll.setSelected(state.selectedItemIndex);
59022
59112
  }
@@ -59038,7 +59128,7 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
59038
59128
  const detailLines = detailContent.split("\n");
59039
59129
  const detailViewportHeight = Math.max(1, rows - 5);
59040
59130
  const activeTab = detailTabs[tabIdx];
59041
- (0, import_react34.useEffect)(() => {
59131
+ (0, import_react35.useEffect)(() => {
59042
59132
  if (!activeTab?.autoScrollBottom) return;
59043
59133
  if (detailLines.length <= detailViewportHeight) return;
59044
59134
  if (detailLines.length > prevDetailLineCountRef.current) {
@@ -59050,12 +59140,12 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
59050
59140
  if ("activeDetailTabIndex" in panel) {
59051
59141
  panel.activeDetailTabIndex = state.detailTabIndex;
59052
59142
  }
59053
- const getContextActions = (0, import_react34.useCallback)(() => {
59143
+ const getContextActions = (0, import_react35.useCallback)(() => {
59054
59144
  if (!selectedItem) return [];
59055
59145
  return panel.getActions().filter((a) => !a.condition || a.condition(selectedItem));
59056
59146
  }, [panel, selectedItem]);
59057
59147
  const contextActions = state.overlay === "context-menu" ? getContextActions() : [];
59058
- const buildPanelHints = (0, import_react34.useCallback)(() => {
59148
+ const buildPanelHints = (0, import_react35.useCallback)(() => {
59059
59149
  const parts = [];
59060
59150
  const bindings = panel.getKeybindings?.() || [];
59061
59151
  for (const b of bindings) {
@@ -59071,7 +59161,7 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
59071
59161
  }
59072
59162
  return parts.length > 0 ? parts.join(" ") + " " : "";
59073
59163
  }, [panel, selectedItem, state.focusTarget]);
59074
- const toggleSessionFilter = (0, import_react34.useCallback)(() => {
59164
+ const toggleSessionFilter = (0, import_react35.useCallback)(() => {
59075
59165
  if (state.sessionFilter) {
59076
59166
  dispatch({ type: "SET_SESSION_FILTER", filter: null });
59077
59167
  addToast("Session filter cleared", "info");
@@ -59109,7 +59199,7 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
59109
59199
  addToast("Cannot filter by this item", "info");
59110
59200
  }
59111
59201
  }, [state.sessionFilter, state.activePanelIndex, selectedItem, panels, metrics, staticData, addToast]);
59112
- const handleMouse = (0, import_react34.useCallback)((event) => {
59202
+ const handleMouse = (0, import_react35.useCallback)((event) => {
59113
59203
  if (state.overlay) {
59114
59204
  if (event.type === "click") {
59115
59205
  dispatch({ type: "SET_OVERLAY", overlay: null });
@@ -59422,7 +59512,8 @@ function Dashboard({ panels, metrics, staticData, isPinned, pendingSessionPath,
59422
59512
  width: sideWidth,
59423
59513
  viewportHeight: sideViewportHeight,
59424
59514
  panelTitle: panel.title,
59425
- sessionFilterActive: !!state.sessionFilter && ["tasks", "kanban", "notes", "decisions", "plans"].includes(panel.id)
59515
+ sessionFilterActive: !!state.sessionFilter && ["tasks", "kanban", "notes", "decisions", "plans"].includes(panel.id),
59516
+ emptyStateHint: panel.emptyStateHint
59426
59517
  }
59427
59518
  ),
59428
59519
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Box_default, { flexDirection: "column", flexGrow: 1, children: [
@@ -59513,11 +59604,11 @@ function filterKanbanColumn(item, filter) {
59513
59604
  data: { status: colData.status, tasks: filtered }
59514
59605
  };
59515
59606
  }
59516
- var import_react34, import_sidekick_shared9, import_jsx_runtime16, changelogEntries, SIDE_PANEL_WIDTH, NARROW_SIDE_WIDTH, MIN_SCREEN_WIDTH, MIN_SCREEN_HEIGHT, WIDE_SIDE_WIDTH, initialState;
59607
+ var import_react35, import_sidekick_shared9, import_jsx_runtime16, changelogEntries, SIDE_PANEL_WIDTH, NARROW_SIDE_WIDTH, MIN_SCREEN_WIDTH, MIN_SCREEN_HEIGHT, WIDE_SIDE_WIDTH, initialState;
59517
59608
  var init_Dashboard = __esm({
59518
59609
  async "src/dashboard/ink/Dashboard.tsx"() {
59519
59610
  "use strict";
59520
- import_react34 = __toESM(require_react(), 1);
59611
+ import_react35 = __toESM(require_react(), 1);
59521
59612
  await init_build2();
59522
59613
  init_phraseFormatters();
59523
59614
  init_useTerminalSize();
@@ -59770,7 +59861,7 @@ async function dashboardAction(_opts, cmd) {
59770
59861
  (0, import_sidekick_shared10.openInBrowser)(outFile);
59771
59862
  };
59772
59863
  const instance = render2(
59773
- import_react35.default.createElement(Dashboard, {
59864
+ import_react36.default.createElement(Dashboard, {
59774
59865
  panels,
59775
59866
  metrics: state.getMetrics(),
59776
59867
  staticData,
@@ -59790,7 +59881,7 @@ async function dashboardAction(_opts, cmd) {
59790
59881
  renderTimer = setTimeout(() => {
59791
59882
  renderTimer = null;
59792
59883
  instance.rerender(
59793
- import_react35.default.createElement(Dashboard, {
59884
+ import_react36.default.createElement(Dashboard, {
59794
59885
  panels,
59795
59886
  metrics: state.getMetrics(),
59796
59887
  staticData,
@@ -59918,11 +60009,11 @@ async function dashboardAction(_opts, cmd) {
59918
60009
  cleanup();
59919
60010
  process.exit(0);
59920
60011
  }
59921
- var import_react35, import_sidekick_shared10, import_sidekick_shared11;
60012
+ var import_react36, import_sidekick_shared10, import_sidekick_shared11;
59922
60013
  var init_dashboard = __esm({
59923
60014
  async "src/commands/dashboard.ts"() {
59924
60015
  "use strict";
59925
- import_react35 = __toESM(require_react(), 1);
60016
+ import_react36 = __toESM(require_react(), 1);
59926
60017
  import_sidekick_shared10 = __toESM(require_dist(), 1);
59927
60018
  import_sidekick_shared11 = __toESM(require_dist(), 1);
59928
60019
  init_cli();
@@ -60103,7 +60194,7 @@ var init_cli = __esm({
60103
60194
  import_sidekick_shared14 = __toESM(require_dist(), 1);
60104
60195
  import_sidekick_shared15 = __toESM(require_dist(), 1);
60105
60196
  program2 = new Command();
60106
- program2.name("sidekick").description("Query Sidekick project intelligence from the command line").version("0.12.7").option("--json", "Output as JSON").option("--project <path>", "Override project path (default: cwd)").option("--provider <id>", "Provider: claude-code, opencode, codex, auto (default: auto)");
60197
+ program2.name("sidekick").description("Query Sidekick project intelligence from the command line").version("0.12.8").option("--json", "Output as JSON").option("--project <path>", "Override project path (default: cwd)").option("--provider <id>", "Provider: claude-code, opencode, codex, auto (default: auto)");
60107
60198
  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) => {
60108
60199
  const { dashboardAction: dashboardAction2 } = await init_dashboard().then(() => dashboard_exports);
60109
60200
  return dashboardAction2(_opts, cmd);