flavor-code 1.4.3-beta.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +25 -0
  2. package/README.zh-CN.md +25 -0
  3. package/dist/agent/loop.d.ts +1 -0
  4. package/dist/{app-G35YBHPR.js → app-TVY2HM5L.js} +342 -112
  5. package/dist/{chunk-FAJ6YDZK.js → chunk-36IDJRLQ.js} +1 -1
  6. package/dist/{chunk-HGTCIHWA.js → chunk-5BDKRA6U.js} +30 -1
  7. package/dist/{chunk-T6RE76D2.js → chunk-IKGT4MDT.js} +35 -23
  8. package/dist/{chunk-K7UGGWJV.js → chunk-JQM2L2YM.js} +1 -1
  9. package/dist/{chunk-6X62CGMA.js → chunk-ONRY3C2L.js} +3 -0
  10. package/dist/{chunk-IDJAHEG6.js → chunk-QACFKPZP.js} +391 -188
  11. package/dist/{chunk-SJUIIHIA.js → chunk-X6U6BO5D.js} +1 -1
  12. package/dist/{claude-ink-BE56DB6N.js → claude-ink-F554I3GJ.js} +1 -1
  13. package/dist/{cli-3MF6EL2H.js → cli-MAWCV2YR.js} +7 -7
  14. package/dist/cli-main.js +16 -16
  15. package/dist/config/protected-file.d.ts +2 -0
  16. package/dist/config/schema.d.ts +3 -0
  17. package/dist/context/global-instructions.d.ts +12 -0
  18. package/dist/context/manager.d.ts +2 -0
  19. package/dist/desktop/main.js +651 -419
  20. package/dist/desktop-renderer/assets/{index-DCqIrF1S.js → index-CjC0Ibiq.js} +2 -2
  21. package/dist/desktop-renderer/assets/{interactive-terminal-B6GbpzIn.js → interactive-terminal-IjIT3Xoa.js} +1 -1
  22. package/dist/desktop-renderer/index.html +1 -1
  23. package/dist/{doctor-OHCGK52S.js → doctor-SEL32R7M.js} +3 -3
  24. package/dist/harness/local.d.ts +1 -0
  25. package/dist/{load-QK6CMLDF.js → load-RHWXNUCS.js} +2 -2
  26. package/dist/{manager-5SI4MPES.js → manager-IYBNNKUP.js} +2 -2
  27. package/dist/{production-6DIZ6YLQ.js → production-TQROFEPV.js} +6 -6
  28. package/dist/sdk/index.js +6 -6
  29. package/dist/{store-ZIHN6363.js → store-MZZERW7K.js} +2 -2
  30. package/dist/ui/commands.d.ts +11 -3
  31. package/dist/ui/session.d.ts +2 -1
  32. package/package.json +1 -1
  33. package//346/212/200/346/234/257/346/226/271/346/241/210/346/212/245/345/221/212.md +649 -1
@@ -18,7 +18,7 @@ import {
18
18
  useStdout,
19
19
  use_app_default,
20
20
  use_input_default
21
- } from "./chunk-T6RE76D2.js";
21
+ } from "./chunk-IKGT4MDT.js";
22
22
  import {
23
23
  require_react
24
24
  } from "./chunk-PULWAH6E.js";
@@ -34,12 +34,12 @@ import {
34
34
  createGlobTool,
35
35
  createProductionRuntime,
36
36
  isDestructiveTool
37
- } from "./chunk-IDJAHEG6.js";
37
+ } from "./chunk-QACFKPZP.js";
38
38
  import {
39
39
  getGraphemeSegmenter
40
40
  } from "./chunk-TIEOVQW6.js";
41
41
  import "./chunk-OKHV7CTB.js";
42
- import "./chunk-K7UGGWJV.js";
42
+ import "./chunk-JQM2L2YM.js";
43
43
  import {
44
44
  execFileNoThrow
45
45
  } from "./chunk-IU3UBETC.js";
@@ -54,7 +54,7 @@ import {
54
54
  import "./chunk-CVP5OUHD.js";
55
55
  import "./chunk-3563SW4X.js";
56
56
  import "./chunk-RBAZLFKB.js";
57
- import "./chunk-FAJ6YDZK.js";
57
+ import "./chunk-36IDJRLQ.js";
58
58
  import {
59
59
  redactErrorText
60
60
  } from "./chunk-WLZUAVVU.js";
@@ -63,7 +63,7 @@ import {
63
63
  } from "./chunk-RV3EXUXM.js";
64
64
  import "./chunk-IQEEFDEE.js";
65
65
  import "./chunk-GTFP2R5I.js";
66
- import "./chunk-HGTCIHWA.js";
66
+ import "./chunk-5BDKRA6U.js";
67
67
  import {
68
68
  charWidth,
69
69
  createTranscriptState,
@@ -71,11 +71,11 @@ import {
71
71
  thinkingWindow,
72
72
  transcriptReducer,
73
73
  withTimeout
74
- } from "./chunk-SJUIIHIA.js";
74
+ } from "./chunk-X6U6BO5D.js";
75
75
  import {
76
76
  message
77
77
  } from "./chunk-BDX777JR.js";
78
- import "./chunk-6X62CGMA.js";
78
+ import "./chunk-ONRY3C2L.js";
79
79
  import "./chunk-EWD7FWTH.js";
80
80
  import "./chunk-KRWWCVXA.js";
81
81
  import "./chunk-X442CJJH.js";
@@ -1046,7 +1046,10 @@ function TaskStatusLine({
1046
1046
  const thinkingLine = thinkingVisible ? (() => {
1047
1047
  const previous = thinkingScroll.current;
1048
1048
  const state = thinkingWindow(thinking, previous.start, {
1049
- width: Math.max(8, (stdout.columns ?? 80) - 8),
1049
+ // Split task tracks are narrower than the terminal. The rail takes
1050
+ // two cells; measuring against stdout.columns hides the tail behind
1051
+ // the track clip instead of letting the preview advance.
1052
+ width: textWidth === void 0 ? Math.max(8, (stdout.columns ?? 80) - 8) : Math.max(1, textWidth - 2),
1050
1053
  dtMs: time - previous.lastTime
1051
1054
  });
1052
1055
  thinkingScroll.current = { start: state.start, lastTime: time };
@@ -1637,9 +1640,17 @@ function WelcomeCard({
1637
1640
  serviceName,
1638
1641
  workspaceName,
1639
1642
  updateTo,
1640
- columns
1643
+ columns,
1644
+ availableRows = Number.POSITIVE_INFINITY
1641
1645
  }) {
1642
- const wide = Math.max(1, Math.floor(columns)) >= WIDE_WELCOME_COLUMNS;
1646
+ const wide = Math.max(1, Math.floor(columns)) >= WIDE_WELCOME_COLUMNS && availableRows >= 9 + Math.max(serviceName === void 0 ? 0 : 1, updateTo === void 0 ? 0 : 1);
1647
+ const minimal = availableRows < 6 + (updateTo === void 0 ? 0 : 2);
1648
+ if (minimal) {
1649
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Box_default, { width: "100%", flexDirection: "column", children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { bold: true, color: FLAVOR_ACCENT, wrap: "truncate-end", children: "\u25C6 Flavor Code" }),
1651
+ availableRows >= 2 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { dimColor: true, wrap: "truncate-end", children: updateTo === void 0 ? "/help \xB7 /init" : `\u25B2 Update v${updateTo} \xB7 flavor update` }) : null
1652
+ ] });
1653
+ }
1643
1654
  const updateHint = updateTo === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Text, { color: "yellowBright", wrap: "wrap", children: [
1644
1655
  "\u25B2 ",
1645
1656
  "Update available: v",
@@ -2051,7 +2062,10 @@ var PromptHistoryStore = class {
2051
2062
  var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
2052
2063
  var HISTORY_CAP = 200;
2053
2064
  var CLIPBOARD_SHORTCUT_FALLBACK_MS = 300;
2054
- var BUILTIN_SLASH_CANDIDATES = MVP_COMMANDS.map((name) => ({ name, description: COMMAND_DESCRIPTIONS[name] }));
2065
+ var BUILTIN_SLASH_CANDIDATES = [
2066
+ ...MVP_COMMANDS.map((name) => ({ name, description: COMMAND_DESCRIPTIONS[name] })),
2067
+ { name: "queue", description: "Review, edit, or cancel queued follow-ups" }
2068
+ ];
2055
2069
  var PROMPT_HORIZONTAL_PADDING = 1;
2056
2070
  function clonePromptDraft(state) {
2057
2071
  return {
@@ -2108,6 +2122,15 @@ function isOutputToggleShortcut(character, key) {
2108
2122
  function outputToggleShortcut(_platform = process.platform) {
2109
2123
  return "Ctrl+O";
2110
2124
  }
2125
+ function fitFooterActions(columns, actions) {
2126
+ let hint = "";
2127
+ for (const action of actions) {
2128
+ const next = hint.length === 0 ? action : `${hint} \xB7 ${action}`;
2129
+ if (stringWidth(next) > columns) break;
2130
+ hint = next;
2131
+ }
2132
+ return hint || actions[0] || "";
2133
+ }
2111
2134
  function removeLastCliImageOnBackspace(input, cursor, images) {
2112
2135
  if (input.length === 0 && cursor === 0 && images.length > 0) {
2113
2136
  return { handled: true, images: images.slice(0, -1) };
@@ -2209,6 +2232,11 @@ var PendingPromptQueue = class {
2209
2232
  const value = this.#values.pop();
2210
2233
  return value === void 0 ? void 0 : cloneQueuedPrompt(value);
2211
2234
  }
2235
+ removeAt(index) {
2236
+ if (!Number.isInteger(index) || index < 0 || index >= this.#values.length) return void 0;
2237
+ const value = this.#values.splice(index, 1)[0];
2238
+ return value === void 0 ? void 0 : cloneQueuedPrompt(value);
2239
+ }
2212
2240
  take() {
2213
2241
  const value = this.#values.shift();
2214
2242
  return value === void 0 ? void 0 : cloneQueuedPrompt(value);
@@ -2277,7 +2305,7 @@ function appRuntimeOptions(props, output, onApprovalChange) {
2277
2305
  }
2278
2306
  function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEnd }) {
2279
2307
  const { exit } = use_app_default();
2280
- const { stdout } = useStdout();
2308
+ const terminalSize = (0, import_react8.useContext)(TerminalSizeContext);
2281
2309
  const [runtime, setRuntime] = (0, import_react8.useState)();
2282
2310
  const [input, setInput] = (0, import_react8.useState)("");
2283
2311
  const [pastedBlocks, setPastedBlocks] = (0, import_react8.useState)([]);
@@ -2297,16 +2325,22 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2297
2325
  const [mentionSelection, setMentionSelection] = (0, import_react8.useState)(0);
2298
2326
  const [dismissedMentionInput, setDismissedMentionInput] = (0, import_react8.useState)();
2299
2327
  const [pendingPrompts, setPendingPrompts] = (0, import_react8.useState)([]);
2328
+ const [queueOpen, setQueueOpen] = (0, import_react8.useState)(false);
2329
+ const [queueSelection, setQueueSelection] = (0, import_react8.useState)(0);
2330
+ const queueSelectionRef = (0, import_react8.useRef)(0);
2331
+ const [scrollPosition, setScrollPosition] = (0, import_react8.useState)({ behind: false, newOutput: false });
2300
2332
  const [revision, setRevision] = (0, import_react8.useState)(0);
2301
2333
  const [ideContext, setIdeContext] = (0, import_react8.useState)();
2302
2334
  const [questionIndex, setQuestionIndex] = (0, import_react8.useState)(0);
2303
2335
  const [questionAnswers, setQuestionAnswers] = (0, import_react8.useState)({});
2304
2336
  const [customQuestionActive, setCustomQuestionActive] = (0, import_react8.useState)(false);
2305
- const [columns, setColumns] = (0, import_react8.useState)(stdout?.columns ?? 80);
2306
- const [rows, setRows] = (0, import_react8.useState)(stdout?.rows ?? 24);
2337
+ const columns = terminalSize?.columns ?? 80;
2338
+ const rows = terminalSize?.rows ?? 24;
2307
2339
  const [updateTo, setUpdateTo] = (0, import_react8.useState)();
2308
2340
  const [transcript, dispatch] = (0, import_react8.useReducer)(transcriptReducer, void 0, createTranscriptState);
2309
2341
  const scrollRef = (0, import_react8.useRef)(null);
2342
+ const focusScrollRef = (0, import_react8.useRef)(null);
2343
+ const turnElementsRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
2310
2344
  const mainTaskScrollRef = (0, import_react8.useRef)(null);
2311
2345
  const subagentTaskScrollRef = (0, import_react8.useRef)(null);
2312
2346
  const hoveredTaskTrack = (0, import_react8.useRef)(null);
@@ -2373,6 +2407,9 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2373
2407
  t.timer = null;
2374
2408
  }
2375
2409
  if (t.pending.length > 0) {
2410
+ if (scrollRef.current !== null && !scrollRef.current.isSticky()) {
2411
+ setScrollPosition((previous) => previous.newOutput ? previous : { behind: true, newOutput: true });
2412
+ }
2376
2413
  dispatch({ type: "session", event: { type: "text", text: t.pending } });
2377
2414
  t.pending = "";
2378
2415
  }
@@ -2420,6 +2457,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2420
2457
  if (event.type === "clear") {
2421
2458
  flushStreamBuffers();
2422
2459
  dispatch({ type: "clear" });
2460
+ setScrollPosition({ behind: false, newOutput: false });
2423
2461
  return;
2424
2462
  }
2425
2463
  if (event.type === "text") {
@@ -2435,6 +2473,9 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2435
2473
  return;
2436
2474
  }
2437
2475
  flushStreamBuffers();
2476
+ if (scrollRef.current !== null && !scrollRef.current.isSticky()) {
2477
+ setScrollPosition((previous) => previous.newOutput ? previous : { behind: true, newOutput: true });
2478
+ }
2438
2479
  dispatch({ type: "session", event });
2439
2480
  };
2440
2481
  void createProductionRuntime(appRuntimeOptions({
@@ -2557,21 +2598,33 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2557
2598
  controller.abort();
2558
2599
  };
2559
2600
  }, [workspace]);
2560
- (0, import_react8.useEffect)(() => {
2561
- if (!stdout || typeof stdout.on !== "function") return;
2562
- const onResize = () => {
2563
- setColumns(stdout.columns ?? 80);
2564
- setRows(stdout.rows ?? 24);
2565
- };
2566
- stdout.on("resize", onResize);
2567
- onResize();
2568
- return () => {
2569
- stdout.off("resize", onResize);
2570
- };
2571
- }, [stdout]);
2572
2601
  const approval = runtime?.approvals.pending;
2573
2602
  const questions = runtime?.services.questions.pending;
2574
2603
  const memoryReviews = runtime?.memoryReviews.pending ?? [];
2604
+ const focusedDecision = approval !== void 0 || questions !== void 0 && questions.length > 0;
2605
+ const transcriptVisible = runtime !== void 0 && (transcript.completed.length > 0 || transcript.active !== void 0) && !focusedDecision && !queueOpen;
2606
+ (0, import_react8.useEffect)(() => {
2607
+ if (!transcriptVisible) return;
2608
+ const scroll = scrollRef.current;
2609
+ if (scroll === null) return;
2610
+ const update = () => {
2611
+ const behind = !scroll.isSticky();
2612
+ setScrollPosition((previous) => previous.behind === behind && (behind || !previous.newOutput) ? previous : { behind, newOutput: behind && previous.newOutput });
2613
+ };
2614
+ update();
2615
+ return scroll.subscribe(update);
2616
+ }, [transcriptVisible]);
2617
+ (0, import_react8.useEffect)(() => {
2618
+ if (pendingPrompts.length === 0) setQueueOpen(false);
2619
+ setQueueSelection((previous) => {
2620
+ const next = Math.max(0, Math.min(previous, pendingPrompts.length - 1));
2621
+ queueSelectionRef.current = next;
2622
+ return next;
2623
+ });
2624
+ }, [pendingPrompts.length]);
2625
+ (0, import_react8.useEffect)(() => {
2626
+ if (focusedDecision) focusScrollRef.current?.scrollTo(0);
2627
+ }, [focusedDecision, approval?.id, questionIndex]);
2575
2628
  const memoryAutoDismissSeconds = runtime?.memoryReviews.autoDismissSeconds ?? 0;
2576
2629
  (0, import_react8.useEffect)(() => {
2577
2630
  setQuestionIndex(0);
@@ -2652,12 +2705,66 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2652
2705
  }
2653
2706
  };
2654
2707
  use_input_default((character, key, event) => {
2708
+ if (queueOpen && !focusedDecision) {
2709
+ const queue = pendingPromptRef.current;
2710
+ if (key.escape) {
2711
+ setQueueOpen(false);
2712
+ return;
2713
+ }
2714
+ if (key.upArrow || key.downArrow || key.pageUp || key.pageDown || key.wheelUp || key.wheelDown || key.home || key.end) {
2715
+ const delta = key.upArrow ? -1 : key.downArrow ? 1 : key.pageUp ? -5 : key.pageDown ? 5 : key.wheelUp ? -3 : 3;
2716
+ const target = key.home ? 0 : key.end ? queue.size - 1 : queueSelectionRef.current + delta;
2717
+ const next = Math.max(0, Math.min(queue.size - 1, target));
2718
+ queueSelectionRef.current = next;
2719
+ setQueueSelection(next);
2720
+ return;
2721
+ }
2722
+ if (key.ctrl && character.toLowerCase() === "c") {
2723
+ interrupt();
2724
+ return;
2725
+ }
2726
+ if (key.return || !key.ctrl && !key.meta && character.toLowerCase() === "d") {
2727
+ const removed = queue.removeAt(queueSelectionRef.current);
2728
+ if (removed === void 0) return;
2729
+ setPendingPrompts([...queue.values]);
2730
+ if (key.return) {
2731
+ const restoredDraft = restoreQueuedPrompt(removed);
2732
+ promptEditHistory.current.reset();
2733
+ commitPromptDraft(restoredDraft, false);
2734
+ setQueueOpen(false);
2735
+ setClipboardNotice("Queued message moved to draft; sending it again puts it at the end of the queue.");
2736
+ } else if (queue.size === 0) {
2737
+ setQueueOpen(false);
2738
+ setClipboardNotice("Queued message cancelled.");
2739
+ }
2740
+ const next = Math.max(0, Math.min(queueSelectionRef.current, queue.size - 1));
2741
+ queueSelectionRef.current = next;
2742
+ setQueueSelection(next);
2743
+ return;
2744
+ }
2745
+ return;
2746
+ }
2747
+ const focusScroll = focusedDecision || queueOpen ? focusScrollRef.current : null;
2748
+ if (key.home || key.end) {
2749
+ const scroll = focusScroll ?? scrollRef.current;
2750
+ if (scroll !== null) {
2751
+ if (key.end) scroll.scrollToBottom();
2752
+ else scroll.scrollTo(0);
2753
+ }
2754
+ return;
2755
+ }
2756
+ if (!focusedDecision && !queueOpen && slashCompletion === null && mentionCompletion === null && key.ctrl && (key.upArrow || key.downArrow)) {
2757
+ if (jumpToAdjacentTurn(scrollRef.current, turnElementsRef.current, key.upArrow ? "previous" : "next")) {
2758
+ setScrollPosition({ behind: true, newOutput: false });
2759
+ }
2760
+ return;
2761
+ }
2655
2762
  const terminalAction = classifyTerminalInput(
2656
2763
  key,
2657
- transcript.active !== void 0 && slashCompletion === null && mentionCompletion === null
2764
+ (transcript.active !== void 0 || focusedDecision) && slashCompletion === null && mentionCompletion === null
2658
2765
  );
2659
2766
  if (terminalAction?.type === "scroll") {
2660
- const scroll = selectWheelScrollTarget(
2767
+ const scroll = focusScroll ?? selectWheelScrollTarget(
2661
2768
  scrollRef.current,
2662
2769
  mainTaskScrollRef.current,
2663
2770
  subagentTaskScrollRef.current,
@@ -2670,7 +2777,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2670
2777
  return;
2671
2778
  }
2672
2779
  if (terminalAction?.type === "page") {
2673
- const scroll = scrollRef.current;
2780
+ const scroll = focusScroll ?? scrollRef.current;
2674
2781
  if (scroll !== null) jumpScroll(scroll, Math.floor(scroll.getViewportHeight() * terminalAction.fraction));
2675
2782
  return;
2676
2783
  }
@@ -2865,6 +2972,21 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2865
2972
  return;
2866
2973
  }
2867
2974
  if (key.return) {
2975
+ if (/^\/queue\s*$/iu.test(input)) {
2976
+ if (imageAttachments.length > 0) {
2977
+ setClipboardNotice("Send or remove image attachments before opening /queue.");
2978
+ return;
2979
+ }
2980
+ setInput("");
2981
+ setPromptCursor(0);
2982
+ if (pendingPromptRef.current.size > 0) {
2983
+ queueSelectionRef.current = 0;
2984
+ setQueueSelection(0);
2985
+ setQueueOpen(true);
2986
+ setClipboardNotice(void 0);
2987
+ } else setClipboardNotice("No queued messages.");
2988
+ return;
2989
+ }
2868
2990
  if (/^\/paste-image\s*$/iu.test(input)) {
2869
2991
  setInput("");
2870
2992
  setPromptCursor(0);
@@ -2894,7 +3016,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
2894
3016
  })) return;
2895
3017
  setPendingPrompts([...pendingPromptRef.current.values]);
2896
3018
  }
2897
- scrollRef.current?.scrollToBottom();
3019
+ if (delivery === "prompt" || scrollRef.current?.isSticky()) scrollRef.current?.scrollToBottom();
2898
3020
  const nextHistory = [...historyRef.current, submittedText].slice(-HISTORY_CAP);
2899
3021
  historyRef.current = nextHistory;
2900
3022
  historyCursorRef.current = nextHistory.length;
@@ -3036,6 +3158,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
3036
3158
  ...ideContext === void 0 ? {} : { ideContext },
3037
3159
  completedSlashTokenLength: completedTokenLength,
3038
3160
  scrollRef,
3161
+ focusScrollRef,
3039
3162
  mainTaskScrollRef,
3040
3163
  subagentTaskScrollRef,
3041
3164
  onTaskPanelHoverChange: (track) => {
@@ -3050,6 +3173,19 @@ function App({ workspace, home, resumeSession, instanceId, palAlias, onSessionEn
3050
3173
  memoryReviews,
3051
3174
  memoryAutoDismissSeconds,
3052
3175
  pendingPrompts,
3176
+ queueOpen,
3177
+ queueSelection,
3178
+ onQueueSelectionChange: (index) => {
3179
+ queueSelectionRef.current = index;
3180
+ setQueueSelection(index);
3181
+ },
3182
+ scrollBehind: scrollPosition.behind,
3183
+ newOutput: scrollPosition.newOutput,
3184
+ onJumpToLatest: () => scrollRef.current?.scrollToBottom(),
3185
+ onTurnElement: (id, element) => {
3186
+ if (element === null) turnElementsRef.current.delete(id);
3187
+ else turnElementsRef.current.set(id, element);
3188
+ },
3053
3189
  questionIndex,
3054
3190
  questionAnswers,
3055
3191
  customQuestionActive
@@ -3249,11 +3385,19 @@ function TerminalLayout({
3249
3385
  questionIndex = 0,
3250
3386
  questionAnswers = {},
3251
3387
  customQuestionActive = false,
3388
+ queueOpen = false,
3389
+ queueSelection = 0,
3390
+ onQueueSelectionChange,
3391
+ scrollBehind = false,
3392
+ newOutput = false,
3393
+ onJumpToLatest,
3394
+ onTurnElement,
3252
3395
  completion,
3253
3396
  mentionCompletion,
3254
3397
  onMentionSelect,
3255
3398
  completedSlashTokenLength: tokenLength = 0,
3256
3399
  scrollRef,
3400
+ focusScrollRef,
3257
3401
  mainTaskScrollRef,
3258
3402
  subagentTaskScrollRef,
3259
3403
  onTaskPanelHoverChange,
@@ -3282,17 +3426,54 @@ function TerminalLayout({
3282
3426
  () => cliTranscriptWindow(completed, budget.turns, budget.blocks, budget.textChars, budget.blocksPerTurn),
3283
3427
  [completed, budget]
3284
3428
  );
3285
- const questionRows = questions === void 0 ? 0 : 4 + (questions[questionIndex]?.options.length ?? 0) + questions.length * 2;
3286
3429
  const memoryReviewRows = memoryReviews.length === 0 ? 0 : 5;
3287
- const approvalRows = approval === void 0 ? 0 : 3 + (approvalExpanded ? approvalDetailLines(approval).length : 0);
3288
- const fixedBottomRows = approvalRows + questionRows + memoryReviewRows + (pendingPrompts.length === 0 ? 0 : 1) + imageAttachments.length + (clipboardNotice === void 0 ? 0 : 1) + 2;
3430
+ const fixedBottomRows = memoryReviewRows + (pendingPrompts.length === 0 ? 0 : 1) + imageAttachments.length + (clipboardNotice === void 0 ? 0 : 1) + (activeSession ? 1 : 0) + 2;
3289
3431
  const taskPanelRows = taskPanelViewportRows(rows, fixedBottomRows, activeTaskBlocks.length > 0);
3290
3432
  const availableBottomRows = Math.max(1, rows - taskPanelRows - 1);
3291
3433
  const bottomMaxRows = Math.min(availableBottomRows, Math.max(Math.floor(rows / 2), fixedBottomRows + 1));
3292
3434
  const promptMaxLines = Math.max(1, bottomMaxRows - fixedBottomRows);
3435
+ let footerHint;
3436
+ if (completion !== void 0 || mentionCompletion !== void 0) {
3437
+ footerHint = columns < 48 ? "\u2191\u2193 select \xB7 Tab choose \xB7 Esc close" : mentionCompletion !== void 0 ? "\u2191/\u2193 select \xB7 Tab complete \xB7 click choose \xB7 Esc close" : "\u2191/\u2193 select \xB7 Tab complete \xB7 Esc close";
3438
+ } else if (activeSession) {
3439
+ footerHint = fitFooterActions(columns, [
3440
+ "Enter queue",
3441
+ `Esc ${pendingPrompts.length > 0 ? "edit" : "stop"}`,
3442
+ "Ctrl+C cancel",
3443
+ "/steer now",
3444
+ "/queue manage",
3445
+ `${outputShortcut} ${expandedOutput ? "collapse" : "expand"}`
3446
+ ]);
3447
+ } else if (columns < 48) {
3448
+ footerHint = "Enter send \xB7 Ctrl+C exit";
3449
+ } else if (columns < 96) {
3450
+ footerHint = `Enter send \xB7 Ctrl+C exit \xB7 \u2191\u2193 history \xB7 ${outputShortcut} output`;
3451
+ } else {
3452
+ footerHint = `Enter send \xB7 \u2191\u2193/Ctrl/Cmd+R history \xB7 ${outputShortcut} ${expandedOutput ? "collapse all output" : "expand all output"} \xB7 Ctrl+C exit`;
3453
+ }
3454
+ if (approval !== void 0 || questions !== void 0 && questions.length > 0 || queueOpen) {
3455
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3456
+ FocusedCliPanel,
3457
+ {
3458
+ rows,
3459
+ columns,
3460
+ input,
3461
+ promptCursor,
3462
+ ...approval === void 0 ? {} : { approval },
3463
+ approvalExpanded,
3464
+ ...questions === void 0 ? {} : { questions },
3465
+ questionIndex,
3466
+ customQuestionActive,
3467
+ pendingPrompts,
3468
+ queueSelection,
3469
+ ...onQueueSelectionChange === void 0 ? {} : { onQueueSelectionChange },
3470
+ ...focusScrollRef === void 0 ? {} : { focusScrollRef }
3471
+ }
3472
+ );
3473
+ }
3293
3474
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { height: rows, width: "100%", flexDirection: "column", overflow: "hidden", children: [
3294
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ScrollBox_default, { ...scrollRef === void 0 ? {} : { ref: scrollRef }, flexGrow: 1, flexDirection: "column", stickyScroll: true, children: [
3295
- showWelcome ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(WelcomeCard, { model, ...serviceName === void 0 ? {} : { serviceName }, workspaceName, ...updateTo === void 0 ? {} : { updateTo }, columns }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { dimColor: true, children: [
3475
+ showWelcome ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexGrow: 1, flexShrink: 1, flexDirection: "column", overflow: "hidden", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(WelcomeCard, { model, ...serviceName === void 0 ? {} : { serviceName }, workspaceName, ...updateTo === void 0 ? {} : { updateTo }, columns, availableRows: Math.max(0, rows - taskPanelRows - fixedBottomRows - 1) }) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ScrollBox_default, { ...scrollRef === void 0 ? {} : { ref: scrollRef }, flexGrow: 1, flexDirection: "column", stickyScroll: true, children: [
3476
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { dimColor: true, children: [
3296
3477
  "flavor \xB7 ",
3297
3478
  model,
3298
3479
  " \xB7 ",
@@ -3308,15 +3489,20 @@ function TerminalLayout({
3308
3489
  outputShortcut,
3309
3490
  " to view all"
3310
3491
  ] }) : null,
3311
- completedWindow.turns.map((turn, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
3492
+ completedWindow.turns.map((turn, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { ref: (element) => onTurnElement?.(turn.id, element), flexDirection: "column", children: [
3312
3493
  index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TurnSeparator, { width: columns }) : null,
3313
3494
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TurnView, { turn, interactive: false, workspaceName, expandedOutput })
3314
3495
  ] }, turn.id)),
3315
- activeWithoutTasks === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
3496
+ activeWithoutTasks === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { ref: (element) => onTurnElement?.(activeWithoutTasks.id, element), flexDirection: "column", children: [
3316
3497
  completedWindow.turns.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TurnSeparator, { width: columns }) : null,
3317
3498
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TurnView, { turn: activeWithoutTasks, interactive: activeSession, workspaceName, expandedOutput })
3318
3499
  ] })
3319
3500
  ] }),
3501
+ !scrollBehind || showWelcome ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { width: "100%", onClick: onJumpToLatest, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "yellow", wrap: "truncate-end", children: [
3502
+ newOutput ? "\u2193 New output" : "\u2191 Reading earlier output",
3503
+ " \xB7 End latest",
3504
+ columns >= 72 ? " \xB7 Ctrl+\u2191/\u2193 turns" : ""
3505
+ ] }) }),
3320
3506
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3321
3507
  TaskProgressPanel,
3322
3508
  {
@@ -3335,49 +3521,12 @@ function TerminalLayout({
3335
3521
  mentionCompletion === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MentionMenu, { completion: mentionCompletion, ...onMentionSelect === void 0 ? {} : { onSelect: onMentionSelect } })
3336
3522
  ] }),
3337
3523
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", flexShrink: 0, maxHeight: bottomMaxRows, width: "100%", overflowY: "hidden", children: [
3338
- approval === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", marginBottom: 1, children: [
3339
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "magenta", children: [
3340
- "\u250C\u2500 approval \xB7 ",
3341
- approval.tool
3342
- ] }),
3343
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { wrap: "truncate-end", color: "magentaBright", children: [
3344
- "\u2502 ",
3345
- approval.reason ?? "This action needs permission."
3346
- ] }),
3347
- approvalExpanded ? approvalDetailLines(approval).map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "magentaBright", wrap: "truncate-end", children: [
3348
- "\u2502 ",
3349
- line
3350
- ] }, `${approval.id}:detail:${index}`)) : null,
3351
- isDestructiveTool(approval.tool) || approval.allowAlways === false ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { bold: true, color: "magenta", children: [
3352
- "\u2514\u2500 ",
3353
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "cyan", children: "v" }),
3354
- "=details / ",
3355
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "green", children: "y" }),
3356
- "=once / ",
3357
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "cyan", children: "e" }),
3358
- "=accept edits / ",
3359
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "red", children: "n" }),
3360
- "=deny"
3361
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { bold: true, color: "magenta", children: [
3362
- "\u2514\u2500 ",
3363
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "cyan", children: "v" }),
3364
- "=details / ",
3365
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "green", children: "y" }),
3366
- "=once / ",
3367
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "yellow", children: "a" }),
3368
- "=same-type / ",
3369
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "cyan", children: "e" }),
3370
- "=accept edits / ",
3371
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "red", children: "n" }),
3372
- "=deny"
3373
- ] })
3374
- ] }),
3375
- !questions || questions.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionCards, { questions, activeIndex: questionIndex, answers: questionAnswers, customActive: customQuestionActive }),
3376
3524
  memoryReviews.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MemoryReviewCards, { reviews: memoryReviews, autoDismissSeconds: memoryAutoDismissSeconds }),
3525
+ !activeSession ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "cyan", wrap: "truncate-end", children: columns < 48 ? "Running \xB7 Enter queues \xB7 /queue list" : "Running \xB7 /queue manage \xB7 Enter queues next \xB7 /steer acts now" }),
3377
3526
  pendingPrompts.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "yellow", wrap: "truncate-end", children: [
3378
3527
  "Pending (",
3379
3528
  pendingPrompts.length,
3380
- ") \xB7 ",
3529
+ ") \xB7 /queue manage \xB7 ",
3381
3530
  queuedPromptLabel(pendingPrompts.at(-1)),
3382
3531
  " \xB7 Esc edit latest"
3383
3532
  ] }),
@@ -3404,7 +3553,8 @@ function TerminalLayout({
3404
3553
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3405
3554
  FooterStatus,
3406
3555
  {
3407
- hint: completion !== void 0 ? "\u2191/\u2193 select \xB7 Tab complete \xB7 Esc close" : mentionCompletion !== void 0 ? "\u2191/\u2193 select \xB7 Tab complete \xB7 click choose \xB7 Esc close" : activeSession ? `Esc ${pendingPrompts.length > 0 ? "edit latest" : "stop"} \xB7 Ctrl+C cancel \xB7 Enter queue \xB7 Ctrl/Cmd+R history \xB7 ${outputShortcut} ${expandedOutput ? "collapse all output" : "expand all output"}` : `Enter send \xB7 \u2191\u2193/Ctrl/Cmd+R history \xB7 ${outputShortcut} ${expandedOutput ? "collapse all output" : "expand all output"} \xB7 Ctrl+C exit`,
3556
+ hint: footerHint,
3557
+ columns,
3408
3558
  ...ideContext === void 0 ? {} : { ideContext }
3409
3559
  }
3410
3560
  )
@@ -3414,12 +3564,14 @@ function TerminalLayout({
3414
3564
  }
3415
3565
  function FooterStatus({
3416
3566
  hint,
3567
+ columns,
3417
3568
  ideContext
3418
3569
  }) {
3419
3570
  const ide = ideFooterPresentation(ideContext);
3571
+ const showIde = ide !== void 0 && (columns === void 0 || stringWidth(hint) + stringWidth(ide) + 3 <= columns);
3420
3572
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "row", width: "100%", justifyContent: "space-between", children: [
3421
3573
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexGrow: 1, flexShrink: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { dimColor: true, wrap: "truncate-end", children: hint }) }),
3422
- ide === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexShrink: 0, marginLeft: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "cyan", wrap: "truncate-end", children: [
3574
+ !showIde ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexShrink: 0, marginLeft: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "cyan", wrap: "truncate-end", children: [
3423
3575
  "\u29C9 ",
3424
3576
  ide
3425
3577
  ] }) })
@@ -3432,42 +3584,110 @@ function ideFooterPresentation(context) {
3432
3584
  const count = Math.max(1, endLine - context.selection.start.line + 1);
3433
3585
  return `${count} ${count === 1 ? "line" : "lines"} selected`;
3434
3586
  }
3435
- function QuestionCards({ questions, activeIndex, answers, customActive }) {
3436
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexDirection: "column", marginBottom: 1, children: questions.map((q, qi) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", marginBottom: qi < questions.length - 1 ? 1 : 0, children: [
3437
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { bold: true, color: "cyan", children: [
3438
- "\u250C\u2500 ",
3439
- q.header
3440
- ] }),
3441
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { wrap: "truncate-end", color: "cyanBright", children: [
3442
- "\u2502 ",
3443
- q.question
3444
- ] }),
3445
- qi < activeIndex ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "green", children: [
3446
- "\u2502 \u2713 ",
3447
- answers[qi]
3448
- ] }) : qi > activeIndex ? null : q.options.map((opt, oi) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "cyan", children: [
3449
- "\u2502 ",
3450
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, color: "green", children: oi + 1 }),
3451
- ". ",
3452
- opt.label,
3453
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { dimColor: true, children: [
3454
- " ",
3455
- opt.description
3456
- ] })
3457
- ] }, oi)),
3458
- qi === activeIndex ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3459
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "cyan", children: [
3460
- "\u2502 ",
3461
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, color: "green", children: q.options.length + 1 }),
3462
- ". Custom input",
3463
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { dimColor: true, children: " Type your own answer" })
3587
+ function FocusedCliPanel({
3588
+ rows,
3589
+ columns,
3590
+ input,
3591
+ promptCursor,
3592
+ approval,
3593
+ approvalExpanded,
3594
+ questions,
3595
+ questionIndex,
3596
+ customQuestionActive,
3597
+ pendingPrompts,
3598
+ queueSelection,
3599
+ onQueueSelectionChange,
3600
+ focusScrollRef
3601
+ }) {
3602
+ if (approval !== void 0) {
3603
+ const allowAlways = !isDestructiveTool(approval.tool) && approval.allowAlways !== false;
3604
+ const narrow = columns < 36;
3605
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { height: rows, width: "100%", flexDirection: "column", overflow: "hidden", children: [
3606
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { bold: true, color: "magenta", wrap: "truncate-end", children: [
3607
+ "Approval \xB7 ",
3608
+ approval.tool
3464
3609
  ] }),
3465
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { dimColor: true, color: "cyan", children: [
3466
- "\u2514\u2500 ",
3467
- customActive ? "Type below and press Enter; Esc returns to choices" : `Press 1-${q.options.length + 1} to choose; Esc dismisses`
3610
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ScrollBox_default, { ...focusScrollRef === void 0 ? {} : { ref: focusScrollRef }, flexGrow: 1, flexDirection: "column", children: [
3611
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "magentaBright", wrap: "wrap", children: approval.reason ?? "This action needs permission." }),
3612
+ approvalExpanded ? approvalDetailLines(approval).map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "magentaBright", wrap: "wrap", children: line }, `${approval.id}:detail:${index}`)) : null
3613
+ ] }),
3614
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, color: "magenta", wrap: "truncate-end", children: narrow ? "y once \xB7 n deny" : "y=once \xB7 n=deny \xB7 Esc=deny" }),
3615
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "magenta", wrap: "truncate-end", children: [
3616
+ narrow ? "v details \xB7 e edits" : "v=details \xB7 e=accept edits",
3617
+ allowAlways && !narrow ? " \xB7 a=same-type" : ""
3618
+ ] }),
3619
+ allowAlways && narrow && rows >= 5 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "magenta", wrap: "truncate-end", children: "a same-type \xB7 Esc deny" }) : null
3620
+ ] });
3621
+ }
3622
+ const question = questions?.[Math.min(questionIndex, questions.length - 1)];
3623
+ if (question !== void 0) {
3624
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { height: rows, width: "100%", flexDirection: "column", overflow: "hidden", children: [
3625
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { bold: true, color: "cyan", wrap: "truncate-end", children: [
3626
+ "Question ",
3627
+ questionIndex + 1,
3628
+ "/",
3629
+ questions.length,
3630
+ " \xB7 ",
3631
+ question.header
3632
+ ] }),
3633
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ScrollBox_default, { ...focusScrollRef === void 0 ? {} : { ref: focusScrollRef }, flexGrow: 1, flexDirection: "column", children: [
3634
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "cyanBright", wrap: "wrap", children: question.question }),
3635
+ question.options.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "cyan", wrap: "wrap", children: [
3636
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { bold: true, color: "green", children: [
3637
+ index + 1,
3638
+ ". ",
3639
+ option.label
3640
+ ] }),
3641
+ option.description ? ` ${option.description}` : ""
3642
+ ] }, index)),
3643
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: "cyan", children: [
3644
+ question.options.length + 1,
3645
+ ". Custom input"
3646
+ ] })
3647
+ ] }),
3648
+ customQuestionActive ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PromptLine, { input, pastedBlocks: [], cursor: promptCursor, columns, maxVisibleLines: Math.max(1, Math.min(3, Math.floor(rows / 3))) }) : null,
3649
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "cyan", wrap: "truncate-end", children: customQuestionActive ? columns < 40 ? "Enter answer \xB7 Esc choices" : "Enter=answer \xB7 Esc=choices \xB7 PgUp/PgDn=scroll" : columns < 40 ? `1-${question.options.length + 1} choose \xB7 Esc cancel` : `1-${question.options.length + 1}=choose \xB7 Esc=cancel \xB7 PgUp/PgDn=scroll` })
3650
+ ] });
3651
+ }
3652
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { height: rows, width: "100%", flexDirection: "column", overflow: "hidden", children: [
3653
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { bold: true, color: "yellow", wrap: "truncate-end", children: [
3654
+ "Queued messages (",
3655
+ pendingPrompts.length,
3656
+ ")"
3657
+ ] }),
3658
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScrollBox_default, { ...focusScrollRef === void 0 ? {} : { ref: focusScrollRef }, flexGrow: 1, flexDirection: "column", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3659
+ QueueItems,
3660
+ {
3661
+ items: pendingPrompts,
3662
+ selection: queueSelection,
3663
+ ...focusScrollRef === void 0 ? {} : { scrollRef: focusScrollRef },
3664
+ ...onQueueSelectionChange === void 0 ? {} : { onSelect: onQueueSelectionChange }
3665
+ }
3666
+ ) }),
3667
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, color: "yellow", wrap: "truncate-end", children: columns < 48 ? "Enter edit \xB7 d cancel" : "Enter=edit selected \xB7 d=cancel selected" }),
3668
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "yellow", wrap: "truncate-end", children: columns < 48 ? "\u2191\u2193 select \xB7 Esc close" : "\u2191/\u2193=select \xB7 PgUp/PgDn=jump \xB7 Esc=close" })
3669
+ ] });
3670
+ }
3671
+ function QueueItems({ items, selection, scrollRef, onSelect }) {
3672
+ const selectedElement = (0, import_react8.useRef)(null);
3673
+ (0, import_react8.useEffect)(() => {
3674
+ if (selectedElement.current !== null) scrollRef?.current?.scrollToElement(selectedElement.current);
3675
+ }, [selection, items.length, scrollRef]);
3676
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexDirection: "column", width: "100%", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3677
+ Box_default,
3678
+ {
3679
+ ref: index === selection ? selectedElement : void 0,
3680
+ onClick: () => onSelect?.(index),
3681
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: index === selection ? "yellowBright" : void 0, bold: index === selection, wrap: "wrap", children: [
3682
+ index === selection ? "\u276F" : " ",
3683
+ " ",
3684
+ index + 1,
3685
+ ". ",
3686
+ queuedPromptLabel(item)
3468
3687
  ] })
3469
- ] }) : null
3470
- ] }, qi)) });
3688
+ },
3689
+ `${index}:${item.text}`
3690
+ )) });
3471
3691
  }
3472
3692
  function MemoryReviewCards({ reviews, autoDismissSeconds }) {
3473
3693
  const review = reviews[0];
@@ -3565,6 +3785,15 @@ function jumpScroll(scroll, delta) {
3565
3785
  scroll.scrollTo(Math.max(0, target));
3566
3786
  }
3567
3787
  }
3788
+ function jumpToAdjacentTurn(scroll, elements, direction) {
3789
+ if (scroll === null) return false;
3790
+ const top = scroll.getScrollTop() + scroll.getPendingDelta();
3791
+ const positions = [...elements.values()].map((element) => ({ element, top: element.yogaNode?.getComputedTop() })).filter((item) => item.top !== void 0).sort((left, right) => left.top - right.top);
3792
+ const target = direction === "previous" ? positions.filter((item) => item.top < top - 1).at(-1) : positions.find((item) => item.top > top + 1);
3793
+ if (target === void 0) return false;
3794
+ scroll.scrollToElement(target.element);
3795
+ return true;
3796
+ }
3568
3797
  function selectWheelScrollTarget(transcript, mainTasks, subagentTasks, hoveredTrack) {
3569
3798
  if (hoveredTrack === "main" && mainTasks !== null) return mainTasks;
3570
3799
  if (hoveredTrack === "subagent" && subagentTasks !== null) return subagentTasks;
@@ -4496,6 +4725,7 @@ export {
4496
4725
  isOutputToggleShortcut,
4497
4726
  isPlatformShortcut,
4498
4727
  jumpScroll,
4728
+ jumpToAdjacentTurn,
4499
4729
  navigateHistory,
4500
4730
  navigatePromptHistory,
4501
4731
  outputToggleShortcut,