@wrongstack/tui 0.141.0 → 0.155.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.d.ts CHANGED
@@ -33,6 +33,8 @@ type Settings = {
33
33
  auditLevel: 'minimal' | 'standard' | 'full';
34
34
  indexOnStart: boolean;
35
35
  maxIterations: number;
36
+ /** Maximum auto-proceed iterations (0 = unlimited). */
37
+ autoProceedMaxIterations: number;
36
38
  /** Prompt refinement preview countdown (ms). */
37
39
  enhanceDelayMs: number;
38
40
  /** Raw SSE stream debugging — hex-dump every byte received from providers. */
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { expectDefined, writeErr, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
2
2
  export { buildGoalPreamble } from '@wrongstack/core';
3
3
  import { Box, Text, useInput, useStdin, useStdout, render, useApp, Static } from 'ink';
4
- import React5, { useState, useEffect, memo, useRef, useCallback, useReducer, useMemo } from 'react';
4
+ import * as path3 from 'path';
5
+ import React5, { useState, useEffect, useMemo, memo, useRef, useCallback, useReducer } from 'react';
5
6
  import * as fs2 from 'fs/promises';
6
- import * as path2 from 'path';
7
7
  import { routeImagesForModel } from '@wrongstack/runtime/vision';
8
8
  import { getIndexState, onIndexStateChange, getProcessRegistry } from '@wrongstack/tools';
9
9
  import { readClipboardImage } from '@wrongstack/runtime/clipboard';
@@ -59,7 +59,9 @@ function StatusBar({
59
59
  goalSummary,
60
60
  indexState,
61
61
  modeLabel,
62
- debugStreamStats
62
+ debugStreamStats,
63
+ enhanceCountdown,
64
+ autoProceedCountdown
63
65
  }) {
64
66
  const { stdout } = useStdout();
65
67
  const [termWidth, setTermWidth] = useState(stdout?.columns ?? 90);
@@ -96,11 +98,13 @@ function StatusBar({
96
98
  const { label: stateLabel, color: stateColor } = stateChip(state, fleet?.running ?? 0);
97
99
  const statePrefix = state === "idle" || state === "aborting" ? "\u25CF" : spinner;
98
100
  const thinking = state === "running" || state === "streaming";
99
- const hasSecondLine = yolo || autonomy && autonomy !== "off" || startedAt != null || git !== null && git !== void 0 || projectName !== void 0 && projectName.length > 0 || goalSummary !== null && goalSummary !== void 0 || !!modeLabel;
101
+ const hasAutoProceed = autoProceedCountdown != null && autoProceedCountdown > 0;
102
+ const hasSecondLine = yolo || autonomy && autonomy !== "off" || startedAt != null || git !== null && git !== void 0 || projectName !== void 0 && projectName.length > 0 || goalSummary !== null && goalSummary !== void 0 || !!modeLabel || hasAutoProceed;
100
103
  const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
101
104
  const hasBrainActivity = !!brain && brain.state !== "idle";
102
105
  const hasDebugStream = !!debugStreamStats;
103
- const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity || hasDebugStream;
106
+ const hasEnhanceCountdown = enhanceCountdown != null && enhanceCountdown > 0;
107
+ const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity || hasDebugStream || hasEnhanceCountdown;
104
108
  return /* @__PURE__ */ jsxs(
105
109
  Box,
106
110
  {
@@ -267,6 +271,14 @@ function StatusBar({
267
271
  yolo || autonomy && autonomy !== "off" || eternalStage || startedAt != null || projectName || goalSummary ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
268
272
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: modeIcon(modeLabel) })
269
273
  ] }) : null,
274
+ hasAutoProceed ? /* @__PURE__ */ jsxs(Fragment, { children: [
275
+ yolo || autonomy && autonomy !== "off" || eternalStage || startedAt != null || projectName || goalSummary || modeLabel ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
276
+ /* @__PURE__ */ jsxs(Text, { color: autoProceedCountdown != null && autoProceedCountdown <= 5 ? "yellow" : "cyan", children: [
277
+ "\u23F3 auto in ",
278
+ autoProceedCountdown,
279
+ "s"
280
+ ] })
281
+ ] }) : null,
270
282
  git ? /* @__PURE__ */ jsxs(Fragment, { children: [
271
283
  yolo || startedAt != null || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
272
284
  /* @__PURE__ */ jsxs(Text, { children: [
@@ -385,6 +397,14 @@ function StatusBar({
385
397
  fmtDebugBytes(debugStreamStats.totalBytes)
386
398
  ] })
387
399
  ] })
400
+ ] }) : null,
401
+ hasEnhanceCountdown && enhanceCountdown != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
402
+ 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,
403
+ /* @__PURE__ */ jsxs(Text, { color: enhanceCountdown <= 5 ? "yellow" : "cyan", children: [
404
+ "\u23F3 auto-send in ",
405
+ enhanceCountdown,
406
+ "s"
407
+ ] })
388
408
  ] }) : null
389
409
  ] }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
390
410
  fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => (
@@ -1327,22 +1347,24 @@ function EnhancePanel({
1327
1347
  refined,
1328
1348
  english,
1329
1349
  delayMs,
1330
- onDecision
1350
+ onDecision,
1351
+ onTick
1331
1352
  }) {
1332
1353
  const totalSecs = Math.max(1, Math.ceil(delayMs / 1e3));
1333
- const [remaining, setRemaining] = React5.useState(totalSecs);
1354
+ const remainingRef = React5.useRef(totalSecs);
1334
1355
  const decideRef = React5.useRef(onDecision);
1335
1356
  decideRef.current = onDecision;
1357
+ const tickRef = React5.useRef(onTick);
1358
+ tickRef.current = onTick;
1336
1359
  React5.useEffect(() => {
1337
1360
  const id = setInterval(() => {
1338
- setRemaining((r) => {
1339
- if (r <= 1) {
1340
- clearInterval(id);
1341
- decideRef.current("refined");
1342
- return 0;
1343
- }
1344
- return r - 1;
1345
- });
1361
+ const r = remainingRef.current - 1;
1362
+ remainingRef.current = r;
1363
+ tickRef.current?.(r);
1364
+ if (r <= 0) {
1365
+ clearInterval(id);
1366
+ decideRef.current("refined");
1367
+ }
1346
1368
  }, 1e3);
1347
1369
  return () => clearInterval(id);
1348
1370
  }, []);
@@ -1358,15 +1380,7 @@ function EnhancePanel({
1358
1380
  }
1359
1381
  });
1360
1382
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
1361
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
1362
- /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u2728 Refined request" }),
1363
- /* @__PURE__ */ jsx(Text, { children: " " }),
1364
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1365
- "\u2014 sending in ",
1366
- remaining,
1367
- "s"
1368
- ] })
1369
- ] }),
1383
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u2728 Refined request" }) }),
1370
1384
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
1371
1385
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "original: " }),
1372
1386
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: original })
@@ -1453,8 +1467,8 @@ function FilePicker({ query, matches, selected }) {
1453
1467
  ] }, m))
1454
1468
  ] });
1455
1469
  }
1456
- function highlight(path3, _query) {
1457
- return path3;
1470
+ function highlight(path5, _query) {
1471
+ return path5;
1458
1472
  }
1459
1473
  function FleetPanel({
1460
1474
  entries,
@@ -1593,7 +1607,7 @@ function HelpOverlay() {
1593
1607
  const keyWidth = Math.max(...sections.flatMap((s2) => s2.entries.map((e) => e.keys.length)), 0);
1594
1608
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
1595
1609
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1596
- /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "WrongStack \u2014 keys & commands" }),
1610
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "Keyboard shortcuts" }),
1597
1611
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Esc to close" })
1598
1612
  ] }),
1599
1613
  sections.map((sec) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
@@ -3394,10 +3408,11 @@ function Banner({
3394
3408
  entry
3395
3409
  }) {
3396
3410
  const cwdShort = shortenPath(entry.cwd, 48);
3411
+ const projectLabel = path3.basename(entry.cwd);
3397
3412
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 0, children: [
3398
3413
  /* @__PURE__ */ jsxs(Text, { children: [
3399
3414
  /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: " \u259F\u259B " }),
3400
- /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: "WrongStack" }),
3415
+ /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: projectLabel }),
3401
3416
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " v" }),
3402
3417
  /* @__PURE__ */ jsx(Text, { children: entry.version })
3403
3418
  ] }),
@@ -3429,6 +3444,20 @@ function Banner({
3429
3444
  ] })
3430
3445
  ] });
3431
3446
  }
3447
+ var NEXT_STEPS_RE = /💡\s*Next steps?\s*\n+((?:\d+\.\s+.+\n?)+)/i;
3448
+ function parseNextSteps(content) {
3449
+ const match = NEXT_STEPS_RE.exec(content);
3450
+ if (!match?.[1]) return { steps: [], stripped: content };
3451
+ const block = match[1];
3452
+ const steps = [];
3453
+ const lines = block.split("\n").filter(Boolean);
3454
+ for (const line of lines) {
3455
+ const m = /^(\d+)\.\s+(.+)$/.exec(line.trim());
3456
+ if (m) steps.push({ index: Number.parseInt(m[1], 10), text: m[2].trim() });
3457
+ }
3458
+ const stripped = content.replace(NEXT_STEPS_RE, "").replace(/\n{3,}/g, "\n\n").trim();
3459
+ return { steps: steps.slice(0, 6), stripped };
3460
+ }
3432
3461
  function brainStatusStyle(status) {
3433
3462
  switch (status) {
3434
3463
  case "thinking":
@@ -3457,6 +3486,10 @@ var Entry = React5.memo(function Entry2({
3457
3486
  entry,
3458
3487
  termWidth
3459
3488
  }) {
3489
+ const nextSteps = useMemo(() => {
3490
+ if (entry.kind !== "assistant") return { steps: [], stripped: "" };
3491
+ return parseNextSteps(entry.text);
3492
+ }, [entry.kind, entry.text]);
3460
3493
  switch (entry.kind) {
3461
3494
  case "user":
3462
3495
  return /* @__PURE__ */ jsx(
@@ -3485,24 +3518,52 @@ var Entry = React5.memo(function Entry2({
3485
3518
  );
3486
3519
  case "assistant": {
3487
3520
  const contentWidth = assistantContentWidth(termWidth);
3488
- return /* @__PURE__ */ jsxs(
3489
- Box,
3490
- {
3491
- flexDirection: "column",
3492
- marginX: MESSAGE_PANEL_MARGIN,
3493
- marginY: 1,
3494
- borderStyle: "single",
3495
- borderTop: false,
3496
- borderRight: false,
3497
- borderBottom: false,
3498
- borderColor: theme.assistant,
3499
- paddingLeft: 1,
3500
- children: [
3501
- /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }) }),
3502
- /* @__PURE__ */ jsx(AssistantBody, { text: entry.text, termWidth, contentWidth })
3503
- ]
3504
- }
3505
- );
3521
+ const { steps, stripped } = nextSteps;
3522
+ const hasNext = steps.length > 0;
3523
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
3524
+ /* @__PURE__ */ jsxs(
3525
+ Box,
3526
+ {
3527
+ flexDirection: "column",
3528
+ marginX: MESSAGE_PANEL_MARGIN,
3529
+ marginY: 1,
3530
+ borderStyle: "single",
3531
+ borderTop: false,
3532
+ borderRight: false,
3533
+ borderBottom: hasNext ? false : void 0,
3534
+ borderColor: theme.assistant,
3535
+ paddingLeft: 1,
3536
+ children: [
3537
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }) }),
3538
+ /* @__PURE__ */ jsx(AssistantBody, { text: stripped, termWidth, contentWidth })
3539
+ ]
3540
+ }
3541
+ ),
3542
+ hasNext && /* @__PURE__ */ jsxs(
3543
+ Box,
3544
+ {
3545
+ flexDirection: "column",
3546
+ marginX: MESSAGE_PANEL_MARGIN,
3547
+ marginY: 1,
3548
+ borderStyle: "single",
3549
+ borderTop: false,
3550
+ borderRight: false,
3551
+ borderBottom: false,
3552
+ borderColor: theme.accent,
3553
+ paddingLeft: 1,
3554
+ children: [
3555
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
3556
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "\u{1F4A1} NEXT STEPS " }),
3557
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(use /next 1, /next 1 2 3 to select)" })
3558
+ ] }),
3559
+ steps.map((s2) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", marginTop: 0, children: /* @__PURE__ */ jsxs(Text, { children: [
3560
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: ` ${s2.index}. ` }),
3561
+ /* @__PURE__ */ jsx(Text, { children: s2.text })
3562
+ ] }) }, s2.index))
3563
+ ]
3564
+ }
3565
+ )
3566
+ ] });
3506
3567
  }
3507
3568
  case "tool": {
3508
3569
  const argSummary = formatToolArgs(entry.name, entry.input);
@@ -4494,6 +4555,7 @@ var LOG_LEVELS = ["error", "warn", "info", "debug", "trace"];
4494
4555
  var AUDIT_LEVELS = ["minimal", "standard", "full"];
4495
4556
  var COMPACTOR_STRATEGIES = ["hybrid", "intelligent", "selective"];
4496
4557
  var MAX_ITERATIONS_PRESETS = [100, 200, 500, 1e3, 0];
4558
+ var AUTO_PROCEED_MAX_PRESETS = [10, 25, 50, 100, 250, 0];
4497
4559
  var ENHANCE_DELAY_PRESETS = [3e4, 45e3, 6e4, 9e4, 12e4];
4498
4560
  function formatSettingsDelay(ms) {
4499
4561
  if (ms === 0) return "disabled";
@@ -4512,7 +4574,7 @@ var MODE_DESC = {
4512
4574
  suggest: "Shows next-step suggestions after each turn",
4513
4575
  auto: "Self-driving \u2014 agent continues automatically"
4514
4576
  };
4515
- var SETTINGS_FIELD_COUNT = 22;
4577
+ var SETTINGS_FIELD_COUNT = 23;
4516
4578
  var CONFIG_SCOPES = ["global", "project"];
4517
4579
  function SettingsPicker({
4518
4580
  field,
@@ -4535,6 +4597,7 @@ function SettingsPicker({
4535
4597
  auditLevel,
4536
4598
  indexOnStart,
4537
4599
  maxIterations,
4600
+ autoProceedMaxIterations,
4538
4601
  enhanceDelayMs,
4539
4602
  debugStream,
4540
4603
  configScope,
@@ -4649,6 +4712,11 @@ function SettingsPicker({
4649
4712
  value: formatMaxIterations(maxIterations),
4650
4713
  detail: "100\u20131000 or unlimited (0)"
4651
4714
  },
4715
+ {
4716
+ label: "Auto-proceed max iterations",
4717
+ value: formatMaxIterations(autoProceedMaxIterations),
4718
+ detail: "Stop auto-proceed after N iterations (0 = unlimited, default 50)"
4719
+ },
4652
4720
  {
4653
4721
  label: "Refine preview countdown",
4654
4722
  value: formatEnhanceDelay(enhanceDelayMs),
@@ -5156,7 +5224,7 @@ async function loadIndex(root) {
5156
5224
  async function walk(root, rel, depth, out) {
5157
5225
  if (out.length >= MAX_FILES_INDEXED) return;
5158
5226
  if (depth > MAX_DEPTH) return;
5159
- const dir = rel ? path2.join(root, rel) : root;
5227
+ const dir = rel ? path3.join(root, rel) : root;
5160
5228
  let entries;
5161
5229
  try {
5162
5230
  entries = await fs2.readdir(dir, { withFileTypes: true });
@@ -5519,6 +5587,20 @@ function useDirectorFleetBridge({
5519
5587
  }
5520
5588
  break;
5521
5589
  }
5590
+ case "ctx.pct": {
5591
+ const payload = event.payload;
5592
+ if (payload?.load !== void 0) {
5593
+ enqueue({
5594
+ type: "fleetCtxPct",
5595
+ id: event.subagentId,
5596
+ load: payload.load,
5597
+ tokens: payload.tokens ?? 0,
5598
+ maxContext: payload.maxContext ?? 0,
5599
+ ctxCost: payload.ctxCost
5600
+ });
5601
+ }
5602
+ break;
5603
+ }
5522
5604
  case "bug.found":
5523
5605
  handleCollabBugFound(event, enqueue, stateRef);
5524
5606
  break;
@@ -6311,6 +6393,9 @@ function reducer(state, action) {
6311
6393
  case "streamReset":
6312
6394
  return { ...state, streamingText: "" };
6313
6395
  case "status":
6396
+ if (action.status === "idle") {
6397
+ return { ...state, status: "idle", debugStreamStats: null };
6398
+ }
6314
6399
  return { ...state, status: action.status };
6315
6400
  case "interrupt":
6316
6401
  return { ...state, interrupts: state.interrupts + 1 };
@@ -6601,6 +6686,7 @@ function reducer(state, action) {
6601
6686
  auditLevel: action.auditLevel,
6602
6687
  indexOnStart: action.indexOnStart,
6603
6688
  maxIterations: action.maxIterations,
6689
+ autoProceedMaxIterations: action.autoProceedMaxIterations,
6604
6690
  enhanceDelayMs: action.enhanceDelayMs,
6605
6691
  debugStream: action.debugStream,
6606
6692
  configScope: action.configScope,
@@ -6676,13 +6762,19 @@ function reducer(state, action) {
6676
6762
  return { ...state, settingsPicker: { ...sp, maxIterations: expectDefined(MAX_ITERATIONS_PRESETS[next]), hint: void 0 } };
6677
6763
  }
6678
6764
  if (f === 19) {
6765
+ const aj = AUTO_PROCEED_MAX_PRESETS.indexOf(sp.autoProceedMaxIterations);
6766
+ const abase = aj < 0 ? 0 : aj;
6767
+ const anext = (abase + action.delta + AUTO_PROCEED_MAX_PRESETS.length) % AUTO_PROCEED_MAX_PRESETS.length;
6768
+ return { ...state, settingsPicker: { ...sp, autoProceedMaxIterations: expectDefined(AUTO_PROCEED_MAX_PRESETS[anext]), hint: void 0 } };
6769
+ }
6770
+ if (f === 20) {
6679
6771
  const ej = ENHANCE_DELAY_PRESETS.indexOf(sp.enhanceDelayMs);
6680
6772
  const ebase = ej < 0 ? 0 : ej;
6681
6773
  const enext = (ebase + action.delta + ENHANCE_DELAY_PRESETS.length) % ENHANCE_DELAY_PRESETS.length;
6682
6774
  return { ...state, settingsPicker: { ...sp, enhanceDelayMs: expectDefined(ENHANCE_DELAY_PRESETS[enext]), hint: void 0 } };
6683
6775
  }
6684
- if (f === 20) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
6685
- if (f === 21) {
6776
+ if (f === 21) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
6777
+ if (f === 22) {
6686
6778
  const i = CONFIG_SCOPES.indexOf(sp.configScope);
6687
6779
  const base = i < 0 ? 0 : i;
6688
6780
  const next = (base + action.delta + CONFIG_SCOPES.length) % CONFIG_SCOPES.length;
@@ -7028,25 +7120,32 @@ function reducer(state, action) {
7028
7120
  return { ...state, streamFleet: action.enabled };
7029
7121
  }
7030
7122
  case "toggleMonitor": {
7031
- return { ...state, monitorOpen: !state.monitorOpen };
7123
+ const opening = !state.monitorOpen;
7124
+ return opening ? { ...state, monitorOpen: true, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, monitorOpen: false };
7032
7125
  }
7033
7126
  case "toggleAgentsMonitor": {
7034
- return { ...state, agentsMonitorOpen: !state.agentsMonitorOpen };
7127
+ const opening = !state.agentsMonitorOpen;
7128
+ return opening ? { ...state, agentsMonitorOpen: true, monitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, agentsMonitorOpen: false };
7035
7129
  }
7036
7130
  case "toggleHelp": {
7037
- return { ...state, helpOpen: !state.helpOpen };
7131
+ const opening = !state.helpOpen;
7132
+ return opening ? { ...state, helpOpen: true, monitorOpen: false, agentsMonitorOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, helpOpen: false };
7038
7133
  }
7039
7134
  case "toggleTodosMonitor": {
7040
- return { ...state, todosMonitorOpen: !state.todosMonitorOpen };
7135
+ const opening = !state.todosMonitorOpen;
7136
+ return opening ? { ...state, todosMonitorOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, queuePanelOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, todosMonitorOpen: false };
7041
7137
  }
7042
7138
  case "toggleQueuePanel": {
7043
- return { ...state, queuePanelOpen: !state.queuePanelOpen };
7139
+ const opening = !state.queuePanelOpen;
7140
+ return opening ? { ...state, queuePanelOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, processListOpen: false, goalPanelOpen: false } : { ...state, queuePanelOpen: false };
7044
7141
  }
7045
7142
  case "toggleProcessList": {
7046
- return { ...state, processListOpen: !state.processListOpen };
7143
+ const opening = !state.processListOpen;
7144
+ return opening ? { ...state, processListOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, goalPanelOpen: false } : { ...state, processListOpen: false };
7047
7145
  }
7048
7146
  case "toggleGoalPanel": {
7049
- return { ...state, goalPanelOpen: !state.goalPanelOpen };
7147
+ const opening = !state.goalPanelOpen;
7148
+ return opening ? { ...state, goalPanelOpen: true, monitorOpen: false, agentsMonitorOpen: false, helpOpen: false, todosMonitorOpen: false, queuePanelOpen: false, processListOpen: false } : { ...state, goalPanelOpen: false };
7050
7149
  }
7051
7150
  case "checkpointReceived": {
7052
7151
  const existing = state.checkpoints.find((c) => c.promptIndex === action.cp.promptIndex);
@@ -7546,7 +7645,7 @@ function App({
7546
7645
  searchQuery: ""
7547
7646
  },
7548
7647
  autonomyPicker: { open: false, options: [], selected: 0 },
7549
- 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, contextAutoCompact: true, contextStrategy: "hybrid", logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, enhanceDelayMs: 6e4, debugStream: false, configScope: "global" },
7648
+ 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, contextAutoCompact: true, contextStrategy: "hybrid", logLevel: "info", auditLevel: "standard", indexOnStart: true, maxIterations: 500, autoProceedMaxIterations: 50, enhanceDelayMs: 6e4, debugStream: false, configScope: "global" },
7550
7649
  confirmQueue: [],
7551
7650
  enhance: null,
7552
7651
  enhanceEnabled,
@@ -7600,8 +7699,8 @@ function App({
7600
7699
  const lastEnterAtRef = useRef(0);
7601
7700
  const tokenPreviewsRef = useRef(/* @__PURE__ */ new Map());
7602
7701
  const projectName = React5.useMemo(() => {
7603
- const base = path2.basename(projectRoot);
7604
- return base && base !== path2.sep ? base : void 0;
7702
+ const base = path3.basename(projectRoot);
7703
+ return base && base !== path3.sep ? base : void 0;
7605
7704
  }, [projectRoot]);
7606
7705
  const chimeRef = useRef(chime);
7607
7706
  chimeRef.current = chime;
@@ -7889,6 +7988,7 @@ function App({
7889
7988
  auditLevel: sp.auditLevel,
7890
7989
  indexOnStart: sp.indexOnStart,
7891
7990
  maxIterations: sp.maxIterations,
7991
+ autoProceedMaxIterations: sp.autoProceedMaxIterations,
7892
7992
  enhanceDelayMs: sp.enhanceDelayMs,
7893
7993
  debugStream: sp.debugStream,
7894
7994
  configScope: sp.configScope
@@ -8006,7 +8106,7 @@ function App({
8006
8106
  dispatch({ type: "pickerClose" });
8007
8107
  return;
8008
8108
  }
8009
- const absPath = path2.isAbsolute(picked) ? picked : path2.join(projectRoot, picked);
8109
+ const absPath = path3.isAbsolute(picked) ? picked : path3.join(projectRoot, picked);
8010
8110
  try {
8011
8111
  const data = await fs2.readFile(absPath, "utf8");
8012
8112
  const token = await builder.registerFile({
@@ -8014,6 +8114,7 @@ function App({
8014
8114
  data,
8015
8115
  meta: { filename: picked, label: picked }
8016
8116
  });
8117
+ tokenPreviewsRef.current.set(token, data);
8017
8118
  const before = draft.buffer.slice(0, tok.start);
8018
8119
  const after = draft.buffer.slice(tok.end);
8019
8120
  const next = `${before}${token}${after}`;
@@ -8225,11 +8326,40 @@ function App({
8225
8326
  auditLevel: s2.auditLevel ?? "standard",
8226
8327
  indexOnStart: s2.indexOnStart ?? true,
8227
8328
  maxIterations: s2.maxIterations ?? 500,
8329
+ autoProceedMaxIterations: s2.autoProceedMaxIterations ?? 50,
8228
8330
  enhanceDelayMs: s2.enhanceDelayMs ?? 6e4,
8229
8331
  debugStream: s2.debugStream ?? false,
8230
8332
  configScope: s2.configScope ?? "global"
8231
8333
  });
8232
8334
  }, [getSettings]);
8335
+ const [autoProceedCountdown, setAutoProceedCountdown] = useState(null);
8336
+ const autoProceedTimerRef = useRef(void 0);
8337
+ useEffect(() => {
8338
+ if (autonomyLive !== "auto") {
8339
+ clearInterval(autoProceedTimerRef.current);
8340
+ autoProceedTimerRef.current = void 0;
8341
+ setAutoProceedCountdown(null);
8342
+ return;
8343
+ }
8344
+ const cfg = getSettings?.();
8345
+ const delay = cfg?.delayMs ?? 45e3;
8346
+ const start = Date.now();
8347
+ setAutoProceedCountdown(Math.ceil(delay / 1e3));
8348
+ autoProceedTimerRef.current = setInterval(() => {
8349
+ const remaining = Math.max(0, Math.ceil((delay - (Date.now() - start)) / 1e3));
8350
+ if (remaining <= 0) {
8351
+ clearInterval(autoProceedTimerRef.current);
8352
+ autoProceedTimerRef.current = void 0;
8353
+ setAutoProceedCountdown(null);
8354
+ } else {
8355
+ setAutoProceedCountdown(remaining);
8356
+ }
8357
+ }, 500);
8358
+ return () => {
8359
+ clearInterval(autoProceedTimerRef.current);
8360
+ autoProceedTimerRef.current = void 0;
8361
+ };
8362
+ }, [autonomyLive, getSettings]);
8233
8363
  const settingsAutoSaveGateRef = useRef(true);
8234
8364
  useEffect(() => {
8235
8365
  if (state.settingsPicker.open) {
@@ -8264,6 +8394,7 @@ function App({
8264
8394
  auditLevel: sp.auditLevel,
8265
8395
  indexOnStart: sp.indexOnStart,
8266
8396
  maxIterations: sp.maxIterations,
8397
+ autoProceedMaxIterations: sp.autoProceedMaxIterations,
8267
8398
  enhanceDelayMs: sp.enhanceDelayMs,
8268
8399
  debugStream: sp.debugStream,
8269
8400
  configScope: sp.configScope
@@ -8291,6 +8422,7 @@ function App({
8291
8422
  state.settingsPicker.auditLevel,
8292
8423
  state.settingsPicker.indexOnStart,
8293
8424
  state.settingsPicker.maxIterations,
8425
+ state.settingsPicker.autoProceedMaxIterations,
8294
8426
  state.settingsPicker.enhanceDelayMs,
8295
8427
  saveSettings
8296
8428
  ]);
@@ -8533,6 +8665,7 @@ function App({
8533
8665
  enhanceEnabledRef.current = state.enhanceEnabled;
8534
8666
  }, [state.enhanceEnabled]);
8535
8667
  const enhanceAbortRef = useRef(null);
8668
+ const [enhanceCountdown, setEnhanceCountdown] = useState(null);
8536
8669
  useTuiEventBridge({
8537
8670
  events,
8538
8671
  dispatch,
@@ -8676,13 +8809,6 @@ function App({
8676
8809
  process.off("SIGINT", onSigint);
8677
8810
  };
8678
8811
  }, [director, getEternalEngine, getParallelEngine, switchAutonomy, onExit, exit]);
8679
- const truncatePastePreview = (text, lines) => {
8680
- const all = text.split("\n");
8681
- if (all.length <= lines) return text;
8682
- const head = all.slice(0, lines).join("\n");
8683
- return `${head}
8684
- ... (${all.length - lines} more lines)`;
8685
- };
8686
8812
  const commitPaste = async (full) => {
8687
8813
  const builder = builderRef.current;
8688
8814
  if (!builder || !full) return;
@@ -8697,7 +8823,7 @@ function App({
8697
8823
  }
8698
8824
  if (mustCollapse || multiLine) {
8699
8825
  const token = await builder.registerPaste(full);
8700
- tokenPreviewsRef.current.set(token, truncatePastePreview(full, 6));
8826
+ tokenPreviewsRef.current.set(token, full);
8701
8827
  const next2 = buffer.slice(0, cursor) + token + buffer.slice(cursor);
8702
8828
  setDraft(next2, cursor + token.length);
8703
8829
  return;
@@ -9088,6 +9214,7 @@ function App({
9088
9214
  auditLevel: cfg.auditLevel ?? "standard",
9089
9215
  indexOnStart: cfg.indexOnStart ?? true,
9090
9216
  maxIterations: cfg.maxIterations ?? 500,
9217
+ autoProceedMaxIterations: cfg.autoProceedMaxIterations ?? 50,
9091
9218
  enhanceDelayMs: cfg.enhanceDelayMs ?? 6e4,
9092
9219
  debugStream: cfg.debugStream ?? false,
9093
9220
  configScope: cfg.configScope ?? "global"
@@ -9180,6 +9307,7 @@ function App({
9180
9307
  auditLevel: cfg.auditLevel ?? "standard",
9181
9308
  indexOnStart: cfg.indexOnStart ?? true,
9182
9309
  maxIterations: cfg.maxIterations ?? 500,
9310
+ autoProceedMaxIterations: cfg.autoProceedMaxIterations ?? 50,
9183
9311
  enhanceDelayMs: cfg.enhanceDelayMs ?? 6e4,
9184
9312
  debugStream: cfg.debugStream ?? false,
9185
9313
  configScope: cfg.configScope ?? "global"
@@ -9580,7 +9708,12 @@ function App({
9580
9708
  const submit = async (overrideRaw) => {
9581
9709
  const raw = overrideRaw ?? draftRef.current.buffer;
9582
9710
  const trimmed = raw.trim();
9583
- if (!trimmed) return;
9711
+ if (!trimmed) {
9712
+ if (state.steeringPending) {
9713
+ dispatch({ type: "steerConsume" });
9714
+ }
9715
+ return;
9716
+ }
9584
9717
  dispatch({ type: "resetInterrupts" });
9585
9718
  const pushSubmittedHistory = () => {
9586
9719
  if (trimmed) dispatch({ type: "historyPush", text: trimmed });
@@ -9592,11 +9725,29 @@ function App({
9592
9725
  return;
9593
9726
  }
9594
9727
  if (trimmed.startsWith("/")) {
9595
- dispatch({ type: "addEntry", entry: { kind: "user", text: trimmed } });
9728
+ let resolvedForDispatch = trimmed;
9729
+ const pasteParts2 = [];
9730
+ for (const m of trimmed.matchAll(new RegExp(INLINE_TOKEN_SRC, "g"))) {
9731
+ const token = m[0];
9732
+ const content = tokenPreviewsRef.current.get(token);
9733
+ if (content) {
9734
+ resolvedForDispatch = resolvedForDispatch.replace(
9735
+ token,
9736
+ `
9737
+ <pasted>
9738
+ ${content}
9739
+ </pasted>`
9740
+ );
9741
+ }
9742
+ pasteParts2.push(token);
9743
+ if (content) pasteParts2.push(` ${content.split("\n").slice(0, 6).join("\n ")}`);
9744
+ }
9745
+ const pasteContent2 = pasteParts2.length > 0 ? pasteParts2.join("\n") : void 0;
9746
+ dispatch({ type: "addEntry", entry: { kind: "user", text: trimmed, pasteContent: pasteContent2 } });
9596
9747
  pushSubmittedHistory();
9597
9748
  clearDraft();
9598
9749
  try {
9599
- const res = await slashRegistry.dispatch(trimmed, agent.ctx);
9750
+ const res = await slashRegistry.dispatch(resolvedForDispatch, agent.ctx);
9600
9751
  if (res?.message) {
9601
9752
  dispatch({ type: "addEntry", entry: { kind: "info", text: res.message } });
9602
9753
  }
@@ -9750,7 +9901,7 @@ User message:
9750
9901
  builder.appendText(toAppend);
9751
9902
  }
9752
9903
  if (steering) dispatch({ type: "steerConsume" });
9753
- const displayText = trimmed ? steering ? `\u21AF ${effectiveText}` : effectiveText : "(attachments only)";
9904
+ const displayText = steering ? `\u21AF ${effectiveText}` : effectiveText;
9754
9905
  const pasteParts = [];
9755
9906
  for (const m of trimmed.matchAll(new RegExp(INLINE_TOKEN_SRC, "g"))) {
9756
9907
  const token = m[0];
@@ -9905,6 +10056,7 @@ User message:
9905
10056
  auditLevel: state.settingsPicker.auditLevel,
9906
10057
  indexOnStart: state.settingsPicker.indexOnStart,
9907
10058
  maxIterations: state.settingsPicker.maxIterations,
10059
+ autoProceedMaxIterations: state.settingsPicker.autoProceedMaxIterations,
9908
10060
  enhanceDelayMs: state.settingsPicker.enhanceDelayMs,
9909
10061
  debugStream: state.settingsPicker.debugStream,
9910
10062
  configScope: state.settingsPicker.configScope,
@@ -10008,6 +10160,7 @@ User message:
10008
10160
  const onDecision = (decision) => {
10009
10161
  if (resolved) return;
10010
10162
  resolved = true;
10163
+ setEnhanceCountdown(null);
10011
10164
  info.resolve(decision);
10012
10165
  };
10013
10166
  return /* @__PURE__ */ jsx(
@@ -10017,7 +10170,8 @@ User message:
10017
10170
  refined: info.refined,
10018
10171
  english: info.english,
10019
10172
  delayMs: enhanceDelayMs,
10020
- onDecision
10173
+ onDecision,
10174
+ onTick: (r) => setEnhanceCountdown(r > 0 ? r : null)
10021
10175
  }
10022
10176
  );
10023
10177
  })() : null,
@@ -10047,7 +10201,9 @@ User message:
10047
10201
  goalSummary: state.goalSummary,
10048
10202
  indexState,
10049
10203
  modeLabel: liveModeLabel || void 0,
10050
- debugStreamStats: state.debugStreamStats
10204
+ debugStreamStats: state.debugStreamStats,
10205
+ enhanceCountdown,
10206
+ autoProceedCountdown
10051
10207
  }
10052
10208
  ),
10053
10209
  state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, {}) : null,
@@ -10221,7 +10377,12 @@ async function runTui(opts) {
10221
10377
  stdout.write(BRACKETED_PASTE_ON);
10222
10378
  stdout.write("\x1B[2J\x1B[H");
10223
10379
  const inkStdin = stdin;
10224
- const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({ stdout, events: opts.events, model: opts.model }) : (() => {
10380
+ const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({
10381
+ stdout,
10382
+ events: opts.events,
10383
+ model: opts.model,
10384
+ appName: opts.projectRoot ? path3.basename(opts.projectRoot) : void 0
10385
+ }) : (() => {
10225
10386
  });
10226
10387
  const swallowSignals = ["SIGTSTP", "SIGQUIT", "SIGTTIN", "SIGTTOU"];
10227
10388
  const swallow = () => {