sisyphi 1.2.19 → 1.2.20

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/cli.js CHANGED
@@ -87,8 +87,8 @@ function askReviewSubmitFlagPath(cwd, sessionId, askId) {
87
87
  function askVisualsDir(cwd, sessionId, askId) {
88
88
  return join(askEntryDir(cwd, sessionId, askId), "visuals");
89
89
  }
90
- function tmuxSessionName(cwd, sessionLabel) {
91
- return `ssyph_${basename(cwd)}_${sessionLabel}`;
90
+ function tmuxSessionName(cwd, sessionLabel2) {
91
+ return `ssyph_${basename(cwd)}_${sessionLabel2}`;
92
92
  }
93
93
  function sessionsManifestPath() {
94
94
  return join(globalDir(), "sessions-manifest.json");
@@ -422,7 +422,7 @@ var init_state = __esm({
422
422
  });
423
423
 
424
424
  // src/shared/platform.ts
425
- import { execSync as execSync7 } from "child_process";
425
+ import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
426
426
  import { existsSync as existsSync9, readFileSync as readFileSync10 } from "fs";
427
427
  function detectPlatform() {
428
428
  if (cachedPlatform) return cachedPlatform;
@@ -467,6 +467,20 @@ function hasCommand(cmd) {
467
467
  return false;
468
468
  }
469
469
  }
470
+ function isTerminalFrontmost() {
471
+ if (detectPlatform() !== "darwin") return false;
472
+ try {
473
+ const raw = execFileSync2(
474
+ "osascript",
475
+ ["-e", 'tell application "System Events" to get name of first application process whose frontmost is true'],
476
+ { timeout: 1e3, stdio: ["ignore", "pipe", "ignore"] }
477
+ );
478
+ const name = raw.toString().trim().toLowerCase();
479
+ return TERMINAL_APP_NAMES.has(name);
480
+ } catch {
481
+ return false;
482
+ }
483
+ }
470
484
  function platformLabel() {
471
485
  switch (detectPlatform()) {
472
486
  case "darwin":
@@ -483,11 +497,24 @@ function platformLabel() {
483
497
  return "unknown";
484
498
  }
485
499
  }
486
- var cachedPlatform, cmdCache;
500
+ var cachedPlatform, cmdCache, TERMINAL_APP_NAMES;
487
501
  var init_platform = __esm({
488
502
  "src/shared/platform.ts"() {
489
503
  "use strict";
490
504
  cmdCache = /* @__PURE__ */ new Map();
505
+ TERMINAL_APP_NAMES = /* @__PURE__ */ new Set([
506
+ "iterm2",
507
+ "iterm",
508
+ "terminal",
509
+ "apple_terminal",
510
+ "alacritty",
511
+ "kitty",
512
+ "wezterm",
513
+ "ghostty",
514
+ "hyper",
515
+ "warp",
516
+ "tmux"
517
+ ]);
491
518
  }
492
519
  });
493
520
 
@@ -635,13 +662,14 @@ var init_notify = __esm({
635
662
  });
636
663
 
637
664
  // src/daemon/ask-store.ts
638
- import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync11, readdirSync as readdirSync3 } from "fs";
665
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
639
666
  import { basename as basename3 } from "path";
640
- function maybeNotifyOnAskCreated(cwd, sessionId, meta) {
667
+ function maybeNotifyOnAskCreated(cwd, sessionId, meta, suppress = false) {
641
668
  if (process.env.NODE_ENV === "test" || process.env.SISYPHUS_DISABLE_NOTIFY === "1") return;
642
669
  const isActionable = meta.kind !== void 0 && ACTIONABLE_KINDS.has(meta.kind);
643
670
  const isHeartbeat = meta.askedBy === HEARTBEAT_ASKED_BY;
644
671
  if (!isActionable && !isHeartbeat) return;
672
+ if (suppress) return;
645
673
  try {
646
674
  const config = loadConfig(cwd);
647
675
  if (config.notifications?.enabled === false) return;
@@ -667,8 +695,7 @@ function createAsk(cwd, sessionId, params) {
667
695
  ...params.title !== void 0 ? { title: params.title } : {},
668
696
  ...params.subtitle !== void 0 ? { subtitle: params.subtitle } : {},
669
697
  ...params.kind !== void 0 ? { kind: params.kind } : {},
670
- ...params.orphanTarget !== void 0 ? { orphanTarget: params.orphanTarget } : {},
671
- ...params.modeTransition !== void 0 ? { modeTransition: params.modeTransition } : {}
698
+ ...params.orphanTarget !== void 0 ? { orphanTarget: params.orphanTarget } : {}
672
699
  };
673
700
  atomicWrite(askMetaPath(cwd, sessionId, params.askId), JSON.stringify(meta, null, 2));
674
701
  emitHistoryEvent(sessionId, "ask-issued", {
@@ -677,7 +704,7 @@ function createAsk(cwd, sessionId, params) {
677
704
  blocking: params.blocking,
678
705
  askedAt
679
706
  });
680
- maybeNotifyOnAskCreated(cwd, sessionId, meta);
707
+ maybeNotifyOnAskCreated(cwd, sessionId, meta, params.suppressTerminalNotification === true);
681
708
  return meta;
682
709
  }
683
710
  function writeDecisions(cwd, sessionId, askId, deck) {
@@ -898,9 +925,9 @@ var init_exec = __esm({
898
925
  });
899
926
 
900
927
  // src/daemon/frontmatter.ts
901
- import { readFileSync as readFileSync15, existsSync as existsSync14, readdirSync as readdirSync5 } from "fs";
928
+ import { readFileSync as readFileSync16, existsSync as existsSync14, readdirSync as readdirSync5 } from "fs";
902
929
  import { homedir as homedir8 } from "os";
903
- import { join as join15, basename as basename5 } from "path";
930
+ import { join as join16, basename as basename5 } from "path";
904
931
  function parseAgentFrontmatter(content) {
905
932
  const match = content.match(/^---\n([\s\S]*?)\n---/);
906
933
  if (!match) return {};
@@ -950,7 +977,7 @@ function discoverAgentTypes(pluginDir, cwd) {
950
977
  if (seen.has(qualifiedName)) continue;
951
978
  seen.add(qualifiedName);
952
979
  try {
953
- const content = readFileSync15(join15(dir, file), "utf-8");
980
+ const content = readFileSync16(join16(dir, file), "utf-8");
954
981
  const fm = parseAgentFrontmatter(content);
955
982
  results.push({ qualifiedName, source, description: fm.description, model: fm.model });
956
983
  } catch {
@@ -958,14 +985,14 @@ function discoverAgentTypes(pluginDir, cwd) {
958
985
  }
959
986
  }
960
987
  }
961
- scanDir(join15(projectAgentPluginDir(cwd), "agents"), null, "project-sis");
962
- scanDir(join15(userAgentPluginDir(), "agents"), null, "user-sis");
963
- scanDir(join15(cwd, ".claude", "agents"), null, "project");
964
- scanDir(join15(homedir8(), ".claude", "agents"), null, "user");
965
- scanDir(join15(pluginDir, "agents"), "sisyphus", "bundled");
988
+ scanDir(join16(projectAgentPluginDir(cwd), "agents"), null, "project-sis");
989
+ scanDir(join16(userAgentPluginDir(), "agents"), null, "user-sis");
990
+ scanDir(join16(cwd, ".claude", "agents"), null, "project");
991
+ scanDir(join16(homedir8(), ".claude", "agents"), null, "user");
992
+ scanDir(join16(pluginDir, "agents"), "sisyphus", "bundled");
966
993
  try {
967
- const registryPath2 = join15(homedir8(), ".claude", "plugins", "installed_plugins.json");
968
- const registry = JSON.parse(readFileSync15(registryPath2, "utf-8"));
994
+ const registryPath2 = join16(homedir8(), ".claude", "plugins", "installed_plugins.json");
995
+ const registry = JSON.parse(readFileSync16(registryPath2, "utf-8"));
969
996
  const pluginEntries = registry.plugins ?? registry;
970
997
  for (const key of Object.keys(pluginEntries)) {
971
998
  const atIdx = key.indexOf("@");
@@ -974,7 +1001,7 @@ function discoverAgentTypes(pluginDir, cwd) {
974
1001
  const entry = pluginEntries[key];
975
1002
  const installPath = Array.isArray(entry) ? entry[0]?.installPath : entry?.installPath;
976
1003
  if (installPath) {
977
- scanDir(join15(installPath, "agents"), namespace, "plugin");
1004
+ scanDir(join16(installPath, "agents"), namespace, "plugin");
978
1005
  }
979
1006
  }
980
1007
  } catch {
@@ -996,8 +1023,8 @@ var init_effort_render = __esm({
996
1023
  });
997
1024
 
998
1025
  // src/daemon/extensions.ts
999
- import { existsSync as existsSync15, readFileSync as readFileSync16, readdirSync as readdirSync6, copyFileSync as copyFileSync2, mkdirSync as mkdirSync8, statSync as statSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
1000
- import { resolve as resolve6, join as join16, basename as basename6, relative } from "path";
1026
+ import { existsSync as existsSync15, readFileSync as readFileSync17, readdirSync as readdirSync6, copyFileSync as copyFileSync2, mkdirSync as mkdirSync8, statSync as statSync3, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "fs";
1027
+ import { resolve as resolve6, join as join17, basename as basename6, relative } from "path";
1001
1028
  function resolveBundledTemplateDir(kind) {
1002
1029
  const built = resolve6(import.meta.dirname, "../templates", kind);
1003
1030
  if (existsSync15(built)) return built;
@@ -1014,12 +1041,12 @@ var init_extensions = __esm({
1014
1041
  });
1015
1042
 
1016
1043
  // src/shared/version.ts
1017
- import { readFileSync as readFileSync21 } from "fs";
1044
+ import { readFileSync as readFileSync22 } from "fs";
1018
1045
  import { resolve as resolve7 } from "path";
1019
1046
  function readSisyphusVersion() {
1020
1047
  for (const rel of ["../package.json", "../../package.json"]) {
1021
1048
  try {
1022
- const raw = readFileSync21(resolve7(import.meta.dirname, rel), "utf-8");
1049
+ const raw = readFileSync22(resolve7(import.meta.dirname, rel), "utf-8");
1023
1050
  const pkg = JSON.parse(raw);
1024
1051
  if (pkg.name === "sisyphi" && pkg.version) return pkg.version;
1025
1052
  } catch {
@@ -1086,9 +1113,9 @@ var init_upload = __esm({
1086
1113
  // src/shared/session-export.ts
1087
1114
  import { execFile as execFile2 } from "child_process";
1088
1115
  import { promisify } from "util";
1089
- import { existsSync as existsSync25, readFileSync as readFileSync25, mkdirSync as mkdirSync11, symlinkSync, rmSync as rmSync5, writeFileSync as writeFileSync12 } from "fs";
1116
+ import { existsSync as existsSync25, readFileSync as readFileSync26, mkdirSync as mkdirSync11, symlinkSync, rmSync as rmSync5, writeFileSync as writeFileSync13 } from "fs";
1090
1117
  import { homedir as homedir12 } from "os";
1091
- import { join as join22 } from "path";
1118
+ import { join as join23 } from "path";
1092
1119
  function sanitizeName(name) {
1093
1120
  return name.replace(/[^a-zA-Z0-9-_]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
1094
1121
  }
@@ -1096,11 +1123,11 @@ function buildOutputPath(label, dir) {
1096
1123
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1097
1124
  mkdirSync11(dir, { recursive: true });
1098
1125
  const base = `sisyphus-${label}-${date}`;
1099
- let candidate = join22(dir, `${base}.zip`);
1126
+ let candidate = join23(dir, `${base}.zip`);
1100
1127
  let counter = 1;
1101
1128
  while (existsSync25(candidate)) {
1102
1129
  counter++;
1103
- candidate = join22(dir, `${base}-${counter}.zip`);
1130
+ candidate = join23(dir, `${base}-${counter}.zip`);
1104
1131
  }
1105
1132
  return candidate;
1106
1133
  }
@@ -1170,24 +1197,24 @@ async function exportSessionToZip(sessionId, cwd, options) {
1170
1197
  const stPath = statePath(cwd, sessionId);
1171
1198
  if (existsSync25(stPath)) {
1172
1199
  try {
1173
- const state = JSON.parse(readFileSync25(stPath, "utf-8"));
1200
+ const state = JSON.parse(readFileSync26(stPath, "utf-8"));
1174
1201
  if (state.name) {
1175
1202
  label = sanitizeName(state.name);
1176
1203
  }
1177
1204
  } catch {
1178
1205
  }
1179
1206
  }
1180
- const dir = options?.outputDir ?? join22(homedir12(), "Downloads");
1207
+ const dir = options?.outputDir ?? join23(homedir12(), "Downloads");
1181
1208
  const outputPath = buildOutputPath(label, dir);
1182
1209
  const tmpDir = `/tmp/sisyphus-export-${sessionId.slice(0, 8)}-${Date.now()}`;
1183
1210
  try {
1184
1211
  mkdirSync11(tmpDir, { recursive: true });
1185
- writeFileSync12(join22(tmpDir, "CLAUDE.md"), generateGuide(), "utf-8");
1212
+ writeFileSync13(join23(tmpDir, "CLAUDE.md"), generateGuide(), "utf-8");
1186
1213
  if (sessExists) {
1187
- symlinkSync(sessDir, join22(tmpDir, "session"));
1214
+ symlinkSync(sessDir, join23(tmpDir, "session"));
1188
1215
  }
1189
1216
  if (histExists) {
1190
- symlinkSync(histDir, join22(tmpDir, "history"));
1217
+ symlinkSync(histDir, join23(tmpDir, "history"));
1191
1218
  }
1192
1219
  const parts = ["CLAUDE.md", sessExists ? "session/" : "", histExists ? "history/" : ""].filter(Boolean);
1193
1220
  await execFileAsync("zip", ["-rq", outputPath, ...parts], { cwd: tmpDir });
@@ -1398,9 +1425,9 @@ var init_companion_normalize = __esm({
1398
1425
  });
1399
1426
 
1400
1427
  // src/daemon/companion.ts
1401
- import { existsSync as existsSync27, mkdirSync as mkdirSync12, readFileSync as readFileSync27, renameSync as renameSync4, writeFileSync as writeFileSync14 } from "fs";
1428
+ import { existsSync as existsSync27, mkdirSync as mkdirSync12, readFileSync as readFileSync28, renameSync as renameSync4, writeFileSync as writeFileSync15 } from "fs";
1402
1429
  import { randomUUID as randomUUID3 } from "crypto";
1403
- import { dirname as dirname9, join as join24 } from "path";
1430
+ import { dirname as dirname9, join as join25 } from "path";
1404
1431
  function loadCompanion() {
1405
1432
  const path = companionPath();
1406
1433
  if (!existsSync27(path)) {
@@ -1408,7 +1435,7 @@ function loadCompanion() {
1408
1435
  saveCompanion(state2);
1409
1436
  return state2;
1410
1437
  }
1411
- const raw = readFileSync27(path, "utf-8");
1438
+ const raw = readFileSync28(path, "utf-8");
1412
1439
  const state = JSON.parse(raw);
1413
1440
  return normalizeCompanion(state);
1414
1441
  }
@@ -1416,8 +1443,8 @@ function saveCompanion(state) {
1416
1443
  const path = companionPath();
1417
1444
  const dir = dirname9(path);
1418
1445
  mkdirSync12(dir, { recursive: true });
1419
- const tmp = join24(dir, `.companion.${randomUUID3()}.tmp`);
1420
- writeFileSync14(tmp, JSON.stringify(state, null, 2), "utf-8");
1446
+ const tmp = join25(dir, `.companion.${randomUUID3()}.tmp`);
1447
+ writeFileSync15(tmp, JSON.stringify(state, null, 2), "utf-8");
1421
1448
  renameSync4(tmp, path);
1422
1449
  }
1423
1450
  function createDefaultCompanion() {
@@ -1470,8 +1497,8 @@ var init_companion = __esm({
1470
1497
  });
1471
1498
 
1472
1499
  // src/daemon/companion-memory.ts
1473
- import { existsSync as existsSync28, mkdirSync as mkdirSync13, readFileSync as readFileSync28, renameSync as renameSync5, writeFileSync as writeFileSync15 } from "fs";
1474
- import { dirname as dirname10, join as join25 } from "path";
1500
+ import { existsSync as existsSync28, mkdirSync as mkdirSync13, readFileSync as readFileSync29, renameSync as renameSync5, writeFileSync as writeFileSync16 } from "fs";
1501
+ import { dirname as dirname10, join as join26 } from "path";
1475
1502
  import { randomUUID as randomUUID4 } from "crypto";
1476
1503
  import { z } from "zod";
1477
1504
  function isSafeObservationText(text) {
@@ -1501,7 +1528,7 @@ function loadMemoryStrict() {
1501
1528
  if (!existsSync28(path)) return defaultMemoryState();
1502
1529
  let raw;
1503
1530
  try {
1504
- raw = readFileSync28(path, "utf-8");
1531
+ raw = readFileSync29(path, "utf-8");
1505
1532
  } catch (err) {
1506
1533
  throw new MemoryStoreParseError(err);
1507
1534
  }
@@ -1597,10 +1624,10 @@ var init_companion_render = __esm({
1597
1624
  });
1598
1625
 
1599
1626
  // src/daemon/companion-popup.ts
1600
- import { writeFileSync as writeFileSync16, readFileSync as readFileSync29, unlinkSync as unlinkSync4, existsSync as existsSync29 } from "fs";
1601
- import { tmpdir as tmpdir2 } from "os";
1602
- import { join as join26, resolve as resolve10 } from "path";
1603
- function wrapText(text, width) {
1627
+ import { writeFileSync as writeFileSync17, readFileSync as readFileSync30, unlinkSync as unlinkSync6, existsSync as existsSync29 } from "fs";
1628
+ import { tmpdir as tmpdir3 } from "os";
1629
+ import { join as join27, resolve as resolve10 } from "path";
1630
+ function wrapText2(text, width) {
1604
1631
  const words = text.split(" ");
1605
1632
  const lines = [];
1606
1633
  let current = "";
@@ -1630,16 +1657,16 @@ function showCommentaryPopupQueue(pages) {
1630
1657
  const defaultTitle = ` (${face}) `;
1631
1658
  let maxContentHeight = 0;
1632
1659
  for (let i = 0; i < pages.length; i++) {
1633
- const lines = wrapText(pages[i].text, INNER_WIDTH);
1660
+ const lines = wrapText2(pages[i].text, INNER_WIDTH2);
1634
1661
  const isLast = i === pages.length - 1;
1635
1662
  const hint = isLast ? "[0:ok 1:good 2:bad 3:whip]" : "[enter:next 0-3:rate]";
1636
- const hintPad = Math.max(0, Math.floor((INNER_WIDTH - hint.length) / 2));
1663
+ const hintPad = Math.max(0, Math.floor((INNER_WIDTH2 - hint.length) / 2));
1637
1664
  const hintLine = " ".repeat(hintPad + 2) + hint;
1638
1665
  const content = "\n\n" + lines.map((l) => ` ${l}`).join("\n") + "\n\n" + hintLine + "\n";
1639
1666
  const contentLineCount = content.split("\n").length - 1;
1640
1667
  const contentHeight = Math.max(contentLineCount + 2, 5);
1641
1668
  if (contentHeight > maxContentHeight) maxContentHeight = contentHeight;
1642
- writeFileSync16(`${POPUP_TMP_PREFIX}-${i}.txt`, content);
1669
+ writeFileSync17(`${POPUP_TMP_PREFIX}-${i}.txt`, content);
1643
1670
  }
1644
1671
  const whipAvailable = existsSync29(WHIP_ANIMATION_PATH);
1645
1672
  if (whipAvailable && maxContentHeight < WHIP_ANIMATION_ROWS + 2) {
@@ -1688,9 +1715,9 @@ if [ ! -f "$RESULT_FILE" ]; then
1688
1715
  printf 'neutral' > "$RESULT_FILE"
1689
1716
  fi
1690
1717
  `;
1691
- writeFileSync16(POPUP_SCRIPT, script, { mode: 493 });
1718
+ writeFileSync17(POPUP_SCRIPT, script, { mode: 493 });
1692
1719
  try {
1693
- unlinkSync4(POPUP_RESULT_PREFIX);
1720
+ unlinkSync6(POPUP_RESULT_PREFIX);
1694
1721
  } catch {
1695
1722
  }
1696
1723
  const clientsRaw = execSafe('tmux list-clients -F "#{client_name} #{client_width}"');
@@ -1700,27 +1727,27 @@ fi
1700
1727
  const client = line.slice(0, lastSpace);
1701
1728
  const clientWidth = parseInt(line.slice(lastSpace + 1), 10);
1702
1729
  if (!clientWidth) continue;
1703
- const x = Math.max(0, clientWidth - POPUP_WIDTH);
1730
+ const x = Math.max(0, clientWidth - POPUP_WIDTH2 - 1);
1704
1731
  const args2 = [
1705
1732
  `-c ${shellQuote(client)}`,
1706
1733
  "-E -b rounded",
1707
1734
  `-T ${shellQuote(initialTitle)}`,
1708
1735
  `-S "fg=${moodColor}"`,
1709
1736
  `-s "fg=${moodColor}"`,
1710
- `-x ${x} -y 0`,
1711
- `-w ${POPUP_WIDTH} -h ${maxContentHeight}`,
1737
+ `-x ${x} -y 2`,
1738
+ `-w ${POPUP_WIDTH2} -h ${maxContentHeight}`,
1712
1739
  shellQuote(POPUP_SCRIPT)
1713
1740
  ].join(" ");
1714
1741
  execSafe(`tmux display-popup ${args2}`);
1715
1742
  }
1716
1743
  let raw;
1717
1744
  try {
1718
- raw = readFileSync29(POPUP_RESULT_PREFIX, "utf8").trim();
1745
+ raw = readFileSync30(POPUP_RESULT_PREFIX, "utf8").trim();
1719
1746
  } catch {
1720
1747
  return null;
1721
1748
  } finally {
1722
1749
  try {
1723
- unlinkSync4(POPUP_RESULT_PREFIX);
1750
+ unlinkSync6(POPUP_RESULT_PREFIX);
1724
1751
  } catch {
1725
1752
  }
1726
1753
  }
@@ -1734,7 +1761,7 @@ fi
1734
1761
  }
1735
1762
  return null;
1736
1763
  }
1737
- var POPUP_WIDTH, INNER_WIDTH, POPUP_DURATION, POPUP_TMP_PREFIX, POPUP_SCRIPT, POPUP_RESULT_PREFIX, WHIP_ANIMATION_PATH, WHIP_ANIMATION_ROWS;
1764
+ var POPUP_WIDTH2, INNER_WIDTH2, POPUP_DURATION, POPUP_TMP_PREFIX, POPUP_SCRIPT, POPUP_RESULT_PREFIX, WHIP_ANIMATION_PATH, WHIP_ANIMATION_ROWS;
1738
1765
  var init_companion_popup = __esm({
1739
1766
  "src/daemon/companion-popup.ts"() {
1740
1767
  "use strict";
@@ -1743,12 +1770,12 @@ var init_companion_popup = __esm({
1743
1770
  init_config();
1744
1771
  init_exec();
1745
1772
  init_shell();
1746
- POPUP_WIDTH = 38;
1747
- INNER_WIDTH = POPUP_WIDTH - 6;
1773
+ POPUP_WIDTH2 = 38;
1774
+ INNER_WIDTH2 = POPUP_WIDTH2 - 6;
1748
1775
  POPUP_DURATION = 15;
1749
- POPUP_TMP_PREFIX = join26(tmpdir2(), "sisyphus-popup");
1750
- POPUP_SCRIPT = join26(tmpdir2(), "sisyphus-popup.sh");
1751
- POPUP_RESULT_PREFIX = join26(tmpdir2(), "sisyphus-popup-result");
1776
+ POPUP_TMP_PREFIX = join27(tmpdir3(), "sisyphus-popup");
1777
+ POPUP_SCRIPT = join27(tmpdir3(), "sisyphus-popup.sh");
1778
+ POPUP_RESULT_PREFIX = join27(tmpdir3(), "sisyphus-popup-result");
1752
1779
  WHIP_ANIMATION_PATH = resolve10(import.meta.dirname, "../templates/whip-animation.sh");
1753
1780
  WHIP_ANIMATION_ROWS = 12;
1754
1781
  }
@@ -1776,9 +1803,9 @@ __export(tmux_exports, {
1776
1803
  windowExists: () => windowExists
1777
1804
  });
1778
1805
  import { execSync as execSync17 } from "child_process";
1779
- import { join as join27 } from "path";
1780
- import { readFileSync as readFileSync30, writeFileSync as writeFileSync17, mkdtempSync, rmSync as rmSync7, cpSync as cpSync3, existsSync as existsSync30, mkdirSync as mkdirSync14 } from "fs";
1781
- import { tmpdir as tmpdir3 } from "os";
1806
+ import { join as join28 } from "path";
1807
+ import { readFileSync as readFileSync31, writeFileSync as writeFileSync18, mkdtempSync, rmSync as rmSync7, cpSync as cpSync3, existsSync as existsSync30, mkdirSync as mkdirSync14 } from "fs";
1808
+ import { tmpdir as tmpdir4 } from "os";
1782
1809
  function getWindowId() {
1783
1810
  const pane = process.env["TMUX_PANE"];
1784
1811
  if (pane) {
@@ -1829,8 +1856,8 @@ function registerDashboardWindow(cwd) {
1829
1856
  }
1830
1857
  }
1831
1858
  function setupCompanionPlugin() {
1832
- const srcDir = join27(import.meta.dirname, "templates", "companion-plugin");
1833
- const destDir = join27(globalDir(), "companion-plugin");
1859
+ const srcDir = join28(import.meta.dirname, "templates", "companion-plugin");
1860
+ const destDir = join28(globalDir(), "companion-plugin");
1834
1861
  if (!existsSync30(destDir)) mkdirSync14(destDir, { recursive: true });
1835
1862
  cpSync3(srcDir, destDir, { recursive: true });
1836
1863
  return destDir;
@@ -1858,18 +1885,18 @@ function openCompanionPane(cwd) {
1858
1885
  return;
1859
1886
  }
1860
1887
  const pluginDir = setupCompanionPlugin();
1861
- const templatePath2 = join27(import.meta.dirname, "templates", "dashboard-claude.md");
1888
+ const templatePath2 = join28(import.meta.dirname, "templates", "dashboard-claude.md");
1862
1889
  let template;
1863
1890
  try {
1864
- template = readFileSync30(templatePath2, "utf-8");
1891
+ template = readFileSync31(templatePath2, "utf-8");
1865
1892
  } catch {
1866
1893
  template = `You are a Sisyphus dashboard companion. Help the user manage multi-agent sessions.
1867
1894
  Project: ${cwd}
1868
1895
  Run \`sis session inspect list\` and \`sis session inspect status\` to see current state.`;
1869
1896
  }
1870
1897
  const rendered = template.replace(/\{\{CWD\}\}/g, cwd);
1871
- const promptPath = join27(globalDir(), "dashboard-companion-prompt.md");
1872
- writeFileSync17(promptPath, rendered, "utf-8");
1898
+ const promptPath = join28(globalDir(), "dashboard-companion-prompt.md");
1899
+ writeFileSync18(promptPath, rendered, "utf-8");
1873
1900
  const pathEnv = augmentedPath();
1874
1901
  const claudeCmd = `SISYPHUS_COMPANION_CWD=${shellQuote(cwd)} PATH=${shellQuote(pathEnv)} claude --dangerously-skip-permissions --plugin-dir ${shellQuote(pluginDir)} --append-system-prompt "$(cat ${shellQuote(promptPath)})"`;
1875
1902
  const result = exec2(
@@ -1884,12 +1911,12 @@ function switchToSession(sessionName) {
1884
1911
  execSafe(`tmux switch-client -t ${shellQuote(sessionName)}`);
1885
1912
  }
1886
1913
  function editInPopup(cwd, editor, opts) {
1887
- const tmpDir = mkdtempSync(join27(tmpdir3(), "sisyphus-"));
1888
- const filePath = join27(tmpDir, "input.md");
1914
+ const tmpDir = mkdtempSync(join28(tmpdir4(), "sisyphus-"));
1915
+ const filePath = join28(tmpDir, "input.md");
1889
1916
  try {
1890
- writeFileSync17(filePath, opts?.content ? opts.content : "", "utf-8");
1917
+ writeFileSync18(filePath, opts?.content ? opts.content : "", "utf-8");
1891
1918
  openEditorPopup(cwd, editor, filePath, opts?.size);
1892
- const result = readFileSync30(filePath, "utf-8").trim();
1919
+ const result = readFileSync31(filePath, "utf-8").trim();
1893
1920
  return result || null;
1894
1921
  } finally {
1895
1922
  rmSync7(tmpDir, { recursive: true, force: true });
@@ -1897,8 +1924,8 @@ function editInPopup(cwd, editor, opts) {
1897
1924
  }
1898
1925
  function promptInPopup(prompt, opts) {
1899
1926
  const { w = "50%", h = "3" } = opts ?? {};
1900
- const tmpDir = mkdtempSync(join27(tmpdir3(), "sisyphus-"));
1901
- const outFile = join27(tmpDir, "result");
1927
+ const tmpDir = mkdtempSync(join28(tmpdir4(), "sisyphus-"));
1928
+ const outFile = join28(tmpDir, "result");
1902
1929
  try {
1903
1930
  const script = `printf ${shellQuote(prompt + " ")} && read -r line && printf '%s' "$line" > ${shellQuote(outFile)}`;
1904
1931
  execSync17(
@@ -1906,7 +1933,7 @@ function promptInPopup(prompt, opts) {
1906
1933
  { stdio: "inherit", env: EXEC_ENV }
1907
1934
  );
1908
1935
  if (!existsSync30(outFile)) return null;
1909
- const result = readFileSync30(outFile, "utf-8").trim();
1936
+ const result = readFileSync31(outFile, "utf-8").trim();
1910
1937
  return result || null;
1911
1938
  } finally {
1912
1939
  rmSync7(tmpDir, { recursive: true, force: true });
@@ -1937,10 +1964,10 @@ function openClaudeResumePopup(cwd, claudeSessionId, resumeEnv, resumeArgs) {
1937
1964
  { stdio: "inherit", env: EXEC_ENV }
1938
1965
  );
1939
1966
  }
1940
- function openClaudeResumeSession(cwd, sessionId, claudeSessionId, sessionLabel, resumeEnv, resumeArgs, cycleNum, mode) {
1941
- const sessionName = tmuxSessionName(cwd, sessionLabel);
1967
+ function openClaudeResumeSession(cwd, sessionId, claudeSessionId, sessionLabel2, resumeEnv, resumeArgs, cycleNum, mode) {
1968
+ const sessionName = tmuxSessionName(cwd, sessionLabel2);
1942
1969
  const cycleLabel = cycleNum != null ? `c${cycleNum}` : "";
1943
- const paneTitle = cycleLabel ? `ssph:orch ${sessionLabel} ${cycleLabel}` : `ssph:orch ${sessionLabel}`;
1970
+ const paneTitle = cycleLabel ? `ssph:orch ${sessionLabel2} ${cycleLabel}` : `ssph:orch ${sessionLabel2}`;
1944
1971
  const existing = execSafe('tmux list-sessions -F "#{session_id}|#{session_name}"');
1945
1972
  const existingLine = existing?.split("\n").find((line) => line.slice(line.indexOf("|") + 1) === sessionName);
1946
1973
  if (existingLine) {
@@ -1948,7 +1975,7 @@ function openClaudeResumeSession(cwd, sessionId, claudeSessionId, sessionLabel,
1948
1975
  execSafe(`tmux set-option -t ${shellQuote(existingSessId)} @sisyphus_cwd ${shellQuote(cwd.replace(/\/+$/, ""))}`);
1949
1976
  execSafe(`tmux set-option -t ${shellQuote(existingSessId)} @sisyphus_session_id ${shellQuote(sessionId)}`);
1950
1977
  const firstPaneId2 = execSafe(`tmux list-panes -t ${shellQuote(existingSessId)} -F '#{pane_id}'`)?.split("\n")[0];
1951
- if (firstPaneId2) applyOrchestratorPaneStyle(firstPaneId2, paneTitle, sessionLabel, cycleLabel, mode);
1978
+ if (firstPaneId2) applyOrchestratorPaneStyle(firstPaneId2, paneTitle, sessionLabel2, cycleLabel, mode);
1952
1979
  return sessionName;
1953
1980
  }
1954
1981
  const pathEnv = augmentedPath();
@@ -1964,14 +1991,14 @@ function openClaudeResumeSession(cwd, sessionId, claudeSessionId, sessionLabel,
1964
1991
  execSafe(`tmux set -w -t ${shellQuote(newSessId + ":")} pane-border-status top`);
1965
1992
  execSafe(`tmux set -w -t ${shellQuote(newSessId + ":")} allow-rename off`);
1966
1993
  execSafe(`tmux set -w -t ${shellQuote(newSessId + ":")} automatic-rename off`);
1967
- if (firstPaneId) applyOrchestratorPaneStyle(firstPaneId, paneTitle, sessionLabel, cycleLabel, mode);
1994
+ if (firstPaneId) applyOrchestratorPaneStyle(firstPaneId, paneTitle, sessionLabel2, cycleLabel, mode);
1968
1995
  return sessionName;
1969
1996
  }
1970
- function applyOrchestratorPaneStyle(paneId, title, sessionLabel, cycleLabel, mode) {
1997
+ function applyOrchestratorPaneStyle(paneId, title, sessionLabel2, cycleLabel, mode) {
1971
1998
  const color = "yellow";
1972
1999
  execSafe(`tmux select-pane -t ${shellQuote(paneId)} -T ${shellQuote(title)}`);
1973
2000
  execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_role ${shellQuote("orch")}`);
1974
- execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_session ${shellQuote(sessionLabel)}`);
2001
+ execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_session ${shellQuote(sessionLabel2)}`);
1975
2002
  if (cycleLabel) execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_cycle ${shellQuote(cycleLabel)}`);
1976
2003
  if (mode) execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_mode ${shellQuote(mode)}`);
1977
2004
  const gitBranch = `#(cd #{pane_current_path} && git branch --show-current 2>/dev/null)`;
@@ -2024,7 +2051,7 @@ __export(creds_exports, {
2024
2051
  readTailscaleEnv: () => readTailscaleEnv,
2025
2052
  writeTailscaleEnv: () => writeTailscaleEnv
2026
2053
  });
2027
- import { chmodSync as chmodSync3, existsSync as existsSync31, mkdirSync as mkdirSync16, readFileSync as readFileSync32 } from "fs";
2054
+ import { chmodSync as chmodSync3, existsSync as existsSync31, mkdirSync as mkdirSync16, readFileSync as readFileSync33 } from "fs";
2028
2055
  import { createInterface as createInterface4 } from "readline";
2029
2056
  function isValidProvider(value) {
2030
2057
  return PROVIDERS.includes(value);
@@ -2058,7 +2085,7 @@ function serializeEnvFile(values) {
2058
2085
  }
2059
2086
  function readEnvFile(path) {
2060
2087
  if (!existsSync31(path)) return null;
2061
- return parseEnvFile(readFileSync32(path, "utf-8"));
2088
+ return parseEnvFile(readFileSync33(path, "utf-8"));
2062
2089
  }
2063
2090
  function writeEnvFile(path, values) {
2064
2091
  ensureDeployDir();
@@ -2188,12 +2215,12 @@ var init_pricing = __esm({
2188
2215
  });
2189
2216
 
2190
2217
  // src/cli/deploy/runtime.ts
2191
- import { existsSync as existsSync32, readFileSync as readFileSync33, unlinkSync as unlinkSync5 } from "fs";
2218
+ import { existsSync as existsSync32, readFileSync as readFileSync34, unlinkSync as unlinkSync7 } from "fs";
2192
2219
  function readRuntimeState(provider) {
2193
2220
  const path = deployRuntimePath(provider);
2194
2221
  if (!existsSync32(path)) return null;
2195
2222
  try {
2196
- return JSON.parse(readFileSync33(path, "utf-8"));
2223
+ return JSON.parse(readFileSync34(path, "utf-8"));
2197
2224
  } catch {
2198
2225
  return null;
2199
2226
  }
@@ -2203,7 +2230,7 @@ function writeRuntimeState(provider, state) {
2203
2230
  }
2204
2231
  function clearRuntimeState(provider) {
2205
2232
  const path = deployRuntimePath(provider);
2206
- if (existsSync32(path)) unlinkSync5(path);
2233
+ if (existsSync32(path)) unlinkSync7(path);
2207
2234
  }
2208
2235
  var init_runtime = __esm({
2209
2236
  "src/cli/deploy/runtime.ts"() {
@@ -2447,7 +2474,7 @@ var init_tailscale = __esm({
2447
2474
 
2448
2475
  // src/cli/deploy/runner.ts
2449
2476
  import { spawn as spawn2, spawnSync as spawnSync5 } from "child_process";
2450
- import { copyFileSync as copyFileSync3, existsSync as existsSync34, mkdirSync as mkdirSync17, readFileSync as readFileSync34 } from "fs";
2477
+ import { copyFileSync as copyFileSync3, existsSync as existsSync34, mkdirSync as mkdirSync17, readFileSync as readFileSync35 } from "fs";
2451
2478
  function runTerraform(provider, args2, extraEnv) {
2452
2479
  ensureProviderStateDir(provider);
2453
2480
  ensureTerraformInstalled();
@@ -2485,7 +2512,7 @@ function readSshPubkey(path) {
2485
2512
  or pass --ssh-key <path>.`
2486
2513
  );
2487
2514
  }
2488
- return readFileSync34(path, "utf-8").trim();
2515
+ return readFileSync35(path, "utf-8").trim();
2489
2516
  }
2490
2517
  function readOutputs(provider) {
2491
2518
  const result = spawnSync5("terraform", ["output", "-json", `-state=${deployStatePath(provider)}`], {
@@ -2800,7 +2827,7 @@ var init_grove = __esm({
2800
2827
  // src/cli/cloud/repo.ts
2801
2828
  import { spawnSync as spawnSync7 } from "child_process";
2802
2829
  import { existsSync as existsSync35 } from "fs";
2803
- import { basename as basename8, join as join30 } from "path";
2830
+ import { basename as basename8, join as join31 } from "path";
2804
2831
  function captureGit(args2, cwd) {
2805
2832
  const result = spawnSync7("git", args2, {
2806
2833
  encoding: "utf-8",
@@ -2840,10 +2867,10 @@ function buildRsyncArgs(localDir, remoteTarget) {
2840
2867
  ];
2841
2868
  }
2842
2869
  function detectPackageManager(toplevel) {
2843
- if (existsSync35(join30(toplevel, "pnpm-lock.yaml"))) return "pnpm";
2844
- if (existsSync35(join30(toplevel, "bun.lockb"))) return "bun";
2845
- if (existsSync35(join30(toplevel, "yarn.lock"))) return "yarn";
2846
- if (existsSync35(join30(toplevel, "package-lock.json"))) return "npm";
2870
+ if (existsSync35(join31(toplevel, "pnpm-lock.yaml"))) return "pnpm";
2871
+ if (existsSync35(join31(toplevel, "bun.lockb"))) return "bun";
2872
+ if (existsSync35(join31(toplevel, "yarn.lock"))) return "yarn";
2873
+ if (existsSync35(join31(toplevel, "package-lock.json"))) return "npm";
2847
2874
  return null;
2848
2875
  }
2849
2876
  function packageManagerInstallCmd(pm) {
@@ -3126,7 +3153,7 @@ var init_protocol = __esm({
3126
3153
  });
3127
3154
 
3128
3155
  // src/daemon/spawn-helpers.ts
3129
- import { writeFileSync as writeFileSync20, existsSync as existsSync38 } from "fs";
3156
+ import { writeFileSync as writeFileSync21, existsSync as existsSync38 } from "fs";
3130
3157
  import { resolve as resolve13 } from "path";
3131
3158
  var init_spawn_helpers = __esm({
3132
3159
  "src/daemon/spawn-helpers.ts"() {
@@ -3308,7 +3335,7 @@ var init_help_inject = __esm({
3308
3335
  });
3309
3336
 
3310
3337
  // src/shared/digest-verbs.ts
3311
- import { existsSync as existsSync39, readFileSync as readFileSync37 } from "fs";
3338
+ import { existsSync as existsSync39, readFileSync as readFileSync38 } from "fs";
3312
3339
  var init_digest_verbs = __esm({
3313
3340
  "src/shared/digest-verbs.ts"() {
3314
3341
  "use strict";
@@ -3324,8 +3351,8 @@ var init_colors = __esm({
3324
3351
  });
3325
3352
 
3326
3353
  // src/daemon/orchestrator-modes.ts
3327
- import { existsSync as existsSync40, readdirSync as readdirSync10, readFileSync as readFileSync38 } from "fs";
3328
- import { resolve as resolve14, join as join32 } from "path";
3354
+ import { existsSync as existsSync40, readdirSync as readdirSync10, readFileSync as readFileSync39 } from "fs";
3355
+ import { resolve as resolve14, join as join33 } from "path";
3329
3356
  import { homedir as homedir14 } from "os";
3330
3357
  var init_orchestrator_modes = __esm({
3331
3358
  "src/daemon/orchestrator-modes.ts"() {
@@ -3336,8 +3363,8 @@ var init_orchestrator_modes = __esm({
3336
3363
  });
3337
3364
 
3338
3365
  // src/daemon/lib/render-plugin.ts
3339
- import { readdirSync as readdirSync11, readFileSync as readFileSync39, writeFileSync as writeFileSync21, mkdirSync as mkdirSync18, copyFileSync as copyFileSync4, rmSync as rmSync8, existsSync as existsSync41 } from "fs";
3340
- import { join as join33 } from "path";
3366
+ import { readdirSync as readdirSync11, readFileSync as readFileSync40, writeFileSync as writeFileSync22, mkdirSync as mkdirSync18, copyFileSync as copyFileSync4, rmSync as rmSync8, existsSync as existsSync41 } from "fs";
3367
+ import { join as join34 } from "path";
3341
3368
  var init_render_plugin = __esm({
3342
3369
  "src/daemon/lib/render-plugin.ts"() {
3343
3370
  "use strict";
@@ -3418,10 +3445,10 @@ var init_orphan_sweep = __esm({
3418
3445
  });
3419
3446
 
3420
3447
  // src/daemon/agent.ts
3421
- import { readFileSync as readFileSync40, writeFileSync as writeFileSync22, mkdirSync as mkdirSync19, readdirSync as readdirSync12, existsSync as existsSync43, unlinkSync as unlinkSync6 } from "fs";
3448
+ import { readFileSync as readFileSync41, writeFileSync as writeFileSync23, mkdirSync as mkdirSync19, readdirSync as readdirSync12, existsSync as existsSync43, unlinkSync as unlinkSync8 } from "fs";
3422
3449
  import { execSync as execSync21 } from "child_process";
3423
3450
  import { randomUUID as randomUUID5 } from "crypto";
3424
- import { resolve as resolve15, relative as relative2, dirname as dirname13, join as join34 } from "path";
3451
+ import { resolve as resolve15, relative as relative2, dirname as dirname13, join as join35 } from "path";
3425
3452
  var init_agent = __esm({
3426
3453
  "src/daemon/agent.ts"() {
3427
3454
  "use strict";
@@ -3499,25 +3526,11 @@ var init_pane_monitor = __esm({
3499
3526
  }
3500
3527
  });
3501
3528
 
3502
- // src/daemon/mode-notify.ts
3503
- import { existsSync as existsSync44 } from "fs";
3504
- import { ulid as ulid3 } from "ulid";
3505
- var init_mode_notify = __esm({
3506
- "src/daemon/mode-notify.ts"() {
3507
- "use strict";
3508
- init_ask_store();
3509
- init_state();
3510
- init_orchestrator_modes();
3511
- init_paths();
3512
- init_types();
3513
- }
3514
- });
3515
-
3516
3529
  // src/daemon/orchestrator.ts
3517
- import { existsSync as existsSync45, readdirSync as readdirSync13, readFileSync as readFileSync41, writeFileSync as writeFileSync23 } from "fs";
3530
+ import { existsSync as existsSync44, readdirSync as readdirSync13, readFileSync as readFileSync42, writeFileSync as writeFileSync24 } from "fs";
3518
3531
  import { execSync as execSync22 } from "child_process";
3519
3532
  import { randomUUID as randomUUID6 } from "crypto";
3520
- import { resolve as resolve16, join as join35, relative as relative3 } from "path";
3533
+ import { resolve as resolve16, join as join36, relative as relative3 } from "path";
3521
3534
  var init_orchestrator = __esm({
3522
3535
  "src/daemon/orchestrator.ts"() {
3523
3536
  "use strict";
@@ -3539,13 +3552,12 @@ var init_orchestrator = __esm({
3539
3552
  init_tmux2();
3540
3553
  init_pane_registry();
3541
3554
  init_pane_monitor();
3542
- init_mode_notify();
3543
3555
  init_plugins();
3544
3556
  }
3545
3557
  });
3546
3558
 
3547
3559
  // src/daemon/status-dots.ts
3548
- import { readFileSync as readFileSync42 } from "fs";
3560
+ import { readFileSync as readFileSync43 } from "fs";
3549
3561
  var COMPLETED_TTL_MS;
3550
3562
  var init_status_dots = __esm({
3551
3563
  "src/daemon/status-dots.ts"() {
@@ -3557,9 +3569,17 @@ var init_status_dots = __esm({
3557
3569
  }
3558
3570
  });
3559
3571
 
3572
+ // src/daemon/mode-transition.ts
3573
+ var init_mode_transition = __esm({
3574
+ "src/daemon/mode-transition.ts"() {
3575
+ "use strict";
3576
+ init_orchestrator_modes();
3577
+ }
3578
+ });
3579
+
3560
3580
  // src/daemon/uploader.ts
3561
3581
  import { rm } from "fs/promises";
3562
- import { tmpdir as tmpdir4 } from "os";
3582
+ import { tmpdir as tmpdir5 } from "os";
3563
3583
  var init_uploader = __esm({
3564
3584
  "src/daemon/uploader.ts"() {
3565
3585
  "use strict";
@@ -3598,7 +3618,7 @@ var init_format = __esm({
3598
3618
 
3599
3619
  // src/daemon/session-manager.ts
3600
3620
  import { v4 as uuidv4 } from "uuid";
3601
- import { existsSync as existsSync46, readFileSync as readFileSync43, readdirSync as readdirSync14, rmSync as rmSync9 } from "fs";
3621
+ import { existsSync as existsSync45, readFileSync as readFileSync44, readdirSync as readdirSync14, rmSync as rmSync9 } from "fs";
3602
3622
  var init_session_manager = __esm({
3603
3623
  "src/daemon/session-manager.ts"() {
3604
3624
  "use strict";
@@ -3621,6 +3641,7 @@ var init_session_manager = __esm({
3621
3641
  init_companion_render();
3622
3642
  init_companion_commentary();
3623
3643
  init_companion_popup();
3644
+ init_mode_transition();
3624
3645
  init_history();
3625
3646
  init_uploader();
3626
3647
  init_upload();
@@ -3635,7 +3656,7 @@ var init_session_manager = __esm({
3635
3656
  // src/daemon/transcript-digest.ts
3636
3657
  import { openSync, fstatSync, readSync, closeSync } from "fs";
3637
3658
  import { homedir as homedir15 } from "os";
3638
- import { join as join36 } from "path";
3659
+ import { join as join37 } from "path";
3639
3660
  var BYTE_CAP, TAIL_BYTES;
3640
3661
  var init_transcript_digest = __esm({
3641
3662
  "src/daemon/transcript-digest.ts"() {
@@ -3649,7 +3670,7 @@ var init_transcript_digest = __esm({
3649
3670
  import {
3650
3671
  closeSync as closeSync2,
3651
3672
  constants,
3652
- existsSync as existsSync47,
3673
+ existsSync as existsSync46,
3653
3674
  fstatSync as fstatSync2,
3654
3675
  lstatSync as lstatSync2,
3655
3676
  openSync as openSync2,
@@ -3685,17 +3706,17 @@ var init_ask_visual = __esm({
3685
3706
 
3686
3707
  // src/daemon/server.ts
3687
3708
  import { createServer } from "net";
3688
- import { unlinkSync as unlinkSync7, existsSync as existsSync48, writeFileSync as writeFileSync24, readFileSync as readFileSync45, mkdirSync as mkdirSync20, readdirSync as readdirSync15, rmSync as rmSync11, chmodSync as chmodSync4 } from "fs";
3689
- import { join as join37, basename as basename10, dirname as dirname15 } from "path";
3709
+ import { unlinkSync as unlinkSync9, existsSync as existsSync47, writeFileSync as writeFileSync25, readFileSync as readFileSync46, mkdirSync as mkdirSync20, readdirSync as readdirSync15, rmSync as rmSync11, chmodSync as chmodSync4 } from "fs";
3710
+ import { join as join38, basename as basename10, dirname as dirname15 } from "path";
3690
3711
  import { scanInbox } from "@crouton-kit/humanloop";
3691
3712
  function registryPath() {
3692
- return join37(globalDir(), "session-registry.json");
3713
+ return join38(globalDir(), "session-registry.json");
3693
3714
  }
3694
3715
  function loadSessionRegistry() {
3695
3716
  const p = registryPath();
3696
- if (!existsSync48(p)) return {};
3717
+ if (!existsSync47(p)) return {};
3697
3718
  try {
3698
- return JSON.parse(readFileSync45(p, "utf-8"));
3719
+ return JSON.parse(readFileSync46(p, "utf-8"));
3699
3720
  } catch (err) {
3700
3721
  console.warn("[sisyphus] Failed to parse session registry:", err instanceof Error ? err.message : err);
3701
3722
  return {};
@@ -3726,8 +3747,8 @@ var init_server = __esm({
3726
3747
 
3727
3748
  // src/cli/index.ts
3728
3749
  import { Command } from "commander";
3729
- import { existsSync as existsSync50, mkdirSync as mkdirSync21, readFileSync as readFileSync46 } from "fs";
3730
- import { dirname as dirname16, join as join38 } from "path";
3750
+ import { existsSync as existsSync49, mkdirSync as mkdirSync21, readFileSync as readFileSync47 } from "fs";
3751
+ import { dirname as dirname16, join as join39 } from "path";
3731
3752
  import { fileURLToPath as fileURLToPath6 } from "url";
3732
3753
 
3733
3754
  // src/cli/commands/start.ts
@@ -5833,6 +5854,10 @@ function assertTmux() {
5833
5854
  throw new Error("Not running inside a tmux pane. Sisyphus requires tmux.");
5834
5855
  }
5835
5856
  }
5857
+ function getTmuxSession() {
5858
+ assertTmux();
5859
+ return execSync4('tmux display-message -p "#{session_name}"', { encoding: "utf8" }).trim();
5860
+ }
5836
5861
  function getTmuxSessionInfo() {
5837
5862
  assertTmux();
5838
5863
  const out = execSync4('tmux display-message -p "#{session_id}|#{session_name}"', { encoding: "utf8" }).trim();
@@ -5849,6 +5874,27 @@ function getCurrentTmuxSessionHome(sessionId) {
5849
5874
  return "";
5850
5875
  }
5851
5876
  }
5877
+ function findHomeSession(cwd) {
5878
+ const normalizedCwd = cwd.replace(/\/+$/, "");
5879
+ let output;
5880
+ try {
5881
+ output = execSync4('tmux list-sessions -F "#{session_id}|#{session_name}"', {
5882
+ encoding: "utf-8",
5883
+ stdio: ["pipe", "pipe", "pipe"]
5884
+ }).trim();
5885
+ } catch {
5886
+ return null;
5887
+ }
5888
+ for (const line of output.split("\n").filter(Boolean)) {
5889
+ const pipeIdx = line.indexOf("|");
5890
+ if (pipeIdx < 0) continue;
5891
+ const sessId = line.slice(0, pipeIdx);
5892
+ const name = line.slice(pipeIdx + 1);
5893
+ if (name.startsWith("ssyph_")) continue;
5894
+ if (getCurrentTmuxSessionHome(sessId) === normalizedCwd) return sessId;
5895
+ }
5896
+ return null;
5897
+ }
5852
5898
 
5853
5899
  // src/cli/commands/start.ts
5854
5900
  init_shell();
@@ -6102,6 +6148,27 @@ function openDashboardWindow(tmuxSession, cwd) {
6102
6148
  }
6103
6149
  } catch {
6104
6150
  }
6151
+ try {
6152
+ const windows = execSync6(
6153
+ `tmux list-windows -t ${shellQuote(tmuxSession)} -F "#{window_id} #{window_name}"`,
6154
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
6155
+ ).trim();
6156
+ for (const line of windows.split("\n").filter(Boolean)) {
6157
+ const spaceIdx = line.indexOf(" ");
6158
+ if (spaceIdx < 0) continue;
6159
+ const wid = line.slice(0, spaceIdx);
6160
+ const wname = line.slice(spaceIdx + 1);
6161
+ if (wname === "sisyphus-dashboard") {
6162
+ execSync6(
6163
+ `tmux set-option -t ${shellQuote(tmuxSession)} @sisyphus_dashboard ${shellQuote(wid)}`,
6164
+ { stdio: "pipe" }
6165
+ );
6166
+ execSync6(`tmux select-window -t ${shellQuote(wid)}`, { stdio: "pipe" });
6167
+ return false;
6168
+ }
6169
+ }
6170
+ } catch {
6171
+ }
6105
6172
  const tuiPath = join6(import.meta.dirname, "tui.js");
6106
6173
  const windowId = execSync6(
6107
6174
  `tmux new-window -t ${shellQuote(tmuxSession + ":")} -n "sisyphus-dashboard" -c ${shellQuote(cwd)} -P -F "#{window_id}"`,
@@ -6570,8 +6637,8 @@ Exit codes: 0 ok | 2 usage (missing content or --session) | 3 not_found.`
6570
6637
  }
6571
6638
 
6572
6639
  // src/cli/commands/ask.ts
6573
- import { existsSync as existsSync12, readFileSync as readFileSync12, unlinkSync as unlinkSync3, watchFile, unwatchFile } from "fs";
6574
- import { basename as basename4, join as join13, resolve as resolve5 } from "path";
6640
+ import { existsSync as existsSync12, readFileSync as readFileSync13, unlinkSync as unlinkSync5, watchFile, unwatchFile } from "fs";
6641
+ import { basename as basename4, join as join14, resolve as resolve5 } from "path";
6575
6642
  import { ulid } from "ulid";
6576
6643
 
6577
6644
  // src/shared/ask-schema.ts
@@ -6634,6 +6701,125 @@ init_state();
6634
6701
  init_types();
6635
6702
  init_exec();
6636
6703
  init_shell();
6704
+ init_platform();
6705
+
6706
+ // src/cli/commands/ask-popup.ts
6707
+ init_exec();
6708
+ init_shell();
6709
+ import { writeFileSync as writeFileSync8, readFileSync as readFileSync12, unlinkSync as unlinkSync4 } from "fs";
6710
+ import { tmpdir } from "os";
6711
+ import { join as join13 } from "path";
6712
+ var POPUP_WIDTH = 46;
6713
+ var INNER_WIDTH = POPUP_WIDTH - 6;
6714
+ var POPUP_TIMEOUT = 10;
6715
+ var ACCENT_COLOR = "colour214";
6716
+ function wrapText(text, width) {
6717
+ const words = text.split(/\s+/).filter(Boolean);
6718
+ const lines = [];
6719
+ let current = "";
6720
+ for (const word of words) {
6721
+ if (current && current.length + 1 + word.length > width) {
6722
+ lines.push(current);
6723
+ current = word;
6724
+ } else {
6725
+ current = current ? `${current} ${word}` : word;
6726
+ }
6727
+ }
6728
+ if (current) lines.push(current);
6729
+ return lines.length > 0 ? lines : [""];
6730
+ }
6731
+ function hasAttachedClient() {
6732
+ const out = execSafe('tmux list-clients -F "#{client_name}"');
6733
+ return !!out && out.split("\n").filter(Boolean).length > 0;
6734
+ }
6735
+ function showAskTriagePopup(opts) {
6736
+ const scriptPath2 = join13(tmpdir(), `sisyphus-ask-${opts.askId}.sh`);
6737
+ const resultPath = join13(tmpdir(), `sisyphus-ask-${opts.askId}.result`);
6738
+ try {
6739
+ const safeTitle = opts.title.trim().length > 0 ? opts.title : "Question pending";
6740
+ const titleLines = wrapText(safeTitle, INNER_WIDTH);
6741
+ const bodyLines = [
6742
+ "",
6743
+ ...titleLines.map((l) => ` ${l}`),
6744
+ "",
6745
+ " [1] Dismiss",
6746
+ " [2] Open in dashboard",
6747
+ " [3] Open in agent",
6748
+ "",
6749
+ ` (auto-dismiss in ${POPUP_TIMEOUT}s)`,
6750
+ ""
6751
+ ];
6752
+ const content = bodyLines.join("\n") + "\n";
6753
+ const height = bodyLines.length + 2;
6754
+ const script = `#!/bin/sh
6755
+ printf '\\033[?25l'
6756
+ stty -echo 2>/dev/null
6757
+ RESULT_FILE=${shellQuote(resultPath)}
6758
+ printf '\\033[2J\\033[H'
6759
+ cat <<'__SISYPHUS_ASK_EOF__'
6760
+ ${content}__SISYPHUS_ASK_EOF__
6761
+ while IFS= read -r -n1 -t ${POPUP_TIMEOUT} k; do
6762
+ case "$k" in
6763
+ 1|d|D|q|Q|'') printf 'dismiss' > "$RESULT_FILE"; break ;;
6764
+ 2|b|B) printf 'dashboard' > "$RESULT_FILE"; break ;;
6765
+ 3|a|A) printf 'agent' > "$RESULT_FILE"; break ;;
6766
+ esac
6767
+ done
6768
+ if [ ! -f "$RESULT_FILE" ]; then printf 'dismiss' > "$RESULT_FILE"; fi
6769
+ `;
6770
+ writeFileSync8(scriptPath2, script, { mode: 493 });
6771
+ try {
6772
+ unlinkSync4(resultPath);
6773
+ } catch {
6774
+ }
6775
+ const popupTitle = ` \u2691 ${opts.sessionLabel} `;
6776
+ const clientsRaw = execSafe('tmux list-clients -F "#{client_name} #{client_width}"');
6777
+ if (!clientsRaw) return "dismiss";
6778
+ const lines = clientsRaw.split("\n").filter(Boolean);
6779
+ if (lines.length === 0) return "dismiss";
6780
+ let raw = null;
6781
+ for (const line of lines) {
6782
+ const lastSpace = line.lastIndexOf(" ");
6783
+ const client = line.slice(0, lastSpace);
6784
+ const clientWidth = parseInt(line.slice(lastSpace + 1), 10);
6785
+ if (!clientWidth) continue;
6786
+ const x = Math.max(0, clientWidth - POPUP_WIDTH - 1);
6787
+ const args2 = [
6788
+ `-c ${shellQuote(client)}`,
6789
+ "-E -b double",
6790
+ `-T ${shellQuote(popupTitle)}`,
6791
+ `-S "fg=${ACCENT_COLOR}"`,
6792
+ `-s "fg=${ACCENT_COLOR}"`,
6793
+ `-x ${x} -y 2`,
6794
+ `-w ${POPUP_WIDTH} -h ${height}`,
6795
+ shellQuote(scriptPath2)
6796
+ ].join(" ");
6797
+ execSafe(`tmux display-popup ${args2}`);
6798
+ try {
6799
+ raw = readFileSync12(resultPath, "utf8").trim();
6800
+ } catch {
6801
+ raw = null;
6802
+ }
6803
+ if (raw) break;
6804
+ }
6805
+ if (raw === "dashboard") return "dashboard";
6806
+ if (raw === "agent") return "agent";
6807
+ return "dismiss";
6808
+ } catch {
6809
+ return "dismiss";
6810
+ } finally {
6811
+ try {
6812
+ unlinkSync4(resultPath);
6813
+ } catch {
6814
+ }
6815
+ try {
6816
+ unlinkSync4(scriptPath2);
6817
+ } catch {
6818
+ }
6819
+ }
6820
+ }
6821
+
6822
+ // src/cli/commands/ask.ts
6637
6823
  import { approveDeck, notifyDeck, launchReview, display } from "@crouton-kit/humanloop";
6638
6824
  var ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
6639
6825
  function validateAskId(askId) {
@@ -7025,7 +7211,7 @@ async function markAnswered(cwd, sessionId, askId) {
7025
7211
  function waitForOutput(cwd, sessionId, askId, initialPpid) {
7026
7212
  const outputPath = askOutputPath(cwd, sessionId, askId);
7027
7213
  if (existsSync12(outputPath)) {
7028
- return Promise.resolve(JSON.parse(readFileSync12(outputPath, "utf-8")));
7214
+ return Promise.resolve(JSON.parse(readFileSync13(outputPath, "utf-8")));
7029
7215
  }
7030
7216
  return new Promise((res, _rej) => {
7031
7217
  let ppidWatcher;
@@ -7037,7 +7223,7 @@ function waitForOutput(cwd, sessionId, askId, initialPpid) {
7037
7223
  const onChange = () => {
7038
7224
  if (!existsSync12(outputPath)) return;
7039
7225
  try {
7040
- const out = JSON.parse(readFileSync12(outputPath, "utf-8"));
7226
+ const out = JSON.parse(readFileSync13(outputPath, "utf-8"));
7041
7227
  cleanup();
7042
7228
  res(out);
7043
7229
  } catch (err) {
@@ -7064,22 +7250,86 @@ function waitForOutput(cwd, sessionId, askId, initialPpid) {
7064
7250
  process.once("SIGINT", onSigint);
7065
7251
  });
7066
7252
  }
7253
+ function focusAgentPane(callerPane) {
7254
+ const sess = execSafe(`tmux display-message -p -t ${shellQuote(callerPane)} "#{session_name}"`)?.trim();
7255
+ const win = execSafe(`tmux display-message -p -t ${shellQuote(callerPane)} "#{window_id}"`)?.trim();
7256
+ if (sess) switchAllClientsToSession(sess);
7257
+ if (win) execSafe(`tmux select-window -t ${shellQuote(win)}`);
7258
+ }
7259
+ function switchAllClientsToSession(session2) {
7260
+ const clients = execSafe('tmux list-clients -F "#{client_name}"');
7261
+ if (!clients) return;
7262
+ for (const c of clients.split("\n").filter(Boolean)) {
7263
+ execSafe(`tmux switch-client -c ${shellQuote(c)} -t ${shellQuote(session2)}`);
7264
+ }
7265
+ }
7067
7266
  function maybeSpawnAskPane(cwd, sessionId, askId, kind) {
7068
7267
  if (kind === "review") return;
7069
7268
  const callerPane = process.env.TMUX_PANE;
7070
7269
  if (!callerPane) return;
7071
7270
  if (process.env.SISYPHUS_DISABLE_ASK_PANE === "1") return;
7072
- const tuiPath = join13(import.meta.dirname, "tui.js");
7271
+ const tuiPath = join14(import.meta.dirname, "tui.js");
7073
7272
  const cmd = `node ${shellQuote(tuiPath)} --cwd ${shellQuote(cwd)} --session-id ${shellQuote(sessionId)} --ask ${shellQuote(askId)}`;
7074
- execSafe(`tmux split-window -d -h -t ${shellQuote(callerPane)} -c ${shellQuote(cwd)} ${shellQuote(cmd)}`);
7273
+ execSafe(`tmux split-window -h -t ${shellQuote(callerPane)} -c ${shellQuote(cwd)} ${shellQuote(cmd)}`);
7274
+ focusAgentPane(callerPane);
7075
7275
  }
7076
7276
  function maybeSpawnReviewPane(cwd, sessionId, askId) {
7077
7277
  const callerPane = process.env.TMUX_PANE;
7078
7278
  if (!callerPane) return;
7079
7279
  if (process.env.SISYPHUS_DISABLE_ASK_PANE === "1") return;
7080
- const cliPath = join13(import.meta.dirname, "cli.js");
7280
+ const cliPath = join14(import.meta.dirname, "cli.js");
7081
7281
  const cmd = `node ${shellQuote(cliPath)} ask review open ${shellQuote(askId)} --session ${shellQuote(sessionId)}`;
7082
7282
  execSafe(`tmux split-window -h -t ${shellQuote(callerPane)} -c ${shellQuote(cwd)} ${shellQuote(cmd)}`);
7283
+ focusAgentPane(callerPane);
7284
+ }
7285
+ function sessionLabel(cwd, sessionId) {
7286
+ try {
7287
+ if (existsSync12(statePath(cwd, sessionId))) {
7288
+ const s = getSession(cwd, sessionId);
7289
+ if (s.name) return s.name;
7290
+ }
7291
+ } catch {
7292
+ }
7293
+ return sessionId.slice(0, 8);
7294
+ }
7295
+ function shouldSuppressBanner() {
7296
+ const popupWillShow = !!process.env.TMUX_PANE && process.env.SISYPHUS_DISABLE_ASK_PANE !== "1" && hasAttachedClient();
7297
+ return popupWillShow && isTerminalFrontmost();
7298
+ }
7299
+ async function triageAsk(cwd, sessionId, askId, kind, title) {
7300
+ const callerPane = process.env.TMUX_PANE;
7301
+ if (!callerPane) return;
7302
+ if (process.env.SISYPHUS_DISABLE_ASK_PANE === "1") return;
7303
+ const choice = showAskTriagePopup({
7304
+ askId,
7305
+ sessionLabel: sessionLabel(cwd, sessionId),
7306
+ title: title !== void 0 ? title : "Question pending"
7307
+ });
7308
+ if (choice === "dismiss") return;
7309
+ if (choice === "agent") {
7310
+ if (kind === "review") maybeSpawnReviewPane(cwd, sessionId, askId);
7311
+ else maybeSpawnAskPane(cwd, sessionId, askId, kind);
7312
+ return;
7313
+ }
7314
+ await openInDashboard(cwd, sessionId, askId, kind);
7315
+ }
7316
+ async function openInDashboard(cwd, sessionId, askId, kind) {
7317
+ try {
7318
+ assertTmux();
7319
+ const tmuxSession = findHomeSession(cwd) ?? getTmuxSession();
7320
+ if (kind === "review") {
7321
+ openDashboardWindow(tmuxSession, cwd);
7322
+ switchAllClientsToSession(tmuxSession);
7323
+ const cliPath = join14(import.meta.dirname, "cli.js");
7324
+ const cmd = `node ${shellQuote(cliPath)} ask review open ${shellQuote(askId)} --session ${shellQuote(sessionId)}`;
7325
+ execSafe(`tmux display-popup -E -w 90% -h 90% -d ${shellQuote(cwd)} ${shellQuote(cmd)}`);
7326
+ return;
7327
+ }
7328
+ await rawSend({ type: "focus-set", cwd, sessionId, askId });
7329
+ openDashboardWindow(tmuxSession, cwd);
7330
+ switchAllClientsToSession(tmuxSession);
7331
+ } catch {
7332
+ }
7083
7333
  }
7084
7334
  async function submitDeck(deck, opts, options) {
7085
7335
  const blocking = options?.blocking !== false;
@@ -7089,6 +7339,8 @@ async function submitDeck(deck, opts, options) {
7089
7339
  const claudeSessionId = resolveClaudeSessionId(cwd, sessionId, askedBy);
7090
7340
  const askId = mintAskId();
7091
7341
  const q0 = deck.interactions[0];
7342
+ const askTitle = deck.title !== void 0 ? deck.title : q0?.title;
7343
+ const suppressTerminalNotification = blocking ? shouldSuppressBanner() : false;
7092
7344
  createAsk(cwd, sessionId, {
7093
7345
  askId,
7094
7346
  askedBy,
@@ -7096,15 +7348,16 @@ async function submitDeck(deck, opts, options) {
7096
7348
  pid: process.pid,
7097
7349
  claudeSessionId,
7098
7350
  cwd,
7099
- title: deck.title !== void 0 ? deck.title : q0?.title,
7351
+ title: askTitle,
7100
7352
  subtitle: q0?.subtitle,
7101
- kind: options?.kindOverride !== void 0 ? options.kindOverride : q0?.kind
7353
+ kind: options?.kindOverride !== void 0 ? options.kindOverride : q0?.kind,
7354
+ suppressTerminalNotification
7102
7355
  });
7103
7356
  writeDecisions(cwd, sessionId, askId, deck);
7104
7357
  if (!blocking) {
7105
7358
  return { askId };
7106
7359
  }
7107
- maybeSpawnAskPane(cwd, sessionId, askId, q0?.kind);
7360
+ await triageAsk(cwd, sessionId, askId, q0?.kind, askTitle);
7108
7361
  const output = await waitForOutput(cwd, sessionId, askId, initialPpid);
7109
7362
  await markAnswered(cwd, sessionId, askId);
7110
7363
  return { askId, output };
@@ -7157,6 +7410,8 @@ async function submitReview(absFile, opts, options) {
7157
7410
  const initialPpid = process.ppid;
7158
7411
  const claudeSessionId = resolveClaudeSessionId(cwd, sessionId, askedBy);
7159
7412
  const askId = mintAskId();
7413
+ const reviewTitle = `Review ${basename4(absFile)}`;
7414
+ const suppressTerminalNotification = blocking ? shouldSuppressBanner() : false;
7160
7415
  createAsk(cwd, sessionId, {
7161
7416
  askId,
7162
7417
  askedBy,
@@ -7164,12 +7419,13 @@ async function submitReview(absFile, opts, options) {
7164
7419
  pid: process.pid,
7165
7420
  claudeSessionId,
7166
7421
  cwd,
7167
- title: `Review ${basename4(absFile)}`,
7168
- kind: "review"
7422
+ title: reviewTitle,
7423
+ kind: "review",
7424
+ suppressTerminalNotification
7169
7425
  });
7170
7426
  writeReview(cwd, sessionId, askId, { file: absFile });
7171
7427
  if (!blocking) return { askId };
7172
- maybeSpawnReviewPane(cwd, sessionId, askId);
7428
+ await triageAsk(cwd, sessionId, askId, "review", reviewTitle);
7173
7429
  const output = await waitForOutput(cwd, sessionId, askId, initialPpid);
7174
7430
  await markAnswered(cwd, sessionId, askId);
7175
7431
  return { askId, output };
@@ -7201,7 +7457,7 @@ async function reviewOpen(askId, opts) {
7201
7457
  if (!reviewData) exitUsage("missing-review-pointer", `review.json missing for ${askId}`, { received: askId });
7202
7458
  const draftPath = askReviewDraftPath(cwd, sessionId, askId);
7203
7459
  const flagPath = askReviewSubmitFlagPath(cwd, sessionId, askId);
7204
- if (existsSync12(flagPath)) unlinkSync3(flagPath);
7460
+ if (existsSync12(flagPath)) unlinkSync5(flagPath);
7205
7461
  const result = await launchReview(reviewData.file, {
7206
7462
  output: draftPath,
7207
7463
  submitFlagPath: flagPath,
@@ -7227,7 +7483,7 @@ async function reviewSubmit(askId, opts) {
7227
7483
  let comments = [];
7228
7484
  if (existsSync12(draftPath)) {
7229
7485
  try {
7230
- const draft = JSON.parse(readFileSync12(draftPath, "utf-8"));
7486
+ const draft = JSON.parse(readFileSync13(draftPath, "utf-8"));
7231
7487
  if (Array.isArray(draft.comments)) comments = draft.comments;
7232
7488
  } catch {
7233
7489
  }
@@ -7344,7 +7600,7 @@ async function peek(askId, opts) {
7344
7600
  if (meta.completedAt) result.completedAt = meta.completedAt;
7345
7601
  try {
7346
7602
  if (existsSync12(outputPath)) {
7347
- result.output = JSON.parse(readFileSync12(outputPath, "utf-8"));
7603
+ result.output = JSON.parse(readFileSync13(outputPath, "utf-8"));
7348
7604
  }
7349
7605
  } catch (err) {
7350
7606
  if (!(err instanceof SyntaxError)) throw err;
@@ -7756,13 +8012,13 @@ Exit codes: 0 ok | 2 usage (bad state) | 3 not_found.`
7756
8012
 
7757
8013
  // src/tui/lib/context.ts
7758
8014
  init_paths();
7759
- import { readFileSync as readFileSync14, readdirSync as readdirSync4 } from "fs";
8015
+ import { readFileSync as readFileSync15, readdirSync as readdirSync4 } from "fs";
7760
8016
 
7761
8017
  // src/tui/lib/reports.ts
7762
- import { readFileSync as readFileSync13 } from "fs";
8018
+ import { readFileSync as readFileSync14 } from "fs";
7763
8019
  function loadReportContent(report) {
7764
8020
  try {
7765
- return readFileSync13(report.filePath, "utf-8");
8021
+ return readFileSync14(report.filePath, "utf-8");
7766
8022
  } catch {
7767
8023
  return report.summary;
7768
8024
  }
@@ -7779,7 +8035,7 @@ function resolveReports(reports) {
7779
8035
  // src/tui/lib/context.ts
7780
8036
  function readFileSafe(filePath) {
7781
8037
  try {
7782
- return readFileSync14(filePath, "utf-8");
8038
+ return readFileSync15(filePath, "utf-8");
7783
8039
  } catch {
7784
8040
  return null;
7785
8041
  }
@@ -7958,7 +8214,7 @@ Exit codes: 0 ok | 3 not_found (unknown session).`
7958
8214
 
7959
8215
  // src/cli/commands/spawn.ts
7960
8216
  import { existsSync as existsSync13 } from "fs";
7961
- import { join as join14 } from "path";
8217
+ import { join as join15 } from "path";
7962
8218
  function registerSpawn(program2) {
7963
8219
  program2.command("spawn").description("Spawn a new agent (orchestrator only)").option("--agent-type <type>", "Agent type (e.g. sisyphus:debug, devcore:programmer)").option("--name <name>", "Agent name").option("--stdin", "Force-read instruction from stdin (avoids shell escaping for long prompts)").option("--repo <name>", "Repo subdirectory to use for this agent").option("--session <sessionId>", "Session ID (defaults to SISYPHUS_SESSION_ID env var)").addHelpText(
7964
8220
  "after",
@@ -8035,7 +8291,7 @@ Exit codes: 0 ok | 2 usage | 3 not_found (unknown session) | 5 conflict.`
8035
8291
  });
8036
8292
  }
8037
8293
  if (opts.repo && opts.repo !== ".") {
8038
- const repoPath = join14(sisyphusCwd, opts.repo);
8294
+ const repoPath = join15(sisyphusCwd, opts.repo);
8039
8295
  if (!existsSync13(repoPath)) {
8040
8296
  exitError({
8041
8297
  code: "repo_not_found",
@@ -8221,7 +8477,7 @@ Exit codes: 0 ok | 2 usage | 3 not_found | 60 transient.`
8221
8477
  }
8222
8478
 
8223
8479
  // src/cli/commands/await.ts
8224
- import { existsSync as existsSync16, readFileSync as readFileSync17 } from "fs";
8480
+ import { existsSync as existsSync16, readFileSync as readFileSync18 } from "fs";
8225
8481
  var AWAIT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
8226
8482
  function registerAwait(program2) {
8227
8483
  program2.command("await").description("Block until an agent reaches a terminal status, then print its final report inline. Marks the agent as consumed-inline so its report is suppressed from the next cycle.").argument("<agentId>", "Agent ID to await").option("--session <sessionId>", "Session ID (defaults to SISYPHUS_SESSION_ID env var)").addHelpText(
@@ -8261,7 +8517,7 @@ Exit codes: 0 ok | 2 usage (missing --session) | 3 not_found (unknown agent) | 6
8261
8517
  let report = "";
8262
8518
  if (reportPath && existsSync16(reportPath)) {
8263
8519
  try {
8264
- report = readFileSync17(reportPath, "utf-8");
8520
+ report = readFileSync18(reportPath, "utf-8");
8265
8521
  } catch (err) {
8266
8522
  process.stderr.write(`Warning: could not read report at ${reportPath}: ${err instanceof Error ? err.message : err}
8267
8523
  `);
@@ -8466,15 +8722,15 @@ import { execSync as execSync10 } from "child_process";
8466
8722
 
8467
8723
  // src/cli/onboard.ts
8468
8724
  import { execSync as execSync9 } from "child_process";
8469
- import { existsSync as existsSync17, readFileSync as readFileSync18, writeFileSync as writeFileSync9 } from "fs";
8725
+ import { existsSync as existsSync17, readFileSync as readFileSync19, writeFileSync as writeFileSync10 } from "fs";
8470
8726
  import { homedir as homedir9 } from "os";
8471
- import { dirname as dirname5, join as join17 } from "path";
8727
+ import { dirname as dirname5, join as join18 } from "path";
8472
8728
  import { fileURLToPath as fileURLToPath2 } from "url";
8473
8729
  init_platform();
8474
8730
 
8475
8731
  // src/shared/clipboard.ts
8476
8732
  init_platform();
8477
- import { execFileSync as execFileSync2, spawnSync } from "child_process";
8733
+ import { execFileSync as execFileSync3, spawnSync } from "child_process";
8478
8734
  function detectClipboard() {
8479
8735
  const platform = detectPlatform();
8480
8736
  if (platform === "darwin") {
@@ -8565,7 +8821,7 @@ function checkItermOptionKey() {
8565
8821
  if (process.platform !== "darwin") {
8566
8822
  return { checked: false, allCorrect: true, incorrectProfiles: [] };
8567
8823
  }
8568
- const plistPath2 = join17(homedir9(), "Library", "Preferences", "com.googlecode.iterm2.plist");
8824
+ const plistPath2 = join18(homedir9(), "Library", "Preferences", "com.googlecode.iterm2.plist");
8569
8825
  if (!existsSync17(plistPath2)) {
8570
8826
  return { checked: false, allCorrect: false, incorrectProfiles: [] };
8571
8827
  }
@@ -8590,7 +8846,7 @@ function checkItermOptionKey() {
8590
8846
  }
8591
8847
  }
8592
8848
  function hasExistingTmuxConf() {
8593
- return existsSync17(join17(homedir9(), ".tmux.conf")) || existsSync17(join17(homedir9(), ".config", "tmux", "tmux.conf"));
8849
+ return existsSync17(join18(homedir9(), ".tmux.conf")) || existsSync17(join18(homedir9(), ".config", "tmux", "tmux.conf"));
8594
8850
  }
8595
8851
  var SISYPHUS_DEFAULTS_MARKER = "# sisyphus-managed \u2014 do not edit";
8596
8852
  function buildTmuxDefaults() {
@@ -8702,8 +8958,8 @@ source-file -q ${sisyphusConf} ${SISYPHUS_DEFAULTS_MARKER}
8702
8958
  `;
8703
8959
  }
8704
8960
  function writeTmuxDefaults() {
8705
- const confPath = join17(homedir9(), ".tmux.conf");
8706
- writeFileSync9(confPath, buildTmuxDefaults(), "utf8");
8961
+ const confPath = join18(homedir9(), ".tmux.conf");
8962
+ writeFileSync10(confPath, buildTmuxDefaults(), "utf8");
8707
8963
  }
8708
8964
  function isNvimAvailable() {
8709
8965
  try {
@@ -8721,21 +8977,21 @@ function getNvimVersion() {
8721
8977
  }
8722
8978
  }
8723
8979
  function hasLazyVimConfig() {
8724
- return existsSync17(join17(homedir9(), ".config", "nvim", "lazy-lock.json"));
8980
+ return existsSync17(join18(homedir9(), ".config", "nvim", "lazy-lock.json"));
8725
8981
  }
8726
8982
  function bundledBaleiaPluginPath() {
8727
8983
  const distDir = dirname5(fileURLToPath2(import.meta.url));
8728
- return join17(distDir, "templates", "baleia.lua");
8984
+ return join18(distDir, "templates", "baleia.lua");
8729
8985
  }
8730
8986
  function installBaleiaPlugin() {
8731
- const pluginsDir = join17(homedir9(), ".config", "nvim", "lua", "plugins");
8987
+ const pluginsDir = join18(homedir9(), ".config", "nvim", "lua", "plugins");
8732
8988
  if (!existsSync17(pluginsDir)) return false;
8733
- const dest = join17(pluginsDir, "sisyphus-baleia.lua");
8989
+ const dest = join18(pluginsDir, "sisyphus-baleia.lua");
8734
8990
  if (existsSync17(dest)) return true;
8735
8991
  const src = bundledBaleiaPluginPath();
8736
8992
  if (!existsSync17(src)) return false;
8737
8993
  try {
8738
- writeFileSync9(dest, readFileSync18(src, "utf-8"), "utf8");
8994
+ writeFileSync10(dest, readFileSync19(src, "utf-8"), "utf8");
8739
8995
  return true;
8740
8996
  } catch {
8741
8997
  return false;
@@ -8758,7 +9014,7 @@ function tryAutoInstallNvim() {
8758
9014
  if (!isNvimAvailable()) {
8759
9015
  return { installed: false, autoInstalled: false, version: "", lazyVimInstalled: false, baleiaInstalled: false };
8760
9016
  }
8761
- const nvimConfigDir = join17(homedir9(), ".config", "nvim");
9017
+ const nvimConfigDir = join18(homedir9(), ".config", "nvim");
8762
9018
  let lazyVimInstalled = false;
8763
9019
  if (!existsSync17(nvimConfigDir)) {
8764
9020
  const cloneCmd = [
@@ -8776,7 +9032,7 @@ function tryAutoInstallNvim() {
8776
9032
  stdio: "inherit",
8777
9033
  env: { ...process.env, GIT_LFS_SKIP_SMUDGE: "1" }
8778
9034
  });
8779
- const gitDir = join17(nvimConfigDir, ".git");
9035
+ const gitDir = join18(nvimConfigDir, ".git");
8780
9036
  if (existsSync17(gitDir)) {
8781
9037
  execSync9(`rm -rf "${gitDir}"`, { stdio: "pipe" });
8782
9038
  }
@@ -9063,7 +9319,7 @@ Exit codes: 0 ok | 1 conflict or requires-force`
9063
9319
 
9064
9320
  // src/cli/commands/check-keybinds.ts
9065
9321
  import { execSync as execSync11 } from "child_process";
9066
- import { readFileSync as readFileSync19 } from "fs";
9322
+ import { readFileSync as readFileSync20 } from "fs";
9067
9323
  function isTmuxInstalled2() {
9068
9324
  try {
9069
9325
  execSync11("which tmux", { stdio: "pipe" });
@@ -9116,7 +9372,7 @@ function runCheck() {
9116
9372
  let userConfAlreadySources = false;
9117
9373
  if (userConfPath !== null) {
9118
9374
  try {
9119
- userConfAlreadySources = readFileSync19(userConfPath, "utf-8").includes(sisyphusConfPath);
9375
+ userConfAlreadySources = readFileSync20(userConfPath, "utf-8").includes(sisyphusConfPath);
9120
9376
  } catch {
9121
9377
  }
9122
9378
  }
@@ -9287,9 +9543,9 @@ Exit codes: 0 ok`
9287
9543
  // src/cli/commands/check-statusbar.ts
9288
9544
  init_paths();
9289
9545
  import { execSync as execSync12 } from "child_process";
9290
- import { existsSync as existsSync18, readFileSync as readFileSync20 } from "fs";
9546
+ import { existsSync as existsSync18, readFileSync as readFileSync21 } from "fs";
9291
9547
  import { homedir as homedir10 } from "os";
9292
- import { join as join18 } from "path";
9548
+ import { join as join19 } from "path";
9293
9549
  var SISYPHUS_LEFT_TOKEN = "@sisyphus_left";
9294
9550
  var SISYPHUS_RIGHT_TOKEN = "@sisyphus_right";
9295
9551
  var TMUX_DEFAULT_STATUS_LEFT = "[#S] ";
@@ -9314,7 +9570,7 @@ function isDaemonRunning() {
9314
9570
  const pidFile = daemonPidPath();
9315
9571
  if (!existsSync18(pidFile)) return false;
9316
9572
  try {
9317
- const pid = parseInt(readFileSync20(pidFile, "utf-8").trim(), 10);
9573
+ const pid = parseInt(readFileSync21(pidFile, "utf-8").trim(), 10);
9318
9574
  if (Number.isNaN(pid) || pid <= 0) return false;
9319
9575
  process.kill(pid, 0);
9320
9576
  return true;
@@ -9357,8 +9613,8 @@ function probeTmuxOptions(serverRunning) {
9357
9613
  };
9358
9614
  }
9359
9615
  function findUserTmuxConf() {
9360
- const xdg = join18(homedir10(), ".config", "tmux", "tmux.conf");
9361
- const dotfile = join18(homedir10(), ".tmux.conf");
9616
+ const xdg = join19(homedir10(), ".config", "tmux", "tmux.conf");
9617
+ const dotfile = join19(homedir10(), ".tmux.conf");
9362
9618
  if (existsSync18(xdg)) return xdg;
9363
9619
  if (existsSync18(dotfile)) return dotfile;
9364
9620
  return null;
@@ -9370,21 +9626,21 @@ function probeUserConf() {
9370
9626
  }
9371
9627
  let contents = "";
9372
9628
  try {
9373
- contents = readFileSync20(path, "utf-8");
9629
+ contents = readFileSync21(path, "utf-8");
9374
9630
  } catch {
9375
9631
  return { path, setsStatusLeft: false, setsStatusRight: false, sourcesSisyphusManaged: false };
9376
9632
  }
9377
9633
  const lines = contents.split("\n").filter((line) => !line.trim().startsWith("#"));
9378
9634
  const setsStatusLeft = lines.some((line) => /^\s*(set|set-option)\s+-g(?:\s+-\w+)*\s+status-left\b/.test(line));
9379
9635
  const setsStatusRight = lines.some((line) => /^\s*(set|set-option)\s+-g(?:\s+-\w+)*\s+status-right\b/.test(line));
9380
- const sourcesSisyphusManaged = contents.includes(join18(homedir10(), ".sisyphus", "tmux.conf"));
9636
+ const sourcesSisyphusManaged = contents.includes(join19(homedir10(), ".sisyphus", "tmux.conf"));
9381
9637
  return { path, setsStatusLeft, setsStatusRight, sourcesSisyphusManaged };
9382
9638
  }
9383
9639
  function loadGlobalSisyphusConfig() {
9384
9640
  const path = globalConfigPath();
9385
9641
  if (!existsSync18(path)) return null;
9386
9642
  try {
9387
- const parsed = JSON.parse(readFileSync20(path, "utf-8"));
9643
+ const parsed = JSON.parse(readFileSync21(path, "utf-8"));
9388
9644
  return parsed.statusBar === void 0 ? null : parsed.statusBar;
9389
9645
  } catch {
9390
9646
  return null;
@@ -9724,7 +9980,7 @@ init_paths();
9724
9980
  import { execSync as execSync14 } from "child_process";
9725
9981
  import { existsSync as existsSync19, statSync as statSync4 } from "fs";
9726
9982
  import { homedir as homedir11 } from "os";
9727
- import { join as join19 } from "path";
9983
+ import { join as join20 } from "path";
9728
9984
  init_platform();
9729
9985
  init_plugins();
9730
9986
  function checkNodeVersion() {
@@ -9958,7 +10214,7 @@ function checkNvim() {
9958
10214
  }
9959
10215
  function checkNotifyBinary() {
9960
10216
  if (process.platform === "darwin") {
9961
- const binary = join19(homedir11(), ".sisyphus", "SisyphusNotify.app", "Contents", "MacOS", "sisyphus-notify");
10217
+ const binary = join20(homedir11(), ".sisyphus", "SisyphusNotify.app", "Contents", "MacOS", "sisyphus-notify");
9962
10218
  if (existsSync19(binary)) {
9963
10219
  return { name: "Notifications", status: "ok", detail: "SisyphusNotify.app built" };
9964
10220
  }
@@ -10072,13 +10328,13 @@ init_version();
10072
10328
  init_platform();
10073
10329
  init_paths();
10074
10330
  init_state();
10075
- import { execFileSync as execFileSync3, spawnSync as spawnSync2 } from "child_process";
10076
- import { existsSync as existsSync20, readFileSync as readFileSync22 } from "fs";
10331
+ import { execFileSync as execFileSync4, spawnSync as spawnSync2 } from "child_process";
10332
+ import { existsSync as existsSync20, readFileSync as readFileSync23 } from "fs";
10077
10333
  import os from "os";
10078
10334
  var REPO = "crouton-labs/sisyphus";
10079
10335
  function tryCmd(bin, args2) {
10080
10336
  try {
10081
- const out = execFileSync3(bin, args2, {
10337
+ const out = execFileSync4(bin, args2, {
10082
10338
  encoding: "utf-8",
10083
10339
  stdio: ["ignore", "pipe", "ignore"],
10084
10340
  timeout: 5e3
@@ -10134,7 +10390,7 @@ function tailLog(lines) {
10134
10390
  const path = daemonLogPath();
10135
10391
  if (!existsSync20(path)) return null;
10136
10392
  try {
10137
- const all = readFileSync22(path, "utf-8").split("\n");
10393
+ const all = readFileSync23(path, "utf-8").split("\n");
10138
10394
  return all.slice(-lines).join("\n").trim() || null;
10139
10395
  } catch {
10140
10396
  return null;
@@ -10423,8 +10679,8 @@ Exit codes: 0 ok | 1 filing error | 2 usage | 60 cloud unreachable (retry-safe)`
10423
10679
  }
10424
10680
 
10425
10681
  // src/cli/commands/init.ts
10426
- import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
10427
- import { join as join20 } from "path";
10682
+ import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "fs";
10683
+ import { join as join21 } from "path";
10428
10684
  var DEFAULT_CONFIG2 = {};
10429
10685
  var ORCHESTRATOR_TEMPLATE = `# Custom Orchestrator Prompt
10430
10686
 
@@ -10453,19 +10709,19 @@ Effects
10453
10709
  Exit codes: 0 ok`
10454
10710
  ).action((opts) => {
10455
10711
  const cwd = process.cwd();
10456
- const sisDir = join20(cwd, ".sisyphus");
10457
- const configPath = join20(sisDir, "config.json");
10712
+ const sisDir = join21(cwd, ".sisyphus");
10713
+ const configPath = join21(sisDir, "config.json");
10458
10714
  if (existsSync21(configPath)) {
10459
10715
  console.log(`Already initialized: ${configPath}`);
10460
10716
  return;
10461
10717
  }
10462
10718
  mkdirSync9(sisDir, { recursive: true });
10463
- writeFileSync10(configPath, JSON.stringify(DEFAULT_CONFIG2, null, 2) + "\n", "utf-8");
10719
+ writeFileSync11(configPath, JSON.stringify(DEFAULT_CONFIG2, null, 2) + "\n", "utf-8");
10464
10720
  console.log(`Created ${configPath}`);
10465
10721
  if (opts.orchestrator) {
10466
- const orchPath = join20(sisDir, "orchestrator.md");
10722
+ const orchPath = join21(sisDir, "orchestrator.md");
10467
10723
  if (!existsSync21(orchPath)) {
10468
- writeFileSync10(orchPath, ORCHESTRATOR_TEMPLATE, "utf-8");
10724
+ writeFileSync11(orchPath, ORCHESTRATOR_TEMPLATE, "utf-8");
10469
10725
  console.log(`Created ${orchPath}`);
10470
10726
  }
10471
10727
  }
@@ -10525,7 +10781,7 @@ Exit codes: 0 ok`
10525
10781
 
10526
10782
  // src/cli/commands/configure-upload.ts
10527
10783
  init_paths();
10528
- import { chmodSync as chmodSync2, existsSync as existsSync22, mkdirSync as mkdirSync10, readFileSync as readFileSync23, writeFileSync as writeFileSync11 } from "fs";
10784
+ import { chmodSync as chmodSync2, existsSync as existsSync22, mkdirSync as mkdirSync10, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
10529
10785
  import { createInterface as createInterface3 } from "readline";
10530
10786
  import { dirname as dirname6 } from "path";
10531
10787
  async function readUrlFromInput(interactive) {
@@ -10606,7 +10862,7 @@ Exit codes: 0 ok | 1 validation or write error`
10606
10862
  let existing = {};
10607
10863
  if (existsSync22(configPath)) {
10608
10864
  try {
10609
- existing = JSON.parse(readFileSync23(configPath, "utf-8"));
10865
+ existing = JSON.parse(readFileSync24(configPath, "utf-8"));
10610
10866
  } catch {
10611
10867
  console.error(`Error: ${configPath} could not be parsed \u2014 fix or delete it first`);
10612
10868
  process.exit(1);
@@ -10614,7 +10870,7 @@ Exit codes: 0 ok | 1 validation or write error`
10614
10870
  }
10615
10871
  const merged = { ...existing, upload: { url, token } };
10616
10872
  mkdirSync10(dirname6(configPath), { recursive: true });
10617
- writeFileSync11(configPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
10873
+ writeFileSync12(configPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
10618
10874
  chmodSync2(configPath, 384);
10619
10875
  console.log(`\u2713 upload configured (${configPath})`);
10620
10876
  });
@@ -10623,10 +10879,10 @@ Exit codes: 0 ok | 1 validation or write error`
10623
10879
  // src/cli/commands/getting-started.ts
10624
10880
  import { execSync as execSync15 } from "child_process";
10625
10881
  import { existsSync as existsSync23 } from "fs";
10626
- import { dirname as dirname7, join as join21 } from "path";
10882
+ import { dirname as dirname7, join as join22 } from "path";
10627
10883
  import { fileURLToPath as fileURLToPath3 } from "url";
10628
10884
  function templatePath(name) {
10629
- return join21(dirname7(fileURLToPath3(import.meta.url)), "templates", name);
10885
+ return join22(dirname7(fileURLToPath3(import.meta.url)), "templates", name);
10630
10886
  }
10631
10887
  function isClaudeCode() {
10632
10888
  return !!process.env["CLAUDECODE"];
@@ -10993,7 +11249,7 @@ sis ui guide --tutorial 4
10993
11249
  `);
10994
11250
  }
10995
11251
  function printStep4() {
10996
- const demoPath = join21(process.cwd(), "tmp", "sisyphus-tutorial-demo");
11252
+ const demoPath = join22(process.cwd(), "tmp", "sisyphus-tutorial-demo");
10997
11253
  console.log(`
10998
11254
  <claude-instructions>
10999
11255
  # Sisyphus Getting Started \u2014 Step 4: Demo Session
@@ -11037,7 +11293,7 @@ Have the user confirm they understand these keybinds before proceeding.
11037
11293
 
11038
11294
  First, copy the demo todo app into ./tmp/ under the user's current directory and init a git repo (sisyphus needs git). Run from the user's current shell \u2014 don't \`cd\` away first:
11039
11295
  \`\`\`
11040
- mkdir -p ${join21(process.cwd(), "tmp")}
11296
+ mkdir -p ${join22(process.cwd(), "tmp")}
11041
11297
  rm -rf ${demoPath}
11042
11298
  cp -r ${templatePath("tutorial-demo")} ${demoPath}
11043
11299
  git -C ${demoPath} init
@@ -11115,7 +11371,7 @@ sis ui guide --tutorial 5
11115
11371
  `);
11116
11372
  }
11117
11373
  function printStep5() {
11118
- const demoPath = join21(process.cwd(), "tmp", "sisyphus-tutorial-demo");
11374
+ const demoPath = join22(process.cwd(), "tmp", "sisyphus-tutorial-demo");
11119
11375
  const demoExists = existsSync23(demoPath);
11120
11376
  let recentCommits = "";
11121
11377
  let topLevelFiles = "";
@@ -11220,9 +11476,9 @@ If they say yes, run:
11220
11476
  rm -rf ${demoPath}
11221
11477
  \`\`\`
11222
11478
 
11223
- Then check whether \`${join21(process.cwd(), "tmp")}\` is now empty, and if so remove it too:
11479
+ Then check whether \`${join22(process.cwd(), "tmp")}\` is now empty, and if so remove it too:
11224
11480
  \`\`\`
11225
- rmdir ${join21(process.cwd(), "tmp")} 2>/dev/null || true
11481
+ rmdir ${join22(process.cwd(), "tmp")} 2>/dev/null || true
11226
11482
  \`\`\`
11227
11483
 
11228
11484
  If they say no or want to explore first, leave it. They can clean up later with the same
@@ -11655,7 +11911,7 @@ Exit codes: 0 ok | 2 usage (invalid --tutorial value)`
11655
11911
 
11656
11912
  // src/cli/commands/history.ts
11657
11913
  init_paths();
11658
- import { readdirSync as readdirSync7, readFileSync as readFileSync24, existsSync as existsSync24 } from "fs";
11914
+ import { readdirSync as readdirSync7, readFileSync as readFileSync25, existsSync as existsSync24 } from "fs";
11659
11915
  import { resolve as resolve8 } from "path";
11660
11916
  function loadAllSummaries() {
11661
11917
  const base = historyBaseDir();
@@ -11665,7 +11921,7 @@ function loadAllSummaries() {
11665
11921
  const summaryPath = historySessionSummaryPath(name);
11666
11922
  if (existsSync24(summaryPath)) {
11667
11923
  try {
11668
- const raw = readFileSync24(summaryPath, "utf-8");
11924
+ const raw = readFileSync25(summaryPath, "utf-8");
11669
11925
  results.push({ id: name, summary: JSON.parse(raw) });
11670
11926
  continue;
11671
11927
  } catch {
@@ -11682,7 +11938,7 @@ function buildLiveSummary(sessionId) {
11682
11938
  if (!existsSync24(eventsPath)) return null;
11683
11939
  let cwd = null;
11684
11940
  try {
11685
- const lines = readFileSync24(eventsPath, "utf-8").split("\n");
11941
+ const lines = readFileSync25(eventsPath, "utf-8").split("\n");
11686
11942
  for (const line of lines) {
11687
11943
  if (!line.trim()) continue;
11688
11944
  try {
@@ -11703,7 +11959,7 @@ function buildLiveSummary(sessionId) {
11703
11959
  if (!existsSync24(sPath)) return null;
11704
11960
  let session2;
11705
11961
  try {
11706
- session2 = JSON.parse(readFileSync24(sPath, "utf-8"));
11962
+ session2 = JSON.parse(readFileSync25(sPath, "utf-8"));
11707
11963
  } catch {
11708
11964
  return null;
11709
11965
  }
@@ -11765,7 +12021,7 @@ function buildLiveSummary(sessionId) {
11765
12021
  function loadEvents(sessionId) {
11766
12022
  const eventsPath = historyEventsPath(sessionId);
11767
12023
  if (!existsSync24(eventsPath)) return [];
11768
- const lines = readFileSync24(eventsPath, "utf-8").split("\n").filter((l) => l.trim());
12024
+ const lines = readFileSync25(eventsPath, "utf-8").split("\n").filter((l) => l.trim());
11769
12025
  const events = [];
11770
12026
  for (const line of lines) {
11771
12027
  try {
@@ -11780,7 +12036,7 @@ function findSession(idOrName) {
11780
12036
  const summaryPath = historySessionSummaryPath(idOrName);
11781
12037
  if (existsSync24(summaryPath)) {
11782
12038
  try {
11783
- return { id: idOrName, summary: JSON.parse(readFileSync24(summaryPath, "utf-8")) };
12039
+ return { id: idOrName, summary: JSON.parse(readFileSync25(summaryPath, "utf-8")) };
11784
12040
  } catch {
11785
12041
  }
11786
12042
  }
@@ -12028,7 +12284,7 @@ Exit codes: 0 ok | 2 usage | 1 export_failed.`).action(async (sessionIdArg, opts
12028
12284
 
12029
12285
  // src/cli/commands/upload.ts
12030
12286
  import { rmSync as rmSync6 } from "fs";
12031
- import { tmpdir } from "os";
12287
+ import { tmpdir as tmpdir2 } from "os";
12032
12288
  init_config();
12033
12289
  init_session_export();
12034
12290
  init_upload();
@@ -12084,7 +12340,7 @@ Exit codes: 0 ok | 1 upload or export error | 2 usage`
12084
12340
  }
12085
12341
  let zipPath;
12086
12342
  try {
12087
- zipPath = await exportSessionToZip(sessionId, cwd, { reveal: false, outputDir: tmpdir() });
12343
+ zipPath = await exportSessionToZip(sessionId, cwd, { reveal: false, outputDir: tmpdir2() });
12088
12344
  } catch (err) {
12089
12345
  exitError({
12090
12346
  code: "export_failed",
@@ -12149,7 +12405,7 @@ Exit codes: 0 ok | 1 upload or export error | 2 usage`
12149
12405
  // src/cli/commands/scratch.ts
12150
12406
  import { execSync as execSync16 } from "child_process";
12151
12407
  init_shell();
12152
- function findHomeSession(cwd) {
12408
+ function findHomeSession2(cwd) {
12153
12409
  const normalizedCwd = cwd.replace(/\/+$/, "");
12154
12410
  let output;
12155
12411
  try {
@@ -12197,7 +12453,7 @@ Effects
12197
12453
  Exit codes: 0 ok | 2 usage.`).action((promptParts, opts) => {
12198
12454
  assertTmux();
12199
12455
  const cwd = opts.cwd ?? process.env["SISYPHUS_CWD"] ?? process.cwd();
12200
- const homeSession = findHomeSession(cwd);
12456
+ const homeSession = findHomeSession2(cwd);
12201
12457
  if (!homeSession) {
12202
12458
  const current = execSync16('tmux display-message -p "#{session_name}"', {
12203
12459
  encoding: "utf-8"
@@ -12225,15 +12481,15 @@ function openScratchWindow(tmuxSession, cwd, prompt) {
12225
12481
 
12226
12482
  // src/cli/commands/review.ts
12227
12483
  init_paths();
12228
- import { join as join23, resolve as resolve9, dirname as dirname8 } from "path";
12229
- import { existsSync as existsSync26, readFileSync as readFileSync26, writeFileSync as writeFileSync13, renameSync as renameSync3, readdirSync as readdirSync8 } from "fs";
12484
+ import { join as join24, resolve as resolve9, dirname as dirname8 } from "path";
12485
+ import { existsSync as existsSync26, readFileSync as readFileSync27, writeFileSync as writeFileSync14, renameSync as renameSync3, readdirSync as readdirSync8 } from "fs";
12230
12486
  var _statusCheck = ["draft", "question", "approved", "rejected", "deferred"];
12231
12487
  function resolveContextArtifact(file, opts, filename, notFoundMessage) {
12232
12488
  const cwd = opts.cwd || process.env.SISYPHUS_CWD || process.cwd();
12233
12489
  if (file) return resolve9(file);
12234
12490
  const sessionId = opts.sessionId || process.env.SISYPHUS_SESSION_ID;
12235
12491
  if (sessionId) {
12236
- const target = join23(contextDir(cwd, sessionId), filename);
12492
+ const target = join24(contextDir(cwd, sessionId), filename);
12237
12493
  if (!existsSync26(target)) {
12238
12494
  exitUsage("file-not-found", `File not found: ${target}`, { received: target });
12239
12495
  }
@@ -12243,7 +12499,7 @@ function resolveContextArtifact(file, opts, filename, notFoundMessage) {
12243
12499
  if (existsSync26(dir)) {
12244
12500
  const sessions = readdirSync8(dir);
12245
12501
  for (const session2 of sessions.reverse()) {
12246
- const candidate = join23(dir, session2, "context", filename);
12502
+ const candidate = join24(dir, session2, "context", filename);
12247
12503
  if (existsSync26(candidate)) return candidate;
12248
12504
  }
12249
12505
  }
@@ -12302,12 +12558,12 @@ Exit codes: 0 ok | 2 usage.`).action(async (file, opts) => {
12302
12558
  if (!existsSync26(targetPath)) {
12303
12559
  exitUsage("file-not-found", `File not found: ${targetPath}`, { received: targetPath });
12304
12560
  }
12305
- const parsed = JSON.parse(readFileSync26(targetPath, "utf-8"));
12561
+ const parsed = JSON.parse(readFileSync27(targetPath, "utf-8"));
12306
12562
  const rendered = renderRequirementsMarkdown(parsed);
12307
- const outPath = join23(dirname8(targetPath), "requirements.md");
12563
+ const outPath = join24(dirname8(targetPath), "requirements.md");
12308
12564
  const tmpPath = outPath + ".tmp";
12309
12565
  if (existsSync26(outPath)) {
12310
- const existing = readFileSync26(outPath, "utf-8");
12566
+ const existing = readFileSync27(outPath, "utf-8");
12311
12567
  if (existing !== rendered) {
12312
12568
  if (!opts.force) {
12313
12569
  exitUsage("conflict", `${outPath} has been hand-edited (differs from rendered output)`, {
@@ -12320,7 +12576,7 @@ Exit codes: 0 ok | 2 usage.`).action(async (file, opts) => {
12320
12576
  `);
12321
12577
  }
12322
12578
  }
12323
- writeFileSync13(tmpPath, rendered, "utf-8");
12579
+ writeFileSync14(tmpPath, rendered, "utf-8");
12324
12580
  renameSync3(tmpPath, outPath);
12325
12581
  emitJsonOk({ path: resolve9(outPath) });
12326
12582
  return;
@@ -12684,8 +12940,8 @@ function renderRequirementsMarkdown(json) {
12684
12940
  }
12685
12941
 
12686
12942
  // src/cli/commands/companion.ts
12687
- import { basename as basename7, dirname as dirname11, join as join28 } from "path";
12688
- import { mkdirSync as mkdirSync15, readFileSync as readFileSync31, writeFileSync as writeFileSync18 } from "fs";
12943
+ import { basename as basename7, dirname as dirname11, join as join29 } from "path";
12944
+ import { mkdirSync as mkdirSync15, readFileSync as readFileSync32, writeFileSync as writeFileSync19 } from "fs";
12689
12945
  init_paths();
12690
12946
  init_companion_types();
12691
12947
  init_companion_memory();
@@ -12788,10 +13044,10 @@ Effects
12788
13044
  Writes/updates ~/.sisyphus/companion-context-cache/<session-id>.json on each call that produces output.
12789
13045
 
12790
13046
  Exit codes: 0 ok.`).action((opts) => {
12791
- const cachePath = join28(globalDir(), "companion-context-cache", `${opts.sessionId}.json`);
13047
+ const cachePath = join29(globalDir(), "companion-context-cache", `${opts.sessionId}.json`);
12792
13048
  let prev = {};
12793
13049
  try {
12794
- prev = JSON.parse(readFileSync31(cachePath, "utf-8"));
13050
+ prev = JSON.parse(readFileSync32(cachePath, "utf-8"));
12795
13051
  } catch {
12796
13052
  prev = {};
12797
13053
  }
@@ -12805,7 +13061,7 @@ Exit codes: 0 ok.`).action((opts) => {
12805
13061
  process.stdout.write(renderFullContext(next));
12806
13062
  }
12807
13063
  mkdirSync15(dirname11(cachePath), { recursive: true });
12808
- writeFileSync18(cachePath, JSON.stringify(next), "utf-8");
13064
+ writeFileSync19(cachePath, JSON.stringify(next), "utf-8");
12809
13065
  });
12810
13066
  companion.command("pane").description("Open (or focus) a side claude pane next to the dashboard").option("--cwd <path>", "Project directory (default: current directory)").addHelpText("after", `
12811
13067
  companion pane: open (or focus) the companion side pane next to the dashboard.
@@ -12909,7 +13165,7 @@ Exit codes: 0 ok | 3 not_found.`
12909
13165
  }));
12910
13166
  emitJsonOk({ ...companionData, badges });
12911
13167
  } else {
12912
- emitJsonOk(companionData);
13168
+ emitJsonOk({ ...companionData });
12913
13169
  }
12914
13170
  });
12915
13171
  }
@@ -12919,7 +13175,7 @@ init_runner();
12919
13175
  init_creds();
12920
13176
  init_tailscale();
12921
13177
  import { homedir as homedir13 } from "os";
12922
- import { join as join29 } from "path";
13178
+ import { join as join30 } from "path";
12923
13179
  function assertArch(raw) {
12924
13180
  if (raw === "arm" || raw === "x86") return raw;
12925
13181
  throw new Error(`Invalid --arch: ${raw}. Must be 'arm' or 'x86'.`);
@@ -12965,7 +13221,7 @@ Exit codes: 0 ok | 1 error (bad credentials or API failure).`).action(async () =
12965
13221
  const sub = deploy.command(provider).description(`${provider} commands.`).addHelpText("before", `
12966
13222
  deploy ${provider}: per-provider box lifecycle. up | down | status | ssh | logs | update.
12967
13223
  `);
12968
- sub.command("up").description(`Provision the ${provider} box (terraform init \u2192 plan \u2192 apply).`).option("--region <region>", `Provider region (defaults: hetzner=nbg1, aws=us-east-1).`).option("--arch <arch>", "'arm' (default) or 'x86'. Picks the default --size and image.", "arm").option("--size <size>", "Instance type override (defaults follow --arch).").option("--ssh-key <path>", "Path to SSH public key.", join29(homedir13(), ".ssh", "id_ed25519.pub")).option("--no-chromium", "Skip headless Chromium install.").option("--no-auto-update", "Skip the daily auto-update systemd timer.").option("--name <name>", "Box hostname / Tailscale node name.", "sisyphus").option("--yes", "Skip the re-provision confirmation prompt when state already exists.").addHelpText("after", `
13224
+ sub.command("up").description(`Provision the ${provider} box (terraform init \u2192 plan \u2192 apply).`).option("--region <region>", `Provider region (defaults: hetzner=nbg1, aws=us-east-1).`).option("--arch <arch>", "'arm' (default) or 'x86'. Picks the default --size and image.", "arm").option("--size <size>", "Instance type override (defaults follow --arch).").option("--ssh-key <path>", "Path to SSH public key.", join30(homedir13(), ".ssh", "id_ed25519.pub")).option("--no-chromium", "Skip headless Chromium install.").option("--no-auto-update", "Skip the daily auto-update systemd timer.").option("--name <name>", "Box hostname / Tailscale node name.", "sisyphus").option("--yes", "Skip the re-provision confirmation prompt when state already exists.").addHelpText("after", `
12969
13225
  deploy ${provider} up: provision the ${provider} box via Terraform (init \u2192 plan \u2192 apply).
12970
13226
 
12971
13227
  Input
@@ -13112,14 +13368,14 @@ init_runner2();
13112
13368
 
13113
13369
  // src/cli/cloud/handoff.ts
13114
13370
  import { spawn as spawn5 } from "child_process";
13115
- import { existsSync as existsSync36, readFileSync as readFileSync35, writeFileSync as writeFileSync19 } from "fs";
13371
+ import { existsSync as existsSync36, readFileSync as readFileSync36, writeFileSync as writeFileSync20 } from "fs";
13116
13372
  init_exec();
13117
13373
  init_paths();
13118
13374
  init_shell();
13119
13375
  init_runner();
13120
13376
  init_ssh_exec();
13121
13377
  init_provider_pick();
13122
- import { join as join31 } from "path";
13378
+ import { join as join32 } from "path";
13123
13379
  async function cloudHandoff(sessionId, opts) {
13124
13380
  const cwd = process.env["SISYPHUS_CWD"] ?? process.cwd();
13125
13381
  const request = {
@@ -13164,7 +13420,7 @@ async function waitForSentOrError(cwd, sessionId) {
13164
13420
  if (!existsSync36(path)) continue;
13165
13421
  let session2;
13166
13422
  try {
13167
- session2 = JSON.parse(readFileSync35(path, "utf-8"));
13423
+ session2 = JSON.parse(readFileSync36(path, "utf-8"));
13168
13424
  } catch (err) {
13169
13425
  void err;
13170
13426
  continue;
@@ -13245,16 +13501,16 @@ async function cloudReclaim(sessionId, opts) {
13245
13501
  await rsyncDown(target, `${remoteRepoDir}/`, `${cwd}/`, { withDelete: false, excludeSisyphus: true, update: true });
13246
13502
  for (const name of ["config.json", "orchestrator.md", "orchestrator-settings.json"]) {
13247
13503
  const remotePath = `${remoteRepoDir}/.sisyphus/${name}`;
13248
- const localPath = join31(projectDir(cwd), name);
13504
+ const localPath = join32(projectDir(cwd), name);
13249
13505
  const probe = runOnBox(provider, `test -f ${shellQuote(remotePath.replace(/^~\//, ""))} && echo y || echo n`);
13250
13506
  if (probe.stdout.trim() !== "y") continue;
13251
13507
  await rsyncDown(target, remotePath, localPath, { withDelete: false });
13252
13508
  }
13253
13509
  const localStatePath = statePath(cwd, sessionId);
13254
- const merged = JSON.parse(readFileSync35(localStatePath, "utf-8"));
13510
+ const merged = JSON.parse(readFileSync36(localStatePath, "utf-8"));
13255
13511
  merged.cwd = cwd;
13256
13512
  merged.handoff = local.handoff;
13257
- writeFileSync19(localStatePath, JSON.stringify(merged, null, 2));
13513
+ writeFileSync20(localStatePath, JSON.stringify(merged, null, 2));
13258
13514
  const reclaimMessage = `Session reclaimed from cloud (${provider}:${repo}). Resuming locally.`;
13259
13515
  console.log(`\u2192 local sis resume`);
13260
13516
  const resumeResp = await sendRequest({
@@ -13287,7 +13543,7 @@ function readLocalSession(cwd, sessionId) {
13287
13543
  received: sessionId
13288
13544
  });
13289
13545
  }
13290
- return JSON.parse(readFileSync35(path, "utf-8"));
13546
+ return JSON.parse(readFileSync36(path, "utf-8"));
13291
13547
  }
13292
13548
  async function waitForBoxPaused(provider, remoteSessionDir) {
13293
13549
  const POLL_INTERVAL_MS = 2e3;
@@ -13571,7 +13827,7 @@ function attachNotify(diagnostic2) {
13571
13827
  // src/cli/commands/tmux-sessions.ts
13572
13828
  init_paths();
13573
13829
  import { execSync as execSync18 } from "child_process";
13574
- import { readFileSync as readFileSync36, existsSync as existsSync37 } from "fs";
13830
+ import { readFileSync as readFileSync37, existsSync as existsSync37 } from "fs";
13575
13831
  var DOT_MAP = {
13576
13832
  "orchestrator:processing": { icon: "\u25CF", color: "#d4ad6a" },
13577
13833
  "orchestrator:idle": { icon: "\u25CF", color: "#d47766" },
@@ -13584,7 +13840,7 @@ function readManifest() {
13584
13840
  const p = sessionsManifestPath();
13585
13841
  if (!existsSync37(p)) return null;
13586
13842
  try {
13587
- return JSON.parse(readFileSync36(p, "utf-8"));
13843
+ return JSON.parse(readFileSync37(p, "utf-8"));
13588
13844
  } catch {
13589
13845
  return null;
13590
13846
  }
@@ -13625,7 +13881,7 @@ init_server();
13625
13881
  init_ask_store();
13626
13882
  init_state();
13627
13883
  init_paths();
13628
- import { existsSync as existsSync49 } from "fs";
13884
+ import { existsSync as existsSync48 } from "fs";
13629
13885
  var HEARTBEAT_ASKED_BY2 = "system:heartbeat";
13630
13886
  var ORPHAN_ASKED_BY2 = "system:orphan-handler";
13631
13887
  function isHeartbeatZombie(cwd, sessionId, askId) {
@@ -13633,14 +13889,14 @@ function isHeartbeatZombie(cwd, sessionId, askId) {
13633
13889
  if (!meta) return false;
13634
13890
  if (meta.askedBy !== HEARTBEAT_ASKED_BY2) return false;
13635
13891
  if (meta.status === "answered") return false;
13636
- if (existsSync49(askOutputPath(cwd, sessionId, askId))) return false;
13892
+ if (existsSync48(askOutputPath(cwd, sessionId, askId))) return false;
13637
13893
  for (const candidateId of listAsks(cwd, sessionId)) {
13638
13894
  if (candidateId === askId) continue;
13639
13895
  const candidateMeta = readMeta(cwd, sessionId, candidateId);
13640
13896
  if (!candidateMeta) continue;
13641
13897
  if (candidateMeta.heartbeatAskId !== askId) continue;
13642
13898
  if (candidateMeta.status === "answered") return true;
13643
- if (existsSync49(askOutputPath(cwd, sessionId, candidateId))) return true;
13899
+ if (existsSync48(askOutputPath(cwd, sessionId, candidateId))) return true;
13644
13900
  }
13645
13901
  return false;
13646
13902
  }
@@ -13649,7 +13905,7 @@ function isOrphanZombie(cwd, sessionId, askId) {
13649
13905
  if (!meta) return false;
13650
13906
  if (meta.askedBy !== ORPHAN_ASKED_BY2) return false;
13651
13907
  if (meta.status === "answered") return false;
13652
- if (existsSync49(askOutputPath(cwd, sessionId, askId))) return false;
13908
+ if (existsSync48(askOutputPath(cwd, sessionId, askId))) return false;
13653
13909
  if (meta.orphanTarget?.kind !== "agent") return false;
13654
13910
  let session2;
13655
13911
  try {
@@ -13662,27 +13918,6 @@ function isOrphanZombie(cwd, sessionId, askId) {
13662
13918
  if (!agent2) return false;
13663
13919
  return agent2.status !== "running";
13664
13920
  }
13665
- function isModeGateZombie(cwd, sessionId, askId) {
13666
- const meta = readMeta(cwd, sessionId, askId);
13667
- if (!meta) return false;
13668
- if (meta.modeTransition !== true) return false;
13669
- if (meta.status === "answered") return false;
13670
- if (existsSync49(askOutputPath(cwd, sessionId, askId))) return false;
13671
- const deck = readDecisions(cwd, sessionId, askId);
13672
- if (!deck) return false;
13673
- const source = deck.source;
13674
- const chain = source?.modeChain;
13675
- if (!chain || chain.length === 0) return false;
13676
- let currentMode;
13677
- try {
13678
- const session2 = getSession(cwd, sessionId);
13679
- currentMode = session2.orchestratorCycles[session2.orchestratorCycles.length - 1]?.mode;
13680
- } catch {
13681
- return false;
13682
- }
13683
- if (!currentMode) return false;
13684
- return !chain.some((e) => e.mode === currentMode);
13685
- }
13686
13921
  async function resolveZombie(cwd, sessionId, entry) {
13687
13922
  const { askId, kind } = entry;
13688
13923
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -13700,11 +13935,6 @@ async function resolveZombie(cwd, sessionId, entry) {
13700
13935
  selectedOptionId = "dismiss";
13701
13936
  freetext = "auto-resolved: agent superseded by replacement (clean-zombies sweep)";
13702
13937
  break;
13703
- case "mode-gate":
13704
- interactionId = "mode-transition";
13705
- selectedOptionId = "ack";
13706
- freetext = "auto-resolved: session advanced past mode-transition (clean-zombies sweep)";
13707
- break;
13708
13938
  }
13709
13939
  writeOutput(cwd, sessionId, askId, [{
13710
13940
  id: interactionId,
@@ -13723,14 +13953,12 @@ async function sweepSession(cwd, sessionId) {
13723
13953
  const meta = readMeta(cwd, sessionId, askId);
13724
13954
  const agentId = meta?.orphanTarget?.kind === "agent" ? meta.orphanTarget.agentId : "unknown";
13725
13955
  zombies.push({ sessionId, askId, kind: "orphan", reason: `agent ${agentId} is no longer running` });
13726
- } else if (isModeGateZombie(cwd, sessionId, askId)) {
13727
- zombies.push({ sessionId, askId, kind: "mode-gate", reason: "session advanced past mode-transition" });
13728
13956
  }
13729
13957
  }
13730
13958
  return zombies;
13731
13959
  }
13732
13960
  function registerCleanZombies(program2) {
13733
- program2.command("clean-zombies").description("Sweep all sessions for zombie asks (heartbeats whose original is answered, orphans whose agent is superseded, stale mode-gate notifications) and dismiss them").addHelpText(
13961
+ program2.command("clean-zombies").description("Sweep all sessions for zombie asks (heartbeats whose original is answered, orphans whose agent is superseded) and dismiss them").addHelpText(
13734
13962
  "after",
13735
13963
  `
13736
13964
  clean-zombies: sweep all sessions and dismiss stale ask records.
@@ -13743,8 +13971,8 @@ Output (stdout, plain text \u2014 human-readable maintenance summary; not for ag
13743
13971
 
13744
13972
  Effects
13745
13973
  Mutates ask records: writes response.json and updates status to "answered" for each
13746
- zombie found. Dismisses heartbeat asks whose original was answered, orphan asks whose
13747
- target agent is no longer running, and mode-gate asks the session has advanced past.
13974
+ zombie found. Dismisses heartbeat asks whose original was answered and orphan asks whose
13975
+ target agent is no longer running.
13748
13976
 
13749
13977
  Exit codes: 0 ok`
13750
13978
  ).action(async () => {
@@ -13757,7 +13985,7 @@ Exit codes: 0 ok`
13757
13985
  const allZombies = [];
13758
13986
  const sessionsSweept = /* @__PURE__ */ new Set();
13759
13987
  for (const [sessionId, cwd] of entries) {
13760
- if (!existsSync49(statePath(cwd, sessionId))) continue;
13988
+ if (!existsSync48(statePath(cwd, sessionId))) continue;
13761
13989
  try {
13762
13990
  const zombies = await sweepSession(cwd, sessionId);
13763
13991
  if (zombies.length > 0) {
@@ -13773,8 +14001,7 @@ Exit codes: 0 ok`
13773
14001
  }
13774
14002
  const summary = {
13775
14003
  heartbeats: allZombies.filter((z4) => z4.kind === "heartbeat").length,
13776
- orphans: allZombies.filter((z4) => z4.kind === "orphan").length,
13777
- modeGates: allZombies.filter((z4) => z4.kind === "mode-gate").length
14004
+ orphans: allZombies.filter((z4) => z4.kind === "orphan").length
13778
14005
  };
13779
14006
  const total = allZombies.length;
13780
14007
  if (total === 0) {
@@ -13782,7 +14009,7 @@ Exit codes: 0 ok`
13782
14009
  return;
13783
14010
  }
13784
14011
  for (const [sessionId, cwd] of entries) {
13785
- if (!existsSync49(statePath(cwd, sessionId))) continue;
14012
+ if (!existsSync48(statePath(cwd, sessionId))) continue;
13786
14013
  const sessionZombies = allZombies.filter((z4) => z4.sessionId === sessionId);
13787
14014
  for (const zombie of sessionZombies) {
13788
14015
  try {
@@ -13795,7 +14022,7 @@ Exit codes: 0 ok`
13795
14022
  }
13796
14023
  }
13797
14024
  }
13798
- console.log(`Dismissed ${total} zombie${total === 1 ? "" : "s"} across ${sessionsSweept.size} session${sessionsSweept.size === 1 ? "" : "s"}: ${summary.heartbeats} heartbeat${summary.heartbeats === 1 ? "" : "s"}, ${summary.orphans} orphan${summary.orphans === 1 ? "" : "s"}, ${summary.modeGates} mode-gate${summary.modeGates === 1 ? "" : "s"}.`);
14025
+ console.log(`Dismissed ${total} zombie${total === 1 ? "" : "s"} across ${sessionsSweept.size} session${sessionsSweept.size === 1 ? "" : "s"}: ${summary.heartbeats} heartbeat${summary.heartbeats === 1 ? "" : "s"}, ${summary.orphans} orphan${summary.orphans === 1 ? "" : "s"}.`);
13799
14026
  });
13800
14027
  }
13801
14028
 
@@ -13824,7 +14051,7 @@ var sessionCounts = null;
13824
14051
  var program = new Command();
13825
14052
  program.name("sis").description("tmux-integrated orchestration daemon for Claude Code").helpOption("-h, --help", "print -h for any node or leaf").version(
13826
14053
  JSON.parse(
13827
- readFileSync46(join38(dirname16(fileURLToPath6(import.meta.url)), "..", "package.json"), "utf-8")
14054
+ readFileSync47(join39(dirname16(fileURLToPath6(import.meta.url)), "..", "package.json"), "utf-8")
13828
14055
  ).version,
13829
14056
  "--version",
13830
14057
  "output the version number"
@@ -13936,7 +14163,7 @@ registerHomeInit(diagnostic);
13936
14163
  var args = process.argv.slice(2);
13937
14164
  var firstArg = args[0];
13938
14165
  var skipWelcome = ["session", "start", "dashboard", "agent", "orch", "ask", "ui", "segment", "admin", "feedback", "help", "--help", "--version"];
13939
- if (!existsSync50(globalDir()) && firstArg && !skipWelcome.includes(firstArg)) {
14166
+ if (!existsSync49(globalDir()) && firstArg && !skipWelcome.includes(firstArg)) {
13940
14167
  mkdirSync21(globalDir(), { recursive: true });
13941
14168
  console.log("");
13942
14169
  console.log(" Welcome to Sisyphus. Run 'sis admin install setup' to get started.");