sisyphi 1.1.38 → 1.1.39

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 {};
@@ -691,7 +738,7 @@ var init_config = __esm({
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
 
@@ -2147,7 +2285,7 @@ function applyColor(result, fields, facePart, mood, opts) {
2147
2285
 
2148
2286
  // src/daemon/companion.ts
2149
2287
  init_paths();
2150
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
2288
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
2151
2289
  import { randomUUID as randomUUID2 } from "crypto";
2152
2290
  import { dirname as dirname2, join as join5 } from "path";
2153
2291
 
@@ -2273,7 +2411,7 @@ var ACHIEVEMENTS = [
2273
2411
 
2274
2412
  // src/daemon/companion-memory.ts
2275
2413
  init_paths();
2276
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "fs";
2414
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync, writeFileSync as writeFileSync2 } from "fs";
2277
2415
  import { dirname, join as join4 } from "path";
2278
2416
  import { randomUUID } from "crypto";
2279
2417
  import { z } from "zod";
@@ -3592,7 +3730,7 @@ function renderCompanionDebugOverlay(buf, rows, cols, companion) {
3592
3730
  // src/tui/panels/mounted-humanloop.ts
3593
3731
  init_ask_store();
3594
3732
  init_paths();
3595
- import { readFileSync as readFileSync9 } from "fs";
3733
+ import { readFileSync as readFileSync10 } from "fs";
3596
3734
  import { mountPanel } from "@crouton-kit/humanloop";
3597
3735
 
3598
3736
  // src/shared/client.ts
@@ -3691,7 +3829,7 @@ function mountResolutionPanel(opts, state2) {
3691
3829
  }, 6e4);
3692
3830
  if (res.ok) {
3693
3831
  const ansiPath = res.data.ansiPath;
3694
- const ansi = readFileSync9(ansiPath, "utf-8");
3832
+ const ansi = readFileSync10(ansiPath, "utf-8");
3695
3833
  state2.visuals.set(qid, { status: "ready", content: ansi, visible: true });
3696
3834
  } else {
3697
3835
  state2.visuals.set(qid, { status: "error", content: "", visible: true, error: res.error });
@@ -4477,7 +4615,7 @@ function handleLeaderAction(action, state2, actions) {
4477
4615
  break;
4478
4616
  }
4479
4617
  try {
4480
- const content = readFileSync10(latest, "utf-8");
4618
+ const content = readFileSync11(latest, "utf-8");
4481
4619
  actions.copyToClipboard(content);
4482
4620
  notify(state2, `Copied latest report (${content.length} chars)`);
4483
4621
  } catch {
@@ -4638,13 +4776,12 @@ function handleLeaderAction(action, state2, actions) {
4638
4776
  notify(state2, "No session selected");
4639
4777
  break;
4640
4778
  }
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");
4779
+ const pasted = pasteFromClipboard();
4780
+ if ("reason" in pasted) {
4781
+ notify(state2, pasted.reason);
4646
4782
  break;
4647
4783
  }
4784
+ const exploreInstruction = pasted.text.trim();
4648
4785
  if (exploreInstruction.length < 20) {
4649
4786
  notify(state2, `Clipboard too short (${exploreInstruction.length} chars; need 20+)`);
4650
4787
  break;
@@ -4660,13 +4797,12 @@ function handleLeaderAction(action, state2, actions) {
4660
4797
  notify(state2, "No session selected");
4661
4798
  break;
4662
4799
  }
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");
4800
+ const pasted = pasteFromClipboard();
4801
+ if ("reason" in pasted) {
4802
+ notify(state2, pasted.reason);
4668
4803
  break;
4669
4804
  }
4805
+ const debugInstruction = pasted.text.trim();
4670
4806
  if (debugInstruction.length < 20) {
4671
4807
  notify(state2, `Clipboard too short (${debugInstruction.length} chars; need 20+)`);
4672
4808
  break;
@@ -5446,10 +5582,10 @@ function precomputePrefixes(nodes) {
5446
5582
  }
5447
5583
 
5448
5584
  // src/tui/lib/reports.ts
5449
- import { readFileSync as readFileSync11 } from "fs";
5585
+ import { readFileSync as readFileSync12 } from "fs";
5450
5586
  function loadReportContent(report) {
5451
5587
  try {
5452
- return readFileSync11(report.filePath, "utf-8");
5588
+ return readFileSync12(report.filePath, "utf-8");
5453
5589
  } catch {
5454
5590
  return report.summary;
5455
5591
  }
@@ -5477,7 +5613,7 @@ async function inboxList() {
5477
5613
  init_paths();
5478
5614
  import { execSync as execSync3 } from "child_process";
5479
5615
  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";
5616
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, mkdtempSync, rmSync as rmSync4, cpSync as cpSync2, existsSync as existsSync9, mkdirSync as mkdirSync8 } from "fs";
5481
5617
  import { tmpdir } from "os";
5482
5618
  init_shell();
5483
5619
 
@@ -5545,7 +5681,7 @@ function registerDashboardWindow(cwd2) {
5545
5681
  function setupCompanionPlugin() {
5546
5682
  const srcDir = join12(import.meta.dirname, "templates", "companion-plugin");
5547
5683
  const destDir = join12(globalDir(), "companion-plugin");
5548
- if (!existsSync8(destDir)) mkdirSync8(destDir, { recursive: true });
5684
+ if (!existsSync9(destDir)) mkdirSync8(destDir, { recursive: true });
5549
5685
  cpSync2(srcDir, destDir, { recursive: true });
5550
5686
  return destDir;
5551
5687
  }
@@ -5575,7 +5711,7 @@ function openCompanionPane(cwd2) {
5575
5711
  const templatePath = join12(import.meta.dirname, "templates", "dashboard-claude.md");
5576
5712
  let template;
5577
5713
  try {
5578
- template = readFileSync12(templatePath, "utf-8");
5714
+ template = readFileSync13(templatePath, "utf-8");
5579
5715
  } catch {
5580
5716
  template = `You are a Sisyphus dashboard companion. Help the user manage multi-agent sessions.
5581
5717
  Project: ${cwd2}
@@ -5604,7 +5740,7 @@ function editInPopup(cwd2, editor, opts) {
5604
5740
  try {
5605
5741
  writeFileSync9(filePath, opts?.content ? opts.content : "", "utf-8");
5606
5742
  openEditorPopup(cwd2, editor, filePath, opts?.size);
5607
- const result = readFileSync12(filePath, "utf-8").trim();
5743
+ const result = readFileSync13(filePath, "utf-8").trim();
5608
5744
  return result || null;
5609
5745
  } finally {
5610
5746
  rmSync4(tmpDir, { recursive: true, force: true });
@@ -5620,8 +5756,8 @@ function promptInPopup(prompt, opts) {
5620
5756
  `tmux display-popup -E -w ${w} -h ${h} ${shellQuote(`bash -c ${shellQuote(script)}`)}`,
5621
5757
  { stdio: "inherit", env: EXEC_ENV }
5622
5758
  );
5623
- if (!existsSync8(outFile)) return null;
5624
- const result = readFileSync12(outFile, "utf-8").trim();
5759
+ if (!existsSync9(outFile)) return null;
5760
+ const result = readFileSync13(outFile, "utf-8").trim();
5625
5761
  return result || null;
5626
5762
  } finally {
5627
5763
  rmSync4(tmpDir, { recursive: true, force: true });
@@ -5716,18 +5852,12 @@ function openEditorPopup(cwd2, editor, filePath, size) {
5716
5852
  }
5717
5853
  }
5718
5854
 
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
5855
  // src/tui/lib/context.ts
5726
5856
  init_paths();
5727
- import { readFileSync as readFileSync13, readdirSync as readdirSync6 } from "fs";
5857
+ import { readFileSync as readFileSync14, readdirSync as readdirSync6 } from "fs";
5728
5858
  function readFileSafe(filePath) {
5729
5859
  try {
5730
- return readFileSync13(filePath, "utf-8");
5860
+ return readFileSync14(filePath, "utf-8");
5731
5861
  } catch {
5732
5862
  return null;
5733
5863
  }
@@ -8264,13 +8394,13 @@ init_paths();
8264
8394
 
8265
8395
  // src/tui/lib/popup-compose.ts
8266
8396
  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";
8397
+ import { execSync as execSync4 } from "child_process";
8398
+ import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync10, readFileSync as readFileSync15, rmSync as rmSync5 } from "fs";
8269
8399
  import { join as join14 } from "path";
8270
8400
  import { tmpdir as tmpdir2 } from "os";
8271
8401
 
8272
8402
  // src/shared/sisyphus-init-lua.ts
8273
- import { mkdirSync as mkdirSync9, existsSync as existsSync9, cpSync as cpSync3 } from "fs";
8403
+ import { mkdirSync as mkdirSync9, existsSync as existsSync10, cpSync as cpSync3 } from "fs";
8274
8404
  import { join as join13 } from "path";
8275
8405
  import { homedir as homedir4 } from "os";
8276
8406
  var initLuaEnsured = false;
@@ -8280,7 +8410,7 @@ function ensureSisyphusInitLua() {
8280
8410
  try {
8281
8411
  const destDir = join13(homedir4(), ".config", "sisyphus");
8282
8412
  const destPath = join13(destDir, "init.lua");
8283
- if (existsSync9(destPath)) return;
8413
+ if (existsSync10(destPath)) return;
8284
8414
  mkdirSync9(destDir, { recursive: true });
8285
8415
  const srcPath = join13(import.meta.dirname, "templates", "sisyphus-init.lua");
8286
8416
  cpSync3(srcPath, destPath);
@@ -8295,13 +8425,13 @@ function composeViaPopup(action, state2, actions) {
8295
8425
  try {
8296
8426
  writeFileSync10(tempFile, "", "utf-8");
8297
8427
  const cmd = `NVIM_APPNAME=sisyphus nvim ${shellQuote(tempFile)}`;
8298
- execSync5(
8428
+ execSync4(
8299
8429
  `tmux display-popup -E -w 90% -h 90% -d ${shellQuote(state2.cwd)} ${shellQuote(cmd)}`,
8300
8430
  { stdio: "inherit", env: EXEC_ENV }
8301
8431
  );
8302
8432
  let rawContent = "";
8303
8433
  try {
8304
- rawContent = readFileSync14(tempFile, "utf-8");
8434
+ rawContent = readFileSync15(tempFile, "utf-8");
8305
8435
  } catch {
8306
8436
  }
8307
8437
  const required = !OPTIONAL_COMPOSE.has(action.kind);
@@ -8326,7 +8456,7 @@ function getCompanion() {
8326
8456
  const { mtimeMs } = statSync4(companionPath());
8327
8457
  if (_cachedCompanion && mtimeMs === _companionMtime) return _cachedCompanion;
8328
8458
  _companionMtime = mtimeMs;
8329
- _cachedCompanion = normalizeCompanion(JSON.parse(readFileSync15(companionPath(), "utf-8")));
8459
+ _cachedCompanion = normalizeCompanion(JSON.parse(readFileSync16(companionPath(), "utf-8")));
8330
8460
  return _cachedCompanion;
8331
8461
  } catch {
8332
8462
  return _cachedCompanion;
@@ -8448,40 +8578,40 @@ function startApp(state2, cleanup2) {
8448
8578
  selectedSession = statusRes.data?.session ?? null;
8449
8579
  }
8450
8580
  if (selectedSession?.tmuxWindowId) {
8451
- const cached = sessions.find((s) => s.id === state2.selectedSessionId);
8452
- paneAlive = cached?.windowAlive ?? false;
8581
+ const cached2 = sessions.find((s) => s.id === state2.selectedSessionId);
8582
+ paneAlive = cached2?.windowAlive ?? false;
8453
8583
  }
8454
8584
  try {
8455
8585
  const pp = roadmapPath(state2.cwd, state2.selectedSessionId);
8456
- if (existsSync10(pp)) {
8457
- planContent = readFileSync15(pp, "utf-8");
8586
+ if (existsSync11(pp)) {
8587
+ planContent = readFileSync16(pp, "utf-8");
8458
8588
  }
8459
8589
  } catch {
8460
8590
  }
8461
8591
  try {
8462
8592
  const gp = goalPath(state2.cwd, state2.selectedSessionId);
8463
- if (existsSync10(gp)) {
8464
- goalContent = readFileSync15(gp, "utf-8");
8593
+ if (existsSync11(gp)) {
8594
+ goalContent = readFileSync16(gp, "utf-8");
8465
8595
  }
8466
8596
  } catch {
8467
8597
  }
8468
8598
  try {
8469
8599
  const sp = strategyPath(state2.cwd, state2.selectedSessionId);
8470
- if (existsSync10(sp)) {
8471
- strategyContent = readFileSync15(sp, "utf-8");
8600
+ if (existsSync11(sp)) {
8601
+ strategyContent = readFileSync16(sp, "utf-8");
8472
8602
  }
8473
8603
  } catch {
8474
8604
  }
8475
8605
  try {
8476
8606
  const cp = join15(contextDir(state2.cwd, state2.selectedSessionId), "completion-summary.md");
8477
- if (existsSync10(cp)) {
8478
- completionSummaryContent = readFileSync15(cp, "utf-8");
8607
+ if (existsSync11(cp)) {
8608
+ completionSummaryContent = readFileSync16(cp, "utf-8");
8479
8609
  }
8480
8610
  } catch {
8481
8611
  }
8482
8612
  try {
8483
8613
  const ld = logsDir(state2.cwd, state2.selectedSessionId);
8484
- if (existsSync10(ld)) {
8614
+ if (existsSync11(ld)) {
8485
8615
  if (state2.selectedSessionId !== cachedLogSessionId) {
8486
8616
  cachedLogFiles = /* @__PURE__ */ new Map();
8487
8617
  cachedLogSessionId = state2.selectedSessionId;
@@ -8494,11 +8624,11 @@ function startApp(state2, cleanup2) {
8494
8624
  for (const f of files) {
8495
8625
  const filePath = join15(ld, f);
8496
8626
  const mtime = statSync4(filePath).mtimeMs;
8497
- const cached = cachedLogFiles.get(f);
8498
- if (!cached || cached.mtime !== mtime) {
8627
+ const cached2 = cachedLogFiles.get(f);
8628
+ if (!cached2 || cached2.mtime !== mtime) {
8499
8629
  const match = f.match(/cycle-(\d+)\.md$/);
8500
8630
  const cycle = match ? parseInt(match[1], 10) : 0;
8501
- const content = readFileSync15(filePath, "utf-8");
8631
+ const content = readFileSync16(filePath, "utf-8");
8502
8632
  cachedLogFiles.set(f, { mtime, cycle, content });
8503
8633
  }
8504
8634
  }
@@ -8512,7 +8642,7 @@ function startApp(state2, cleanup2) {
8512
8642
  }
8513
8643
  try {
8514
8644
  const cd = contextDir(state2.cwd, state2.selectedSessionId);
8515
- if (existsSync10(cd)) {
8645
+ if (existsSync11(cd)) {
8516
8646
  const entries = readdirSync7(cd, { withFileTypes: true }).filter((e) => !e.name.startsWith("."));
8517
8647
  const flat = [];
8518
8648
  for (const e of entries) {
@@ -8532,8 +8662,8 @@ function startApp(state2, cleanup2) {
8532
8662
  }
8533
8663
  try {
8534
8664
  const dp = digestPath(state2.cwd, state2.selectedSessionId);
8535
- if (existsSync10(dp)) {
8536
- const raw = JSON.parse(readFileSync15(dp, "utf-8"));
8665
+ if (existsSync11(dp)) {
8666
+ const raw = JSON.parse(readFileSync16(dp, "utf-8"));
8537
8667
  if (raw && typeof raw.recentWork === "string" && typeof raw.currentActivity === "string" && typeof raw.whatsNext === "string" && Array.isArray(raw.unusualEvents)) {
8538
8668
  digestData = raw;
8539
8669
  }
@@ -8676,8 +8806,8 @@ function startApp(state2, cleanup2) {
8676
8806
  if (cursorNode.filePath !== cachedContextFilePath) {
8677
8807
  cachedContextFilePath = cursorNode.filePath;
8678
8808
  try {
8679
- if (existsSync10(cursorNode.filePath)) {
8680
- cachedContextFileContent = readFileSync15(cursorNode.filePath, "utf-8");
8809
+ if (existsSync11(cursorNode.filePath)) {
8810
+ cachedContextFileContent = readFileSync16(cursorNode.filePath, "utf-8");
8681
8811
  } else {
8682
8812
  cachedContextFileContent = null;
8683
8813
  }
@@ -8821,7 +8951,10 @@ function startApp(state2, cleanup2) {
8821
8951
  openLogPopup,
8822
8952
  openShellPopup,
8823
8953
  openInFileManager,
8824
- copyToClipboard,
8954
+ copyToClipboard: (text) => {
8955
+ const err = copyToClipboard(text);
8956
+ if (err !== null) notify(state2, err.reason);
8957
+ },
8825
8958
  buildSessionContext,
8826
8959
  resolveEditor: () => {
8827
8960
  if (config.editor) return config.editor;