sidekick-agent-hub 0.13.5 → 0.13.6

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
@@ -25,6 +25,8 @@ Requires **Node.js 20+**.
25
25
  3. The dashboard auto-detects your project and session provider
26
26
  4. Press `?` to see all keybindings
27
27
 
28
+ > **OpenCode note:** OpenCode session monitoring reads `opencode.db` and currently expects an executable `sqlite3` runtime in the host environment.
29
+
28
30
  ## Usage
29
31
 
30
32
  ```bash
@@ -4323,6 +4323,11 @@ var require_detect = __commonJS({
4323
4323
  const xdg = process.env.XDG_DATA_HOME;
4324
4324
  if (xdg)
4325
4325
  return path7.join(xdg, "opencode");
4326
+ if (process.platform === "darwin")
4327
+ return path7.join(os5.homedir(), "Library", "Application Support", "opencode");
4328
+ if (process.platform === "win32") {
4329
+ return path7.join(process.env.LOCALAPPDATA || process.env.APPDATA || path7.join(os5.homedir(), "AppData", "Local"), "opencode");
4330
+ }
4326
4331
  return path7.join(os5.homedir(), ".local", "share", "opencode");
4327
4332
  }
4328
4333
  function getCodexHome() {
@@ -6125,29 +6130,42 @@ var require_openCodeDatabase = __commonJS({
6125
6130
  var child_process_1 = __require("child_process");
6126
6131
  var OpenCodeDatabase = class {
6127
6132
  dbPath;
6128
- sqlite3Available = null;
6133
+ runtimeStatus = null;
6129
6134
  constructor(dataDir) {
6130
6135
  this.dbPath = path7.join(dataDir, "opencode.db");
6131
6136
  }
6132
6137
  isAvailable() {
6133
6138
  return fs9.existsSync(this.dbPath);
6134
6139
  }
6140
+ getRuntimeStatus() {
6141
+ if (this.runtimeStatus)
6142
+ return this.runtimeStatus;
6143
+ if (!this.isAvailable()) {
6144
+ this.runtimeStatus = { available: false, kind: "db_missing" };
6145
+ return this.runtimeStatus;
6146
+ }
6147
+ return { available: false, kind: "query_failed", message: "OpenCode database has not been initialized yet." };
6148
+ }
6135
6149
  open() {
6136
- if (this.sqlite3Available !== null)
6137
- return this.sqlite3Available;
6150
+ if (this.runtimeStatus)
6151
+ return this.runtimeStatus.available;
6152
+ if (!this.isAvailable()) {
6153
+ this.runtimeStatus = { available: false, kind: "db_missing" };
6154
+ return false;
6155
+ }
6138
6156
  try {
6139
6157
  (0, child_process_1.execFileSync)("sqlite3", ["--version"], { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] });
6140
- this.sqlite3Available = true;
6158
+ this.runtimeStatus = { available: true, kind: "available" };
6141
6159
  return true;
6142
- } catch {
6143
- this.sqlite3Available = false;
6160
+ } catch (error) {
6161
+ this.runtimeStatus = toRuntimeStatus(error);
6144
6162
  return false;
6145
6163
  }
6146
6164
  }
6147
6165
  close() {
6148
6166
  }
6149
6167
  query(sql, params = []) {
6150
- if (!this.sqlite3Available)
6168
+ if (!this.open())
6151
6169
  return [];
6152
6170
  let query = sql;
6153
6171
  for (const param of params) {
@@ -6165,11 +6183,13 @@ var require_openCodeDatabase = __commonJS({
6165
6183
  stdio: ["pipe", "pipe", "pipe"],
6166
6184
  maxBuffer: 50 * 1024 * 1024
6167
6185
  });
6186
+ this.runtimeStatus = { available: true, kind: "available" };
6168
6187
  const trimmed = result.trim();
6169
6188
  if (!trimmed)
6170
6189
  return [];
6171
6190
  return JSON.parse(trimmed);
6172
- } catch {
6191
+ } catch (error) {
6192
+ this.runtimeStatus = toRuntimeStatus(error, "query_failed");
6173
6193
  return [];
6174
6194
  }
6175
6195
  }
@@ -6179,27 +6199,49 @@ var require_openCodeDatabase = __commonJS({
6179
6199
  }
6180
6200
  findProjectByWorktree(workspacePath) {
6181
6201
  const normalized = normalizePath(workspacePath);
6182
- const exact = this.queryOne("SELECT id, worktree, name, time_created, time_updated FROM project WHERE worktree = ?", [normalized]);
6183
- if (exact)
6184
- return exact;
6185
- const all = this.query("SELECT id, worktree, name, time_created, time_updated FROM project");
6186
- const matches = [];
6187
- for (const proj of all) {
6188
- const projPath = normalizePath(proj.worktree);
6189
- if (projPath === normalized)
6190
- return proj;
6191
- if (normalized.startsWith(projPath + path7.sep) || projPath.startsWith(normalized + path7.sep)) {
6192
- matches.push({ ...proj, pathLen: projPath.length });
6202
+ const all = this.getAllProjects();
6203
+ let best = null;
6204
+ let bestScore = -1;
6205
+ for (const project of all) {
6206
+ const worktreeScore = pathMatchScore(project.worktree, normalized);
6207
+ if (worktreeScore > bestScore) {
6208
+ best = project;
6209
+ bestScore = worktreeScore;
6210
+ }
6211
+ for (const sandbox of project.sandboxes) {
6212
+ const sandboxScore = pathMatchScore(sandbox, normalized);
6213
+ if (sandboxScore > bestScore) {
6214
+ best = project;
6215
+ bestScore = sandboxScore;
6216
+ }
6193
6217
  }
6194
6218
  }
6195
- if (matches.length > 0) {
6196
- matches.sort((a, b) => b.pathLen - a.pathLen);
6197
- return matches[0];
6219
+ return bestScore >= 0 ? best : null;
6220
+ }
6221
+ findProjectBySessionDirectory(workspacePath) {
6222
+ const normalized = normalizePath(workspacePath);
6223
+ const sessions = this.query("SELECT id, project_id, title, directory, time_created, time_updated FROM session WHERE parent_id IS NULL ORDER BY time_updated DESC");
6224
+ let bestProjectId = null;
6225
+ let bestScore = -1;
6226
+ for (const session of sessions) {
6227
+ const score = pathMatchScore(session.directory, normalized);
6228
+ if (score > bestScore) {
6229
+ bestProjectId = session.project_id;
6230
+ bestScore = score;
6231
+ }
6198
6232
  }
6199
- return null;
6233
+ if (!bestProjectId)
6234
+ return null;
6235
+ return this.getAllProjects().find((project) => project.id === bestProjectId) ?? null;
6200
6236
  }
6201
6237
  getAllProjects() {
6202
- return this.query("SELECT id, worktree, name, time_created, time_updated FROM project");
6238
+ return this.query("SELECT id, worktree, name, sandboxes, time_created, time_updated FROM project").map((project) => ({
6239
+ ...project,
6240
+ sandboxes: parseStringArray(project.sandboxes)
6241
+ }));
6242
+ }
6243
+ hasProject(projectId) {
6244
+ return this.queryOne("SELECT id FROM project WHERE id = ? LIMIT 1", [projectId]) !== null;
6203
6245
  }
6204
6246
  getSessionsForProject(projectId) {
6205
6247
  return this.query("SELECT id, project_id, title, directory, time_created, time_updated FROM session WHERE project_id = ? AND parent_id IS NULL ORDER BY time_updated DESC", [projectId]);
@@ -6312,6 +6354,48 @@ var require_openCodeDatabase = __commonJS({
6312
6354
  return path7.resolve(input);
6313
6355
  }
6314
6356
  }
6357
+ function parseStringArray(value) {
6358
+ if (!value)
6359
+ return [];
6360
+ try {
6361
+ const parsed = JSON.parse(value);
6362
+ return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === "string" && entry.length > 0).map(normalizePath) : [];
6363
+ } catch {
6364
+ return [];
6365
+ }
6366
+ }
6367
+ function normalizeForCompare(input) {
6368
+ const normalized = normalizePath(input);
6369
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
6370
+ }
6371
+ function pathMatchScore(candidate, workspacePath) {
6372
+ if (!candidate)
6373
+ return -1;
6374
+ const normalizedCandidate = normalizeForCompare(candidate);
6375
+ const normalizedWorkspace = normalizeForCompare(workspacePath);
6376
+ if (normalizedCandidate === normalizedWorkspace)
6377
+ return 1e4 + normalizedCandidate.length;
6378
+ const candidatePrefix = normalizedCandidate.endsWith(path7.sep) ? normalizedCandidate : normalizedCandidate + path7.sep;
6379
+ const workspacePrefix = normalizedWorkspace.endsWith(path7.sep) ? normalizedWorkspace : normalizedWorkspace + path7.sep;
6380
+ if (normalizedWorkspace.startsWith(candidatePrefix))
6381
+ return 5e3 + normalizedCandidate.length;
6382
+ if (normalizedCandidate.startsWith(workspacePrefix))
6383
+ return 1e3 + normalizedCandidate.length;
6384
+ return -1;
6385
+ }
6386
+ function toRuntimeStatus(error, fallback = "sqlite_missing") {
6387
+ if (isErrno(error, "ENOENT")) {
6388
+ return { available: false, kind: "sqlite_missing", message: "sqlite3 executable not found in PATH." };
6389
+ }
6390
+ if (isErrno(error, "EPERM") || isErrno(error, "EACCES")) {
6391
+ return { available: false, kind: "sqlite_blocked", message: "sqlite3 exists but could not be executed." };
6392
+ }
6393
+ const message = error instanceof Error ? error.message : String(error);
6394
+ return { available: false, kind: fallback, message };
6395
+ }
6396
+ function isErrno(error, code) {
6397
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
6398
+ }
6315
6399
  }
6316
6400
  });
6317
6401
 
@@ -6369,6 +6453,12 @@ var require_openCode = __commonJS({
6369
6453
  if (xdg) {
6370
6454
  return path7.join(xdg, "opencode");
6371
6455
  }
6456
+ if (process.platform === "darwin") {
6457
+ return path7.join(os5.homedir(), "Library", "Application Support", "opencode");
6458
+ }
6459
+ if (process.platform === "win32") {
6460
+ return path7.join(process.env.LOCALAPPDATA || process.env.APPDATA || path7.join(os5.homedir(), "AppData", "Local"), "opencode");
6461
+ }
6372
6462
  return path7.join(os5.homedir(), ".local", "share", "opencode");
6373
6463
  }
6374
6464
  function getStorageDir() {
@@ -6435,11 +6525,17 @@ var require_openCode = __commonJS({
6435
6525
  return null;
6436
6526
  }
6437
6527
  }
6438
- function resolveProjectId(workspacePath, db) {
6528
+ function resolveProjectId(workspacePath, db, runtimeStatus) {
6439
6529
  if (db) {
6440
6530
  const dbProject = db.findProjectByWorktree(workspacePath);
6441
6531
  if (dbProject)
6442
6532
  return dbProject.id;
6533
+ const byDirectory = db.findProjectBySessionDirectory(workspacePath);
6534
+ if (byDirectory)
6535
+ return byDirectory.id;
6536
+ }
6537
+ if (runtimeStatus.kind !== "db_missing") {
6538
+ return null;
6443
6539
  }
6444
6540
  return resolveProjectIdFromFiles(workspacePath);
6445
6541
  }
@@ -6774,6 +6870,7 @@ var require_openCode = __commonJS({
6774
6870
  displayName = "OpenCode";
6775
6871
  db = null;
6776
6872
  dbInitialized = false;
6873
+ dbStatus = { available: false, kind: "db_missing" };
6777
6874
  /** Cache of session metadata populated during listing */
6778
6875
  sessionMetaCache = /* @__PURE__ */ new Map();
6779
6876
  /** Lazy-initialize the database connection. */
@@ -6783,41 +6880,80 @@ var require_openCode = __commonJS({
6783
6880
  this.dbInitialized = true;
6784
6881
  const dataDir = getOpenCodeDataDir();
6785
6882
  const db = new openCodeDatabase_1.OpenCodeDatabase(dataDir);
6786
- if (db.isAvailable() && db.open()) {
6883
+ if (db.open()) {
6787
6884
  this.db = db;
6788
6885
  }
6886
+ this.dbStatus = db.getRuntimeStatus();
6789
6887
  return this.db;
6790
6888
  }
6889
+ getRuntimeStatus() {
6890
+ const db = this.ensureDb();
6891
+ if (db)
6892
+ return db.getRuntimeStatus();
6893
+ return this.dbStatus;
6894
+ }
6895
+ canMonitorDirectory(dir) {
6896
+ if (fs9.existsSync(dir))
6897
+ return true;
6898
+ const db = this.ensureDb();
6899
+ if (!db)
6900
+ return false;
6901
+ const projectId = extractProjectIdFromDbPath(dir + path7.sep + "dummy.json") || path7.basename(dir);
6902
+ return projectId.length > 0 && db.hasProject(projectId);
6903
+ }
6904
+ mapDbSessions(projectId) {
6905
+ const db = this.ensureDb();
6906
+ if (!db)
6907
+ return [];
6908
+ const sessions = db.getSessionsForProject(projectId);
6909
+ const dataDir = getOpenCodeDataDir();
6910
+ return sessions.map((session) => {
6911
+ const syntheticPath = makeDbSessionPath(dataDir, projectId, session.id);
6912
+ this.sessionMetaCache.set(syntheticPath, {
6913
+ title: session.title,
6914
+ timeUpdated: session.time_updated
6915
+ });
6916
+ return syntheticPath;
6917
+ });
6918
+ }
6791
6919
  // --- Path resolution ---
6792
6920
  getSessionDirectory(workspacePath) {
6793
6921
  const db = this.ensureDb();
6794
- const projectId = resolveProjectId(workspacePath, db);
6922
+ const dbStatus = this.getRuntimeStatus();
6923
+ const projectId = resolveProjectId(workspacePath, db, dbStatus);
6795
6924
  if (projectId) {
6796
6925
  if (db) {
6797
6926
  return path7.join(getOpenCodeDataDir(), DB_SESSION_PREFIX, projectId);
6798
6927
  }
6799
6928
  return path7.join(getStorageDir(), "session", projectId);
6800
6929
  }
6930
+ if (dbStatus.kind !== "db_missing") {
6931
+ return path7.join(getOpenCodeDataDir(), DB_SESSION_PREFIX);
6932
+ }
6801
6933
  return path7.join(getStorageDir(), "session");
6802
6934
  }
6803
6935
  discoverSessionDirectory(workspacePath) {
6804
6936
  const db = this.ensureDb();
6805
- const projectId = resolveProjectId(workspacePath, db);
6937
+ const dbStatus = this.getRuntimeStatus();
6938
+ const projectId = resolveProjectId(workspacePath, db, dbStatus);
6806
6939
  if (!projectId)
6807
6940
  return null;
6808
6941
  if (db) {
6809
- const sessions = db.getSessionsForProject(projectId);
6810
- if (sessions.length > 0) {
6942
+ if (db.hasProject(projectId)) {
6811
6943
  return path7.join(getOpenCodeDataDir(), DB_SESSION_PREFIX, projectId);
6812
6944
  }
6813
6945
  }
6946
+ if (dbStatus.kind !== "db_missing") {
6947
+ return null;
6948
+ }
6814
6949
  const dir = path7.join(getStorageDir(), "session", projectId);
6815
6950
  return fs9.existsSync(dir) ? dir : null;
6816
6951
  }
6817
6952
  // --- Session discovery ---
6818
6953
  findActiveSession(workspacePath) {
6819
6954
  const db = this.ensureDb();
6820
- const projectId = resolveProjectId(workspacePath, db);
6955
+ const dbStatus = this.getRuntimeStatus();
6956
+ const projectId = resolveProjectId(workspacePath, db, dbStatus);
6821
6957
  if (!projectId)
6822
6958
  return null;
6823
6959
  if (db) {
@@ -6831,6 +6967,9 @@ var require_openCode = __commonJS({
6831
6967
  return syntheticPath;
6832
6968
  }
6833
6969
  }
6970
+ if (dbStatus.kind !== "db_missing") {
6971
+ return null;
6972
+ }
6834
6973
  return this.findActiveSessionFromFiles(projectId);
6835
6974
  }
6836
6975
  findActiveSessionFromFiles(projectId) {
@@ -6883,58 +7022,37 @@ var require_openCode = __commonJS({
6883
7022
  }
6884
7023
  findAllSessions(workspacePath) {
6885
7024
  const db = this.ensureDb();
6886
- const projectId = resolveProjectId(workspacePath, db);
7025
+ const dbStatus = this.getRuntimeStatus();
7026
+ const projectId = resolveProjectId(workspacePath, db, dbStatus);
6887
7027
  if (!projectId)
6888
7028
  return [];
6889
7029
  if (db) {
6890
- const sessions = db.getSessionsForProject(projectId);
6891
- if (sessions.length > 0) {
6892
- const dataDir = getOpenCodeDataDir();
6893
- return sessions.map((s) => {
6894
- const syntheticPath = makeDbSessionPath(dataDir, projectId, s.id);
6895
- this.sessionMetaCache.set(syntheticPath, {
6896
- title: s.title,
6897
- timeUpdated: s.time_updated
6898
- });
6899
- return syntheticPath;
6900
- });
6901
- }
7030
+ return this.mapDbSessions(projectId);
7031
+ }
7032
+ if (dbStatus.kind !== "db_missing") {
7033
+ return [];
6902
7034
  }
6903
7035
  const sessionDir = path7.join(getStorageDir(), "session", projectId);
6904
7036
  return this.findSessionsInDirectoryFromFiles(sessionDir);
6905
7037
  }
6906
7038
  findSessionsInDirectory(dir) {
6907
7039
  const db = this.ensureDb();
7040
+ const dbStatus = this.getRuntimeStatus();
6908
7041
  if (db && dir.includes(path7.sep + DB_SESSION_PREFIX + path7.sep)) {
6909
7042
  const projectId = extractProjectIdFromDbPath(dir + path7.sep + "dummy.json");
6910
7043
  if (projectId) {
6911
- const sessions = db.getSessionsForProject(projectId);
6912
- const dataDir = getOpenCodeDataDir();
6913
- return sessions.map((s) => {
6914
- const syntheticPath = makeDbSessionPath(dataDir, projectId, s.id);
6915
- this.sessionMetaCache.set(syntheticPath, {
6916
- title: s.title,
6917
- timeUpdated: s.time_updated
6918
- });
6919
- return syntheticPath;
6920
- });
7044
+ return this.mapDbSessions(projectId);
6921
7045
  }
6922
7046
  }
6923
7047
  if (db) {
6924
7048
  const dirName = path7.basename(dir);
6925
- const sessions = db.getSessionsForProject(dirName);
6926
- if (sessions.length > 0) {
6927
- const dataDir = getOpenCodeDataDir();
6928
- return sessions.map((s) => {
6929
- const syntheticPath = makeDbSessionPath(dataDir, dirName, s.id);
6930
- this.sessionMetaCache.set(syntheticPath, {
6931
- title: s.title,
6932
- timeUpdated: s.time_updated
6933
- });
6934
- return syntheticPath;
6935
- });
7049
+ if (db.hasProject(dirName)) {
7050
+ return this.mapDbSessions(dirName);
6936
7051
  }
6937
7052
  }
7053
+ if (dbStatus.kind !== "db_missing") {
7054
+ return [];
7055
+ }
6938
7056
  return this.findSessionsInDirectoryFromFiles(dir);
6939
7057
  }
6940
7058
  findSessionsInDirectoryFromFiles(dir) {
@@ -6957,13 +7075,14 @@ var require_openCode = __commonJS({
6957
7075
  getAllProjectFolders(workspacePath) {
6958
7076
  const db = this.ensureDb();
6959
7077
  const folders = [];
7078
+ const dbStatus = this.getRuntimeStatus();
6960
7079
  if (db) {
6961
7080
  const projects = db.getAllProjects();
6962
7081
  const stats = db.getProjectSessionStats();
6963
7082
  const statsMap = new Map(stats.map((s) => [s.projectId, s]));
6964
7083
  let currentProjectId = null;
6965
7084
  if (workspacePath) {
6966
- currentProjectId = resolveProjectId(workspacePath, db);
7085
+ currentProjectId = resolveProjectId(workspacePath, db, dbStatus);
6967
7086
  }
6968
7087
  const dataDir = getOpenCodeDataDir();
6969
7088
  for (const project of projects) {
@@ -6992,6 +7111,9 @@ var require_openCode = __commonJS({
6992
7111
  if (folders.length > 0)
6993
7112
  return folders;
6994
7113
  }
7114
+ if (dbStatus.kind !== "db_missing") {
7115
+ return [];
7116
+ }
6995
7117
  return this.getAllProjectFoldersFromFiles(workspacePath);
6996
7118
  }
6997
7119
  getAllProjectFoldersFromFiles(workspacePath) {
@@ -7077,7 +7199,7 @@ var require_openCode = __commonJS({
7077
7199
  }
7078
7200
  encodeWorkspacePath(workspacePath) {
7079
7201
  const db = this.ensureDb();
7080
- return resolveProjectId(workspacePath, db) || workspacePath;
7202
+ return resolveProjectId(workspacePath, db, this.getRuntimeStatus()) || workspacePath;
7081
7203
  }
7082
7204
  extractSessionLabel(sessionPath) {
7083
7205
  const db = this.ensureDb();
@@ -19343,7 +19465,7 @@ var init_UpdateCheckService = __esm({
19343
19465
  /** Run the update check (one-shot). */
19344
19466
  async check() {
19345
19467
  try {
19346
- const current = "0.13.5";
19468
+ const current = "0.13.6";
19347
19469
  const cached = this.readCache();
19348
19470
  let latest;
19349
19471
  if (cached && Date.now() - cached.checkedAt < CACHE_TTL_MS) {
@@ -58928,6 +59050,24 @@ var init_SessionPickerHelpers = __esm({
58928
59050
  }
58929
59051
  });
58930
59052
 
59053
+ // src/dashboard/branding.ts
59054
+ var BRAND_NAME, BRAND_TAGLINE, LOGO_ART, BRAND_INLINE;
59055
+ var init_branding = __esm({
59056
+ "src/dashboard/branding.ts"() {
59057
+ "use strict";
59058
+ BRAND_NAME = "SIDEKICK";
59059
+ BRAND_TAGLINE = "Agent Hub";
59060
+ LOGO_ART = [
59061
+ " {bold}{magenta-fg} ___ ___ ___ ___ _ _____ ___ _ __{/magenta-fg}{/bold}",
59062
+ " {bold}{magenta-fg}/ __|_ _| \\| __| |/ /_ _/ __| |/ /{/magenta-fg}{/bold}",
59063
+ " {bold}{magenta-fg}\\__ \\| || |) | _|| ' < | | (__| ' < {/magenta-fg}{/bold}",
59064
+ " {bold}{magenta-fg}|___/___|___/|___|_|\\_\\___\\___|_|\\_\\{/magenta-fg}{/bold}",
59065
+ ` {grey-fg}${BRAND_TAGLINE}{/grey-fg}`
59066
+ ];
59067
+ BRAND_INLINE = `{bold}{magenta-fg}${BRAND_NAME}{/magenta-fg}{/bold}`;
59068
+ }
59069
+ });
59070
+
58931
59071
  // node_modules/react/cjs/react-jsx-runtime.production.js
58932
59072
  var require_react_jsx_runtime_production = __commonJS({
58933
59073
  "node_modules/react/cjs/react-jsx-runtime.production.js"(exports) {
@@ -59227,6 +59367,81 @@ var require_jsx_runtime = __commonJS({
59227
59367
  }
59228
59368
  });
59229
59369
 
59370
+ // src/dashboard/ink/parseBlessedTags.tsx
59371
+ function mapColor(c) {
59372
+ if (c === "grey") return "gray";
59373
+ return c;
59374
+ }
59375
+ function parseBlessedTags(input) {
59376
+ if (!input) return null;
59377
+ if (!input.includes("{")) {
59378
+ return input;
59379
+ }
59380
+ const segments = [];
59381
+ const styleStack = [{}];
59382
+ let lastIndex = 0;
59383
+ let segKey = 0;
59384
+ TAG_RE.lastIndex = 0;
59385
+ let match;
59386
+ while ((match = TAG_RE.exec(input)) !== null) {
59387
+ const beforeText = input.slice(lastIndex, match.index);
59388
+ if (beforeText) {
59389
+ segments.push(renderSpan(beforeText, currentStyle(styleStack), segKey++));
59390
+ }
59391
+ lastIndex = match.index + match[0].length;
59392
+ const isClose = match[1] === "/";
59393
+ const tagName = match[2];
59394
+ if (isClose) {
59395
+ if (styleStack.length > 1) {
59396
+ styleStack.pop();
59397
+ }
59398
+ } else if (tagName === "center") {
59399
+ } else if (tagName === "bold") {
59400
+ styleStack.push({ ...currentStyle(styleStack), bold: true });
59401
+ } else if (tagName === "underline") {
59402
+ styleStack.push({ ...currentStyle(styleStack), underline: true });
59403
+ } else if (tagName.endsWith("-fg")) {
59404
+ const color = tagName.slice(0, -3);
59405
+ styleStack.push({ ...currentStyle(styleStack), color: mapColor(color) });
59406
+ }
59407
+ }
59408
+ const trailing = input.slice(lastIndex);
59409
+ if (trailing) {
59410
+ segments.push(renderSpan(trailing, currentStyle(styleStack), segKey++));
59411
+ }
59412
+ if (segments.length === 0) return null;
59413
+ if (segments.length === 1) return segments[0];
59414
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: segments });
59415
+ }
59416
+ function currentStyle(stack) {
59417
+ return stack[stack.length - 1];
59418
+ }
59419
+ function renderSpan(text, style, key) {
59420
+ const hasStyle = style.bold || style.underline || style.color;
59421
+ if (!hasStyle) {
59422
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: text }, key);
59423
+ }
59424
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
59425
+ Text,
59426
+ {
59427
+ bold: style.bold,
59428
+ underline: style.underline,
59429
+ color: style.color,
59430
+ children: text
59431
+ },
59432
+ key
59433
+ );
59434
+ }
59435
+ var import_jsx_runtime, TAG_RE;
59436
+ var init_parseBlessedTags = __esm({
59437
+ async "src/dashboard/ink/parseBlessedTags.tsx"() {
59438
+ "use strict";
59439
+ await init_build2();
59440
+ import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
59441
+ TAG_RE = /\{(\/?)([^}]+)\}/g;
59442
+ }
59443
+ });
59444
+
59230
59445
  // src/dashboard/ink/SessionPickerInk.tsx
59231
59446
  function buildGroupedRows(items) {
59232
59447
  const providerIds = new Set(items.map((it) => it.providerId).filter(Boolean));
@@ -59278,8 +59493,8 @@ function SessionPickerInk({ items, onSelect }) {
59278
59493
  const viewportHeight = Math.max(5, rows - 15);
59279
59494
  function renderSessionRow(i, isSelected) {
59280
59495
  if (i === items.length) {
59281
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { inverse: isSelected, children: [
59282
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "yellow", children: "+" }),
59496
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { inverse: isSelected, children: [
59497
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "yellow", children: "+" }),
59283
59498
  " Wait for a new session to start..."
59284
59499
  ] }) }, "wait");
59285
59500
  }
@@ -59288,21 +59503,21 @@ function SessionPickerInk({ items, onSelect }) {
59288
59503
  const dotColor = item.isActive ? "green" : "gray";
59289
59504
  const badge = item.providerId ? PROVIDER_BADGES[item.providerId] : null;
59290
59505
  const truncLabel = item.label.length > 40 ? item.label.substring(0, 37) + "..." : item.label;
59291
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { inverse: isSelected, children: [
59292
- badge && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: badge.color, children: [
59506
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { inverse: isSelected, children: [
59507
+ badge && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: badge.color, children: [
59293
59508
  "[",
59294
59509
  badge.badge,
59295
59510
  "]"
59296
59511
  ] }),
59297
59512
  " ",
59298
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: dotColor, children: dot }),
59513
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: dotColor, children: dot }),
59299
59514
  " ",
59300
59515
  truncLabel.padEnd(40),
59301
59516
  " ",
59302
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: item.age.padEnd(9) }),
59517
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "gray", children: item.age.padEnd(9) }),
59303
59518
  " ",
59304
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: item.sessionId }),
59305
- item.isActive ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "green", children: " LIVE" }) : ""
59519
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "gray", children: item.sessionId }),
59520
+ item.isActive ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "green", children: " LIVE" }) : ""
59306
59521
  ] }) }, item.sessionPath);
59307
59522
  }
59308
59523
  function renderList() {
@@ -59329,14 +59544,14 @@ function SessionPickerInk({ items, onSelect }) {
59329
59544
  const name = PROVIDER_NAMES[row.providerId] || row.providerId;
59330
59545
  const badge = PROVIDER_BADGES[row.providerId];
59331
59546
  elements.push(
59332
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { children: [
59333
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { dimColor: true, children: [
59547
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
59548
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
59334
59549
  "\u2500\u2500",
59335
59550
  " "
59336
59551
  ] }),
59337
- badge && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: badge.color, children: name }),
59338
- !badge && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: name }),
59339
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { dimColor: true, children: [
59552
+ badge && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: badge.color, children: name }),
59553
+ !badge && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: name }),
59554
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
59340
59555
  " ",
59341
59556
  "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
59342
59557
  ] })
@@ -59358,12 +59573,9 @@ function SessionPickerInk({ items, onSelect }) {
59358
59573
  return renderSessionRow(i, i === selectedIndex);
59359
59574
  });
59360
59575
  }
59361
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", width: "100%", height: rows, children: [
59362
- /* @__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: [
59363
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, color: "magenta", children: " S I D E K I C K" }),
59364
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, children: " Agent Hub" })
59365
- ] }) }),
59366
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
59576
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", width: "100%", height: rows, children: [
59577
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { justifyContent: "center", marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { flexDirection: "column", width: 50, children: LOGO_ART.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: parseBlessedTags(line) }, `logo-${i}`)) }) }),
59578
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
59367
59579
  Box_default,
59368
59580
  {
59369
59581
  flexDirection: "column",
@@ -59372,7 +59584,7 @@ function SessionPickerInk({ items, onSelect }) {
59372
59584
  marginX: 2,
59373
59585
  flexGrow: 1,
59374
59586
  children: [
59375
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: "magenta", children: [
59587
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: "magenta", children: [
59376
59588
  " Sessions (",
59377
59589
  items.length,
59378
59590
  ") "
@@ -59381,21 +59593,21 @@ function SessionPickerInk({ items, onSelect }) {
59381
59593
  ]
59382
59594
  }
59383
59595
  ),
59384
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { height: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { children: [
59596
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { height: 1, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
59385
59597
  " ",
59386
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, color: "magenta", children: "SIDEKICK" }),
59598
+ parseBlessedTags(BRAND_INLINE),
59387
59599
  " ",
59388
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: "Session Picker" }),
59600
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "gray", children: "Session Picker" }),
59389
59601
  " ",
59390
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { bold: true, children: [
59602
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { bold: true, children: [
59391
59603
  "\u2191",
59392
59604
  "/",
59393
59605
  "\u2193"
59394
59606
  ] }),
59395
59607
  " navigate ",
59396
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, children: "Enter" }),
59608
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: true, children: "Enter" }),
59397
59609
  " select ",
59398
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { bold: true, children: "q" }),
59610
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: true, children: "q" }),
59399
59611
  " quit"
59400
59612
  ] }) })
59401
59613
  ] });
@@ -59414,7 +59626,7 @@ async function showSessionPicker(provider, workspacePath, additionalProviders) {
59414
59626
  if (items.length === 0) return { sessionPath: null };
59415
59627
  return new Promise((resolve, reject) => {
59416
59628
  const instance = render2(
59417
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
59629
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
59418
59630
  SessionPickerInk,
59419
59631
  {
59420
59632
  items,
@@ -59431,14 +59643,16 @@ async function showSessionPicker(provider, workspacePath, additionalProviders) {
59431
59643
  }).catch(reject);
59432
59644
  });
59433
59645
  }
59434
- var import_react29, import_jsx_runtime, PROVIDER_NAMES;
59646
+ var import_react29, import_jsx_runtime2, PROVIDER_NAMES;
59435
59647
  var init_SessionPickerInk = __esm({
59436
59648
  async "src/dashboard/ink/SessionPickerInk.tsx"() {
59437
59649
  "use strict";
59438
59650
  import_react29 = __toESM(require_react(), 1);
59439
59651
  await init_build2();
59440
59652
  init_SessionPickerHelpers();
59441
- import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
59653
+ init_branding();
59654
+ await init_parseBlessedTags();
59655
+ import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
59442
59656
  PROVIDER_NAMES = {
59443
59657
  "claude-code": "Claude Code",
59444
59658
  "opencode": "OpenCode",
@@ -59587,19 +59801,19 @@ var init_useWindowedScroll = __esm({
59587
59801
  // src/dashboard/ink/TabBar.tsx
59588
59802
  function TabBar({ panels, activeIndex, layoutMode }) {
59589
59803
  const modeLabel = MODE_LABELS[layoutMode] || layoutMode;
59590
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { height: 1, width: "100%", children: [
59591
- /* @__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: [
59804
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { height: 1, width: "100%", children: [
59805
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexGrow: 1, children: panels.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { marginRight: 1, children: i === activeIndex ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { bold: true, underline: true, color: "magenta", children: [
59592
59806
  p.shortcutKey,
59593
59807
  " ",
59594
59808
  p.title
59595
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
59596
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: p.shortcutKey }),
59597
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: "gray", children: [
59809
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
59810
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: p.shortcutKey }),
59811
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: "gray", children: [
59598
59812
  " ",
59599
59813
  p.title
59600
59814
  ] })
59601
59815
  ] }) }, p.id)) }),
59602
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
59816
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { dimColor: true, children: [
59603
59817
  "z: ",
59604
59818
  modeLabel,
59605
59819
  " ",
@@ -59607,12 +59821,12 @@ function TabBar({ panels, activeIndex, layoutMode }) {
59607
59821
  ] }) })
59608
59822
  ] });
59609
59823
  }
59610
- var import_jsx_runtime2, MODE_LABELS;
59824
+ var import_jsx_runtime3, MODE_LABELS;
59611
59825
  var init_TabBar = __esm({
59612
59826
  async "src/dashboard/ink/TabBar.tsx"() {
59613
59827
  "use strict";
59614
59828
  await init_build2();
59615
- import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
59829
+ import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
59616
59830
  MODE_LABELS = {
59617
59831
  normal: "Normal",
59618
59832
  expanded: "Expanded",
@@ -59621,81 +59835,6 @@ var init_TabBar = __esm({
59621
59835
  }
59622
59836
  });
59623
59837
 
59624
- // src/dashboard/ink/parseBlessedTags.tsx
59625
- function mapColor(c) {
59626
- if (c === "grey") return "gray";
59627
- return c;
59628
- }
59629
- function parseBlessedTags(input) {
59630
- if (!input) return null;
59631
- if (!input.includes("{")) {
59632
- return input;
59633
- }
59634
- const segments = [];
59635
- const styleStack = [{}];
59636
- let lastIndex = 0;
59637
- let segKey = 0;
59638
- TAG_RE.lastIndex = 0;
59639
- let match;
59640
- while ((match = TAG_RE.exec(input)) !== null) {
59641
- const beforeText = input.slice(lastIndex, match.index);
59642
- if (beforeText) {
59643
- segments.push(renderSpan(beforeText, currentStyle(styleStack), segKey++));
59644
- }
59645
- lastIndex = match.index + match[0].length;
59646
- const isClose = match[1] === "/";
59647
- const tagName = match[2];
59648
- if (isClose) {
59649
- if (styleStack.length > 1) {
59650
- styleStack.pop();
59651
- }
59652
- } else if (tagName === "center") {
59653
- } else if (tagName === "bold") {
59654
- styleStack.push({ ...currentStyle(styleStack), bold: true });
59655
- } else if (tagName === "underline") {
59656
- styleStack.push({ ...currentStyle(styleStack), underline: true });
59657
- } else if (tagName.endsWith("-fg")) {
59658
- const color = tagName.slice(0, -3);
59659
- styleStack.push({ ...currentStyle(styleStack), color: mapColor(color) });
59660
- }
59661
- }
59662
- const trailing = input.slice(lastIndex);
59663
- if (trailing) {
59664
- segments.push(renderSpan(trailing, currentStyle(styleStack), segKey++));
59665
- }
59666
- if (segments.length === 0) return null;
59667
- if (segments.length === 1) return segments[0];
59668
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: segments });
59669
- }
59670
- function currentStyle(stack) {
59671
- return stack[stack.length - 1];
59672
- }
59673
- function renderSpan(text, style, key) {
59674
- const hasStyle = style.bold || style.underline || style.color;
59675
- if (!hasStyle) {
59676
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: text }, key);
59677
- }
59678
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
59679
- Text,
59680
- {
59681
- bold: style.bold,
59682
- underline: style.underline,
59683
- color: style.color,
59684
- children: text
59685
- },
59686
- key
59687
- );
59688
- }
59689
- var import_jsx_runtime3, TAG_RE;
59690
- var init_parseBlessedTags = __esm({
59691
- async "src/dashboard/ink/parseBlessedTags.tsx"() {
59692
- "use strict";
59693
- await init_build2();
59694
- import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
59695
- TAG_RE = /\{(\/?)([^}]+)\}/g;
59696
- }
59697
- });
59698
-
59699
59838
  // src/dashboard/ink/SideList.tsx
59700
59839
  function truncateTaggedLabel(label, maxVisible) {
59701
59840
  const stripped = label.replace(TAG_RE2, "");
@@ -59912,13 +60051,10 @@ function StatusBar({
59912
60051
  const statusColor = providerStatus?.indicator === "minor" ? "yellow" : "red";
59913
60052
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { height: 1, width: "100%", children: [
59914
60053
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
59915
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { bold: true, color: "magenta", children: [
59916
- "\u26A1",
59917
- " SIDEKICK"
59918
- ] }),
60054
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: parseBlessedTags(BRAND_INLINE) }),
59919
60055
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { dimColor: true, children: [
59920
60056
  " v",
59921
- "0.13.5"
60057
+ "0.13.6"
59922
60058
  ] }),
59923
60059
  updateInfo && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: "yellow", children: [
59924
60060
  " (v",
@@ -60013,6 +60149,8 @@ var init_StatusBar = __esm({
60013
60149
  async "src/dashboard/ink/StatusBar.tsx"() {
60014
60150
  "use strict";
60015
60151
  await init_build2();
60152
+ init_branding();
60153
+ await init_parseBlessedTags();
60016
60154
  import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
60017
60155
  }
60018
60156
  });
@@ -60038,18 +60176,6 @@ var init_useSpinner = __esm({
60038
60176
  }
60039
60177
  });
60040
60178
 
60041
- // src/dashboard/branding.ts
60042
- var LOGO_ART;
60043
- var init_branding = __esm({
60044
- "src/dashboard/branding.ts"() {
60045
- "use strict";
60046
- LOGO_ART = [
60047
- " {bold}{magenta-fg}\u26A1 S I D E K I C K{/magenta-fg}{/bold}",
60048
- " {grey-fg}Agent Hub \xB7 Terminal Dashboard{/grey-fg}"
60049
- ];
60050
- }
60051
- });
60052
-
60053
60179
  // src/dashboard/ink/SplashOverlay.tsx
60054
60180
  function SplashOverlay() {
60055
60181
  const spinner = useSpinner();
@@ -60306,7 +60432,7 @@ function ChangelogOverlay({ entries, scrollOffset }) {
60306
60432
  " ",
60307
60433
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { bold: true, color: "cyan", children: [
60308
60434
  "Terminal Dashboard v",
60309
- "0.13.5"
60435
+ "0.13.6"
60310
60436
  ] }),
60311
60437
  latestDate ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { color: "gray", children: [
60312
60438
  " \u2014 ",
@@ -60628,7 +60754,7 @@ var init_mouse = __esm({
60628
60754
  var CHANGELOG_default;
60629
60755
  var init_CHANGELOG = __esm({
60630
60756
  "CHANGELOG.md"() {
60631
- 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.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';
60757
+ 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.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';
60632
60758
  }
60633
60759
  });
60634
60760
 
@@ -61412,7 +61538,8 @@ var init_Dashboard = __esm({
61412
61538
  // src/commands/dashboard.ts
61413
61539
  var dashboard_exports = {};
61414
61540
  __export(dashboard_exports, {
61415
- dashboardAction: () => dashboardAction
61541
+ dashboardAction: () => dashboardAction,
61542
+ getProviderRuntimeIssue: () => getProviderRuntimeIssue
61416
61543
  });
61417
61544
  import * as path4 from "path";
61418
61545
  import * as os3 from "os";
@@ -61428,6 +61555,18 @@ function createProviderById(id) {
61428
61555
  return new import_sidekick_shared14.ClaudeCodeProvider();
61429
61556
  }
61430
61557
  }
61558
+ function getProviderRuntimeIssue(provider) {
61559
+ if (provider.id !== "opencode") {
61560
+ return null;
61561
+ }
61562
+ const status = provider.getRuntimeStatus?.();
61563
+ if (!status || status.available || status.kind === "db_missing") {
61564
+ return null;
61565
+ }
61566
+ const detail = status.message ? ` ${status.message}` : "";
61567
+ const recommendation = status.kind === "sqlite_missing" ? " Recommendation: install `sqlite3`, ensure it is on PATH for the current shell, then retry." : status.kind === "sqlite_blocked" ? " Recommendation: ensure `sqlite3` is executable in the same environment as this shell, then retry." : " Recommendation: verify `sqlite3` can read `opencode.db` in the current environment, then retry.";
61568
+ return `${provider.displayName} session database is unavailable.${detail}${recommendation}`;
61569
+ }
61431
61570
  async function dashboardAction(_opts, cmd) {
61432
61571
  const globalOpts = cmd.parent.opts();
61433
61572
  const opts = cmd.opts();
@@ -61436,14 +61575,18 @@ async function dashboardAction(_opts, cmd) {
61436
61575
  let sessionId = opts.session;
61437
61576
  let replay = !!opts.replay;
61438
61577
  let activeProvider = provider;
61578
+ const providerIssue = getProviderRuntimeIssue(provider);
61439
61579
  const detectedIds = (0, import_sidekick_shared13.getAllDetectedProviders)();
61440
61580
  const additionalProviders = detectedIds.filter((id) => id !== provider.id).map((id) => createProviderById(id));
61441
61581
  if (!sessionId) {
61442
- const sessions = provider.findAllSessions(workspacePath);
61443
- const hasAnySessions = sessions.length > 0 || additionalProviders.some((p) => p.findAllSessions(workspacePath).length > 0);
61582
+ const sessions = providerIssue ? [] : provider.findAllSessions(workspacePath);
61583
+ const healthyAdditionalProviders = additionalProviders.filter((p) => !getProviderRuntimeIssue(p));
61584
+ const hasAnySessions = sessions.length > 0 || healthyAdditionalProviders.some((p) => p.findAllSessions(workspacePath).length > 0);
61444
61585
  if (hasAnySessions) {
61445
61586
  try {
61446
- const result = await showSessionPicker(provider, workspacePath, additionalProviders);
61587
+ const pickerProvider = providerIssue ? healthyAdditionalProviders[0] || provider : provider;
61588
+ const pickerAdditionalProviders = providerIssue ? healthyAdditionalProviders.slice(1) : healthyAdditionalProviders;
61589
+ const result = await showSessionPicker(pickerProvider, workspacePath, pickerAdditionalProviders);
61447
61590
  if (result.sessionPath) {
61448
61591
  sessionId = path4.basename(result.sessionPath, path4.extname(result.sessionPath));
61449
61592
  replay = true;
@@ -61455,11 +61598,22 @@ async function dashboardAction(_opts, cmd) {
61455
61598
  for (const p of additionalProviders) p.dispose();
61456
61599
  process.exit(0);
61457
61600
  }
61601
+ } else if (providerIssue) {
61602
+ for (const p of additionalProviders) p.dispose();
61603
+ console.error(providerIssue);
61604
+ process.exitCode = 1;
61605
+ return;
61458
61606
  }
61459
61607
  }
61460
61608
  for (const p of additionalProviders) {
61461
61609
  if (p !== activeProvider) p.dispose();
61462
61610
  }
61611
+ const activeProviderIssue = getProviderRuntimeIssue(activeProvider);
61612
+ if (activeProviderIssue) {
61613
+ console.error(activeProviderIssue);
61614
+ process.exitCode = 1;
61615
+ return;
61616
+ }
61463
61617
  let staticData;
61464
61618
  try {
61465
61619
  staticData = await loadStaticData(workspacePath);
@@ -62850,7 +63004,7 @@ var init_cli = __esm({
62850
63004
  import_sidekick_shared25 = __toESM(require_dist(), 1);
62851
63005
  import_sidekick_shared26 = __toESM(require_dist(), 1);
62852
63006
  program2 = new Command();
62853
- program2.name("sidekick").description("Query Sidekick project intelligence from the command line").version("0.13.5").option("--json", "Output as JSON").option("--project <path>", "Override project path (default: cwd)").option("--provider <id>", "Provider: claude-code, opencode, codex, auto (default: auto)");
63007
+ program2.name("sidekick").description("Query Sidekick project intelligence from the command line").version("0.13.6").option("--json", "Output as JSON").option("--project <path>", "Override project path (default: cwd)").option("--provider <id>", "Provider: claude-code, opencode, codex, auto (default: auto)");
62854
63008
  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) => {
62855
63009
  const { dashboardAction: dashboardAction2 } = await init_dashboard().then(() => dashboard_exports);
62856
63010
  return dashboardAction2(_opts, cmd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sidekick-agent-hub",
3
- "version": "0.13.5",
3
+ "version": "0.13.6",
4
4
  "description": "Terminal dashboard for monitoring AI coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {