claude-doom-statusbar 0.1.1 → 0.2.0

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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-doom-statusbar",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "DOOM-inspired status bar for the Claude Code CLI — a mugshot that tracks session health, plus usage, model, project, system, and a live subagent list.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/render.js CHANGED
@@ -36,10 +36,10 @@ export const SAMPLE = {
36
36
  "pr.state": "#1234",
37
37
  "act.subagents": [["hook events", "2m13s"], ["find configs", "12s"]], "act.agents": "2",
38
38
  "act.tasklist": [
39
- { mark:"", markRgb: OK, text:"scaffold project" },
40
- { mark:"", markRgb: OK, text:"render engine" },
41
- { mark:"", markRgb: CRIT, text:"port PIL alpha" },
42
- { mark:"", markRgb: null, text:"statusline values" },
39
+ { mark:"", markRgb: OK, text:"scaffold project" },
40
+ { mark:"", markRgb: OK, text:"render engine" },
41
+ { mark:"", markRgb: CRIT, text:"port PIL alpha" },
42
+ { mark:"", markRgb: null, text:"statusline values" },
43
43
  { mark:"🎯", markRgb: null, text:"hook bus" },
44
44
  { mark:"🎯", markRgb: null, text:"installer" },
45
45
  ],
@@ -58,7 +58,8 @@ export function vlen(s) {
58
58
  let n = 0;
59
59
  for (const ch of String(s).replace(ANSI_RE, "")) {
60
60
  const cp = ch.codePointAt(0);
61
- n += (cp >= 0x1f300 && cp <= 0x1faff) || (cp >= 0x23e9 && cp <= 0x23ec) ? 2 : 1;
61
+ n += (cp >= 0x1f300 && cp <= 0x1faff) || (cp >= 0x23e9 && cp <= 0x23ec)
62
+ || cp === 0x2705 || cp === 0x274c ? 2 : 1; // ✅ ❌ are emoji-presentation (2 cols)
62
63
  }
63
64
  return n;
64
65
  }
@@ -368,30 +369,35 @@ export function buildBar(cfg, target, spriteFor) {
368
369
  const items = VALUES[m.id] || [];
369
370
  const H = totalRows - (headers ? 1 : 0);
370
371
  const boundary = items.filter((it) => !Array.isArray(it) &&
371
- (it.mark === "" || it.mark === "")).length; // settled count (ignored for top anchor)
372
+ (it.mark === "" || it.mark === "")).length; // settled count (ignored for top anchor)
372
373
  const win = scrollWindow(items.length, H, m.anchor || "top", boundary);
373
374
  const shown = items.slice(win.start, win.start + H);
374
375
  shown.forEach((item, k) => {
375
376
  const first = k === 0, last = k === shown.length - 1;
376
- const over = first && win.up > 0 ? `↑${win.up} ` : last && win.down > 0 ? `↓${win.down} ` : "";
377
+ const marker = first && win.up > 0 ? `↑${win.up}` : last && win.down > 0 ? `↓${win.down}` : "";
378
+ const tail = marker ? " " + marker : ""; // right-aligned scroll marker (gap + ↑k/↓k)
379
+ const tailW = vlen(tail);
377
380
  let body;
378
381
  if (Array.isArray(item)) { // [left, right] (agents)
379
- const right = f(TEXT) + String(item[1]);
380
- const prefix = over + lbl; // ↑k/↓k marker + icon
381
- const labelMax = Math.max(0, w - vlen(prefix) - vlen(String(item[1])) - 1); // 1 = min gap
382
+ const right = f(TEXT) + String(item[1]) + (marker ? f(TEXT) + tail : "");
383
+ const rightW = vlen(String(item[1])) + tailW;
384
+ const labelMax = Math.max(0, w - vlen(lbl) - rightW - 1); // 1 = min gap
382
385
  let label = String(item[0]);
383
386
  if (vlen(label) > labelMax) label = [...label].slice(0, Math.max(0, labelMax - 1)).join("") + "…";
384
- const left = prefix + f(TEXT) + label;
385
- const room = Math.max(0, w - vlen(left) - vlen(right));
387
+ const left = lbl + f(TEXT) + label;
388
+ const room = Math.max(0, w - vlen(left) - rightW);
386
389
  body = left + " ".repeat(room) + right;
387
390
  } else { // {mark, markRgb, text} (tasks)
388
391
  const markCol = item.markRgb ? f(item.markRgb) : f(TEXT);
392
+ const m = String(item.mark);
393
+ const mPad = m + (vlen(m) < 2 ? " " : ""); // normalize mark to 2 cols so text aligns
389
394
  let text = String(item.text);
390
- const head = over + markCol + String(item.mark) + " " + f(TEXT);
391
- const max = w - vlen(over) - vlen(String(item.mark)) - 1;
395
+ const head = markCol + mPad + " " + f(TEXT);
396
+ const max = w - vlen(mPad) - 1 - tailW; // reserve gap + marker on the right
392
397
  if (vlen(text) > max) text = [...text].slice(0, Math.max(0, max - 1)).join("") + "…";
393
398
  body = head + text;
394
- body += " ".repeat(Math.max(0, w - vlen(body)));
399
+ body += " ".repeat(Math.max(0, w - tailW - vlen(body)));
400
+ if (tail) body += f(TEXT) + tail;
395
401
  }
396
402
  col.push(bgsgrBox(boxRgb) + " " + body + " " + RESET);
397
403
  });
package/src/statusline.js CHANGED
@@ -218,8 +218,8 @@ function sysValues(cwd) {
218
218
  const PERM = { plan: "📋 plan", auto: "⏩ auto", acceptEdits: "⏩ auto", bypassPermissions: "⏩ bypass" };
219
219
  const OK_RGB = [96, 200, 104]; // matches render.js OK (done, green)
220
220
  const CRIT_RGB = [224, 84, 64]; // matches render.js CRIT (deleted, red)
221
- const TASK_MARK = { completed: ["", OK_RGB], deleted: ["", CRIT_RGB], in_progress: ["", null], pending: ["🎯", null] };
222
- const TASK_ORDER = { completed: 0, deleted: 1, in_progress: 2, pending: 3 }; // settled first, then open
221
+ const TASK_MARK = { completed: ["", OK_RGB], deleted: ["", CRIT_RGB], in_progress: ["", null], pending: ["🎯", null] };
222
+ const TASK_ORDER = { completed: 0, deleted: 0, in_progress: 1, pending: 2 }; // settled (done+deleted, by time) first, then open
223
223
 
224
224
  export function activityValues(st, now) {
225
225
  const v = {};