@wrongstack/tui 0.257.2 → 0.264.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.
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
1
- import { writeErr, resolveProjectDir, wstackGlobalRoot, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, truncate, buildChildEnv } from '@wrongstack/core';
1
+ import { writeErr, resolveProjectDir, wstackGlobalRoot, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
2
2
  export { buildGoalPreamble } from '@wrongstack/core';
3
3
  import { Box as Box$1, useInput, useStdin, useStdout, Text as Text$1, render, useApp, measureElement, Static } from 'ink';
4
4
  import { randomUUID } from 'crypto';
5
5
  import * as path4 from 'path';
6
6
  import React5, { forwardRef, useState, useEffect, useMemo, memo, useRef, useCallback, useReducer, useLayoutEffect } from 'react';
7
7
  import * as fs2 from 'fs/promises';
8
+ import { expectDefined, toErrorMessage } from '@wrongstack/core/utils';
8
9
  import { routeImagesForModel } from '@wrongstack/runtime/vision';
9
10
  import { getIndexState, onIndexStateChange, getProcessRegistry } from '@wrongstack/tools';
10
11
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
- import { readClipboardImage } from '@wrongstack/runtime/clipboard';
12
- import { expectDefined } from '@wrongstack/core/utils';
12
+ import { readClipboardText, readClipboardImage } from '@wrongstack/runtime/clipboard';
13
13
  import * as v8 from 'v8';
14
14
  import { spawn } from 'child_process';
15
15
 
@@ -126,9 +126,13 @@ function modeIcon(label) {
126
126
  const icon = MODE_ICONS[label] ?? "\u25AA";
127
127
  return `${icon} ${label}`;
128
128
  }
129
- function truncateLabel(label, maxWidth) {
130
- const stripped = label.replace(/^\/next\s+[\d\s]+\s*/, "");
131
- return truncate(stripped, maxWidth);
129
+ function formatSuggestionLabel(label, maxLen = 28) {
130
+ const stripped = label.replace(/^\/next\s+[\d\s]+\s*/, "").trim();
131
+ if (!stripped) return "";
132
+ if (stripped.length <= maxLen) return stripped;
133
+ const shortened = stripped.slice(0, maxLen);
134
+ const lastSpace = shortened.lastIndexOf(" ");
135
+ return lastSpace > 10 ? `${shortened.slice(0, lastSpace)}\u2026` : `${shortened}\u2026`;
132
136
  }
133
137
  var COMPACT_THRESHOLD = 50;
134
138
  var COMFORTABLE_THRESHOLD = 90;
@@ -156,6 +160,7 @@ function StatusBar({
156
160
  workingDir,
157
161
  processCount,
158
162
  context,
163
+ contextStrategy,
159
164
  hiddenItems,
160
165
  events,
161
166
  eternalStage,
@@ -215,6 +220,7 @@ function StatusBar({
215
220
  const hasDebugStream = !!debugStreamStats;
216
221
  const hasEnhanceCountdown = enhanceCountdown != null && enhanceCountdown > 0;
217
222
  const hasNextStepsAutoSubmit = nextStepsAutoSubmitCountdown != null && nextStepsAutoSubmitCountdown > 0;
223
+ const countdownColor = nextStepsAutoSubmitCountdown != null ? nextStepsAutoSubmitCountdown > 20 ? "green" : nextStepsAutoSubmitCountdown > 10 ? "yellow" : "red" : "green";
218
224
  const hasTaskActivity = tasks && (tasks.pending > 0 || tasks.inProgress > 0 || tasks.completed > 0 || tasks.blocked > 0 || tasks.failed > 0);
219
225
  const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || hasTaskActivity || fleetHasActivity || hasBrainActivity || hasDebugStream || hasEnhanceCountdown || hasNextStepsAutoSubmit;
220
226
  return /* @__PURE__ */ jsxs(
@@ -268,7 +274,12 @@ function StatusBar({
268
274
  "ctx ",
269
275
  renderMeter(clampedRatio, 8),
270
276
  " ",
271
- pctText
277
+ pctText,
278
+ contextStrategy ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
279
+ " [",
280
+ contextStrategy,
281
+ "]"
282
+ ] }) : null
272
283
  ] });
273
284
  })()
274
285
  ] }) : null,
@@ -574,7 +585,7 @@ function StatusBar({
574
585
  ] }) : null,
575
586
  hasEnhanceCountdown && enhanceCountdown != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
576
587
  todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity || hasDebugStream ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
577
- /* @__PURE__ */ jsxs(Text, { color: enhanceCountdown <= 5 ? "yellow" : "cyan", children: [
588
+ /* @__PURE__ */ jsxs(Text, { color: enhanceCountdown > 15 ? "green" : enhanceCountdown > 5 ? "yellow" : "red", children: [
578
589
  "\u23F3 auto-send in ",
579
590
  enhanceCountdown,
580
591
  "s"
@@ -582,12 +593,15 @@ function StatusBar({
582
593
  ] }) : null,
583
594
  hasNextStepsAutoSubmit && nextStepsAutoSubmitCountdown != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
584
595
  todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity || hasDebugStream || hasEnhanceCountdown ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
585
- /* @__PURE__ */ jsxs(Text, { color: nextStepsAutoSubmitCountdown <= 3 ? "yellow" : "cyan", children: [
596
+ /* @__PURE__ */ jsxs(Text, { color: countdownColor, bold: true, children: [
586
597
  "\u23F3 ",
587
- nextStepsAutoSubmitLabel ? truncateLabel(nextStepsAutoSubmitLabel, 30) : "next step",
588
- " in ",
589
598
  nextStepsAutoSubmitCountdown,
590
599
  "s"
600
+ ] }),
601
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
602
+ " ",
603
+ nextStepsAutoSubmitLabel ? formatSuggestionLabel(nextStepsAutoSubmitLabel) : "",
604
+ " \xB7 \u21E5 edit"
591
605
  ] })
592
606
  ] }) : null
593
607
  ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
@@ -1564,9 +1578,9 @@ function buttonLabels(suggestedPattern) {
1564
1578
  function stringifyInput(input) {
1565
1579
  if (!input || typeof input !== "object") return "";
1566
1580
  const obj = input;
1567
- return Object.entries(obj).filter(([k]) => k !== "content" && k !== "new_string").map(([k, v]) => `${k}: ${truncate2(JSON.stringify(v), 80)}`).join(" ");
1581
+ return Object.entries(obj).filter(([k]) => k !== "content" && k !== "new_string").map(([k, v]) => `${k}: ${truncate(JSON.stringify(v), 80)}`).join(" ");
1568
1582
  }
1569
- function truncate2(s2, max) {
1583
+ function truncate(s2, max) {
1570
1584
  return s2.length <= max ? s2 : `${s2.slice(0, max - 1)}\u2026`;
1571
1585
  }
1572
1586
  function hasDiff(input) {
@@ -3915,10 +3929,14 @@ function parseWithHeading(content, strict) {
3915
3929
  if (steps.length === 0) {
3916
3930
  return { steps: [], texts: [], stripped: content, autoTexts: [] };
3917
3931
  }
3932
+ const headingWasXmlTag = headingMatch[0].startsWith("<");
3933
+ if (strict && headingWasXmlTag && !afterHeading.includes("</next_steps>")) {
3934
+ return { steps: [], texts: [], stripped: content, autoTexts: [] };
3935
+ }
3918
3936
  const texts = steps.map((s2) => s2.text);
3919
3937
  const autoTexts = steps.filter((s2) => s2.auto).map((s2) => s2.text);
3920
3938
  const blockStart = headingMatch.index;
3921
- const blockEnd = headingEnd + findBlockEnd(afterHeading, steps.length);
3939
+ const blockEnd = headingMatch[0].length + findBlockEnd(afterHeading, steps.length);
3922
3940
  const stripped = (content.slice(0, blockStart) + content.slice(blockStart + blockEnd)).replace(/\n{3,}/g, "\n\n").trim();
3923
3941
  return { steps, texts, stripped, autoTexts };
3924
3942
  }
@@ -3927,27 +3945,32 @@ function buildPermissiveHeadingRe() {
3927
3945
  return new RegExp(variants, "i");
3928
3946
  }
3929
3947
  function findBlockEnd(afterHeading, stepCount) {
3948
+ const closeIdx = afterHeading.indexOf("</next_steps>");
3949
+ if (closeIdx !== -1) {
3950
+ let end = closeIdx + "</next_steps>".length;
3951
+ if (afterHeading[end] === "\n") end += 1;
3952
+ return end;
3953
+ }
3930
3954
  const lines = afterHeading.split("\n");
3931
3955
  let consumed = 0;
3932
3956
  let found = 0;
3933
3957
  for (const rawLine of lines) {
3934
3958
  const line = rawLine.trim();
3935
- if (line === "</next_steps>") {
3936
- consumed += rawLine.length + 1;
3937
- break;
3938
- }
3939
- if (!line) {
3940
- consumed += rawLine.length + 1;
3941
- continue;
3942
- }
3959
+ if (!line) break;
3943
3960
  const m = ITEM_RE.exec(line);
3944
3961
  if (!m) break;
3945
3962
  consumed += rawLine.length + 1;
3946
3963
  found++;
3947
- if (found >= stepCount) break;
3964
+ if (found >= stepCount) {
3965
+ consumed -= 1;
3966
+ break;
3967
+ }
3948
3968
  }
3949
3969
  return consumed;
3950
3970
  }
3971
+ function stripNextStepsBlock(text) {
3972
+ return text.replace(/<next_steps\b[^>]*>[\s\S]*?<\/next_steps>/gi, "").replace(/<next_steps\b[^>]*\/?>/gi, "").replace(/\n{3,}/g, "\n\n").trim();
3973
+ }
3951
3974
  function brainStatusStyle(status) {
3952
3975
  switch (status) {
3953
3976
  case "thinking":
@@ -3977,7 +4000,9 @@ function brainRiskColor(risk) {
3977
4000
  var Entry = React5.memo(function Entry2({
3978
4001
  entry,
3979
4002
  termWidth,
3980
- setSuggestions
4003
+ setSuggestions,
4004
+ autonomyMode,
4005
+ autoSubmitCountdown
3981
4006
  }) {
3982
4007
  const nextSteps = useMemo(() => {
3983
4008
  if (entry.kind !== "assistant") return { steps: [], stripped: "" };
@@ -3985,6 +4010,7 @@ var Entry = React5.memo(function Entry2({
3985
4010
  }, [entry.kind, entry.text]);
3986
4011
  useEffect(() => {
3987
4012
  if (!setSuggestions) return;
4013
+ if (entry.kind !== "assistant") return;
3988
4014
  const text = entry.text ?? "";
3989
4015
  const { texts } = parseNextSteps(text, true);
3990
4016
  if (texts.length > 0) setSuggestions(texts);
@@ -4055,10 +4081,11 @@ var Entry = React5.memo(function Entry2({
4055
4081
  /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "\u{1F4A1} NEXT STEPS " }),
4056
4082
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(use /next 1, /next 1 2 3 to select)" })
4057
4083
  ] }),
4058
- steps.map((s2) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", marginTop: 0, children: /* @__PURE__ */ jsxs(Text, { children: [
4084
+ steps.map((s2, i) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", marginTop: 0, children: /* @__PURE__ */ jsxs(Text, { children: [
4059
4085
  /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: ` ${s2.index}. ` }),
4060
4086
  /* @__PURE__ */ jsx(Text, { children: s2.text }),
4061
- s2.auto ? /* @__PURE__ */ jsx(Text, { color: "cyan", dimColor: true, children: " auto" }) : null
4087
+ s2.auto ? /* @__PURE__ */ jsx(Text, { color: "cyan", dimColor: true, children: " auto" }) : null,
4088
+ autonomyMode === "auto" && i === 0 ? autoSubmitCountdown != null && autoSubmitCountdown > 0 ? /* @__PURE__ */ jsx(Text, { color: autoSubmitCountdown > 20 ? "green" : autoSubmitCountdown > 10 ? "yellow" : "red", children: ` auto in ${autoSubmitCountdown}s` }) : /* @__PURE__ */ jsx(Text, { color: "cyan", children: " \u23E9" }) : null
4062
4089
  ] }) }, s2.index))
4063
4090
  ]
4064
4091
  }
@@ -4230,7 +4257,7 @@ var Entry = React5.memo(function Entry2({
4230
4257
  }
4231
4258
  }
4232
4259
  });
4233
- function History({ entries, generation, streamingText, toolStream, setSuggestions }) {
4260
+ function History({ entries, generation, streamingText, toolStream, setSuggestions, autonomyMode, autoSubmitCountdown }) {
4234
4261
  const { stdout } = useStdout();
4235
4262
  const [termSize, setTermSize] = useState({
4236
4263
  columns: stdout?.columns ?? 80,
@@ -4248,7 +4275,7 @@ function History({ entries, generation, streamingText, toolStream, setSuggestion
4248
4275
  const termWidth = termSize.columns;
4249
4276
  const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
4250
4277
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4251
- /* @__PURE__ */ jsx(Static, { items: entries, children: (entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth, setSuggestions }) }, entry.id) }, generation ?? 0),
4278
+ /* @__PURE__ */ jsx(Static, { items: entries, children: (entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth, setSuggestions, autonomyMode, autoSubmitCountdown }) }, entry.id) }, generation ?? 0),
4252
4279
  /* @__PURE__ */ jsx(Box, { flexGrow: 1, children: tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail, termWidth }) : null })
4253
4280
  ] });
4254
4281
  }
@@ -4298,7 +4325,9 @@ function ScrollableHistory({
4298
4325
  totalLines,
4299
4326
  onMeasure,
4300
4327
  maxWidth,
4301
- setSuggestions
4328
+ setSuggestions,
4329
+ autonomyMode,
4330
+ autoSubmitCountdown
4302
4331
  }) {
4303
4332
  const { stdout } = useStdout();
4304
4333
  const rawWidth = stdout?.columns ?? 80;
@@ -4337,7 +4366,7 @@ function ScrollableHistory({
4337
4366
  flexShrink: 0,
4338
4367
  children: [
4339
4368
  hiddenCount > 0 ? /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: ` \u2191 ${hiddenCount} earlier ${hiddenCount === 1 ? "entry" : "entries"} (scroll lives in this session; full log on disk)` }) }) : null,
4340
- shown.map((entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, flexShrink: 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth, setSuggestions }) }, entry.id)),
4369
+ shown.map((entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, flexShrink: 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth, setSuggestions, autonomyMode, autoSubmitCountdown }) }, entry.id)),
4341
4370
  tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail, termWidth }) : null,
4342
4371
  toolTail && toolStream ? /* @__PURE__ */ jsx(
4343
4372
  ToolStreamBox,
@@ -4917,12 +4946,8 @@ function PhaseMonitor({
4917
4946
  phases,
4918
4947
  runningPhaseIds,
4919
4948
  elapsedMs,
4920
- nowTick,
4921
- onClose
4949
+ nowTick
4922
4950
  }) {
4923
- useInput((_, key) => {
4924
- if (key.escape) onClose();
4925
- });
4926
4951
  const phaseList = Object.values(phases);
4927
4952
  const running = phaseList.filter(
4928
4953
  (p) => runningPhaseIds.includes(Object.keys(phases).find((k) => phases[k] === p) ?? "")
@@ -4954,7 +4979,7 @@ function PhaseMonitor({
4954
4979
  failed.length
4955
4980
  ] })
4956
4981
  ] }) : null,
4957
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 Ctrl+P / Esc to close" })
4982
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 Ctrl+P to close" })
4958
4983
  ] }),
4959
4984
  phaseList.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No phases active. Use /autophase start [title] to begin." }) : phaseList.map((phase, i) => {
4960
4985
  const s2 = fmtPhase(phase.status);
@@ -4983,7 +5008,7 @@ function PhaseMonitor({
4983
5008
  ] })
4984
5009
  ] }) }, phaseKey);
4985
5010
  }),
4986
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate phases \xB7 Esc close" }) })
5011
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate phases" }) })
4987
5012
  ] });
4988
5013
  }
4989
5014
  var fmtElapsed3 = (ms) => {
@@ -5164,7 +5189,7 @@ function QueuePanel({ items }) {
5164
5189
  "+",
5165
5190
  overflow
5166
5191
  ] }) : null,
5167
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F7 / Esc to close" })
5192
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F7 to close" })
5168
5193
  ] }) }),
5169
5194
  items.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No queued messages" }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
5170
5195
  visible.map((item, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexShrink: 0, children: [
@@ -5240,7 +5265,7 @@ function ProcessListMonitor() {
5240
5265
  breakerState,
5241
5266
  b.state !== "closed" ? ` fail=${b.consecutiveFailures}/5 slow=${b.slowCallsInWindow}/3` : ""
5242
5267
  ] }),
5243
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F8 / Esc close" })
5268
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F8 to close" })
5244
5269
  ] }),
5245
5270
  all.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No active processes. Bash/exec spawns appear here." }) : null,
5246
5271
  all.map((p, i) => {
@@ -5281,7 +5306,7 @@ function GoalPanel({ goal }) {
5281
5306
  ] }),
5282
5307
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " to create one." })
5283
5308
  ] }),
5284
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press F9 or Esc to close." }) })
5309
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press F9 to close." }) })
5285
5310
  ] });
5286
5311
  }
5287
5312
  const displayGoal = goal.refinedGoal || goal.goal;
@@ -5347,7 +5372,7 @@ function GoalPanel({ goal }) {
5347
5372
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Last task: " }),
5348
5373
  /* @__PURE__ */ jsx(Text, { children: goal.lastTask.length > 50 ? goal.lastTask.slice(0, 47) + "\u2026" : goal.lastTask })
5349
5374
  ] }),
5350
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press F9 or Esc to close." }) })
5375
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press F9 to close." }) })
5351
5376
  ] })
5352
5377
  ] });
5353
5378
  }
@@ -5372,6 +5397,115 @@ function renderProgressBar(progress, trend) {
5372
5397
  ] })
5373
5398
  ] });
5374
5399
  }
5400
+ var KIND_COLOR = {
5401
+ goal: "cyan",
5402
+ task: "yellow",
5403
+ knowledge: "green",
5404
+ consensus: "magenta",
5405
+ deadlock: "red"
5406
+ };
5407
+ function fmtElapsed4(at, nowTick) {
5408
+ const s2 = Math.floor((nowTick - at) / 1e3);
5409
+ if (s2 < 60) return `${s2}s ago`;
5410
+ const m = Math.floor(s2 / 60);
5411
+ if (m < 60) return `${m}m ago`;
5412
+ return `${Math.floor(m / 60)}h ago`;
5413
+ }
5414
+ function GoalRow({
5415
+ goal
5416
+ }) {
5417
+ const statusColor = {
5418
+ active: "green",
5419
+ paused: "yellow",
5420
+ completed: "gray",
5421
+ failed: "red"
5422
+ };
5423
+ const color = statusColor[goal.status] ?? "gray";
5424
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [
5425
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color, bold: true, children: [
5426
+ goal.status === "active" ? "\u25B6" : goal.status === "paused" ? "\u23F8" : goal.status === "completed" ? "\u2713" : "\u2717",
5427
+ " ",
5428
+ goal.title || "(unnamed goal)"
5429
+ ] }) }),
5430
+ goal.tasks.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingLeft: 2, children: goal.tasks.map((task) => {
5431
+ const taskColor = {
5432
+ pending: "gray",
5433
+ running: "yellow",
5434
+ done: "green",
5435
+ failed: "red"
5436
+ };
5437
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: taskColor[task.status] ?? "gray", children: [
5438
+ task.status === "pending" ? "\u25CB" : task.status === "running" ? "\u25B6" : task.status === "done" ? "\u2713" : "\u2717",
5439
+ " ",
5440
+ task.title,
5441
+ task.assignedTo ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5442
+ " \u2192 ",
5443
+ task.assignedTo
5444
+ ] }) : null
5445
+ ] }) }, task.id);
5446
+ }) }),
5447
+ goal.participants.length > 0 && /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5448
+ "participants: ",
5449
+ goal.participants.join(", ")
5450
+ ] }) })
5451
+ ] }, goal.id);
5452
+ }
5453
+ function CoordinatorPanel({
5454
+ coordinator,
5455
+ nowTick,
5456
+ onClose
5457
+ }) {
5458
+ const handleInput = useCallback(
5459
+ (input, _key) => {
5460
+ if (input === "q" || input === "Q" || input === "\x1B") {
5461
+ onClose();
5462
+ }
5463
+ },
5464
+ [onClose]
5465
+ );
5466
+ useInput(handleInput);
5467
+ const { goals, timeline, knowledgeCount, healthy } = coordinator;
5468
+ return /* @__PURE__ */ jsxs(
5469
+ Box,
5470
+ {
5471
+ flexDirection: "column",
5472
+ borderStyle: "round",
5473
+ borderColor: "cyan",
5474
+ paddingX: 1,
5475
+ height: Math.min(30, Math.max(10, goals.length * 4 + timeline.length + 8)),
5476
+ width: 80,
5477
+ children: [
5478
+ /* @__PURE__ */ jsxs(Box, { borderStyle: "bold", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
5479
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u{1F916} AutonomousCoordinator" }),
5480
+ /* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
5481
+ /* @__PURE__ */ jsx(Text, { dimColor: !healthy, color: healthy ? "green" : "red", children: healthy ? "\u25CF connected" : "\u25CB disconnected" }),
5482
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 q/esc to close" })
5483
+ ] }),
5484
+ goals.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
5485
+ /* @__PURE__ */ jsxs(Text, { bold: true, children: [
5486
+ "Goals (",
5487
+ goals.length,
5488
+ ")"
5489
+ ] }),
5490
+ goals.map((goal) => /* @__PURE__ */ jsx(GoalRow, { goal }, goal.id))
5491
+ ] }),
5492
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
5493
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Knowledge " }),
5494
+ /* @__PURE__ */ jsx(Text, { color: "green", children: knowledgeCount }),
5495
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " shared facts" })
5496
+ ] }),
5497
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
5498
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Activity" }),
5499
+ timeline.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " No activity yet" }) : timeline.slice(0, 10).map((entry, i) => /* @__PURE__ */ jsxs(Box, { alignItems: "flex-start", children: [
5500
+ /* @__PURE__ */ jsx(Text, { color: KIND_COLOR[entry.kind] ?? "gray", dimColor: i > 2, children: entry.icon }),
5501
+ /* @__PURE__ */ jsx(Box, { flexGrow: 1, marginLeft: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: i > 2, children: entry.text }) }),
5502
+ /* @__PURE__ */ jsx(Box, { marginLeft: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtElapsed4(entry.at, nowTick) }) })
5503
+ ] }, i))
5504
+ ] })
5505
+ ]
5506
+ }
5507
+ );
5508
+ }
5375
5509
  function ResumePicker({
5376
5510
  sessions,
5377
5511
  selected,
@@ -5479,7 +5613,7 @@ function SessionsPanel({
5479
5613
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, flexShrink: 0, children: [
5480
5614
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
5481
5615
  /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u29C9 Sessions" }),
5482
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 F10 or Esc to close" }),
5616
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 F10 to close" }),
5483
5617
  busy && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 loading\u2026" })
5484
5618
  ] }),
5485
5619
  resumeConfirm ? /* @__PURE__ */ jsxs(Box, { marginY: 1, borderStyle: "single", borderColor: "yellow", paddingX: 1, children: [
@@ -5592,7 +5726,7 @@ var MODE_DESC = {
5592
5726
  suggest: "Shows next-step suggestions after each turn",
5593
5727
  auto: "Self-driving \u2014 agent continues automatically"
5594
5728
  };
5595
- var SETTINGS_FIELD_COUNT = 26;
5729
+ var SETTINGS_FIELD_COUNT = 27;
5596
5730
  var CONFIG_SCOPES = ["global", "project"];
5597
5731
  function SettingsPicker({
5598
5732
  field,
@@ -5610,6 +5744,7 @@ function SettingsPicker({
5610
5744
  featureSkills,
5611
5745
  featureModelsRegistry,
5612
5746
  featureTokenSaving,
5747
+ allowOutsideProjectRoot,
5613
5748
  contextAutoCompact,
5614
5749
  contextStrategy,
5615
5750
  logLevel,
@@ -5698,6 +5833,11 @@ function SettingsPicker({
5698
5833
  value: boolVal(featureTokenSaving),
5699
5834
  detail: "Omit non-essential tools and trim system prompt to save tokens"
5700
5835
  },
5836
+ {
5837
+ label: "Allow outside project",
5838
+ value: boolVal(allowOutsideProjectRoot),
5839
+ detail: "Allow tools to access paths outside project root"
5840
+ },
5701
5841
  // ── Context ──
5702
5842
  { section: "Context" },
5703
5843
  {
@@ -5803,7 +5943,7 @@ function SettingsPicker({
5803
5943
  };
5804
5944
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
5805
5945
  /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Settings \u2501\u2501" }),
5806
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 field \xB7 \u2190/\u2192 change (instant save) \xB7 Esc / F5 close" }),
5946
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 field \xB7 \u2190/\u2192 change (instant apply) \xB7 F5 to close" }),
5807
5947
  hasAbove ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2191 ${windowStart} field${windowStart === 1 ? "" : "s"} above` }) : null,
5808
5948
  rows.map((row, i) => {
5809
5949
  const fieldAtRow = fieldRowIndex.indexOf(i);
@@ -6053,7 +6193,7 @@ function TodosMonitor({ todos }) {
6053
6193
  done
6054
6194
  ] })
6055
6195
  ] }) : null,
6056
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F6 / Esc to close" })
6196
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 F6 to close" })
6057
6197
  ] }),
6058
6198
  todos.length === 0 ? /* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No todos. The agent will create them as it plans work." }) }) : twoCols ? (
6059
6199
  /* Two-column layout: split the list in half, render side-by-side.
@@ -6068,7 +6208,7 @@ function TodosMonitor({ todos }) {
6068
6208
  )
6069
6209
  ] });
6070
6210
  }
6071
- var fmtElapsed4 = (ms) => {
6211
+ var fmtElapsed5 = (ms) => {
6072
6212
  const s2 = Math.floor(ms / 1e3);
6073
6213
  const m = Math.floor(s2 / 60);
6074
6214
  const h = Math.floor(m / 60);
@@ -6095,7 +6235,7 @@ function WorktreeMonitor({
6095
6235
  onClose
6096
6236
  }) {
6097
6237
  useInput((input, key) => {
6098
- if (key.escape || key.ctrl && input === "w") onClose();
6238
+ if (key.ctrl && input === "w") onClose();
6099
6239
  });
6100
6240
  const TERMINAL_TTL_MS = 5 * 6e4;
6101
6241
  const list = Object.values(worktrees);
@@ -6132,12 +6272,12 @@ function WorktreeMonitor({
6132
6272
  failed
6133
6273
  ] })
6134
6274
  ] }) : null,
6135
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 Ctrl+T / F4 / Esc to close" })
6275
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 Ctrl+T / F4 to close" })
6136
6276
  ] }),
6137
6277
  recent.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No worktrees. They appear when AutoPhase runs with isolation on." }) : recent.map((w) => {
6138
6278
  const s2 = fmt(w.status);
6139
6279
  const short = w.branch.replace(/^wstack\/ap\//, "");
6140
- const elapsed = w.allocatedAt ? fmtElapsed4(nowTick - w.allocatedAt) : "\u2014";
6280
+ const elapsed = w.allocatedAt ? fmtElapsed5(nowTick - w.allocatedAt) : "\u2014";
6141
6281
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
6142
6282
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
6143
6283
  /* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
@@ -6182,12 +6322,12 @@ function WorktreeMonitor({
6182
6322
  ] }, w.branch);
6183
6323
  }),
6184
6324
  /* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
6185
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Esc close \xB7 merge conflicts with /worktree merge <branch>" }),
6325
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Ctrl+T to close \xB7 merge conflicts with /worktree merge <branch>" }),
6186
6326
  staleTerminal > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${staleTerminal} terminal pruned` }) : null
6187
6327
  ] })
6188
6328
  ] });
6189
6329
  }
6190
- var fmtElapsed5 = (ms) => {
6330
+ var fmtElapsed6 = (ms) => {
6191
6331
  const s2 = Math.floor(ms / 1e3);
6192
6332
  const m = Math.floor(s2 / 60);
6193
6333
  const h = Math.floor(m / 60);
@@ -6253,7 +6393,7 @@ function WorktreePanel({
6253
6393
  list.map((w) => {
6254
6394
  const s2 = st(w.status);
6255
6395
  const conflict = w.status === "needs-review";
6256
- const elapsed = w.allocatedAt ? fmtElapsed5(nowTick - w.allocatedAt) : "";
6396
+ const elapsed = w.allocatedAt ? fmtElapsed6(nowTick - w.allocatedAt) : "";
6257
6397
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
6258
6398
  /* @__PURE__ */ jsx(Text, { color: s2.color, children: s2.icon }),
6259
6399
  /* @__PURE__ */ jsx(Text, { children: w.branch.replace(/^wstack\/ap\//, "").slice(0, 18).padEnd(18) }),
@@ -6456,10 +6596,10 @@ function useDirectorFleetBridge({
6456
6596
  let streamFlushTimer = null;
6457
6597
  const flushStreamBufs = () => {
6458
6598
  for (const [id, text] of streamBuf) {
6459
- const trimmed = text.trim();
6460
- if (!trimmed) continue;
6599
+ const cleaned = stripNextStepsBlock(text);
6600
+ if (!cleaned) continue;
6461
6601
  const label = labelFor(labelsRef, id);
6462
- enq({ type: "fleetMessage", id, text: trimmed });
6602
+ enq({ type: "fleetMessage", id, text: cleaned });
6463
6603
  if (streamFleetRef.current) {
6464
6604
  enq({
6465
6605
  type: "addEntry",
@@ -6468,7 +6608,7 @@ function useDirectorFleetBridge({
6468
6608
  agentLabel: label.label,
6469
6609
  agentColor: label.color,
6470
6610
  icon: "\u{1F4AC}",
6471
- text: trimmed
6611
+ text: cleaned
6472
6612
  }
6473
6613
  });
6474
6614
  }
@@ -6798,6 +6938,21 @@ function handleCollabDone(event, dispatch, stateRef) {
6798
6938
  verdict: payload.report.overallVerdict ?? "needs_revision"
6799
6939
  });
6800
6940
  }
6941
+ function useAutonomousCoordinator(subscribeCoordinatorEvents, dispatch) {
6942
+ const dispatchRef = useRef(dispatch);
6943
+ dispatchRef.current = dispatch;
6944
+ const handler = useCallback((event) => {
6945
+ dispatchRef.current({
6946
+ type: "coordinatorEvent",
6947
+ event
6948
+ });
6949
+ }, []);
6950
+ useEffect(() => {
6951
+ if (!subscribeCoordinatorEvents) return;
6952
+ const unsubscribe = subscribeCoordinatorEvents(handler);
6953
+ return unsubscribe;
6954
+ }, [subscribeCoordinatorEvents, handler]);
6955
+ }
6801
6956
  function useStatuslineState(opts) {
6802
6957
  const [liveModel, setLiveModel] = useState(opts.model);
6803
6958
  const [liveProvider, setLiveProvider] = useState(opts.provider ?? "agent");
@@ -7549,11 +7704,17 @@ function reducer(state, action) {
7549
7704
  const banner = state.entries.find((e) => e.kind === "banner");
7550
7705
  return {
7551
7706
  ...state,
7552
- entries: banner ? [banner] : state.entries,
7707
+ entries: banner ? [banner] : [],
7553
7708
  queue: [],
7554
7709
  nextQueueId: 1,
7555
7710
  scrollOffset: 0,
7556
7711
  pendingNewLines: 0,
7712
+ // Bump the generation so <Static> remounts — without this, Ink's
7713
+ // already-written index exceeds the new (shorter) array and the
7714
+ // committed entries stay on screen even though `state.entries` no
7715
+ // longer references them. /clear would otherwise appear to do
7716
+ // nothing to the visible chat history.
7717
+ historyGen: state.historyGen + 1,
7557
7718
  // Reset fleet state on /clear so old subagent entries don't
7558
7719
  // cause the LiveActivityStrip to render stale spacers, and
7559
7720
  // the fleet cost/tokens chips show zero.
@@ -7895,6 +8056,7 @@ function reducer(state, action) {
7895
8056
  featureSkills: action.featureSkills,
7896
8057
  featureModelsRegistry: action.featureModelsRegistry,
7897
8058
  featureTokenSaving: action.featureTokenSaving,
8059
+ allowOutsideProjectRoot: action.allowOutsideProjectRoot,
7898
8060
  contextAutoCompact: action.contextAutoCompact,
7899
8061
  contextStrategy: action.contextStrategy,
7900
8062
  logLevel: action.logLevel,
@@ -7929,6 +8091,7 @@ function reducer(state, action) {
7929
8091
  case "settingsValueChange": {
7930
8092
  const sp = state.settingsPicker;
7931
8093
  const f = sp.field;
8094
+ const bootHint = "\u21BB Takes effect next session";
7932
8095
  if (f === 0) {
7933
8096
  const i = SETTINGS_MODES.indexOf(sp.mode);
7934
8097
  const base = i < 0 ? 0 : i;
@@ -7947,59 +8110,60 @@ function reducer(state, action) {
7947
8110
  if (f === 5) return { ...state, settingsPicker: { ...sp, chime: !sp.chime, hint: void 0 } };
7948
8111
  if (f === 6) return { ...state, settingsPicker: { ...sp, confirmExit: !sp.confirmExit, hint: void 0 } };
7949
8112
  if (f === 7) return { ...state, settingsPicker: { ...sp, nextPrediction: !sp.nextPrediction, hint: void 0 } };
7950
- if (f === 8) return { ...state, settingsPicker: { ...sp, featureMcp: !sp.featureMcp, hint: void 0 } };
7951
- if (f === 9) return { ...state, settingsPicker: { ...sp, featurePlugins: !sp.featurePlugins, hint: void 0 } };
7952
- if (f === 10) return { ...state, settingsPicker: { ...sp, featureMemory: !sp.featureMemory, hint: void 0 } };
7953
- if (f === 11) return { ...state, settingsPicker: { ...sp, featureSkills: !sp.featureSkills, hint: void 0 } };
7954
- if (f === 12) return { ...state, settingsPicker: { ...sp, featureModelsRegistry: !sp.featureModelsRegistry, hint: void 0 } };
7955
- if (f === 13) return { ...state, settingsPicker: { ...sp, featureTokenSaving: !sp.featureTokenSaving, hint: void 0 } };
7956
- if (f === 14) return { ...state, settingsPicker: { ...sp, contextAutoCompact: !sp.contextAutoCompact, hint: void 0 } };
7957
- if (f === 15) {
8113
+ if (f === 8) return { ...state, settingsPicker: { ...sp, featureMcp: !sp.featureMcp, hint: bootHint } };
8114
+ if (f === 9) return { ...state, settingsPicker: { ...sp, featurePlugins: !sp.featurePlugins, hint: bootHint } };
8115
+ if (f === 10) return { ...state, settingsPicker: { ...sp, featureMemory: !sp.featureMemory, hint: bootHint } };
8116
+ if (f === 11) return { ...state, settingsPicker: { ...sp, featureSkills: !sp.featureSkills, hint: bootHint } };
8117
+ if (f === 12) return { ...state, settingsPicker: { ...sp, featureModelsRegistry: !sp.featureModelsRegistry, hint: bootHint } };
8118
+ if (f === 13) return { ...state, settingsPicker: { ...sp, featureTokenSaving: !sp.featureTokenSaving, hint: bootHint } };
8119
+ if (f === 14) return { ...state, settingsPicker: { ...sp, allowOutsideProjectRoot: !sp.allowOutsideProjectRoot, hint: void 0 } };
8120
+ if (f === 15) return { ...state, settingsPicker: { ...sp, contextAutoCompact: !sp.contextAutoCompact, hint: void 0 } };
8121
+ if (f === 16) {
7958
8122
  const i = COMPACTOR_STRATEGIES.indexOf(sp.contextStrategy);
7959
8123
  const base = i < 0 ? 0 : i;
7960
8124
  const next = (base + action.delta + COMPACTOR_STRATEGIES.length) % COMPACTOR_STRATEGIES.length;
7961
- return { ...state, settingsPicker: { ...sp, contextStrategy: expectDefined$1(COMPACTOR_STRATEGIES[next]), hint: void 0 } };
8125
+ return { ...state, settingsPicker: { ...sp, contextStrategy: expectDefined$1(COMPACTOR_STRATEGIES[next]), hint: bootHint } };
7962
8126
  }
7963
- if (f === 16) {
8127
+ if (f === 17) {
7964
8128
  const i = LOG_LEVELS.indexOf(sp.logLevel);
7965
8129
  const base = i < 0 ? 0 : i;
7966
8130
  const next = (base + action.delta + LOG_LEVELS.length) % LOG_LEVELS.length;
7967
8131
  return { ...state, settingsPicker: { ...sp, logLevel: expectDefined$1(LOG_LEVELS[next]), hint: void 0 } };
7968
8132
  }
7969
- if (f === 17) {
8133
+ if (f === 18) {
7970
8134
  const i = AUDIT_LEVELS.indexOf(sp.auditLevel);
7971
8135
  const base = i < 0 ? 0 : i;
7972
8136
  const next = (base + action.delta + AUDIT_LEVELS.length) % AUDIT_LEVELS.length;
7973
8137
  return { ...state, settingsPicker: { ...sp, auditLevel: expectDefined$1(AUDIT_LEVELS[next]), hint: void 0 } };
7974
8138
  }
7975
- if (f === 18) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: void 0 } };
7976
- if (f === 19) {
8139
+ if (f === 19) return { ...state, settingsPicker: { ...sp, indexOnStart: !sp.indexOnStart, hint: bootHint } };
8140
+ if (f === 20) {
7977
8141
  const j = MAX_ITERATIONS_PRESETS.indexOf(sp.maxIterations);
7978
8142
  const base = j < 0 ? 0 : j;
7979
8143
  const next = (base + action.delta + MAX_ITERATIONS_PRESETS.length) % MAX_ITERATIONS_PRESETS.length;
7980
8144
  return { ...state, settingsPicker: { ...sp, maxIterations: expectDefined$1(MAX_ITERATIONS_PRESETS[next]), hint: void 0 } };
7981
8145
  }
7982
- if (f === 20) {
8146
+ if (f === 21) {
7983
8147
  const aj = AUTO_PROCEED_MAX_PRESETS.indexOf(sp.autoProceedMaxIterations);
7984
8148
  const abase = aj < 0 ? 0 : aj;
7985
8149
  const anext = (abase + action.delta + AUTO_PROCEED_MAX_PRESETS.length) % AUTO_PROCEED_MAX_PRESETS.length;
7986
8150
  return { ...state, settingsPicker: { ...sp, autoProceedMaxIterations: expectDefined$1(AUTO_PROCEED_MAX_PRESETS[anext]), hint: void 0 } };
7987
8151
  }
7988
- if (f === 21) {
8152
+ if (f === 22) {
7989
8153
  const ej = ENHANCE_DELAY_PRESETS.indexOf(sp.enhanceDelayMs);
7990
8154
  const ebase = ej < 0 ? 0 : ej;
7991
8155
  const enext = (ebase + action.delta + ENHANCE_DELAY_PRESETS.length) % ENHANCE_DELAY_PRESETS.length;
7992
8156
  return { ...state, settingsPicker: { ...sp, enhanceDelayMs: expectDefined$1(ENHANCE_DELAY_PRESETS[enext]), hint: void 0 } };
7993
8157
  }
7994
- if (f === 22) return { ...state, settingsPicker: { ...sp, enhanceEnabled: !sp.enhanceEnabled, hint: void 0 } };
7995
- if (f === 23) {
8158
+ if (f === 23) return { ...state, settingsPicker: { ...sp, enhanceEnabled: !sp.enhanceEnabled, hint: void 0 } };
8159
+ if (f === 24) {
7996
8160
  const i = ENHANCE_LANGUAGES.indexOf(sp.enhanceLanguage);
7997
8161
  const base = i < 0 ? 0 : i;
7998
8162
  const next = (base + action.delta + ENHANCE_LANGUAGES.length) % ENHANCE_LANGUAGES.length;
7999
8163
  return { ...state, settingsPicker: { ...sp, enhanceLanguage: expectDefined$1(ENHANCE_LANGUAGES[next]), hint: void 0 } };
8000
8164
  }
8001
- if (f === 24) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
8002
- if (f === 25) {
8165
+ if (f === 25) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
8166
+ if (f === 26) {
8003
8167
  const i = CONFIG_SCOPES.indexOf(sp.configScope);
8004
8168
  const base = i < 0 ? 0 : i;
8005
8169
  const next = (base + action.delta + CONFIG_SCOPES.length) % CONFIG_SCOPES.length;
@@ -8730,9 +8894,10 @@ function reducer(state, action) {
8730
8894
  return { ...state, sessionsPanelOpen: !state.sessionsPanelOpen };
8731
8895
  }
8732
8896
  case "sessionsPanelSet": {
8897
+ const sessions = Array.isArray(action.sessions) ? action.sessions : [];
8733
8898
  return {
8734
8899
  ...state,
8735
- sessionsPanel: { sessions: action.sessions, busy: false, selected: action.sessions.length > 0 ? 0 : -1 }
8900
+ sessionsPanel: { sessions, busy: false, selected: sessions.length > 0 ? 0 : -1 }
8736
8901
  };
8737
8902
  }
8738
8903
  case "sessionsPanelMove": {
@@ -8767,6 +8932,81 @@ function reducer(state, action) {
8767
8932
  if (state.countdown === null) return state;
8768
8933
  return { ...state, countdown: null };
8769
8934
  }
8935
+ // --- AutonomousCoordinator ---
8936
+ case "coordinatorEvent": {
8937
+ const { event } = action;
8938
+ const now = Date.now();
8939
+ let kind;
8940
+ let icon;
8941
+ switch (event.type) {
8942
+ case "goal:added":
8943
+ kind = "goal";
8944
+ icon = "\u{1F3AF}";
8945
+ break;
8946
+ case "goal:completed":
8947
+ kind = "goal";
8948
+ icon = "\u2705";
8949
+ break;
8950
+ case "goal:failed":
8951
+ kind = "goal";
8952
+ icon = "\u274C";
8953
+ break;
8954
+ case "task:ready":
8955
+ kind = "task";
8956
+ icon = "\u26A1";
8957
+ break;
8958
+ case "task:completed":
8959
+ kind = "task";
8960
+ icon = "\u2713";
8961
+ break;
8962
+ case "knowledge:added":
8963
+ kind = "knowledge";
8964
+ icon = "\u{1F4A1}";
8965
+ break;
8966
+ case "consensus:reached":
8967
+ kind = "consensus";
8968
+ icon = "\u{1F91D}";
8969
+ break;
8970
+ case "deadlock:detected":
8971
+ kind = "deadlock";
8972
+ icon = "\u26A0\uFE0F";
8973
+ break;
8974
+ default:
8975
+ kind = "goal";
8976
+ icon = "\u2022";
8977
+ break;
8978
+ }
8979
+ const timelineEntry = {
8980
+ at: now,
8981
+ kind,
8982
+ icon,
8983
+ text: event.text ?? event.type
8984
+ };
8985
+ return {
8986
+ ...state,
8987
+ coordinator: {
8988
+ ...state.coordinator,
8989
+ healthy: true,
8990
+ knowledgeCount: event.type === "knowledge:added" ? state.coordinator.knowledgeCount + 1 : state.coordinator.knowledgeCount,
8991
+ timeline: [timelineEntry, ...state.coordinator.timeline].slice(0, 50)
8992
+ }
8993
+ };
8994
+ }
8995
+ case "toggleCoordinatorMonitor": {
8996
+ const opening = !state.coordinator.monitorOpen;
8997
+ return opening ? {
8998
+ ...state,
8999
+ coordinator: { ...state.coordinator, monitorOpen: true },
9000
+ // Close other monitors when opening coordinator
9001
+ monitorOpen: false,
9002
+ agentsMonitorOpen: false,
9003
+ helpOpen: false,
9004
+ todosMonitorOpen: false,
9005
+ queuePanelOpen: false,
9006
+ processListOpen: false,
9007
+ goalPanelOpen: false
9008
+ } : { ...state, coordinator: { ...state.coordinator, monitorOpen: false } };
9009
+ }
8770
9010
  }
8771
9011
  }
8772
9012
  var INPUT_PROMPT = "\u203A ";
@@ -8821,6 +9061,7 @@ function App({
8821
9061
  yolo = false,
8822
9062
  chime = false,
8823
9063
  confirmExit = true,
9064
+ titleController,
8824
9065
  mouse = false,
8825
9066
  enhanceEnabled = true,
8826
9067
  enhanceController,
@@ -8876,7 +9117,8 @@ function App({
8876
9117
  requestExit,
8877
9118
  getLiveSessions,
8878
9119
  onSwitchToSession,
8879
- initialAgentsMonitorOpen
9120
+ initialAgentsMonitorOpen,
9121
+ subscribeCoordinatorEvents
8880
9122
  }) {
8881
9123
  const { exit } = useApp();
8882
9124
  const { stdout } = useStdout();
@@ -9009,7 +9251,7 @@ function App({
9009
9251
  },
9010
9252
  autonomyPicker: { open: false, options: [], selected: 0 },
9011
9253
  resumePicker: { open: false, sessions: [], selected: 0, busy: false, hint: void 0, error: void 0 },
9012
- settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0, titleAnimation: true, yolo: false, streamFleet: true, chime: false, confirmExit: true, nextPrediction: false, featureMcp: true, featurePlugins: true, featureMemory: true, featureSkills: true, featureModelsRegistry: true, featureTokenSaving: false, contextAutoCompact: true, contextStrategy: "hybrid", logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, autoProceedMaxIterations: 50, enhanceDelayMs: 6e4, enhanceEnabled: true, enhanceLanguage: "original", debugStream: false, configScope: "global" },
9254
+ settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0, titleAnimation: true, yolo: false, streamFleet: true, chime: false, confirmExit: true, nextPrediction: false, featureMcp: true, featurePlugins: true, featureMemory: true, featureSkills: true, featureModelsRegistry: true, featureTokenSaving: false, allowOutsideProjectRoot: true, contextAutoCompact: true, contextStrategy: "hybrid", logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, autoProceedMaxIterations: 50, enhanceDelayMs: 6e4, enhanceEnabled: true, enhanceLanguage: "original", debugStream: false, configScope: "global" },
9013
9255
  projectPicker: { open: false, allItems: [], items: [], selected: 0, filter: "", hint: void 0 },
9014
9256
  confirmQueue: [],
9015
9257
  enhance: null,
@@ -9049,6 +9291,13 @@ function App({
9049
9291
  autoPhase: null,
9050
9292
  worktrees: {},
9051
9293
  worktreeMonitorOpen: false,
9294
+ coordinator: {
9295
+ goals: [],
9296
+ timeline: [],
9297
+ knowledgeCount: 0,
9298
+ monitorOpen: false,
9299
+ healthy: false
9300
+ },
9052
9301
  scrollOffset: 0,
9053
9302
  totalLines: 0,
9054
9303
  viewportRows: 0,
@@ -9056,6 +9305,7 @@ function App({
9056
9305
  debugStreamStats: null,
9057
9306
  countdown: null
9058
9307
  });
9308
+ useAutonomousCoordinator(subscribeCoordinatorEvents, dispatch);
9059
9309
  const builderRef = useRef(null);
9060
9310
  if (builderRef.current === null) {
9061
9311
  builderRef.current = new InputBuilder({ store: attachments });
@@ -9085,10 +9335,16 @@ function App({
9085
9335
  setWorkingDirChip(rel === "." ? void 0 : rel);
9086
9336
  });
9087
9337
  }, [agent.ctx, projectRoot]);
9338
+ const liveSettings = getSettings?.();
9088
9339
  const chimeRef = useRef(chime);
9089
- chimeRef.current = chime;
9340
+ chimeRef.current = liveSettings?.chime ?? chime;
9090
9341
  const confirmExitRef = useRef(confirmExit);
9091
- confirmExitRef.current = confirmExit;
9342
+ confirmExitRef.current = liveSettings?.confirmExit ?? confirmExit;
9343
+ const liveTitleAnimation = liveSettings?.titleAnimation;
9344
+ useEffect(() => {
9345
+ if (!titleController) return;
9346
+ titleController.setEnabled(liveTitleAnimation !== false);
9347
+ }, [titleController, liveTitleAnimation]);
9092
9348
  const streamingTextRef = useRef("");
9093
9349
  const pendingDeltaRef = useRef("");
9094
9350
  const flushTimerRef = useRef(null);
@@ -9556,7 +9812,7 @@ function App({
9556
9812
  }
9557
9813
  }, []);
9558
9814
  React5.useLayoutEffect(() => {
9559
- const anyOpenNow = state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.resumePicker.open || state.settingsPicker.open || state.enhanceBusy || state.enhance != null || state.escConfirm != null || state.confirmQueue.length > 0;
9815
+ const anyOpenNow = state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.resumePicker.open || state.settingsPicker.open || state.enhanceBusy || state.enhance != null || state.coordinator.monitorOpen || state.escConfirm != null || state.confirmQueue.length > 0;
9560
9816
  const overlayClosed = prevAnyOverlayOpen.current && !anyOpenNow;
9561
9817
  const newEntryCommitted = state.entries.length > prevEntriesCount.current;
9562
9818
  const curToolStreamLen = state.toolStream?.text.length ?? 0;
@@ -9575,6 +9831,7 @@ function App({
9575
9831
  state.settingsPicker.open,
9576
9832
  state.enhanceBusy,
9577
9833
  state.enhance,
9834
+ state.coordinator.monitorOpen,
9578
9835
  state.escConfirm,
9579
9836
  state.confirmQueue.length,
9580
9837
  state.entries.length,
@@ -9599,7 +9856,8 @@ function App({
9599
9856
  queue: stateRef.current.queuePanelOpen,
9600
9857
  processList: stateRef.current.processListOpen,
9601
9858
  goalPanel: stateRef.current.goalPanelOpen,
9602
- sessionsPanel: stateRef.current.sessionsPanelOpen
9859
+ sessionsPanel: stateRef.current.sessionsPanelOpen,
9860
+ coordinator: stateRef.current.coordinator.monitorOpen
9603
9861
  };
9604
9862
  if (stateRef.current.settingsPicker.open) dispatch({ type: "settingsClose" });
9605
9863
  if (stateRef.current.projectPicker.open) dispatch({ type: "projectPickerClose" });
@@ -9642,6 +9900,7 @@ function App({
9642
9900
  featureSkills: sp.featureSkills,
9643
9901
  featureModelsRegistry: sp.featureModelsRegistry,
9644
9902
  featureTokenSaving: sp.featureTokenSaving,
9903
+ allowOutsideProjectRoot: sp.allowOutsideProjectRoot,
9645
9904
  contextAutoCompact: sp.contextAutoCompact,
9646
9905
  contextStrategy: sp.contextStrategy,
9647
9906
  logLevel: sp.logLevel,
@@ -9669,6 +9928,7 @@ function App({
9669
9928
  if (prev.processList) dispatch({ type: "toggleProcessList" });
9670
9929
  if (prev.goalPanel) dispatch({ type: "toggleGoalPanel" });
9671
9930
  if (prev.sessionsPanel) dispatch({ type: "toggleSessionsPanel" });
9931
+ if (prev.coordinator) dispatch({ type: "toggleCoordinatorMonitor" });
9672
9932
  preResizePanelsRef.current = null;
9673
9933
  resizeRestoreTimerRef.current = null;
9674
9934
  }, 300);
@@ -9762,7 +10022,28 @@ function App({
9762
10022
  type: "addEntry",
9763
10023
  entry: {
9764
10024
  kind: "error",
9765
- text: `Clipboard image error: ${err instanceof Error ? err.message : String(err)}`
10025
+ text: `Clipboard image error: ${toErrorMessage(err)}`
10026
+ }
10027
+ });
10028
+ }
10029
+ };
10030
+ const pasteClipboardText = async () => {
10031
+ try {
10032
+ const text = await readClipboardText();
10033
+ if (!text) {
10034
+ dispatch({
10035
+ type: "addEntry",
10036
+ entry: { kind: "info", text: "No text on the clipboard." }
10037
+ });
10038
+ return;
10039
+ }
10040
+ await commitPaste(text);
10041
+ } catch (err) {
10042
+ dispatch({
10043
+ type: "addEntry",
10044
+ entry: {
10045
+ kind: "error",
10046
+ text: `Clipboard error: ${toErrorMessage(err)}`
9766
10047
  }
9767
10048
  });
9768
10049
  }
@@ -9799,7 +10080,7 @@ function App({
9799
10080
  type: "addEntry",
9800
10081
  entry: {
9801
10082
  kind: "error",
9802
- text: `Attach failed: ${err instanceof Error ? err.message : String(err)}`
10083
+ text: `Attach failed: ${toErrorMessage(err)}`
9803
10084
  }
9804
10085
  });
9805
10086
  dispatch({ type: "pickerClose" });
@@ -9985,7 +10266,10 @@ function App({
9985
10266
  dispatch({ type: "projectPickerOpen", items });
9986
10267
  }, [getProjectPickerItems]);
9987
10268
  const loadLiveSessions = React5.useCallback(async () => {
9988
- if (!getLiveSessions) return;
10269
+ if (!getLiveSessions) {
10270
+ dispatch({ type: "sessionsPanelSet", sessions: [] });
10271
+ return;
10272
+ }
9989
10273
  dispatch({ type: "sessionsPanelBusy", on: true });
9990
10274
  try {
9991
10275
  const sessions = await getLiveSessions();
@@ -10020,6 +10304,7 @@ function App({
10020
10304
  featureSkills: s2.featureSkills ?? true,
10021
10305
  featureModelsRegistry: s2.featureModelsRegistry ?? true,
10022
10306
  featureTokenSaving: s2.featureTokenSaving ?? false,
10307
+ allowOutsideProjectRoot: s2.allowOutsideProjectRoot ?? true,
10023
10308
  contextAutoCompact: s2.contextAutoCompact ?? true,
10024
10309
  contextStrategy: s2.contextStrategy ?? "hybrid",
10025
10310
  logLevel: s2.logLevel ?? "info",
@@ -10100,7 +10385,6 @@ function App({
10100
10385
  nextStepsAutoSubmitSuggestionRef.current = null;
10101
10386
  if (suggestion) {
10102
10387
  autoSubmitStreakRef.current += 1;
10103
- setDraft(suggestion, suggestion.length);
10104
10388
  void (async () => {
10105
10389
  const trimmed = suggestion.trim();
10106
10390
  if (!trimmed) {
@@ -10156,6 +10440,7 @@ function App({
10156
10440
  featureSkills: sp.featureSkills,
10157
10441
  featureModelsRegistry: sp.featureModelsRegistry,
10158
10442
  featureTokenSaving: sp.featureTokenSaving,
10443
+ allowOutsideProjectRoot: sp.allowOutsideProjectRoot,
10159
10444
  contextAutoCompact: sp.contextAutoCompact,
10160
10445
  contextStrategy: sp.contextStrategy,
10161
10446
  logLevel: sp.logLevel,
@@ -10186,6 +10471,8 @@ function App({
10186
10471
  state.settingsPicker.featureMemory,
10187
10472
  state.settingsPicker.featureSkills,
10188
10473
  state.settingsPicker.featureModelsRegistry,
10474
+ state.settingsPicker.featureTokenSaving,
10475
+ state.settingsPicker.allowOutsideProjectRoot,
10189
10476
  state.settingsPicker.contextAutoCompact,
10190
10477
  state.settingsPicker.contextStrategy,
10191
10478
  state.settingsPicker.logLevel,
@@ -10194,6 +10481,9 @@ function App({
10194
10481
  state.settingsPicker.maxIterations,
10195
10482
  state.settingsPicker.autoProceedMaxIterations,
10196
10483
  state.settingsPicker.enhanceDelayMs,
10484
+ state.settingsPicker.enhanceEnabled,
10485
+ state.settingsPicker.enhanceLanguage,
10486
+ state.settingsPicker.debugStream,
10197
10487
  saveSettings
10198
10488
  ]);
10199
10489
  useEffect(() => {
@@ -10276,7 +10566,7 @@ function App({
10276
10566
  dispatch({ type: "resumePickerOpen", sessions });
10277
10567
  } catch (err) {
10278
10568
  return {
10279
- message: err instanceof Error ? err.message : String(err)
10569
+ message: toErrorMessage(err)
10280
10570
  };
10281
10571
  }
10282
10572
  return { message: void 0 };
@@ -10879,7 +11169,7 @@ function App({
10879
11169
  }).catch((err) => {
10880
11170
  dispatch({
10881
11171
  type: "resumePickerError",
10882
- text: err instanceof Error ? err.message : String(err)
11172
+ text: toErrorMessage(err)
10883
11173
  });
10884
11174
  });
10885
11175
  return;
@@ -11328,7 +11618,7 @@ function App({
11328
11618
  }
11329
11619
  return;
11330
11620
  }
11331
- if (key.fn === 10) {
11621
+ if (key.fn === 10 || key.escape && state.sessionsPanelOpen) {
11332
11622
  if (state.sessionsPanelOpen) {
11333
11623
  dispatch({ type: "toggleSessionsPanel" });
11334
11624
  } else {
@@ -11347,6 +11637,10 @@ function App({
11347
11637
  }
11348
11638
  return;
11349
11639
  }
11640
+ if (key.fn === 11 || input === "\x1B" && state.coordinator.monitorOpen) {
11641
+ dispatch({ type: "toggleCoordinatorMonitor" });
11642
+ return;
11643
+ }
11350
11644
  if (key.ctrl && input === "s") {
11351
11645
  if (state.settingsPicker.open) {
11352
11646
  dispatch({ type: "settingsClose" });
@@ -11375,6 +11669,7 @@ function App({
11375
11669
  featureSkills: cfg.featureSkills ?? true,
11376
11670
  featureModelsRegistry: cfg.featureModelsRegistry ?? true,
11377
11671
  featureTokenSaving: cfg.featureTokenSaving ?? false,
11672
+ allowOutsideProjectRoot: cfg.allowOutsideProjectRoot ?? true,
11378
11673
  contextAutoCompact: cfg.contextAutoCompact ?? true,
11379
11674
  contextStrategy: cfg.contextStrategy ?? "hybrid",
11380
11675
  logLevel: cfg.logLevel ?? "info",
@@ -11424,10 +11719,18 @@ function App({
11424
11719
  dispatch({ type: "toggleGoalPanel" });
11425
11720
  return;
11426
11721
  }
11722
+ if (state.helpOpen) {
11723
+ dispatch({ type: "toggleHelp" });
11724
+ return;
11725
+ }
11427
11726
  if (state.sessionsPanelOpen) {
11428
11727
  dispatch({ type: "toggleSessionsPanel" });
11429
11728
  return;
11430
11729
  }
11730
+ if (state.coordinator.monitorOpen) {
11731
+ dispatch({ type: "toggleCoordinatorMonitor" });
11732
+ return;
11733
+ }
11431
11734
  }
11432
11735
  if (state.processListOpen) {
11433
11736
  return;
@@ -11450,6 +11753,17 @@ function App({
11450
11753
  return;
11451
11754
  }
11452
11755
  const { buffer, cursor } = draftRef.current;
11756
+ if (key.tab && nextStepsAutoSubmitTimerRef.current != null) {
11757
+ const pending = nextStepsAutoSubmitSuggestionRef.current ?? nextStepsAutoSubmitLabel ?? "";
11758
+ clearInterval(nextStepsAutoSubmitTimerRef.current);
11759
+ nextStepsAutoSubmitTimerRef.current = void 0;
11760
+ setNextStepsAutoSubmitCountdown(null);
11761
+ setNextStepsAutoSubmitLabel(null);
11762
+ nextStepsAutoSubmitSuggestionRef.current = null;
11763
+ const text = pending.trim();
11764
+ if (text) setDraft(text, text.length);
11765
+ return;
11766
+ }
11453
11767
  if (key.backspace) {
11454
11768
  if (key.ctrl) {
11455
11769
  if (cursor === 0) return;
@@ -11537,7 +11851,7 @@ function App({
11537
11851
  setDraft(buffer, buffer.length);
11538
11852
  return;
11539
11853
  }
11540
- const overlayOpen = state.monitorOpen || state.agentsMonitorOpen || state.worktreeMonitorOpen || state.todosMonitorOpen || state.queuePanelOpen || state.processListOpen || state.goalPanelOpen || state.sessionsPanelOpen || state.helpOpen || (state.autoPhase?.monitorOpen ?? false) || state.rewindOverlay !== null;
11854
+ const overlayOpen = state.monitorOpen || state.agentsMonitorOpen || state.worktreeMonitorOpen || state.todosMonitorOpen || state.queuePanelOpen || state.processListOpen || state.goalPanelOpen || state.sessionsPanelOpen || state.coordinator.monitorOpen || state.helpOpen || (state.autoPhase?.monitorOpen ?? false) || state.rewindOverlay !== null;
11541
11855
  if (mouseMode && !overlayOpen) {
11542
11856
  if (key.mouse?.kind === "wheel") {
11543
11857
  if (key.mouse.shift) dispatch({ type: "scrollPage", dir: key.mouse.wheel > 0 ? "up" : "down" });
@@ -11666,6 +11980,10 @@ function App({
11666
11980
  setDraft(next2, cursor);
11667
11981
  return;
11668
11982
  }
11983
+ if (key.ctrl && input === "v") {
11984
+ await pasteClipboardText();
11985
+ return;
11986
+ }
11669
11987
  if (key.meta && input === "v") {
11670
11988
  await pasteClipboardImage();
11671
11989
  return;
@@ -11789,7 +12107,7 @@ function App({
11789
12107
  } catch (err) {
11790
12108
  dispatch({
11791
12109
  type: "addEntry",
11792
- entry: { kind: "error", text: err instanceof Error ? err.message : String(err) }
12110
+ entry: { kind: "error", text: toErrorMessage(err) }
11793
12111
  });
11794
12112
  } finally {
11795
12113
  activeCtrlRef.current = null;
@@ -11831,7 +12149,7 @@ function App({
11831
12149
  type: "addEntry",
11832
12150
  entry: {
11833
12151
  kind: "error",
11834
- text: `[eternal] ${err instanceof Error ? err.message : String(err)}`
12152
+ text: `[eternal] ${toErrorMessage(err)}`
11835
12153
  }
11836
12154
  });
11837
12155
  }
@@ -11867,7 +12185,7 @@ function App({
11867
12185
  type: "addEntry",
11868
12186
  entry: {
11869
12187
  kind: "error",
11870
- text: `[parallel] ${err instanceof Error ? err.message : String(err)}`
12188
+ text: `[parallel] ${toErrorMessage(err)}`
11871
12189
  }
11872
12190
  });
11873
12191
  }
@@ -12014,7 +12332,6 @@ ${content}
12014
12332
  while (stateRef.current.status !== "idle" && Date.now() - start < 1500) {
12015
12333
  await new Promise((r) => setTimeout(r, 25));
12016
12334
  }
12017
- setDraft(res.runText, res.runText.length);
12018
12335
  try {
12019
12336
  await runBlocks(blocks2);
12020
12337
  } finally {
@@ -12030,7 +12347,7 @@ ${content}
12030
12347
  } catch (err) {
12031
12348
  dispatch({
12032
12349
  type: "addEntry",
12033
- entry: { kind: "error", text: err instanceof Error ? err.message : String(err) }
12350
+ entry: { kind: "error", text: toErrorMessage(err) }
12034
12351
  });
12035
12352
  }
12036
12353
  return;
@@ -12215,7 +12532,9 @@ User message:
12215
12532
  viewportRows: state.viewportRows,
12216
12533
  totalLines: state.totalLines,
12217
12534
  onMeasure: (totalLines) => dispatch({ type: "setMeasuredLines", totalLines }),
12218
- setSuggestions
12535
+ setSuggestions,
12536
+ autonomyMode: autonomyLive,
12537
+ autoSubmitCountdown: nextStepsAutoSubmitCountdown
12219
12538
  }
12220
12539
  ) : /* @__PURE__ */ jsx(
12221
12540
  History,
@@ -12224,7 +12543,9 @@ User message:
12224
12543
  generation: state.historyGen,
12225
12544
  streamingText: state.streamingText,
12226
12545
  toolStream: state.toolStream,
12227
- setSuggestions
12546
+ setSuggestions,
12547
+ autonomyMode: autonomyLive,
12548
+ autoSubmitCountdown: nextStepsAutoSubmitCountdown
12228
12549
  }
12229
12550
  ),
12230
12551
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexShrink: 0, ref: bottomRegionRef, children: [
@@ -12306,6 +12627,7 @@ User message:
12306
12627
  featureSkills: state.settingsPicker.featureSkills,
12307
12628
  featureModelsRegistry: state.settingsPicker.featureModelsRegistry,
12308
12629
  featureTokenSaving: state.settingsPicker.featureTokenSaving,
12630
+ allowOutsideProjectRoot: state.settingsPicker.allowOutsideProjectRoot,
12309
12631
  contextAutoCompact: state.settingsPicker.contextAutoCompact,
12310
12632
  contextStrategy: state.settingsPicker.contextStrategy,
12311
12633
  logLevel: state.settingsPicker.logLevel,
@@ -12340,6 +12662,14 @@ User message:
12340
12662
  currentSessionId: agent.ctx.session?.id
12341
12663
  }
12342
12664
  ) : null,
12665
+ state.coordinator.monitorOpen ? /* @__PURE__ */ jsx(
12666
+ CoordinatorPanel,
12667
+ {
12668
+ coordinator: state.coordinator,
12669
+ nowTick,
12670
+ onClose: () => dispatch({ type: "toggleCoordinatorMonitor" })
12671
+ }
12672
+ ) : null,
12343
12673
  state.rewindOverlay ? (() => {
12344
12674
  const overlay = state.rewindOverlay;
12345
12675
  return /* @__PURE__ */ jsx(
@@ -12470,6 +12800,7 @@ User message:
12470
12800
  fleet: fleetCounts,
12471
12801
  git: gitInfo,
12472
12802
  context: contextWindow,
12803
+ contextStrategy: getSettings ? getSettings().contextStrategy : void 0,
12473
12804
  brain: state.brain,
12474
12805
  projectName,
12475
12806
  workingDir: workingDirChip,
@@ -12518,8 +12849,7 @@ User message:
12518
12849
  phases: state.autoPhase.phases,
12519
12850
  runningPhaseIds: state.autoPhase.runningPhaseIds,
12520
12851
  elapsedMs: state.autoPhase.elapsedMs,
12521
- nowTick,
12522
- onClose: () => dispatch({ type: "autoPhaseMonitorToggle" })
12852
+ nowTick
12523
12853
  }
12524
12854
  ) : state.worktreeMonitorOpen ? /* @__PURE__ */ jsx(
12525
12855
  WorktreeMonitor,
@@ -12735,13 +13065,30 @@ async function runTui(opts) {
12735
13065
  const mouseEnabled = opts.mouse ?? opts.getSettings?.().mouseMode ?? process.env.WRONGSTACK_MOUSE === "1";
12736
13066
  stdout.write("\x1B[2J\x1B[H");
12737
13067
  const inkStdin = stdin;
12738
- const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({
12739
- stdout,
12740
- events: opts.events,
12741
- model: opts.model,
12742
- appName: opts.projectRoot ? path4.basename(opts.projectRoot) : void 0
12743
- }) : (() => {
12744
- });
13068
+ let titleStop = null;
13069
+ const startTitle = () => {
13070
+ if (titleStop) return;
13071
+ titleStop = startTerminalTitle({
13072
+ stdout,
13073
+ events: opts.events,
13074
+ model: opts.model,
13075
+ appName: opts.projectRoot ? path4.basename(opts.projectRoot) : void 0
13076
+ });
13077
+ };
13078
+ const stopTitle = () => {
13079
+ try {
13080
+ titleStop?.();
13081
+ } catch {
13082
+ }
13083
+ titleStop = null;
13084
+ };
13085
+ const titleController = {
13086
+ setEnabled(on) {
13087
+ if (on) startTitle();
13088
+ else stopTitle();
13089
+ }
13090
+ };
13091
+ if (opts.titleAnimation !== false) startTitle();
12745
13092
  const swallowSignals = ["SIGTSTP", "SIGQUIT", "SIGTTIN", "SIGTTOU"];
12746
13093
  const swallow = () => {
12747
13094
  };
@@ -12920,6 +13267,7 @@ async function runTui(opts) {
12920
13267
  setSuggestions: opts.setSuggestions,
12921
13268
  chime: opts.chime,
12922
13269
  confirmExit: opts.confirmExit,
13270
+ titleController,
12923
13271
  mouse: mouseEnabled,
12924
13272
  modeLabel: opts.modeLabel,
12925
13273
  tokenSavingMode: opts.tokenSavingMode,
@@ -12936,7 +13284,8 @@ async function runTui(opts) {
12936
13284
  requestExit: opts.requestExit,
12937
13285
  getLiveSessions: opts.getLiveSessions,
12938
13286
  onSwitchToSession: opts.onSwitchToSession,
12939
- initialAgentsMonitorOpen: opts.initialAgentsMonitorOpen
13287
+ initialAgentsMonitorOpen: opts.initialAgentsMonitorOpen,
13288
+ subscribeCoordinatorEvents: opts.subscribeCoordinatorEvents
12940
13289
  }),
12941
13290
  { exitOnCtrlC: false, stdin: inkStdin }
12942
13291
  );