sisyphi 1.0.14 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/{chunk-Q6VQOUN3.js → chunk-M7LZ2ZHD.js} +3 -27
  2. package/dist/chunk-M7LZ2ZHD.js.map +1 -0
  3. package/dist/{chunk-YGBGKMTF.js → chunk-REUQ4B45.js} +7 -11
  4. package/dist/chunk-REUQ4B45.js.map +1 -0
  5. package/dist/{chunk-MMA43N67.js → chunk-Z32YVDMY.js} +2 -2
  6. package/dist/chunk-Z32YVDMY.js.map +1 -0
  7. package/dist/cli.js +38 -47
  8. package/dist/cli.js.map +1 -1
  9. package/dist/daemon.js +795 -796
  10. package/dist/daemon.js.map +1 -1
  11. package/dist/{paths-FYYSBD27.js → paths-IJXOAN4E.js} +4 -6
  12. package/dist/templates/CLAUDE.md +16 -14
  13. package/dist/templates/agent-plugin/agents/CLAUDE.md +17 -6
  14. package/dist/templates/agent-plugin/agents/design.md +134 -0
  15. package/dist/templates/agent-plugin/agents/explore.md +39 -0
  16. package/dist/templates/agent-plugin/agents/operator.md +24 -0
  17. package/dist/templates/agent-plugin/agents/plan.md +15 -20
  18. package/dist/templates/agent-plugin/agents/problem.md +119 -0
  19. package/dist/templates/agent-plugin/agents/requirements.md +138 -0
  20. package/dist/templates/agent-plugin/agents/review/CLAUDE.md +29 -0
  21. package/dist/templates/agent-plugin/agents/review/compliance.md +6 -6
  22. package/dist/templates/agent-plugin/agents/review-plan/code-smells.md +4 -4
  23. package/dist/templates/agent-plugin/agents/review-plan/requirements-coverage.md +62 -0
  24. package/dist/templates/agent-plugin/agents/review-plan/security.md +1 -1
  25. package/dist/templates/agent-plugin/agents/review-plan.md +9 -8
  26. package/dist/templates/agent-plugin/agents/review.md +1 -1
  27. package/dist/templates/agent-plugin/agents/test-spec.md +2 -2
  28. package/dist/templates/agent-plugin/hooks/CLAUDE.md +2 -2
  29. package/dist/templates/agent-plugin/hooks/explore-user-prompt.sh +13 -0
  30. package/dist/templates/agent-plugin/hooks/plan-user-prompt.sh +1 -1
  31. package/dist/templates/agent-plugin/hooks/require-submit.sh +69 -2
  32. package/dist/templates/agent-plugin/hooks/review-plan-user-prompt.sh +4 -4
  33. package/dist/templates/agent-plugin/hooks/review-user-prompt.sh +1 -1
  34. package/dist/templates/agent-suffix.md +0 -2
  35. package/dist/templates/orchestrator-base.md +167 -145
  36. package/dist/templates/orchestrator-impl.md +92 -57
  37. package/dist/templates/orchestrator-planning.md +46 -56
  38. package/dist/templates/orchestrator-plugin/commands/sisyphus/design.md +13 -0
  39. package/dist/templates/orchestrator-plugin/commands/sisyphus/problem.md +13 -0
  40. package/dist/templates/orchestrator-plugin/commands/sisyphus/requirements.md +13 -0
  41. package/dist/templates/orchestrator-plugin/commands/sisyphus/strategize.md +19 -0
  42. package/dist/templates/orchestrator-plugin/hooks/explore-gate.sh +15 -0
  43. package/dist/templates/orchestrator-plugin/hooks/hooks.json +14 -1
  44. package/dist/templates/orchestrator-plugin/skills/orchestration/task-patterns.md +34 -27
  45. package/dist/templates/orchestrator-plugin/skills/orchestration/workflow-examples.md +56 -24
  46. package/dist/templates/orchestrator-strategy.md +233 -0
  47. package/dist/templates/orchestrator-validation.md +94 -0
  48. package/dist/tui.js +134 -91
  49. package/dist/tui.js.map +1 -1
  50. package/package.json +1 -1
  51. package/templates/CLAUDE.md +16 -14
  52. package/templates/agent-plugin/agents/CLAUDE.md +17 -6
  53. package/templates/agent-plugin/agents/design.md +134 -0
  54. package/templates/agent-plugin/agents/explore.md +39 -0
  55. package/templates/agent-plugin/agents/operator.md +24 -0
  56. package/templates/agent-plugin/agents/plan.md +15 -20
  57. package/templates/agent-plugin/agents/problem.md +119 -0
  58. package/templates/agent-plugin/agents/requirements.md +138 -0
  59. package/templates/agent-plugin/agents/review/CLAUDE.md +29 -0
  60. package/templates/agent-plugin/agents/review/compliance.md +6 -6
  61. package/templates/agent-plugin/agents/review-plan/code-smells.md +4 -4
  62. package/templates/agent-plugin/agents/review-plan/requirements-coverage.md +62 -0
  63. package/templates/agent-plugin/agents/review-plan/security.md +1 -1
  64. package/templates/agent-plugin/agents/review-plan.md +9 -8
  65. package/templates/agent-plugin/agents/review.md +1 -1
  66. package/templates/agent-plugin/agents/test-spec.md +2 -2
  67. package/templates/agent-plugin/hooks/CLAUDE.md +2 -2
  68. package/templates/agent-plugin/hooks/explore-user-prompt.sh +13 -0
  69. package/templates/agent-plugin/hooks/plan-user-prompt.sh +1 -1
  70. package/templates/agent-plugin/hooks/require-submit.sh +69 -2
  71. package/templates/agent-plugin/hooks/review-plan-user-prompt.sh +4 -4
  72. package/templates/agent-plugin/hooks/review-user-prompt.sh +1 -1
  73. package/templates/agent-suffix.md +0 -2
  74. package/templates/orchestrator-base.md +167 -145
  75. package/templates/orchestrator-impl.md +92 -57
  76. package/templates/orchestrator-planning.md +46 -56
  77. package/templates/orchestrator-plugin/commands/sisyphus/design.md +13 -0
  78. package/templates/orchestrator-plugin/commands/sisyphus/problem.md +13 -0
  79. package/templates/orchestrator-plugin/commands/sisyphus/requirements.md +13 -0
  80. package/templates/orchestrator-plugin/commands/sisyphus/strategize.md +19 -0
  81. package/templates/orchestrator-plugin/hooks/explore-gate.sh +15 -0
  82. package/templates/orchestrator-plugin/hooks/hooks.json +14 -1
  83. package/templates/orchestrator-plugin/skills/orchestration/task-patterns.md +34 -27
  84. package/templates/orchestrator-plugin/skills/orchestration/workflow-examples.md +56 -24
  85. package/templates/orchestrator-strategy.md +233 -0
  86. package/templates/orchestrator-validation.md +94 -0
  87. package/dist/chunk-MMA43N67.js.map +0 -1
  88. package/dist/chunk-Q6VQOUN3.js.map +0 -1
  89. package/dist/chunk-YGBGKMTF.js.map +0 -1
  90. package/dist/templates/agent-plugin/agents/review-plan/spec-coverage.md +0 -44
  91. package/dist/templates/agent-plugin/agents/spec-draft.md +0 -78
  92. package/dist/templates/agent-plugin/hooks/hooks.json +0 -25
  93. package/dist/templates/agent-plugin/hooks/spec-user-prompt.sh +0 -19
  94. package/dist/templates/orchestrator-plugin/skills/git-management/SKILL.md +0 -111
  95. package/templates/agent-plugin/agents/review-plan/spec-coverage.md +0 -44
  96. package/templates/agent-plugin/agents/spec-draft.md +0 -78
  97. package/templates/agent-plugin/hooks/hooks.json +0 -25
  98. package/templates/agent-plugin/hooks/spec-user-prompt.sh +0 -19
  99. package/templates/orchestrator-plugin/skills/git-management/SKILL.md +0 -111
  100. /package/dist/{paths-FYYSBD27.js.map → paths-IJXOAN4E.js.map} +0 -0
package/dist/tui.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  exec,
6
6
  execSafe,
7
7
  loadConfig
8
- } from "./chunk-MMA43N67.js";
8
+ } from "./chunk-Z32YVDMY.js";
9
9
  import {
10
10
  buildSessionContext,
11
11
  computeActiveTimeMs,
@@ -13,7 +13,7 @@ import {
13
13
  rawSend,
14
14
  resolveReports,
15
15
  statusColor
16
- } from "./chunk-Q6VQOUN3.js";
16
+ } from "./chunk-M7LZ2ZHD.js";
17
17
  import {
18
18
  shellQuote
19
19
  } from "./chunk-6G226ZK7.js";
@@ -23,8 +23,9 @@ import {
23
23
  goalPath,
24
24
  logsDir,
25
25
  roadmapPath,
26
- sessionDir
27
- } from "./chunk-YGBGKMTF.js";
26
+ sessionDir,
27
+ strategyPath
28
+ } from "./chunk-REUQ4B45.js";
28
29
 
29
30
  // src/tui/terminal.ts
30
31
  function emptyKey() {
@@ -311,6 +312,7 @@ function createAppState(cwd2) {
311
312
  notification: null,
312
313
  notificationTimer: null,
313
314
  showLogs: false,
315
+ showStrategy: false,
314
316
  inputText: "",
315
317
  inputCursorPos: 0,
316
318
  detailScroll,
@@ -318,6 +320,7 @@ function createAppState(cwd2) {
318
320
  sessions: [],
319
321
  selectedSession: null,
320
322
  planContent: "",
323
+ strategyContent: "",
321
324
  goalContent: "",
322
325
  logsContent: "",
323
326
  logsCycles: [],
@@ -544,6 +547,8 @@ function abbreviateMode(mode) {
544
547
  if (!mode) return "";
545
548
  if (mode === "implementation") return "impl";
546
549
  if (mode === "planning") return "plan";
550
+ if (mode === "strategy") return "strat";
551
+ if (mode === "validation") return "valid";
547
552
  return mode;
548
553
  }
549
554
  function ansiBold(text) {
@@ -564,22 +569,10 @@ function ansiColor(text, color, bold = false) {
564
569
  function modeColor(mode) {
565
570
  if (mode === "planning") return "blue";
566
571
  if (mode === "implementation") return "green";
572
+ if (mode === "strategy") return "yellow";
573
+ if (mode === "validation") return "magenta";
567
574
  return "cyan";
568
575
  }
569
- function mergeStatusDisplay(status) {
570
- switch (status) {
571
- case "merged":
572
- return { icon: "\u2295", label: "merged", color: "green" };
573
- case "pending":
574
- return { icon: "\u25CC", label: "pending", color: "yellow" };
575
- case "no-changes":
576
- return { icon: "\u2205", label: "no changes", color: "gray" };
577
- case "conflict":
578
- return { icon: "\u26A0", label: "conflict", color: "red" };
579
- default:
580
- return null;
581
- }
582
- }
583
576
  function wrapText(text, width) {
584
577
  const cleaned = cleanMarkdown(text);
585
578
  if (width <= 0) return cleaned.split("\n");
@@ -674,6 +667,7 @@ function buildTree(sessions, selectedSession, expanded, cwd2, polledContextFiles
674
667
  cycleNumber: cycle.cycle,
675
668
  timestamp: cycle.timestamp,
676
669
  completedAt: cycle.completedAt,
670
+ activeMs: cycle.activeMs,
677
671
  agentCount: allCycleAgents.length,
678
672
  mode: cycle.mode
679
673
  });
@@ -695,8 +689,8 @@ function buildTree(sessions, selectedSession, expanded, cwd2, polledContextFiles
695
689
  status: agent.status,
696
690
  spawnedAt: agent.spawnedAt,
697
691
  completedAt: agent.completedAt,
698
- reportCount: agent.reports.length,
699
- mergeStatus: agent.mergeStatus
692
+ activeMs: agent.activeMs,
693
+ reportCount: agent.reports.length
700
694
  });
701
695
  if (!agentExpanded || !hasReports) continue;
702
696
  for (let ri = 0; ri < agent.reports.length; ri++) {
@@ -1410,6 +1404,30 @@ function handleNavigateKey(input, key, state2, actions) {
1410
1404
  })();
1411
1405
  return;
1412
1406
  }
1407
+ if (input === "o") {
1408
+ if (!cursorNode) {
1409
+ notify(state2, "No node selected");
1410
+ return;
1411
+ }
1412
+ let claudeSessionId;
1413
+ if (cursorNode.type === "agent" || cursorNode.type === "report") {
1414
+ const agent = actions.getAgentForNode(cursorNode);
1415
+ claudeSessionId = agent?.claudeSessionId ?? void 0;
1416
+ } else if (cursorNode.type === "cycle" && session) {
1417
+ const cycle = session.orchestratorCycles.find((c) => c.cycle === cursorNode.cycleNumber);
1418
+ claudeSessionId = cycle?.claudeSessionId;
1419
+ }
1420
+ if (!claudeSessionId) {
1421
+ notify(state2, "No Claude session ID available");
1422
+ return;
1423
+ }
1424
+ try {
1425
+ actions.openClaudeResumePopup(state2.cwd, claudeSessionId);
1426
+ } catch {
1427
+ notify(state2, "Failed to open Claude session");
1428
+ }
1429
+ return;
1430
+ }
1413
1431
  if (input === "g") {
1414
1432
  if (!state2.selectedSessionId) {
1415
1433
  notify(state2, "No session selected");
@@ -1551,6 +1569,29 @@ function handleNavigateKey(input, key, state2, actions) {
1551
1569
  }
1552
1570
  return;
1553
1571
  }
1572
+ if (input === "s") {
1573
+ if (!state2.strategyContent) {
1574
+ notify(state2, "No strategy for this session");
1575
+ return;
1576
+ }
1577
+ state2.showStrategy = !state2.showStrategy;
1578
+ requestRender();
1579
+ return;
1580
+ }
1581
+ if (input === "S") {
1582
+ if (!state2.selectedSessionId) {
1583
+ notify(state2, "No session selected");
1584
+ return;
1585
+ }
1586
+ const sp = strategyPath(state2.cwd, state2.selectedSessionId);
1587
+ const editor = actions.resolveEditor();
1588
+ try {
1589
+ actions.openEditorPopup(state2.cwd, editor, sp);
1590
+ } catch {
1591
+ notify(state2, `Failed to open strategy in ${editor}`);
1592
+ }
1593
+ return;
1594
+ }
1554
1595
  if (input === "t") {
1555
1596
  if (state2.showLogs) {
1556
1597
  if (state2.focusPane === "logs") state2.focusPane = "detail";
@@ -1831,6 +1872,14 @@ function openShellPopup(cwd2, command) {
1831
1872
  function openInFileManager(path) {
1832
1873
  execSync(`open ${shellQuote(path)}`, { stdio: "inherit", env: EXEC_ENV });
1833
1874
  }
1875
+ function openClaudeResumePopup(cwd2, claudeSessionId) {
1876
+ const pathEnv = augmentedPath();
1877
+ const cmd = `PATH=${shellQuote(pathEnv)} claude --resume ${shellQuote(claudeSessionId)}`;
1878
+ execSync(
1879
+ `tmux display-popup -E -w 90% -h 80% -d ${shellQuote(cwd2)} ${shellQuote(cmd)}`,
1880
+ { stdio: "inherit", env: EXEC_ENV }
1881
+ );
1882
+ }
1834
1883
  function openEditorPopup(cwd2, editor, filePath, size) {
1835
1884
  const { w = "90%", h = "90%" } = size ?? {};
1836
1885
  const editorBin = editor.split(/\s+/)[0].split("/").pop();
@@ -1902,7 +1951,7 @@ function renderNodeContent(node, maxWidth) {
1902
1951
  }
1903
1952
  case "cycle": {
1904
1953
  const isRunning = !node.completedAt;
1905
- const dur = node.completedAt ? formatDuration(node.timestamp, node.completedAt) : "running";
1954
+ const dur = isRunning ? "running" : formatDuration(node.activeMs);
1906
1955
  const agents = `${node.agentCount} agent${node.agentCount !== 1 ? "s" : ""}`;
1907
1956
  const modeShort = abbreviateMode(node.mode);
1908
1957
  const mode = modeShort ? ` \xB7 ${modeShort}` : "";
@@ -1917,34 +1966,22 @@ function renderNodeContent(node, maxWidth) {
1917
1966
  case "agent": {
1918
1967
  const icon = agentStatusIcon(node.status);
1919
1968
  const color = statusColor(node.status);
1920
- const dur = formatDuration(node.spawnedAt, node.completedAt);
1921
- const durClr = durationColor(node.spawnedAt, node.completedAt) || void 0;
1969
+ const dur = formatDuration(node.activeMs);
1970
+ const durClr = durationColor(node.activeMs) || void 0;
1922
1971
  const dim = node.status === "completed";
1923
1972
  const displayName = agentDisplayName({
1924
1973
  name: node.name,
1925
1974
  id: node.agentId,
1926
1975
  agentType: node.agentType
1927
1976
  });
1928
- let suffix;
1929
- let suffixColor;
1930
- if (node.mergeStatus) {
1931
- const ms = node.mergeStatus === "pending" ? { icon: "\u2387", color: "yellow" } : mergeStatusDisplay(node.mergeStatus);
1932
- if (ms) {
1933
- suffix = ms.icon;
1934
- suffixColor = ms.color;
1935
- }
1936
- }
1937
- const suffixLen = suffix ? 2 : 0;
1938
- const maxLabel = Math.max(8, maxWidth - dur.length - suffixLen - 4);
1977
+ const maxLabel = Math.max(8, maxWidth - dur.length - 4);
1939
1978
  return {
1940
1979
  icon,
1941
1980
  label: truncate(displayName, maxLabel),
1942
1981
  meta: dur,
1943
1982
  color,
1944
1983
  dim,
1945
- metaColor: durClr,
1946
- suffix,
1947
- suffixColor
1984
+ metaColor: durClr
1948
1985
  };
1949
1986
  }
1950
1987
  case "report": {
@@ -2148,14 +2185,13 @@ function buildPlanLines(content, maxLines, width) {
2148
2185
  }
2149
2186
  return lines;
2150
2187
  }
2151
- function buildSessionLines(session, planContent, goalContent, width, paneAlive) {
2188
+ function buildSessionLines(session, planContent, goalContent, width, paneAlive, strategyContent = "", showStrategy = false) {
2152
2189
  const lines = [];
2153
2190
  const contentWidth = width - 4;
2154
2191
  const agents = session.agents;
2155
2192
  const cycles = session.orchestratorCycles;
2156
2193
  const messages = session.messages;
2157
2194
  const isDead = session.status === "active" && !paneAlive;
2158
- const conflicts = agents.filter((a) => a.mergeStatus === "conflict");
2159
2195
  const goalText = goalContent ? cleanMarkdown(stripFrontmatter(goalContent).trim()) : session.task;
2160
2196
  goalText.split("\n").flatMap((l) => wrapText(l, contentWidth - 2)).forEach((line, i) => {
2161
2197
  lines.push(singleLine(`${i === 0 ? " " : " "}${line}`, { bold: true }));
@@ -2189,28 +2225,34 @@ function buildSessionLines(session, planContent, goalContent, width, paneAlive)
2189
2225
  seg(" tmux window closed \u2014 [w] reopen [R] resume", { color: "red" })
2190
2226
  ]);
2191
2227
  }
2192
- if (conflicts.length > 0) {
2193
- lines.push(
2194
- singleLine(
2195
- ` \u26A0 ${conflicts.length} merge conflict${conflicts.length > 1 ? "s" : ""}`,
2196
- { color: "red", bold: true }
2197
- )
2198
- );
2199
- lines.push(
2200
- singleLine(
2201
- " resolve in worktree, then [x] restart agent",
2202
- { color: "red", dim: true }
2203
- )
2204
- );
2205
- }
2206
2228
  lines.push(singleLine(" "));
2207
- lines.push([seg(" \u258E \u25C8 PLAN", { color: "yellow", bold: true })]);
2208
- const planLines = buildPlanLines(planContent, 99999, width);
2209
- if (planLines.length === 0) {
2210
- lines.push(singleLine(" orchestrator will create one", { dim: true, italic: true }));
2229
+ if (showStrategy && strategyContent) {
2230
+ const stratHint = strategyContent ? " [s] toggle plan" : "";
2231
+ lines.push([
2232
+ seg(" \u258E \u25C8 STRATEGY", { color: "yellow", bold: true }),
2233
+ seg(stratHint, { dim: true })
2234
+ ]);
2235
+ const stratLines = buildPlanLines(strategyContent, 99999, width);
2236
+ if (stratLines.length === 0) {
2237
+ lines.push(singleLine(" (empty)", { dim: true, italic: true }));
2238
+ } else {
2239
+ for (const pl of stratLines) {
2240
+ lines.push(singleLine(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));
2241
+ }
2242
+ }
2211
2243
  } else {
2212
- for (const pl of planLines) {
2213
- lines.push(singleLine(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));
2244
+ const toggleHint = strategyContent ? " [s] toggle strategy" : "";
2245
+ lines.push([
2246
+ seg(" \u258E \u25C8 PLAN", { color: "yellow", bold: true }),
2247
+ seg(toggleHint, { dim: true })
2248
+ ]);
2249
+ const planLines = buildPlanLines(planContent, 99999, width);
2250
+ if (planLines.length === 0) {
2251
+ lines.push(singleLine(" orchestrator will create one", { dim: true, italic: true }));
2252
+ } else {
2253
+ for (const pl of planLines) {
2254
+ lines.push(singleLine(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));
2255
+ }
2214
2256
  }
2215
2257
  }
2216
2258
  if (session.status === "completed" && session.completionReport) {
@@ -2258,7 +2300,7 @@ function buildSessionLines(session, planContent, goalContent, width, paneAlive)
2258
2300
  const dot = isRunning ? "\u25CF" : "\u25CB";
2259
2301
  const dotColor = isRunning ? "green" : isNewest ? "white" : "gray";
2260
2302
  const rowDim = !isRunning && !isNewest && !isSecond;
2261
- const duration = isRunning ? "running" : formatDuration(cycle.timestamp, cycle.completedAt);
2303
+ const duration = isRunning ? "running" : formatDuration(cycle.activeMs);
2262
2304
  const n = cycle.agentsSpawned.length;
2263
2305
  const startTime = formatTime(cycle.timestamp);
2264
2306
  const modeLabel = abbreviateMode(cycle.mode);
@@ -2314,7 +2356,7 @@ function buildCycleLines(cycle, agents, width) {
2314
2356
  const lines = [];
2315
2357
  const contentWidth = width - 4;
2316
2358
  const isRunning = !cycle.completedAt;
2317
- const dur = cycle.completedAt ? formatDuration(cycle.timestamp, cycle.completedAt) : "running";
2359
+ const dur = isRunning ? "running" : formatDuration(cycle.activeMs);
2318
2360
  const cycleAgents = agents.filter((a) => cycle.agentsSpawned.includes(a.id));
2319
2361
  lines.push(singleLine(` Cycle ${cycle.cycle}`, { bold: true }));
2320
2362
  lines.push([
@@ -2327,6 +2369,9 @@ function buildCycleLines(cycle, agents, width) {
2327
2369
  ` ${formatTime(cycle.timestamp)}${cycle.completedAt ? ` \u2192 ${formatTime(cycle.completedAt)}` : ""}`,
2328
2370
  { dim: true }
2329
2371
  ));
2372
+ if (cycle.claudeSessionId) {
2373
+ lines.push(singleLine(` Session: ${cycle.claudeSessionId}`, { dim: true }));
2374
+ }
2330
2375
  lines.push(singleLine(" "));
2331
2376
  lines.push([seg(" \u258E \u229E AGENTS", { color: "green", bold: true })]);
2332
2377
  if (cycleAgents.length === 0) {
@@ -2337,8 +2382,8 @@ function buildCycleLines(cycle, agents, width) {
2337
2382
  const instrPreview = agent.instruction.split("\n")[0];
2338
2383
  const latestReport = agent.reports.length > 0 ? agent.reports[agent.reports.length - 1] : null;
2339
2384
  const reportSummary = latestReport !== null && agent.status === "completed" ? extractFirstSentence(latestReport.summary, contentWidth - 14) : null;
2340
- const agentDur = formatDuration(agent.spawnedAt, agent.completedAt);
2341
- const durClrRaw = durationColor(agent.spawnedAt, agent.completedAt);
2385
+ const agentDur = formatDuration(agent.activeMs);
2386
+ const durClrRaw = durationColor(agent.activeMs);
2342
2387
  const durClr = durClrRaw !== "" ? durClrRaw : void 0;
2343
2388
  const typeClrRaw = agentTypeColor(agent.agentType);
2344
2389
  const typeClr = typeClrRaw !== void 0 ? typeClrRaw : void 0;
@@ -2377,34 +2422,23 @@ function buildCycleLines(cycle, agents, width) {
2377
2422
  function buildAgentLines(agent, reportBlocks, width) {
2378
2423
  const lines = [];
2379
2424
  const contentWidth = width - 4;
2380
- const dur = formatDuration(agent.spawnedAt, agent.completedAt);
2425
+ const dur = formatDuration(agent.activeMs);
2381
2426
  const icon = agentStatusIcon(agent.status);
2382
2427
  const color = statusColor(agent.status);
2383
2428
  const nameLabel = agentDisplayName(agent);
2384
- const maxMergeLines = 3;
2385
2429
  lines.push([
2386
2430
  seg(" "),
2387
2431
  seg(icon, { color }),
2388
2432
  seg(` ${agent.id} \xB7 ${nameLabel}`, { bold: true })
2389
2433
  ]);
2390
- const merge = agent.mergeStatus ? mergeStatusDisplay(agent.mergeStatus) : null;
2391
2434
  lines.push([
2392
2435
  seg(" "),
2393
2436
  seg(agent.status, { color }),
2394
- seg(` \xB7 ${dur} \xB7 ${agent.agentType}`, { dim: true }),
2395
- ...merge ? [seg(" \xB7 ", { dim: true }), seg(`${merge.icon} ${merge.label}`, { color: merge.color })] : agent.mergeStatus ? [seg(" \xB7 ", { dim: true }), seg(agent.mergeStatus, { dim: true })] : []
2437
+ seg(` \xB7 ${dur} \xB7 ${agent.agentType}`, { dim: true })
2396
2438
  ]);
2397
2439
  if (agent.killedReason) {
2398
2440
  lines.push(singleLine(` \u26A0 ${agent.killedReason}`, { color: "red" }));
2399
2441
  }
2400
- if (agent.mergeStatus === "conflict" && agent.mergeDetails) {
2401
- for (const ml of wrapText(agent.mergeDetails, contentWidth - 6).slice(0, maxMergeLines)) {
2402
- lines.push(singleLine(` \u26A0 ${ml}`, { color: "red" }));
2403
- }
2404
- }
2405
- if (agent.mergeStatus === "conflict") {
2406
- lines.push(singleLine(" resolve conflicts in worktree dir, then restart", { color: "red", dim: true }));
2407
- }
2408
2442
  lines.push(singleLine(" "));
2409
2443
  lines.push(singleLine(" \u258E \u25B7 INSTRUCTION", { color: "white", bold: true }));
2410
2444
  for (const wl of wrapText(agent.instruction, contentWidth - 6)) {
@@ -2445,21 +2479,18 @@ function buildAgentLines(agent, reportBlocks, width) {
2445
2479
  if (agent.completedAt) {
2446
2480
  lines.push(singleLine(` Completed: ${formatTime(agent.completedAt)}`, { dim: true }));
2447
2481
  }
2482
+ if (agent.claudeSessionId) {
2483
+ lines.push(singleLine(` Session: ${agent.claudeSessionId}`, { dim: true }));
2484
+ }
2448
2485
  if (agent.paneId) {
2449
2486
  lines.push(singleLine(` Pane: ${agent.paneId}`, { dim: true }));
2450
2487
  }
2451
- if (agent.worktreePath) {
2452
- lines.push(singleLine(` Worktree: ${agent.worktreePath}`, { dim: true }));
2453
- }
2454
- if (agent.branchName) {
2455
- lines.push(singleLine(` Branch: ${agent.branchName}`, { dim: true }));
2456
- }
2457
2488
  return lines;
2458
2489
  }
2459
2490
  function buildReportViewLines(agent, reportBlocks, width) {
2460
2491
  const lines = [];
2461
2492
  const contentWidth = width - 6;
2462
- const dur = formatDuration(agent.spawnedAt, agent.completedAt);
2493
+ const dur = formatDuration(agent.activeMs);
2463
2494
  const icon = agentStatusIcon(agent.status);
2464
2495
  const color = statusColor(agent.status);
2465
2496
  const totalReports = agent.reports.length;
@@ -2552,14 +2583,14 @@ function renderDetailContent(buf, rect, state2, detailCtx) {
2552
2583
  let borderColor = "gray";
2553
2584
  switch (cursorNode.type) {
2554
2585
  case "session": {
2555
- lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive);
2586
+ lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive, state2.strategyContent, state2.showStrategy);
2556
2587
  break;
2557
2588
  }
2558
2589
  case "cycle": {
2559
2590
  const cycleNode = cursorNode;
2560
2591
  const cycle = session.orchestratorCycles.find((c) => c.cycle === cycleNode.cycleNumber);
2561
2592
  if (!cycle) {
2562
- lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive);
2593
+ lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive, state2.strategyContent, state2.showStrategy);
2563
2594
  } else {
2564
2595
  lines = buildCycleLines(cycle, session.agents, rect.w);
2565
2596
  }
@@ -2569,7 +2600,7 @@ function renderDetailContent(buf, rect, state2, detailCtx) {
2569
2600
  const agentNode = cursorNode;
2570
2601
  const agent = agents.find((a) => a.id === agentNode.agentId);
2571
2602
  if (!agent) {
2572
- lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive);
2603
+ lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive, state2.strategyContent, state2.showStrategy);
2573
2604
  } else {
2574
2605
  lines = buildAgentLines(agent, detailReportBlocks, rect.w);
2575
2606
  }
@@ -2579,7 +2610,7 @@ function renderDetailContent(buf, rect, state2, detailCtx) {
2579
2610
  const reportNode = cursorNode;
2580
2611
  const agent = agents.find((a) => a.id === reportNode.agentId);
2581
2612
  if (!agent) {
2582
- lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive);
2613
+ lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive, state2.strategyContent, state2.showStrategy);
2583
2614
  break;
2584
2615
  }
2585
2616
  const reportIdx = reportNode.reportIndex;
@@ -2671,7 +2702,7 @@ function renderDetailContent(buf, rect, state2, detailCtx) {
2671
2702
  break;
2672
2703
  }
2673
2704
  default: {
2674
- lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive);
2705
+ lines = buildSessionLines(session, state2.planContent, state2.goalContent, rect.w, state2.paneAlive, state2.strategyContent, state2.showStrategy);
2675
2706
  break;
2676
2707
  }
2677
2708
  }
@@ -2744,7 +2775,7 @@ function renderStatusLine(buf, y, state2, cursorNodeType) {
2744
2775
  } else if (mode !== "navigate") {
2745
2776
  content = D("[enter] send [esc] cancel");
2746
2777
  } else if (focusPane === "logs" || focusPane === "detail") {
2747
- content = B("[jk/\u2191\u2193]") + D(" scroll ") + B("[h/\u2190/tab]") + D(" back ") + B("[t]") + D("oggle logs ") + SEP + B("[m]") + D("sg ") + B("[g]") + D("oal ") + B("[n]") + D("ew ") + B("[p]") + D("lan ") + B("[w]") + D("indow ") + B("[R]") + D("esume ") + B("[q]") + D("uit");
2778
+ content = B("[jk/\u2191\u2193]") + D(" scroll ") + B("[h/\u2190/tab]") + D(" back ") + B("[t]") + D("oggle logs ") + SEP + B("[m]") + D("sg ") + B("[g]") + D("oal ") + B("[n]") + D("ew ") + B("[p]") + D("lan ") + B("[s]") + D("trat ") + B("[w]") + D("indow ") + B("[R]") + D("esume ") + B("[q]") + D("uit");
2748
2779
  } else {
2749
2780
  let contextFilePart = "";
2750
2781
  if (cursorNodeType === "context-file") {
@@ -2821,8 +2852,10 @@ function renderHelpOverlay(buf, rows, cols) {
2821
2852
  helpRow(" R resume session", " C continue session", innerWidth),
2822
2853
  helpRow(" b rollback cycle", " x restart agent", innerWidth),
2823
2854
  helpRow(" r re-run agent", " g edit goal", innerWidth),
2824
- helpRow(" p open roadmap", " w go to window", innerWidth),
2825
- helpRow(" c claude companion", " q quit", innerWidth),
2855
+ helpRow(" p open roadmap", " s toggle strategy", innerWidth),
2856
+ helpRow(" S edit strategy", " w go to window", innerWidth),
2857
+ helpRow(" o resume claude session", " c claude companion", innerWidth),
2858
+ helpRow(" q quit", "", innerWidth),
2826
2859
  " ".padEnd(innerWidth),
2827
2860
  helpRow(" space \u2192 y copy submenu", " space \u2192 d delete session", innerWidth),
2828
2861
  helpRow(" space \u2192 j jump to pane", " space \u2192 k kill", innerWidth),
@@ -2868,6 +2901,7 @@ function startApp(state2, cleanup2) {
2868
2901
  try {
2869
2902
  let selectedSession = null;
2870
2903
  let planContent = "";
2904
+ let strategyContent = "";
2871
2905
  let goalContent = "";
2872
2906
  let logsContent = "";
2873
2907
  let logsCycles = [];
@@ -2911,6 +2945,13 @@ function startApp(state2, cleanup2) {
2911
2945
  }
2912
2946
  } catch {
2913
2947
  }
2948
+ try {
2949
+ const sp = strategyPath(state2.cwd, state2.selectedSessionId);
2950
+ if (existsSync2(sp)) {
2951
+ strategyContent = readFileSync2(sp, "utf-8");
2952
+ }
2953
+ } catch {
2954
+ }
2914
2955
  try {
2915
2956
  const ld = logsDir(state2.cwd, state2.selectedSessionId);
2916
2957
  if (existsSync2(ld)) {
@@ -2942,6 +2983,7 @@ function startApp(state2, cleanup2) {
2942
2983
  state2.sessions = sessions;
2943
2984
  state2.selectedSession = selectedSession;
2944
2985
  state2.planContent = planContent;
2986
+ state2.strategyContent = strategyContent;
2945
2987
  state2.goalContent = goalContent;
2946
2988
  state2.logsContent = logsContent;
2947
2989
  state2.logsCycles = logsCycles;
@@ -3088,6 +3130,7 @@ function startApp(state2, cleanup2) {
3088
3130
  openEditorPopup,
3089
3131
  editInPopup,
3090
3132
  openCompanionPane,
3133
+ openClaudeResumePopup,
3091
3134
  selectWindow,
3092
3135
  selectPane,
3093
3136
  switchToSession,