sisyphi 1.1.38 → 1.1.40

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/dist/tui.js CHANGED
@@ -302,6 +302,53 @@ var init_paths = __esm({
302
302
  }
303
303
  });
304
304
 
305
+ // src/shared/platform.ts
306
+ import { execSync } from "child_process";
307
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
308
+ function detectPlatform() {
309
+ if (cachedPlatform) return cachedPlatform;
310
+ if (process.platform === "darwin") {
311
+ cachedPlatform = "darwin";
312
+ } else if (process.platform === "win32") {
313
+ cachedPlatform = "win32";
314
+ } else if (process.platform === "linux") {
315
+ cachedPlatform = isWsl() ? "wsl" : "linux";
316
+ } else {
317
+ cachedPlatform = "unknown";
318
+ }
319
+ return cachedPlatform;
320
+ }
321
+ function isWsl() {
322
+ if (process.env["WSL_DISTRO_NAME"] || process.env["WSL_INTEROP"]) return true;
323
+ try {
324
+ if (existsSync2("/proc/version")) {
325
+ const v = readFileSync2("/proc/version", "utf-8").toLowerCase();
326
+ if (v.includes("microsoft") || v.includes("wsl")) return true;
327
+ }
328
+ } catch {
329
+ }
330
+ return false;
331
+ }
332
+ function hasCommand(cmd) {
333
+ const cached2 = cmdCache.get(cmd);
334
+ if (cached2 !== void 0) return cached2;
335
+ try {
336
+ execSync(`command -v ${cmd}`, { stdio: "pipe", shell: "/bin/sh" });
337
+ cmdCache.set(cmd, true);
338
+ return true;
339
+ } catch {
340
+ cmdCache.set(cmd, false);
341
+ return false;
342
+ }
343
+ }
344
+ var cachedPlatform, cmdCache;
345
+ var init_platform = __esm({
346
+ "src/shared/platform.ts"() {
347
+ "use strict";
348
+ cmdCache = /* @__PURE__ */ new Map();
349
+ }
350
+ });
351
+
305
352
  // src/tui/render.ts
306
353
  import stringWidth2 from "string-width";
307
354
  function colorToSGR(color) {
@@ -630,10 +677,10 @@ var init_render = __esm({
630
677
  });
631
678
 
632
679
  // src/shared/config.ts
633
- import { readFileSync as readFileSync4 } from "fs";
680
+ import { readFileSync as readFileSync5 } from "fs";
634
681
  function readJsonFile(filePath) {
635
682
  try {
636
- const content = readFileSync4(filePath, "utf-8");
683
+ const content = readFileSync5(filePath, "utf-8");
637
684
  return JSON.parse(content);
638
685
  } catch {
639
686
  return {};
@@ -684,14 +731,14 @@ var init_config = __esm({
684
731
  },
685
732
  companionPopup: true,
686
733
  requiredPlugins: [
687
- { name: "devcore", marketplace: "crouton-kit" }
734
+ { name: "devcore", marketplace: "crouton-kit", owner: "crouton-labs" }
688
735
  ]
689
736
  };
690
737
  }
691
738
  });
692
739
 
693
740
  // src/daemon/history.ts
694
- import { appendFileSync, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, renameSync as renameSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as rmSync2, statSync } from "fs";
741
+ import { appendFileSync, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, renameSync as renameSync3, readdirSync as readdirSync2, readFileSync as readFileSync6, rmSync as rmSync2, statSync } from "fs";
695
742
  import { randomUUID as randomUUID3 } from "crypto";
696
743
  import { dirname as dirname3, join as join6 } from "path";
697
744
  var init_history = __esm({
@@ -737,7 +784,7 @@ var init_atomic = __esm({
737
784
  });
738
785
 
739
786
  // src/shared/gitignore.ts
740
- import { existsSync as existsSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
787
+ import { existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
741
788
  import { join as join8 } from "path";
742
789
  var init_gitignore = __esm({
743
790
  "src/shared/gitignore.ts"() {
@@ -753,7 +800,7 @@ var init_types = __esm({
753
800
  });
754
801
 
755
802
  // src/daemon/state.ts
756
- import { copyFileSync, cpSync, existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync7, readdirSync as readdirSync3, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
803
+ import { copyFileSync, cpSync, existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync8, readdirSync as readdirSync3, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
757
804
  import { join as join9 } from "path";
758
805
  var init_state = __esm({
759
806
  "src/daemon/state.ts"() {
@@ -777,7 +824,7 @@ var init_shell = __esm({
777
824
 
778
825
  // src/daemon/notify.ts
779
826
  import { spawn, execFile as execFile2 } from "child_process";
780
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, existsSync as existsSync6 } from "fs";
827
+ import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, existsSync as existsSync7 } from "fs";
781
828
  import { join as join10 } from "path";
782
829
  import { homedir as homedir3 } from "os";
783
830
  var TMUX_SOCKET, SWITCH_SCRIPT;
@@ -785,55 +832,57 @@ var init_notify = __esm({
785
832
  "src/daemon/notify.ts"() {
786
833
  "use strict";
787
834
  init_shell();
835
+ init_platform();
788
836
  TMUX_SOCKET = `/tmp/tmux-${process.getuid?.() ?? 0}/default`;
789
837
  SWITCH_SCRIPT = [
790
838
  "#!/bin/bash",
791
839
  'SESSION="$1"',
792
840
  `TMUX_SOCKET="${TMUX_SOCKET}"`,
793
- "TMUX=/opt/homebrew/bin/tmux",
794
841
  "",
795
842
  "# Find any attached client (user is likely on a different session)",
796
- `CLIENT_TTY=$("$TMUX" -S "$TMUX_SOCKET" list-clients -F '#{client_tty}' 2>/dev/null | head -1)`,
843
+ `CLIENT_TTY=$(tmux -S "$TMUX_SOCKET" list-clients -F '#{client_tty}' 2>/dev/null | head -1)`,
797
844
  '[ -z "$CLIENT_TTY" ] && exit 0',
798
845
  "",
799
846
  "# Switch that client to the target session",
800
- '"$TMUX" -S "$TMUX_SOCKET" switch-client -c "$CLIENT_TTY" -t "$SESSION" 2>/dev/null',
801
- '"$TMUX" -S "$TMUX_SOCKET" select-window -t "$SESSION" 2>/dev/null',
847
+ 'tmux -S "$TMUX_SOCKET" switch-client -c "$CLIENT_TTY" -t "$SESSION" 2>/dev/null',
848
+ 'tmux -S "$TMUX_SOCKET" select-window -t "$SESSION" 2>/dev/null',
802
849
  "",
803
- "# Bring iTerm2 to front and select the tab with this client",
804
- `TTY_SHORT=$(echo "$CLIENT_TTY" | sed 's|/dev/||')`,
805
- 'osascript -e "',
806
- ' tell application \\"iTerm2\\"',
807
- " activate",
808
- " repeat with w in windows",
809
- " tell w",
810
- " repeat with t in tabs",
811
- " tell t",
812
- " repeat with s in sessions",
813
- " tell s",
814
- ' if tty contains \\"$TTY_SHORT\\" then',
815
- " select t",
816
- " return",
817
- " end if",
818
- " end tell",
819
- " end repeat",
820
- " end tell",
821
- " end repeat",
822
- " end tell",
823
- " end repeat",
824
- " end tell",
825
- `" 2>/dev/null || osascript -e 'tell application "iTerm2" to activate' 2>/dev/null`,
850
+ "# macOS-only: bring iTerm2 to front and select the tab with this client",
851
+ 'if [ "$(uname -s)" = "Darwin" ] && command -v osascript >/dev/null 2>&1; then',
852
+ ` TTY_SHORT=$(echo "$CLIENT_TTY" | sed 's|/dev/||')`,
853
+ ' osascript -e "',
854
+ ' tell application \\"iTerm2\\"',
855
+ " activate",
856
+ " repeat with w in windows",
857
+ " tell w",
858
+ " repeat with t in tabs",
859
+ " tell t",
860
+ " repeat with s in sessions",
861
+ " tell s",
862
+ ' if tty contains \\"$TTY_SHORT\\" then',
863
+ " select t",
864
+ " return",
865
+ " end if",
866
+ " end tell",
867
+ " end repeat",
868
+ " end tell",
869
+ " end repeat",
870
+ " end tell",
871
+ " end repeat",
872
+ " end tell",
873
+ ` " 2>/dev/null || osascript -e 'tell application "iTerm2" to activate' 2>/dev/null`,
874
+ "fi",
826
875
  ""
827
876
  ].join("\n");
828
877
  }
829
878
  });
830
879
 
831
880
  // src/daemon/ask-store.ts
832
- import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync8, readdirSync as readdirSync4 } from "fs";
881
+ import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync9, readdirSync as readdirSync4 } from "fs";
833
882
  function readDecisions(cwd2, sessionId2, askId2) {
834
883
  const p = askDecisionsPath(cwd2, sessionId2, askId2);
835
884
  try {
836
- return JSON.parse(readFileSync8(p, { encoding: "utf-8" }));
885
+ return JSON.parse(readFileSync9(p, { encoding: "utf-8" }));
837
886
  } catch (_e) {
838
887
  return null;
839
888
  }
@@ -841,7 +890,7 @@ function readDecisions(cwd2, sessionId2, askId2) {
841
890
  function readProgress(cwd2, sessionId2, askId2) {
842
891
  const p = askProgressPath(cwd2, sessionId2, askId2);
843
892
  try {
844
- const data = JSON.parse(readFileSync8(p, { encoding: "utf-8" }));
893
+ const data = JSON.parse(readFileSync9(p, { encoding: "utf-8" }));
845
894
  if (!Array.isArray(data["responses"])) return null;
846
895
  return { responses: data["responses"], savedAt: data["savedAt"] };
847
896
  } catch (_e) {
@@ -856,10 +905,10 @@ function writeOutput(cwd2, sessionId2, askId2, responses, completedAt) {
856
905
  }
857
906
  function readMeta(cwd2, sessionId2, askId2) {
858
907
  const p = askMetaPath(cwd2, sessionId2, askId2);
859
- if (!existsSync7(p)) {
908
+ if (!existsSync8(p)) {
860
909
  return null;
861
910
  }
862
- return JSON.parse(readFileSync8(p, "utf-8"));
911
+ return JSON.parse(readFileSync9(p, "utf-8"));
863
912
  }
864
913
  async function updateMeta(cwd2, sessionId2, askId2, patch) {
865
914
  return withLock(askId2, () => {
@@ -890,7 +939,7 @@ var single_ask_exports = {};
890
939
  __export(single_ask_exports, {
891
940
  runSingleAsk: () => runSingleAsk
892
941
  });
893
- import { existsSync as existsSync11, watchFile, unwatchFile } from "fs";
942
+ import { existsSync as existsSync12, watchFile, unwatchFile } from "fs";
894
943
  import { mountPanel as mountPanel2 } from "@crouton-kit/humanloop";
895
944
  async function runSingleAsk(opts) {
896
945
  const { cwd: cwd2, sessionId: sessionId2, askId: askId2 } = opts;
@@ -936,7 +985,7 @@ async function runSingleAsk(opts) {
936
985
  };
937
986
  const onExternalChange = () => {
938
987
  if (exiting) return;
939
- if (!existsSync11(outputPath)) return;
988
+ if (!existsSync12(outputPath)) return;
940
989
  exit(0);
941
990
  };
942
991
  let lastResponses = [];
@@ -990,7 +1039,7 @@ async function runSingleAsk(opts) {
990
1039
  flushHost(panel.render());
991
1040
  });
992
1041
  watchFile(outputPath, { interval: 250 }, onExternalChange);
993
- if (existsSync11(outputPath)) {
1042
+ if (existsSync12(outputPath)) {
994
1043
  exit(0);
995
1044
  return;
996
1045
  }
@@ -1216,12 +1265,11 @@ function autoExpandCycle(state2) {
1216
1265
  }
1217
1266
 
1218
1267
  // src/tui/app.ts
1219
- import { readFileSync as readFileSync15, existsSync as existsSync10, readdirSync as readdirSync7, statSync as statSync4 } from "fs";
1268
+ import { readFileSync as readFileSync16, existsSync as existsSync11, readdirSync as readdirSync7, statSync as statSync4 } from "fs";
1220
1269
  import { join as join15 } from "path";
1221
1270
 
1222
1271
  // src/tui/input.ts
1223
- import { execSync } from "child_process";
1224
- import { readFileSync as readFileSync10, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
1272
+ import { readFileSync as readFileSync11, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
1225
1273
  import { join as join11 } from "path";
1226
1274
 
1227
1275
  // src/shared/session-export.ts
@@ -1346,6 +1394,96 @@ async function exportSessionToZip(sessionId2, cwd2, options) {
1346
1394
  return outputPath;
1347
1395
  }
1348
1396
 
1397
+ // src/shared/clipboard.ts
1398
+ init_platform();
1399
+ import { execFileSync, spawnSync } from "child_process";
1400
+ function detectClipboard() {
1401
+ const platform = detectPlatform();
1402
+ if (platform === "darwin") {
1403
+ return {
1404
+ copy: { cmd: "pbcopy", args: [] },
1405
+ paste: { cmd: "pbpaste", args: [] },
1406
+ hint: null
1407
+ };
1408
+ }
1409
+ if (platform === "wsl") {
1410
+ const copy = hasCommand("clip.exe") ? { cmd: "clip.exe", args: [] } : null;
1411
+ const paste = hasCommand("powershell.exe") ? { cmd: "powershell.exe", args: ["-NoProfile", "-Command", "Get-Clipboard"] } : null;
1412
+ return {
1413
+ copy,
1414
+ paste,
1415
+ hint: copy && paste ? null : "WSL clipboard needs Windows interop. Ensure /mnt/c/Windows/System32 is on PATH (it is by default)."
1416
+ };
1417
+ }
1418
+ if (platform === "linux") {
1419
+ if (process.env["WAYLAND_DISPLAY"] && hasCommand("wl-copy") && hasCommand("wl-paste")) {
1420
+ return {
1421
+ copy: { cmd: "wl-copy", args: [] },
1422
+ paste: { cmd: "wl-paste", args: ["--no-newline"] },
1423
+ hint: null
1424
+ };
1425
+ }
1426
+ if (hasCommand("xclip")) {
1427
+ return {
1428
+ copy: { cmd: "xclip", args: ["-selection", "clipboard"] },
1429
+ paste: { cmd: "xclip", args: ["-selection", "clipboard", "-o"] },
1430
+ hint: null
1431
+ };
1432
+ }
1433
+ if (hasCommand("xsel")) {
1434
+ return {
1435
+ copy: { cmd: "xsel", args: ["--clipboard", "--input"] },
1436
+ paste: { cmd: "xsel", args: ["--clipboard", "--output"] },
1437
+ hint: null
1438
+ };
1439
+ }
1440
+ return {
1441
+ copy: null,
1442
+ paste: null,
1443
+ hint: "Install a clipboard tool: `sudo apt install xclip` (or wl-clipboard for Wayland)."
1444
+ };
1445
+ }
1446
+ return {
1447
+ copy: null,
1448
+ paste: null,
1449
+ hint: "Clipboard not supported on this platform."
1450
+ };
1451
+ }
1452
+ var cached;
1453
+ function cap() {
1454
+ if (!cached) cached = detectClipboard();
1455
+ return cached;
1456
+ }
1457
+ function copyToClipboard(text) {
1458
+ const c = cap();
1459
+ if (!c.copy) {
1460
+ return { reason: c.hint === null ? "No clipboard backend available" : c.hint };
1461
+ }
1462
+ try {
1463
+ execFileSync(c.copy.cmd, c.copy.args, { input: text, stdio: ["pipe", "ignore", "pipe"] });
1464
+ return null;
1465
+ } catch (err) {
1466
+ const msg = err instanceof Error ? err.message.split("\n")[0] : String(err);
1467
+ return { reason: `${c.copy.cmd} failed: ${msg}` };
1468
+ }
1469
+ }
1470
+ function pasteFromClipboard() {
1471
+ const c = cap();
1472
+ if (!c.paste) {
1473
+ return { reason: c.hint === null ? "No clipboard backend available" : c.hint };
1474
+ }
1475
+ const result = spawnSync(c.paste.cmd, c.paste.args, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
1476
+ if (result.status !== 0) {
1477
+ const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
1478
+ if (stderr.length > 0) {
1479
+ return { reason: `${c.paste.cmd}: ${stderr.split("\n")[0]}` };
1480
+ }
1481
+ return { reason: `${c.paste.cmd} exited ${result.status}` };
1482
+ }
1483
+ const stdout = typeof result.stdout === "string" ? result.stdout : "";
1484
+ return { text: stdout.replace(/\s+$/, "") };
1485
+ }
1486
+
1349
1487
  // src/tui/input.ts
1350
1488
  init_paths();
1351
1489
 
@@ -1392,6 +1530,19 @@ function statusColor(status) {
1392
1530
  return "white";
1393
1531
  }
1394
1532
  }
1533
+ var COLOR_ENABLED = process.env["FORCE_COLOR"] === "1" || process.stdout.isTTY === true && process.env["NO_COLOR"] === void 0 && process.env["TERM"] !== "dumb";
1534
+ function wrap(open, close = "\x1B[0m") {
1535
+ return (s) => COLOR_ENABLED ? `${open}${s}${close}` : s;
1536
+ }
1537
+ var bold = wrap("\x1B[1m");
1538
+ var dim = wrap("\x1B[2m");
1539
+ var red = wrap("\x1B[31m");
1540
+ var green = wrap("\x1B[32m");
1541
+ var yellow = wrap("\x1B[33m");
1542
+ var cyan = wrap("\x1B[36m");
1543
+ var gray = wrap("\x1B[90m");
1544
+ var magenta = wrap("\x1B[35m");
1545
+ var white = wrap("\x1B[37m");
1395
1546
 
1396
1547
  // src/tui/lib/format.ts
1397
1548
  function formatTimeAgo(iso) {
@@ -1547,10 +1698,10 @@ function ansiBold(text) {
1547
1698
  function ansiDim(text) {
1548
1699
  return `\x1B[2m${text}\x1B[0m`;
1549
1700
  }
1550
- function ansiColor(text, color, bold = false) {
1701
+ function ansiColor(text, color, bold2 = false) {
1551
1702
  const COLOR_MAP = { black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37, gray: 90 };
1552
1703
  const codes = [];
1553
- if (bold) codes.push(1);
1704
+ if (bold2) codes.push(1);
1554
1705
  const sgr = COLOR_MAP[color];
1555
1706
  if (sgr !== void 0) codes.push(sgr);
1556
1707
  if (codes.length === 0) return text;
@@ -2147,7 +2298,7 @@ function applyColor(result, fields, facePart, mood, opts) {
2147
2298
 
2148
2299
  // src/daemon/companion.ts
2149
2300
  init_paths();
2150
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
2301
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
2151
2302
  import { randomUUID as randomUUID2 } from "crypto";
2152
2303
  import { dirname as dirname2, join as join5 } from "path";
2153
2304
 
@@ -2273,7 +2424,7 @@ var ACHIEVEMENTS = [
2273
2424
 
2274
2425
  // src/daemon/companion-memory.ts
2275
2426
  init_paths();
2276
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "fs";
2427
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync, writeFileSync as writeFileSync2 } from "fs";
2277
2428
  import { dirname, join as join4 } from "path";
2278
2429
  import { randomUUID } from "crypto";
2279
2430
  import { z } from "zod";
@@ -3096,7 +3247,7 @@ function stripAnsiForWidth(s) {
3096
3247
  return s.replace(/\x1b\[[0-9;]*m/g, "");
3097
3248
  }
3098
3249
  function renderBadgeCard(def, unlock, opts) {
3099
- const dim = opts?.dim === true || unlock === null;
3250
+ const dim2 = opts?.dim === true || unlock === null;
3100
3251
  const art = BADGE_ART[def.id] ?? [];
3101
3252
  const lines = [];
3102
3253
  const category = def.category.toUpperCase();
@@ -3110,7 +3261,7 @@ function renderBadgeCard(def, unlock, opts) {
3110
3261
  const artSlice = art.slice(0, artMaxLines);
3111
3262
  for (const artLine of artSlice) {
3112
3263
  const centered = centerLine(artLine, CARD_INNER);
3113
- lines.push(`\u2502${dim ? dimText(centered) : centered}\u2502`);
3264
+ lines.push(`\u2502${dim2 ? dimText(centered) : centered}\u2502`);
3114
3265
  }
3115
3266
  for (let i = artSlice.length; i < artMaxLines; i++) {
3116
3267
  lines.push(`\u2502${" ".repeat(CARD_INNER)}\u2502`);
@@ -3121,7 +3272,7 @@ function renderBadgeCard(def, unlock, opts) {
3121
3272
  const descLines = wrapText2(def.description, CARD_INNER - 4);
3122
3273
  for (const dl of descLines.slice(0, 2)) {
3123
3274
  const centered = centerLine(dl, CARD_INNER);
3124
- lines.push(`\u2502${dim ? dimText(centered) : centered}\u2502`);
3275
+ lines.push(`\u2502${dim2 ? dimText(centered) : centered}\u2502`);
3125
3276
  }
3126
3277
  const usedContent = 1 + 1 + artMaxLines + 1 + 1 + Math.min(descLines.length, 2);
3127
3278
  const remaining = CARD_HEIGHT - 2 - usedContent;
@@ -3592,7 +3743,7 @@ function renderCompanionDebugOverlay(buf, rows, cols, companion) {
3592
3743
  // src/tui/panels/mounted-humanloop.ts
3593
3744
  init_ask_store();
3594
3745
  init_paths();
3595
- import { readFileSync as readFileSync9 } from "fs";
3746
+ import { readFileSync as readFileSync10 } from "fs";
3596
3747
  import { mountPanel } from "@crouton-kit/humanloop";
3597
3748
 
3598
3749
  // src/shared/client.ts
@@ -3691,7 +3842,7 @@ function mountResolutionPanel(opts, state2) {
3691
3842
  }, 6e4);
3692
3843
  if (res.ok) {
3693
3844
  const ansiPath = res.data.ansiPath;
3694
- const ansi = readFileSync9(ansiPath, "utf-8");
3845
+ const ansi = readFileSync10(ansiPath, "utf-8");
3695
3846
  state2.visuals.set(qid, { status: "ready", content: ansi, visible: true });
3696
3847
  } else {
3697
3848
  state2.visuals.set(qid, { status: "error", content: "", visible: true, error: res.error });
@@ -4277,8 +4428,9 @@ function handleLeaderAction(action, state2, actions) {
4277
4428
  break;
4278
4429
  }
4279
4430
  try {
4280
- const text = actions.promptInPopup("Delete session? (yes/no):");
4281
- if (text?.trim() === "yes") {
4431
+ const text = actions.promptInPopup("Delete session? (y/yes to confirm):");
4432
+ const answer = text?.trim().toLowerCase();
4433
+ if (answer === "y" || answer === "yes") {
4282
4434
  actions.sendAndNotify({ type: "delete", sessionId: selectedSessionId, cwd: state2.cwd }, "Session deleted");
4283
4435
  } else {
4284
4436
  notify(state2, "Delete cancelled");
@@ -4477,7 +4629,7 @@ function handleLeaderAction(action, state2, actions) {
4477
4629
  break;
4478
4630
  }
4479
4631
  try {
4480
- const content = readFileSync10(latest, "utf-8");
4632
+ const content = readFileSync11(latest, "utf-8");
4481
4633
  actions.copyToClipboard(content);
4482
4634
  notify(state2, `Copied latest report (${content.length} chars)`);
4483
4635
  } catch {
@@ -4638,13 +4790,12 @@ function handleLeaderAction(action, state2, actions) {
4638
4790
  notify(state2, "No session selected");
4639
4791
  break;
4640
4792
  }
4641
- let exploreInstruction;
4642
- try {
4643
- exploreInstruction = execSync("pbpaste", { stdio: ["pipe", "pipe", "pipe"] }).toString().trim();
4644
- } catch {
4645
- notify(state2, "pbpaste not available \u2014 macOS only");
4793
+ const pasted = pasteFromClipboard();
4794
+ if ("reason" in pasted) {
4795
+ notify(state2, pasted.reason);
4646
4796
  break;
4647
4797
  }
4798
+ const exploreInstruction = pasted.text.trim();
4648
4799
  if (exploreInstruction.length < 20) {
4649
4800
  notify(state2, `Clipboard too short (${exploreInstruction.length} chars; need 20+)`);
4650
4801
  break;
@@ -4660,13 +4811,12 @@ function handleLeaderAction(action, state2, actions) {
4660
4811
  notify(state2, "No session selected");
4661
4812
  break;
4662
4813
  }
4663
- let debugInstruction;
4664
- try {
4665
- debugInstruction = execSync("pbpaste", { stdio: ["pipe", "pipe", "pipe"] }).toString().trim();
4666
- } catch {
4667
- notify(state2, "pbpaste not available \u2014 macOS only");
4814
+ const pasted = pasteFromClipboard();
4815
+ if ("reason" in pasted) {
4816
+ notify(state2, pasted.reason);
4668
4817
  break;
4669
4818
  }
4819
+ const debugInstruction = pasted.text.trim();
4670
4820
  if (debugInstruction.length < 20) {
4671
4821
  notify(state2, `Clipboard too short (${debugInstruction.length} chars; need 20+)`);
4672
4822
  break;
@@ -5446,10 +5596,10 @@ function precomputePrefixes(nodes) {
5446
5596
  }
5447
5597
 
5448
5598
  // src/tui/lib/reports.ts
5449
- import { readFileSync as readFileSync11 } from "fs";
5599
+ import { readFileSync as readFileSync12 } from "fs";
5450
5600
  function loadReportContent(report) {
5451
5601
  try {
5452
- return readFileSync11(report.filePath, "utf-8");
5602
+ return readFileSync12(report.filePath, "utf-8");
5453
5603
  } catch {
5454
5604
  return report.summary;
5455
5605
  }
@@ -5477,7 +5627,7 @@ async function inboxList() {
5477
5627
  init_paths();
5478
5628
  import { execSync as execSync3 } from "child_process";
5479
5629
  import { join as join12 } from "path";
5480
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, mkdtempSync, rmSync as rmSync4, cpSync as cpSync2, existsSync as existsSync8, mkdirSync as mkdirSync8 } from "fs";
5630
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, mkdtempSync, rmSync as rmSync4, cpSync as cpSync2, existsSync as existsSync9, mkdirSync as mkdirSync8 } from "fs";
5481
5631
  import { tmpdir } from "os";
5482
5632
  init_shell();
5483
5633
 
@@ -5545,7 +5695,7 @@ function registerDashboardWindow(cwd2) {
5545
5695
  function setupCompanionPlugin() {
5546
5696
  const srcDir = join12(import.meta.dirname, "templates", "companion-plugin");
5547
5697
  const destDir = join12(globalDir(), "companion-plugin");
5548
- if (!existsSync8(destDir)) mkdirSync8(destDir, { recursive: true });
5698
+ if (!existsSync9(destDir)) mkdirSync8(destDir, { recursive: true });
5549
5699
  cpSync2(srcDir, destDir, { recursive: true });
5550
5700
  return destDir;
5551
5701
  }
@@ -5575,7 +5725,7 @@ function openCompanionPane(cwd2) {
5575
5725
  const templatePath = join12(import.meta.dirname, "templates", "dashboard-claude.md");
5576
5726
  let template;
5577
5727
  try {
5578
- template = readFileSync12(templatePath, "utf-8");
5728
+ template = readFileSync13(templatePath, "utf-8");
5579
5729
  } catch {
5580
5730
  template = `You are a Sisyphus dashboard companion. Help the user manage multi-agent sessions.
5581
5731
  Project: ${cwd2}
@@ -5604,7 +5754,7 @@ function editInPopup(cwd2, editor, opts) {
5604
5754
  try {
5605
5755
  writeFileSync9(filePath, opts?.content ? opts.content : "", "utf-8");
5606
5756
  openEditorPopup(cwd2, editor, filePath, opts?.size);
5607
- const result = readFileSync12(filePath, "utf-8").trim();
5757
+ const result = readFileSync13(filePath, "utf-8").trim();
5608
5758
  return result || null;
5609
5759
  } finally {
5610
5760
  rmSync4(tmpDir, { recursive: true, force: true });
@@ -5620,8 +5770,8 @@ function promptInPopup(prompt, opts) {
5620
5770
  `tmux display-popup -E -w ${w} -h ${h} ${shellQuote(`bash -c ${shellQuote(script)}`)}`,
5621
5771
  { stdio: "inherit", env: EXEC_ENV }
5622
5772
  );
5623
- if (!existsSync8(outFile)) return null;
5624
- const result = readFileSync12(outFile, "utf-8").trim();
5773
+ if (!existsSync9(outFile)) return null;
5774
+ const result = readFileSync13(outFile, "utf-8").trim();
5625
5775
  return result || null;
5626
5776
  } finally {
5627
5777
  rmSync4(tmpDir, { recursive: true, force: true });
@@ -5716,18 +5866,12 @@ function openEditorPopup(cwd2, editor, filePath, size) {
5716
5866
  }
5717
5867
  }
5718
5868
 
5719
- // src/tui/lib/clipboard.ts
5720
- import { execSync as execSync4 } from "child_process";
5721
- function copyToClipboard(text) {
5722
- execSync4("pbcopy", { input: text });
5723
- }
5724
-
5725
5869
  // src/tui/lib/context.ts
5726
5870
  init_paths();
5727
- import { readFileSync as readFileSync13, readdirSync as readdirSync6 } from "fs";
5871
+ import { readFileSync as readFileSync14, readdirSync as readdirSync6 } from "fs";
5728
5872
  function readFileSafe(filePath) {
5729
5873
  try {
5730
- return readFileSync13(filePath, "utf-8");
5874
+ return readFileSync14(filePath, "utf-8");
5731
5875
  } catch {
5732
5876
  return null;
5733
5877
  }
@@ -5830,7 +5974,7 @@ function renderNodeContent(node, maxWidth) {
5830
5974
  case "session": {
5831
5975
  const icon = statusIndicator(node.status);
5832
5976
  const color = statusColor(node.status);
5833
- const dim = node.status === "completed" || node.orphaned === true;
5977
+ const dim2 = node.status === "completed" || node.orphaned === true;
5834
5978
  const cyclePart = node.cycleCount > 0 ? `C${node.cycleCount}` : "";
5835
5979
  const dur = formatDuration(node.activeMs);
5836
5980
  const agopart = node.status === "completed" && node.completedAt ? formatTimeAgo(node.completedAt) : "";
@@ -5842,7 +5986,7 @@ function renderNodeContent(node, maxWidth) {
5842
5986
  const displayText = node.name ?? node.task;
5843
5987
  const suffixWidth = suffix ? suffix.length + 1 : 0;
5844
5988
  const maxLabel = Math.max(8, maxWidth - meta.length - 4 - suffixWidth);
5845
- return { icon, label: truncate(displayText, maxLabel), meta, color, dim, metaColor, suffix, suffixColor };
5989
+ return { icon, label: truncate(displayText, maxLabel), meta, color, dim: dim2, metaColor, suffix, suffixColor };
5846
5990
  }
5847
5991
  case "cycle": {
5848
5992
  const isRunning = !node.completedAt;
@@ -5863,7 +6007,7 @@ function renderNodeContent(node, maxWidth) {
5863
6007
  const color = statusColor(node.status);
5864
6008
  const dur = formatDuration(node.activeMs);
5865
6009
  const durClr = durationColor(node.activeMs) || void 0;
5866
- const dim = node.status === "completed" || node.orphaned === true;
6010
+ const dim2 = node.status === "completed" || node.orphaned === true;
5867
6011
  const displayName = agentDisplayName({
5868
6012
  name: node.name,
5869
6013
  id: node.agentId,
@@ -5878,7 +6022,7 @@ function renderNodeContent(node, maxWidth) {
5878
6022
  label: truncate(displayName, maxLabel),
5879
6023
  meta: dur,
5880
6024
  color,
5881
- dim,
6025
+ dim: dim2,
5882
6026
  metaColor: durClr,
5883
6027
  suffix,
5884
6028
  suffixColor
@@ -6001,16 +6145,16 @@ function renderTreePanel(buf, rect, nodes, cursorIndex, focused, companion) {
6001
6145
  const isSelected = realIdx === cursorIndex;
6002
6146
  const prefix = node.prefix ?? renderTreePrefix(node, nodes, realIdx);
6003
6147
  const contentWidth = innerW;
6004
- const { icon, label, meta, color, dim, metaColor, suffix, suffixColor } = renderNodeContent(
6148
+ const { icon, label, meta, color, dim: dim2, metaColor, suffix, suffixColor } = renderNodeContent(
6005
6149
  node,
6006
6150
  contentWidth - prefix.length
6007
6151
  );
6008
6152
  let content = "";
6009
6153
  if (icon) {
6010
- if (dim) content += `\x1B[2;${colorToSGR(color)}m${icon}\x1B[0m `;
6154
+ if (dim2) content += `\x1B[2;${colorToSGR(color)}m${icon}\x1B[0m `;
6011
6155
  else content += `\x1B[${colorToSGR(color)}m${icon}\x1B[0m `;
6012
6156
  }
6013
- if (dim) content += `\x1B[2m${label}\x1B[0m`;
6157
+ if (dim2) content += `\x1B[2m${label}\x1B[0m`;
6014
6158
  else content += label;
6015
6159
  if (meta) {
6016
6160
  if (metaColor) content += ` \x1B[${colorToSGR(metaColor)}m${meta}\x1B[0m`;
@@ -6021,9 +6165,9 @@ function renderTreePanel(buf, rect, nodes, cursorIndex, focused, companion) {
6021
6165
  }
6022
6166
  let line = prefix;
6023
6167
  if (isSelected) {
6024
- const bold = "\x1B[1m";
6168
+ const bold2 = "\x1B[1m";
6025
6169
  const inverse = focused ? "\x1B[7m" : "";
6026
- line += `${inverse}${bold}${content}\x1B[0m`;
6170
+ line += `${inverse}${bold2}${content}\x1B[0m`;
6027
6171
  } else {
6028
6172
  line += content;
6029
6173
  }
@@ -6106,7 +6250,7 @@ function buildOrchestratorNode(cycle, agents, width, bright, showConnectorBottom
6106
6250
  const lines = [];
6107
6251
  const inner = width - 2;
6108
6252
  const bg2 = BG_TINTS.yellow;
6109
- const dim = !bright;
6253
+ const dim2 = !bright;
6110
6254
  const isRunning = !cycle.completedAt;
6111
6255
  const icon = isRunning ? "\u25CF" : "\u25CB";
6112
6256
  const cycleLabel = `C${cycle.cycle}`;
@@ -6124,63 +6268,63 @@ function buildOrchestratorNode(cycle, agents, width, bright, showConnectorBottom
6124
6268
  const leftW = stringWidth5(leftContent);
6125
6269
  const rightW = stringWidth5(rightText);
6126
6270
  const gap = Math.max(1, inner - 2 - leftW - rightW);
6127
- lines.push([seg("\u256D" + "\u2500".repeat(inner) + "\u256E", { color: "yellow", dim })]);
6271
+ lines.push([seg("\u256D" + "\u2500".repeat(inner) + "\u256E", { color: "yellow", dim: dim2 })]);
6128
6272
  const contentSegs = [
6129
- seg("\u2502", { color: "yellow", dim }),
6130
- seg(" " + icon + " ", { bg: bg2, color: isRunning ? "green" : void 0, dim: !isRunning && dim, bold: bright }),
6131
- seg(cycleLabel, { bg: bg2, dim, bold: bright }),
6273
+ seg("\u2502", { color: "yellow", dim: dim2 }),
6274
+ seg(" " + icon + " ", { bg: bg2, color: isRunning ? "green" : void 0, dim: !isRunning && dim2, bold: bright }),
6275
+ seg(cycleLabel, { bg: bg2, dim: dim2, bold: bright }),
6132
6276
  seg(" ", { bg: bg2 }),
6133
- seg(modeLabel, { bg: bg2, color: mColor, dim }),
6277
+ seg(modeLabel, { bg: bg2, color: mColor, dim: dim2 }),
6134
6278
  seg(" ".repeat(gap), { bg: bg2 })
6135
6279
  ];
6136
6280
  if (isRunning && bright) {
6137
6281
  contentSegs.push(seg(rightText, { bg: bg2, color: "green", bold: true }));
6138
6282
  } else {
6139
- contentSegs.push(seg(rightText, { bg: bg2, dim }));
6283
+ contentSegs.push(seg(rightText, { bg: bg2, dim: dim2 }));
6140
6284
  }
6141
6285
  contentSegs.push(seg(" ", { bg: bg2 }));
6142
6286
  const usedWidth = 1 + 1 + 1 + 1 + stringWidth5(cycleLabel) + 2 + stringWidth5(modeLabel) + gap + stringWidth5(rightText) + 1;
6143
6287
  if (usedWidth < inner) {
6144
6288
  contentSegs.push(seg(" ".repeat(inner - usedWidth), { bg: bg2 }));
6145
6289
  }
6146
- contentSegs.push(seg("\u2502", { color: "yellow", dim }));
6290
+ contentSegs.push(seg("\u2502", { color: "yellow", dim: dim2 }));
6147
6291
  lines.push(contentSegs);
6148
6292
  if (agents.length > 0) {
6149
6293
  const running = agents.filter((a) => a.status === "running").length;
6150
6294
  const done = agents.filter((a) => a.status === "completed").length;
6151
6295
  const failed = agents.filter((a) => a.status === "killed" || a.status === "crashed").length;
6152
6296
  const parts = [
6153
- seg("\u2502", { color: "yellow", dim }),
6297
+ seg("\u2502", { color: "yellow", dim: dim2 }),
6154
6298
  seg(` ${agents.length} agent${agents.length !== 1 ? "s" : ""}: `, { bg: bg2, dim: true })
6155
6299
  ];
6156
- if (running > 0) parts.push(seg(`${running}\u25B6 `, { bg: bg2, color: "green", dim }));
6157
- if (done > 0) parts.push(seg(`${done}\u2713 `, { bg: bg2, color: "cyan", dim }));
6158
- if (failed > 0) parts.push(seg(`${failed}\u2715 `, { bg: bg2, color: "red", dim }));
6300
+ if (running > 0) parts.push(seg(`${running}\u25B6 `, { bg: bg2, color: "green", dim: dim2 }));
6301
+ if (done > 0) parts.push(seg(`${done}\u2713 `, { bg: bg2, color: "cyan", dim: dim2 }));
6302
+ if (failed > 0) parts.push(seg(`${failed}\u2715 `, { bg: bg2, color: "red", dim: dim2 }));
6159
6303
  const labelLen = ` ${agents.length} agent${agents.length !== 1 ? "s" : ""}: `.length;
6160
6304
  const countLen = (running > 0 ? `${running}\u25B6 `.length : 0) + (done > 0 ? `${done}\u2713 `.length : 0) + (failed > 0 ? `${failed}\u2715 `.length : 0);
6161
6305
  const remaining = Math.max(0, inner - labelLen - countLen);
6162
6306
  parts.push(seg(" ".repeat(remaining), { bg: bg2 }));
6163
- parts.push(seg("\u2502", { color: "yellow", dim }));
6307
+ parts.push(seg("\u2502", { color: "yellow", dim: dim2 }));
6164
6308
  lines.push(parts);
6165
6309
  }
6166
6310
  if (showConnectorBottom) {
6167
6311
  const mid = Math.floor(inner / 2);
6168
6312
  const left = mid;
6169
6313
  const right = inner - mid - 1;
6170
- lines.push([seg("\u2570" + "\u2500".repeat(left) + "\u252C" + "\u2500".repeat(right) + "\u256F", { color: "yellow", dim })]);
6314
+ lines.push([seg("\u2570" + "\u2500".repeat(left) + "\u252C" + "\u2500".repeat(right) + "\u256F", { color: "yellow", dim: dim2 })]);
6171
6315
  } else {
6172
- lines.push([seg("\u2570" + "\u2500".repeat(inner) + "\u256F", { color: "yellow", dim })]);
6316
+ lines.push([seg("\u2570" + "\u2500".repeat(inner) + "\u256F", { color: "yellow", dim: dim2 })]);
6173
6317
  }
6174
6318
  return lines;
6175
6319
  }
6176
6320
  function stemCol(width) {
6177
6321
  return Math.floor(width / 2);
6178
6322
  }
6179
- function buildVerticalConnector(width, dim) {
6323
+ function buildVerticalConnector(width, dim2) {
6180
6324
  const col = stemCol(width);
6181
6325
  return [
6182
6326
  seg(" ".repeat(col)),
6183
- seg("\u2502", { dim })
6327
+ seg("\u2502", { dim: dim2 })
6184
6328
  ];
6185
6329
  }
6186
6330
  function buildBranchConnector(boxWidth, count, totalWidth, direction) {
@@ -6286,9 +6430,9 @@ function buildAgentBoxRows(agents, boxWidth, totalWidth, bright, maxPerRow) {
6286
6430
  const a = rowAgents[i];
6287
6431
  const isError = a.status === "killed" || a.status === "crashed";
6288
6432
  const borderColor = isError ? "red" : resolveColor(a.color);
6289
- const dim = !bright;
6433
+ const dim2 = !bright;
6290
6434
  const mid = Math.floor(innerW / 2);
6291
- topSegs.push(seg("\u256D" + "\u2500".repeat(mid) + "\u2534" + "\u2500".repeat(innerW - mid - 1) + "\u256E", { color: borderColor, dim }));
6435
+ topSegs.push(seg("\u256D" + "\u2500".repeat(mid) + "\u2534" + "\u2500".repeat(innerW - mid - 1) + "\u256E", { color: borderColor, dim: dim2 }));
6292
6436
  }
6293
6437
  lines.push(topSegs);
6294
6438
  const line1Segs = [];
@@ -6297,14 +6441,14 @@ function buildAgentBoxRows(agents, boxWidth, totalWidth, bright, maxPerRow) {
6297
6441
  const isError = a.status === "killed" || a.status === "crashed";
6298
6442
  const borderColor = isError ? "red" : resolveColor(a.color);
6299
6443
  const agentBg = BG_TINTS[isError ? "red" : resolveColor(a.color)] ?? BG_TINTS.gray;
6300
- const dim = !bright;
6444
+ const dim2 = !bright;
6301
6445
  const icon = agentStatusIcon(a.status);
6302
6446
  const iconColor = statusColor(a.status);
6303
6447
  const idPadded = padTo(` ${a.id}`, innerW - stringWidth5(icon));
6304
- line1Segs.push(seg("\u2502", { color: borderColor, dim }));
6448
+ line1Segs.push(seg("\u2502", { color: borderColor, dim: dim2 }));
6305
6449
  line1Segs.push(seg(icon, { bg: agentBg, color: iconColor, bold: bright }));
6306
- line1Segs.push(seg(idPadded, { bg: agentBg, dim, bold: bright && a.status === "running" }));
6307
- line1Segs.push(seg("\u2502", { color: borderColor, dim }));
6450
+ line1Segs.push(seg(idPadded, { bg: agentBg, dim: dim2, bold: bright && a.status === "running" }));
6451
+ line1Segs.push(seg("\u2502", { color: borderColor, dim: dim2 }));
6308
6452
  }
6309
6453
  lines.push(line1Segs);
6310
6454
  const line2Segs = [];
@@ -6313,11 +6457,11 @@ function buildAgentBoxRows(agents, boxWidth, totalWidth, bright, maxPerRow) {
6313
6457
  const isError = a.status === "killed" || a.status === "crashed";
6314
6458
  const borderColor = isError ? "red" : resolveColor(a.color);
6315
6459
  const agentBg = BG_TINTS[isError ? "red" : resolveColor(a.color)] ?? BG_TINTS.gray;
6316
- const dim = !bright;
6460
+ const dim2 = !bright;
6317
6461
  const name = padTo(agentDisplayName(a), innerW);
6318
- line2Segs.push(seg("\u2502", { color: borderColor, dim }));
6319
- line2Segs.push(seg(name, { bg: agentBg, dim }));
6320
- line2Segs.push(seg("\u2502", { color: borderColor, dim }));
6462
+ line2Segs.push(seg("\u2502", { color: borderColor, dim: dim2 }));
6463
+ line2Segs.push(seg(name, { bg: agentBg, dim: dim2 }));
6464
+ line2Segs.push(seg("\u2502", { color: borderColor, dim: dim2 }));
6321
6465
  }
6322
6466
  lines.push(line2Segs);
6323
6467
  const line3Segs = [];
@@ -6326,7 +6470,7 @@ function buildAgentBoxRows(agents, boxWidth, totalWidth, bright, maxPerRow) {
6326
6470
  const isError = a.status === "killed" || a.status === "crashed";
6327
6471
  const borderColor = isError ? "red" : resolveColor(a.color);
6328
6472
  const agentBg = BG_TINTS[isError ? "red" : resolveColor(a.color)] ?? BG_TINTS.gray;
6329
- const dim = !bright;
6473
+ const dim2 = !bright;
6330
6474
  const dur = formatDuration(a.activeMs);
6331
6475
  const durClr = isError ? "red" : durationColor(a.activeMs) || void 0;
6332
6476
  let durText;
@@ -6338,9 +6482,9 @@ function buildAgentBoxRows(agents, boxWidth, totalWidth, bright, maxPerRow) {
6338
6482
  } else {
6339
6483
  durText = padTo(dur, innerW);
6340
6484
  }
6341
- line3Segs.push(seg("\u2502", { color: borderColor, dim }));
6342
- line3Segs.push(seg(durText, { bg: agentBg, dim, color: durClr }));
6343
- line3Segs.push(seg("\u2502", { color: borderColor, dim }));
6485
+ line3Segs.push(seg("\u2502", { color: borderColor, dim: dim2 }));
6486
+ line3Segs.push(seg(durText, { bg: agentBg, dim: dim2, color: durClr }));
6487
+ line3Segs.push(seg("\u2502", { color: borderColor, dim: dim2 }));
6344
6488
  }
6345
6489
  lines.push(line3Segs);
6346
6490
  const line4Segs = [];
@@ -6349,11 +6493,11 @@ function buildAgentBoxRows(agents, boxWidth, totalWidth, bright, maxPerRow) {
6349
6493
  const isError = a.status === "killed" || a.status === "crashed";
6350
6494
  const borderColor = isError ? "red" : resolveColor(a.color);
6351
6495
  const agentBg = BG_TINTS[isError ? "red" : resolveColor(a.color)] ?? BG_TINTS.gray;
6352
- const dim = !bright;
6496
+ const dim2 = !bright;
6353
6497
  const summary = padTo(agentSummary(a, innerW), innerW);
6354
- line4Segs.push(seg("\u2502", { color: borderColor, dim }));
6498
+ line4Segs.push(seg("\u2502", { color: borderColor, dim: dim2 }));
6355
6499
  line4Segs.push(seg(summary, { bg: agentBg, dim: true }));
6356
- line4Segs.push(seg("\u2502", { color: borderColor, dim }));
6500
+ line4Segs.push(seg("\u2502", { color: borderColor, dim: dim2 }));
6357
6501
  }
6358
6502
  lines.push(line4Segs);
6359
6503
  const botSegs = [];
@@ -6361,11 +6505,11 @@ function buildAgentBoxRows(agents, boxWidth, totalWidth, bright, maxPerRow) {
6361
6505
  for (const a of rowAgents) {
6362
6506
  const isError = a.status === "killed" || a.status === "crashed";
6363
6507
  const borderColor = isError ? "red" : resolveColor(a.color);
6364
- const dim = !bright;
6508
+ const dim2 = !bright;
6365
6509
  const mid = Math.floor(innerW / 2);
6366
6510
  const left = mid;
6367
6511
  const right = innerW - mid - 1;
6368
- botSegs.push(seg("\u2570" + "\u2500".repeat(left) + "\u252C" + "\u2500".repeat(right) + "\u256F", { color: borderColor, dim }));
6512
+ botSegs.push(seg("\u2570" + "\u2500".repeat(left) + "\u252C" + "\u2500".repeat(right) + "\u256F", { color: borderColor, dim: dim2 }));
6369
6513
  }
6370
6514
  lines.push(botSegs);
6371
6515
  }
@@ -6406,19 +6550,19 @@ function buildYieldNode(prompt, width, bright, known) {
6406
6550
  const lines = [];
6407
6551
  const inner = width - 2;
6408
6552
  const bg2 = BG_TINTS.gray;
6409
- const dim = !bright;
6553
+ const dim2 = !bright;
6410
6554
  if (known && prompt) {
6411
- lines.push([seg("\u256D" + "\u2500".repeat(inner) + "\u256E", { color: "yellow", dim })]);
6555
+ lines.push([seg("\u256D" + "\u2500".repeat(inner) + "\u256E", { color: "yellow", dim: dim2 })]);
6412
6556
  const wrapped = wrapText(prompt, inner - 2);
6413
6557
  for (const wl of wrapped) {
6414
6558
  const padded = padTo(" " + wl, inner);
6415
6559
  lines.push([
6416
- seg("\u2502", { color: "yellow", dim }),
6560
+ seg("\u2502", { color: "yellow", dim: dim2 }),
6417
6561
  seg(padded, { bg: bg2, dim: true }),
6418
- seg("\u2502", { color: "yellow", dim })
6562
+ seg("\u2502", { color: "yellow", dim: dim2 })
6419
6563
  ]);
6420
6564
  }
6421
- lines.push([seg("\u2570" + "\u2500".repeat(inner) + "\u256F", { color: "yellow", dim })]);
6565
+ lines.push([seg("\u2570" + "\u2500".repeat(inner) + "\u256F", { color: "yellow", dim: dim2 })]);
6422
6566
  } else {
6423
6567
  lines.push([seg("\u256D" + "\u2500".repeat(inner) + "\u256E", { dim: true })]);
6424
6568
  const placeholder = padTo(" awaiting agents\u2026", inner);
@@ -8264,13 +8408,13 @@ init_paths();
8264
8408
 
8265
8409
  // src/tui/lib/popup-compose.ts
8266
8410
  init_shell();
8267
- import { execSync as execSync5 } from "child_process";
8268
- import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync10, readFileSync as readFileSync14, rmSync as rmSync5 } from "fs";
8411
+ import { execSync as execSync4 } from "child_process";
8412
+ import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync10, readFileSync as readFileSync15, rmSync as rmSync5 } from "fs";
8269
8413
  import { join as join14 } from "path";
8270
8414
  import { tmpdir as tmpdir2 } from "os";
8271
8415
 
8272
8416
  // src/shared/sisyphus-init-lua.ts
8273
- import { mkdirSync as mkdirSync9, existsSync as existsSync9, cpSync as cpSync3 } from "fs";
8417
+ import { mkdirSync as mkdirSync9, existsSync as existsSync10, cpSync as cpSync3 } from "fs";
8274
8418
  import { join as join13 } from "path";
8275
8419
  import { homedir as homedir4 } from "os";
8276
8420
  var initLuaEnsured = false;
@@ -8280,7 +8424,7 @@ function ensureSisyphusInitLua() {
8280
8424
  try {
8281
8425
  const destDir = join13(homedir4(), ".config", "sisyphus");
8282
8426
  const destPath = join13(destDir, "init.lua");
8283
- if (existsSync9(destPath)) return;
8427
+ if (existsSync10(destPath)) return;
8284
8428
  mkdirSync9(destDir, { recursive: true });
8285
8429
  const srcPath = join13(import.meta.dirname, "templates", "sisyphus-init.lua");
8286
8430
  cpSync3(srcPath, destPath);
@@ -8295,13 +8439,13 @@ function composeViaPopup(action, state2, actions) {
8295
8439
  try {
8296
8440
  writeFileSync10(tempFile, "", "utf-8");
8297
8441
  const cmd = `NVIM_APPNAME=sisyphus nvim ${shellQuote(tempFile)}`;
8298
- execSync5(
8442
+ execSync4(
8299
8443
  `tmux display-popup -E -w 90% -h 90% -d ${shellQuote(state2.cwd)} ${shellQuote(cmd)}`,
8300
8444
  { stdio: "inherit", env: EXEC_ENV }
8301
8445
  );
8302
8446
  let rawContent = "";
8303
8447
  try {
8304
- rawContent = readFileSync14(tempFile, "utf-8");
8448
+ rawContent = readFileSync15(tempFile, "utf-8");
8305
8449
  } catch {
8306
8450
  }
8307
8451
  const required = !OPTIONAL_COMPOSE.has(action.kind);
@@ -8326,7 +8470,7 @@ function getCompanion() {
8326
8470
  const { mtimeMs } = statSync4(companionPath());
8327
8471
  if (_cachedCompanion && mtimeMs === _companionMtime) return _cachedCompanion;
8328
8472
  _companionMtime = mtimeMs;
8329
- _cachedCompanion = normalizeCompanion(JSON.parse(readFileSync15(companionPath(), "utf-8")));
8473
+ _cachedCompanion = normalizeCompanion(JSON.parse(readFileSync16(companionPath(), "utf-8")));
8330
8474
  return _cachedCompanion;
8331
8475
  } catch {
8332
8476
  return _cachedCompanion;
@@ -8448,40 +8592,40 @@ function startApp(state2, cleanup2) {
8448
8592
  selectedSession = statusRes.data?.session ?? null;
8449
8593
  }
8450
8594
  if (selectedSession?.tmuxWindowId) {
8451
- const cached = sessions.find((s) => s.id === state2.selectedSessionId);
8452
- paneAlive = cached?.windowAlive ?? false;
8595
+ const cached2 = sessions.find((s) => s.id === state2.selectedSessionId);
8596
+ paneAlive = cached2?.windowAlive ?? false;
8453
8597
  }
8454
8598
  try {
8455
8599
  const pp = roadmapPath(state2.cwd, state2.selectedSessionId);
8456
- if (existsSync10(pp)) {
8457
- planContent = readFileSync15(pp, "utf-8");
8600
+ if (existsSync11(pp)) {
8601
+ planContent = readFileSync16(pp, "utf-8");
8458
8602
  }
8459
8603
  } catch {
8460
8604
  }
8461
8605
  try {
8462
8606
  const gp = goalPath(state2.cwd, state2.selectedSessionId);
8463
- if (existsSync10(gp)) {
8464
- goalContent = readFileSync15(gp, "utf-8");
8607
+ if (existsSync11(gp)) {
8608
+ goalContent = readFileSync16(gp, "utf-8");
8465
8609
  }
8466
8610
  } catch {
8467
8611
  }
8468
8612
  try {
8469
8613
  const sp = strategyPath(state2.cwd, state2.selectedSessionId);
8470
- if (existsSync10(sp)) {
8471
- strategyContent = readFileSync15(sp, "utf-8");
8614
+ if (existsSync11(sp)) {
8615
+ strategyContent = readFileSync16(sp, "utf-8");
8472
8616
  }
8473
8617
  } catch {
8474
8618
  }
8475
8619
  try {
8476
8620
  const cp = join15(contextDir(state2.cwd, state2.selectedSessionId), "completion-summary.md");
8477
- if (existsSync10(cp)) {
8478
- completionSummaryContent = readFileSync15(cp, "utf-8");
8621
+ if (existsSync11(cp)) {
8622
+ completionSummaryContent = readFileSync16(cp, "utf-8");
8479
8623
  }
8480
8624
  } catch {
8481
8625
  }
8482
8626
  try {
8483
8627
  const ld = logsDir(state2.cwd, state2.selectedSessionId);
8484
- if (existsSync10(ld)) {
8628
+ if (existsSync11(ld)) {
8485
8629
  if (state2.selectedSessionId !== cachedLogSessionId) {
8486
8630
  cachedLogFiles = /* @__PURE__ */ new Map();
8487
8631
  cachedLogSessionId = state2.selectedSessionId;
@@ -8494,11 +8638,11 @@ function startApp(state2, cleanup2) {
8494
8638
  for (const f of files) {
8495
8639
  const filePath = join15(ld, f);
8496
8640
  const mtime = statSync4(filePath).mtimeMs;
8497
- const cached = cachedLogFiles.get(f);
8498
- if (!cached || cached.mtime !== mtime) {
8641
+ const cached2 = cachedLogFiles.get(f);
8642
+ if (!cached2 || cached2.mtime !== mtime) {
8499
8643
  const match = f.match(/cycle-(\d+)\.md$/);
8500
8644
  const cycle = match ? parseInt(match[1], 10) : 0;
8501
- const content = readFileSync15(filePath, "utf-8");
8645
+ const content = readFileSync16(filePath, "utf-8");
8502
8646
  cachedLogFiles.set(f, { mtime, cycle, content });
8503
8647
  }
8504
8648
  }
@@ -8512,7 +8656,7 @@ function startApp(state2, cleanup2) {
8512
8656
  }
8513
8657
  try {
8514
8658
  const cd = contextDir(state2.cwd, state2.selectedSessionId);
8515
- if (existsSync10(cd)) {
8659
+ if (existsSync11(cd)) {
8516
8660
  const entries = readdirSync7(cd, { withFileTypes: true }).filter((e) => !e.name.startsWith("."));
8517
8661
  const flat = [];
8518
8662
  for (const e of entries) {
@@ -8532,8 +8676,8 @@ function startApp(state2, cleanup2) {
8532
8676
  }
8533
8677
  try {
8534
8678
  const dp = digestPath(state2.cwd, state2.selectedSessionId);
8535
- if (existsSync10(dp)) {
8536
- const raw = JSON.parse(readFileSync15(dp, "utf-8"));
8679
+ if (existsSync11(dp)) {
8680
+ const raw = JSON.parse(readFileSync16(dp, "utf-8"));
8537
8681
  if (raw && typeof raw.recentWork === "string" && typeof raw.currentActivity === "string" && typeof raw.whatsNext === "string" && Array.isArray(raw.unusualEvents)) {
8538
8682
  digestData = raw;
8539
8683
  }
@@ -8676,8 +8820,8 @@ function startApp(state2, cleanup2) {
8676
8820
  if (cursorNode.filePath !== cachedContextFilePath) {
8677
8821
  cachedContextFilePath = cursorNode.filePath;
8678
8822
  try {
8679
- if (existsSync10(cursorNode.filePath)) {
8680
- cachedContextFileContent = readFileSync15(cursorNode.filePath, "utf-8");
8823
+ if (existsSync11(cursorNode.filePath)) {
8824
+ cachedContextFileContent = readFileSync16(cursorNode.filePath, "utf-8");
8681
8825
  } else {
8682
8826
  cachedContextFileContent = null;
8683
8827
  }
@@ -8821,7 +8965,10 @@ function startApp(state2, cleanup2) {
8821
8965
  openLogPopup,
8822
8966
  openShellPopup,
8823
8967
  openInFileManager,
8824
- copyToClipboard,
8968
+ copyToClipboard: (text) => {
8969
+ const err = copyToClipboard(text);
8970
+ if (err !== null) notify(state2, err.reason);
8971
+ },
8825
8972
  buildSessionContext,
8826
8973
  resolveEditor: () => {
8827
8974
  if (config.editor) return config.editor;