flavor-code 1.4.0-beta.10 → 1.4.0-beta.12

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.
@@ -19,9 +19,9 @@ import {
19
19
  thinkingWindow,
20
20
  transcriptReducer,
21
21
  withTimeout
22
- } from "./chunk-BYHO2CA5.js";
22
+ } from "./chunk-AOOVLNX4.js";
23
23
  import "./chunk-N5MXHJKD.js";
24
- import "./chunk-EXOSMO57.js";
24
+ import "./chunk-7YFHRORG.js";
25
25
  import {
26
26
  Box_default,
27
27
  ClockContext,
@@ -34,13 +34,15 @@ import {
34
34
  instances_default,
35
35
  osc,
36
36
  shiftAnchor,
37
+ stringWidth,
37
38
  stripAnsi,
38
39
  useStdout,
39
40
  use_app_default,
40
41
  use_input_default
41
- } from "./chunk-XMRKRPNC.js";
42
+ } from "./chunk-VMQWXQEC.js";
42
43
  import {
43
- execFileNoThrow
44
+ execFileNoThrow,
45
+ getGraphemeSegmenter
44
46
  } from "./chunk-ZJCAQXA7.js";
45
47
  import "./chunk-S32JRDZK.js";
46
48
 
@@ -969,7 +971,13 @@ function wrapPromptInput(input, codePointCursor, options) {
969
971
  // src/ui/task-progress.tsx
970
972
  import { useRef as useRef3 } from "react";
971
973
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
972
- function TaskStatusLine({ block, interactive }) {
974
+ function TaskStatusLine({
975
+ block,
976
+ interactive,
977
+ textWidth,
978
+ maxTextLines,
979
+ showRoleBadge = true
980
+ }) {
973
981
  const running = block.state === "running";
974
982
  const { stdout } = useStdout();
975
983
  const foreground = interactive && (block.activity === "model" || block.task?.role === "main");
@@ -982,6 +990,8 @@ function TaskStatusLine({ block, interactive }) {
982
990
  const elapsed = block.startedAt === void 0 ? startedAt.current === void 0 ? 0 : Math.max(0, time - startedAt.current) : Math.max(0, Date.now() - block.startedAt);
983
991
  const presentation = statusPresentation(block, elapsed, foreground);
984
992
  const { metaColor, metaLabel, statusLabel, statusColor, text } = presentation;
993
+ const badge = showRoleBadge ? presentation.badge : void 0;
994
+ const badgeColor = presentation.badgeColor;
985
995
  let before = text;
986
996
  let after = "";
987
997
  if (statusLabel !== void 0) {
@@ -1007,14 +1017,26 @@ function TaskStatusLine({ block, interactive }) {
1007
1017
  thinkingScroll.current = { start: state.start, lastTime: time };
1008
1018
  return state.text;
1009
1019
  })() : void 0;
1020
+ const textSegments = [
1021
+ { text: `${presentation.glyph} `, color: presentation.color },
1022
+ ...badge ? [{ text: `${badge} `, color: badgeColor }] : [],
1023
+ { text: before, color: presentation.color },
1024
+ ...statusLabel === void 0 ? [] : [
1025
+ { text: " \xB7 ", color: presentation.color },
1026
+ { text: statusLabel, color: statusColor ?? presentation.color }
1027
+ ],
1028
+ ...after ? [{ text: after, color: presentation.color }] : [],
1029
+ ...metaLabel === void 0 ? [] : [{ text: ` ${metaLabel}`, color: metaColor ?? "ansi:blackBright" }]
1030
+ ];
1031
+ const boundedText = textWidth === void 0 || maxTextLines === void 0 ? void 0 : limitTaskTextSegments(textSegments, textWidth, maxTextLines).segments;
1010
1032
  return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "column", width: "100%", children: [
1011
- /* @__PURE__ */ jsxs2(Box_default, { ref, flexDirection: "row", children: [
1033
+ /* @__PURE__ */ jsx3(Box_default, { ref, flexDirection: "row", width: "100%", children: boundedText === void 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1012
1034
  /* @__PURE__ */ jsxs2(Text, { ...presentation.color === void 0 ? {} : { color: presentation.color }, children: [
1013
1035
  presentation.glyph,
1014
1036
  " "
1015
1037
  ] }),
1016
- presentation.badge ? /* @__PURE__ */ jsxs2(Text, { color: presentation.badgeColor, children: [
1017
- presentation.badge,
1038
+ badge ? /* @__PURE__ */ jsxs2(Text, { color: badgeColor, children: [
1039
+ badge,
1018
1040
  " "
1019
1041
  ] }) : null,
1020
1042
  /* @__PURE__ */ jsx3(Text, { ...presentation.color === void 0 ? {} : { color: presentation.color }, children: before }),
@@ -1027,10 +1049,69 @@ function TaskStatusLine({ block, interactive }) {
1027
1049
  " ",
1028
1050
  metaLabel
1029
1051
  ] })
1030
- ] }),
1052
+ ] }) : /* @__PURE__ */ jsx3(Text, { children: boundedText.map((segment, index) => /* @__PURE__ */ jsx3(Text, { ...segment.color === void 0 ? {} : { color: segment.color }, children: segment.text }, index)) }) }),
1031
1053
  thinkingLine === void 0 ? null : /* @__PURE__ */ jsx3(ThinkingLineView, { text: thinkingLine })
1032
1054
  ] });
1033
1055
  }
1056
+ function limitTaskTextSegments(segments, width, maxLines = 3) {
1057
+ const lineWidth = Math.max(3, Math.floor(width));
1058
+ const lineLimit = Math.max(1, Math.floor(maxLines));
1059
+ const lines = [[]];
1060
+ const widths = [0];
1061
+ let truncated = false;
1062
+ outer: for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex += 1) {
1063
+ const segment = segments[segmentIndex];
1064
+ for (const { segment: grapheme } of getGraphemeSegmenter().segment(segment.text)) {
1065
+ if (grapheme === "\n" || grapheme === "\r" || grapheme === "\r\n") {
1066
+ if (lines.length >= lineLimit) {
1067
+ truncated = true;
1068
+ break outer;
1069
+ }
1070
+ lines.push([]);
1071
+ widths.push(0);
1072
+ continue;
1073
+ }
1074
+ const glyphWidth = stringWidth(grapheme);
1075
+ const lineIndex = lines.length - 1;
1076
+ if (glyphWidth > 0 && widths[lineIndex] + glyphWidth > lineWidth && lines[lineIndex].length > 0) {
1077
+ if (lines.length >= lineLimit) {
1078
+ truncated = true;
1079
+ break outer;
1080
+ }
1081
+ lines.push([]);
1082
+ widths.push(0);
1083
+ }
1084
+ const target = lines.length - 1;
1085
+ lines[target].push({ value: grapheme, width: glyphWidth, segmentIndex });
1086
+ widths[target] = widths[target] + glyphWidth;
1087
+ }
1088
+ }
1089
+ if (truncated) {
1090
+ const lastIndex = lines.length - 1;
1091
+ const last = lines[lastIndex];
1092
+ while (last.length > 0 && widths[lastIndex] > lineWidth - 3) {
1093
+ widths[lastIndex] = widths[lastIndex] - last.pop().width;
1094
+ }
1095
+ while (last.length > 0 && /^\s$/u.test(last.at(-1).value)) {
1096
+ widths[lastIndex] = widths[lastIndex] - last.pop().width;
1097
+ }
1098
+ last.push({ value: "...", width: 3, segmentIndex: last.at(-1)?.segmentIndex ?? 0 });
1099
+ }
1100
+ const output = [];
1101
+ const append = (value, segmentIndex) => {
1102
+ const previous = output.at(-1);
1103
+ if (previous?.segmentIndex === segmentIndex) previous.text += value;
1104
+ else output.push({ text: value, color: segments[segmentIndex]?.color, segmentIndex });
1105
+ };
1106
+ lines.forEach((line, lineIndex) => {
1107
+ if (lineIndex > 0) append("\n", line[0]?.segmentIndex ?? output.at(-1)?.segmentIndex ?? 0);
1108
+ for (const token of line) append(token.value, token.segmentIndex);
1109
+ });
1110
+ return {
1111
+ truncated,
1112
+ segments: output.map(({ text, color }) => ({ text, ...color === void 0 ? {} : { color } }))
1113
+ };
1114
+ }
1034
1115
  var THINKING_RAIL = "#416f84";
1035
1116
  var THINKING_TEXT = "#91a0a8";
1036
1117
  function ThinkingLineView({ text }) {
@@ -1039,13 +1120,16 @@ function ThinkingLineView({ text }) {
1039
1120
  /* @__PURE__ */ jsx3(Text, { color: THINKING_TEXT, wrap: "truncate-end", children: text })
1040
1121
  ] });
1041
1122
  }
1042
- var SPLIT_TRACK_MIN_COLUMNS = 72;
1123
+ var SPLIT_TRACK_MIN_COLUMNS = 96;
1124
+ var SPLIT_TRACK_GUTTER_COLUMNS = 3;
1125
+ var SPLIT_TRACK_MAIN_RATIO = 0.44;
1043
1126
  function TaskProgressPanel({
1044
1127
  blocks,
1045
1128
  interactive,
1046
1129
  maxHeight = 8,
1047
1130
  columns = 80,
1048
- scrollRef,
1131
+ mainScrollRef,
1132
+ subagentScrollRef,
1049
1133
  onHoverChange
1050
1134
  }) {
1051
1135
  if (blocks.length === 0 || maxHeight <= 0) return null;
@@ -1054,54 +1138,210 @@ function TaskProgressPanel({
1054
1138
  const hasTasks = taskBlocks.length > 0;
1055
1139
  const hasSubagents = subagentBlocks.length > 0;
1056
1140
  const split = hasTasks && hasSubagents && columns >= SPLIT_TRACK_MIN_COLUMNS;
1057
- return /* @__PURE__ */ jsxs2(
1141
+ const hoverProps = (track) => ({
1142
+ onMouseEnter: () => onHoverChange?.(track)
1143
+ });
1144
+ return /* @__PURE__ */ jsx3(
1058
1145
  Box_default,
1059
1146
  {
1060
1147
  flexDirection: "column",
1061
1148
  flexShrink: 0,
1062
1149
  width: "100%",
1063
1150
  maxHeight,
1064
- onMouseEnter: () => onHoverChange?.(true),
1065
- onMouseLeave: () => onHoverChange?.(false),
1066
- children: [
1067
- split ? /* @__PURE__ */ jsx3(SplitTrackHeaders, {}) : /* @__PURE__ */ jsx3(TrackHeader, { role: hasTasks ? "main" : "subagent" }),
1068
- maxHeight > 1 ? /* @__PURE__ */ jsx3(
1069
- ScrollBox_default,
1070
- {
1071
- ...scrollRef === void 0 ? {} : { ref: scrollRef },
1072
- flexDirection: "column",
1073
- flexShrink: 1,
1074
- width: "100%",
1075
- maxHeight: maxHeight - 1,
1076
- children: split ? pairedTrackRows(taskBlocks, subagentBlocks).map(([task, subagent], index) => /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "row", width: "100%", columnGap: 2, children: [
1077
- /* @__PURE__ */ jsx3(Box_default, { flexBasis: 0, flexGrow: 1, minWidth: 0, flexDirection: "column", children: task === void 0 ? null : /* @__PURE__ */ jsx3(TaskStatusLine, { block: task, interactive }) }),
1078
- /* @__PURE__ */ jsx3(Box_default, { flexBasis: 0, flexGrow: 1, minWidth: 0, flexDirection: "column", children: subagent === void 0 ? null : /* @__PURE__ */ jsx3(TaskStatusLine, { block: subagent, interactive }) })
1079
- ] }, `${task?.id ?? "task"}:${subagent?.id ?? "subagent"}:${index}`)) : hasTasks && hasSubagents ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1080
- taskBlocks.map((block) => /* @__PURE__ */ jsx3(TaskStatusLine, { block, interactive }, block.id)),
1081
- /* @__PURE__ */ jsx3(TrackHeader, { role: "subagent" }),
1082
- subagentBlocks.map((block) => /* @__PURE__ */ jsx3(TaskStatusLine, { block, interactive }, block.id))
1083
- ] }) : (hasTasks ? taskBlocks : subagentBlocks).map((block) => /* @__PURE__ */ jsx3(TaskStatusLine, { block, interactive }, block.id))
1084
- }
1085
- ) : null
1086
- ]
1151
+ onMouseLeave: () => onHoverChange?.(null),
1152
+ children: split ? /* @__PURE__ */ jsx3(
1153
+ SplitTracks,
1154
+ {
1155
+ taskBlocks,
1156
+ subagentBlocks,
1157
+ interactive,
1158
+ height: maxHeight,
1159
+ columns,
1160
+ mainScrollRef,
1161
+ subagentScrollRef,
1162
+ hoverProps
1163
+ }
1164
+ ) : hasTasks && hasSubagents ? /* @__PURE__ */ jsx3(
1165
+ StackedTracks,
1166
+ {
1167
+ taskBlocks,
1168
+ subagentBlocks,
1169
+ interactive,
1170
+ height: maxHeight,
1171
+ columns,
1172
+ mainScrollRef,
1173
+ subagentScrollRef,
1174
+ hoverProps
1175
+ }
1176
+ ) : /* @__PURE__ */ jsx3(
1177
+ SingleTrack,
1178
+ {
1179
+ role: hasTasks ? "main" : "subagent",
1180
+ blocks: hasTasks ? taskBlocks : subagentBlocks,
1181
+ interactive,
1182
+ height: maxHeight,
1183
+ width: columns,
1184
+ scrollRef: hasTasks ? mainScrollRef : subagentScrollRef,
1185
+ hoverProps
1186
+ }
1187
+ )
1087
1188
  }
1088
1189
  );
1089
1190
  }
1090
- function TrackHeader({ role }) {
1091
- return /* @__PURE__ */ jsxs2(Text, { dimColor: true, children: [
1092
- "\u2500\u2500 ",
1093
- role === "main" ? "task plan" : "subagent exploration",
1094
- " \u2500\u2500"
1191
+ function SplitTracks({
1192
+ taskBlocks,
1193
+ subagentBlocks,
1194
+ interactive,
1195
+ height,
1196
+ columns,
1197
+ mainScrollRef,
1198
+ subagentScrollRef,
1199
+ hoverProps
1200
+ }) {
1201
+ const contentHeight = Math.max(0, height - 1);
1202
+ const availableWidth = columns - SPLIT_TRACK_GUTTER_COLUMNS;
1203
+ const leftWidth = Math.max(1, Math.floor(availableWidth * SPLIT_TRACK_MAIN_RATIO));
1204
+ const rightWidth = Math.max(1, availableWidth - leftWidth);
1205
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
1206
+ /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "row", width: "100%", children: [
1207
+ /* @__PURE__ */ jsx3(Box_default, { width: leftWidth, ...hoverProps("main"), children: /* @__PURE__ */ jsx3(TrackHeader, { role: "main", count: taskBlocks.length, width: leftWidth }) }),
1208
+ /* @__PURE__ */ jsx3(Text, { color: "ansi:white", children: "\u2500\u252C\u2500" }),
1209
+ /* @__PURE__ */ jsx3(Box_default, { width: rightWidth, ...hoverProps("subagent"), children: /* @__PURE__ */ jsx3(TrackHeader, { role: "subagent", count: subagentBlocks.length, width: rightWidth }) })
1210
+ ] }),
1211
+ contentHeight <= 0 ? null : /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "row", width: "100%", height: contentHeight, children: [
1212
+ /* @__PURE__ */ jsx3(Box_default, { width: leftWidth, minWidth: 0, flexDirection: "column", ...hoverProps("main"), children: /* @__PURE__ */ jsx3(
1213
+ TrackScrollBox,
1214
+ {
1215
+ ref: mainScrollRef,
1216
+ blocks: taskBlocks,
1217
+ interactive,
1218
+ height: contentHeight,
1219
+ width: leftWidth,
1220
+ maxTextLines: 2
1221
+ }
1222
+ ) }),
1223
+ /* @__PURE__ */ jsx3(TrackDivider, { height: contentHeight }),
1224
+ /* @__PURE__ */ jsx3(Box_default, { width: rightWidth, minWidth: 0, flexDirection: "column", ...hoverProps("subagent"), children: /* @__PURE__ */ jsx3(
1225
+ TrackScrollBox,
1226
+ {
1227
+ ref: subagentScrollRef,
1228
+ blocks: subagentBlocks,
1229
+ interactive,
1230
+ height: contentHeight,
1231
+ width: rightWidth,
1232
+ maxTextLines: 2
1233
+ }
1234
+ ) })
1235
+ ] })
1095
1236
  ] });
1096
1237
  }
1097
- function SplitTrackHeaders() {
1098
- return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "row", width: "100%", columnGap: 2, children: [
1099
- /* @__PURE__ */ jsx3(Box_default, { flexBasis: 0, flexGrow: 1, minWidth: 0, children: /* @__PURE__ */ jsx3(TrackHeader, { role: "main" }) }),
1100
- /* @__PURE__ */ jsx3(Box_default, { flexBasis: 0, flexGrow: 1, minWidth: 0, children: /* @__PURE__ */ jsx3(TrackHeader, { role: "subagent" }) })
1238
+ function StackedTracks({
1239
+ taskBlocks,
1240
+ subagentBlocks,
1241
+ interactive,
1242
+ height,
1243
+ columns,
1244
+ mainScrollRef,
1245
+ subagentScrollRef,
1246
+ hoverProps
1247
+ }) {
1248
+ if (height <= 1) {
1249
+ return /* @__PURE__ */ jsx3(Box_default, { ...hoverProps("main"), children: /* @__PURE__ */ jsx3(TrackHeader, { role: "main", count: taskBlocks.length, width: columns }) });
1250
+ }
1251
+ const mainHeight = Math.ceil(height / 2);
1252
+ const subagentHeight = Math.floor(height / 2);
1253
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
1254
+ /* @__PURE__ */ jsx3(
1255
+ SingleTrack,
1256
+ {
1257
+ role: "main",
1258
+ blocks: taskBlocks,
1259
+ interactive,
1260
+ height: mainHeight,
1261
+ width: columns,
1262
+ scrollRef: mainScrollRef,
1263
+ hoverProps
1264
+ }
1265
+ ),
1266
+ /* @__PURE__ */ jsx3(
1267
+ SingleTrack,
1268
+ {
1269
+ role: "subagent",
1270
+ blocks: subagentBlocks,
1271
+ interactive,
1272
+ height: subagentHeight,
1273
+ width: columns,
1274
+ scrollRef: subagentScrollRef,
1275
+ hoverProps
1276
+ }
1277
+ )
1278
+ ] });
1279
+ }
1280
+ function SingleTrack({
1281
+ role,
1282
+ blocks,
1283
+ interactive,
1284
+ height,
1285
+ width,
1286
+ scrollRef,
1287
+ hoverProps
1288
+ }) {
1289
+ const contentHeight = Math.max(0, height - 1);
1290
+ return /* @__PURE__ */ jsxs2(Box_default, { flexDirection: "column", width: "100%", height, ...hoverProps(role), children: [
1291
+ /* @__PURE__ */ jsx3(TrackHeader, { role, count: blocks.length, width }),
1292
+ contentHeight <= 0 ? null : /* @__PURE__ */ jsx3(
1293
+ TrackScrollBox,
1294
+ {
1295
+ ref: scrollRef,
1296
+ blocks,
1297
+ interactive,
1298
+ height: contentHeight,
1299
+ width,
1300
+ maxTextLines: 3
1301
+ }
1302
+ )
1101
1303
  ] });
1102
1304
  }
1103
- function pairedTrackRows(tasks, subagents) {
1104
- return Array.from({ length: Math.max(tasks.length, subagents.length) }, (_, index) => [tasks[index], subagents[index]]);
1305
+ function TrackScrollBox({
1306
+ ref,
1307
+ blocks,
1308
+ interactive,
1309
+ height,
1310
+ width,
1311
+ maxTextLines
1312
+ }) {
1313
+ return /* @__PURE__ */ jsx3(
1314
+ ScrollBox_default,
1315
+ {
1316
+ ...ref === void 0 ? {} : { ref },
1317
+ flexDirection: "column",
1318
+ flexShrink: 1,
1319
+ width: "100%",
1320
+ height,
1321
+ maxHeight: height,
1322
+ paddingX: 1,
1323
+ children: blocks.map((block) => /* @__PURE__ */ jsx3(
1324
+ TaskStatusLine,
1325
+ {
1326
+ block,
1327
+ interactive,
1328
+ textWidth: Math.max(3, width - 2),
1329
+ maxTextLines,
1330
+ showRoleBadge: false
1331
+ },
1332
+ block.id
1333
+ ))
1334
+ }
1335
+ );
1336
+ }
1337
+ function TrackHeader({ role, count, width }) {
1338
+ const label = role === "main" ? `task plan (${count})` : `subagents (${count})`;
1339
+ const prefix = `\u2500\u2500 ${label} `;
1340
+ const line = prefix.length >= width ? prefix.slice(0, Math.max(0, width)) : `${prefix}${"\u2500".repeat(width - prefix.length)}`;
1341
+ return /* @__PURE__ */ jsx3(Text, { color: "ansi:white", wrap: "truncate-end", children: line });
1342
+ }
1343
+ function TrackDivider({ height }) {
1344
+ return /* @__PURE__ */ jsx3(Box_default, { flexDirection: "column", width: SPLIT_TRACK_GUTTER_COLUMNS, flexShrink: 0, children: Array.from({ length: height }, (_, index) => /* @__PURE__ */ jsx3(Text, { color: "ansi:white", children: " \u2502 " }, index)) });
1105
1345
  }
1106
1346
 
1107
1347
  // src/ui/file-diff-style.ts
@@ -1117,6 +1357,12 @@ function fileDiffLineStyle(kind) {
1117
1357
  }
1118
1358
 
1119
1359
  // src/ui/slash-completion.ts
1360
+ var CANDIDATE_KIND_PRIORITY = {
1361
+ skill: 0,
1362
+ plugin: 0,
1363
+ command: 1,
1364
+ tool: 2
1365
+ };
1120
1366
  function slashCandidatePresentation(selected) {
1121
1367
  return {
1122
1368
  marker: selected ? "\u203A " : " ",
@@ -1177,6 +1423,8 @@ function deriveSlashCompletion(input, cursor, candidates, selectedIndex, visible
1177
1423
  const leftPrefix = left.name.toLowerCase().startsWith(normalized);
1178
1424
  const rightPrefix = right.name.toLowerCase().startsWith(normalized);
1179
1425
  if (leftPrefix !== rightPrefix) return leftPrefix ? -1 : 1;
1426
+ const kindPriority = CANDIDATE_KIND_PRIORITY[left.kind] - CANDIDATE_KIND_PRIORITY[right.kind];
1427
+ if (kindPriority !== 0) return kindPriority;
1180
1428
  return left.name.localeCompare(right.name);
1181
1429
  });
1182
1430
  if (items.length === 0) return null;
@@ -1656,21 +1904,63 @@ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-run
1656
1904
  var HISTORY_CAP = 200;
1657
1905
  var BUILTIN_SLASH_CANDIDATES = MVP_COMMANDS.map((name) => ({ name, description: COMMAND_DESCRIPTIONS[name] }));
1658
1906
  var PROMPT_HORIZONTAL_PADDING = 1;
1907
+ function clonePromptDraft(state) {
1908
+ return {
1909
+ ...state,
1910
+ pastedBlocks: [...state.pastedBlocks],
1911
+ imageAttachments: [...state.imageAttachments]
1912
+ };
1913
+ }
1914
+ var PromptEditHistory = class {
1915
+ constructor(limit = 100) {
1916
+ this.limit = limit;
1917
+ }
1918
+ limit;
1919
+ #undo = [];
1920
+ #redo = [];
1921
+ record(previous, next) {
1922
+ if (previous.text === next.text && previous.pastedBlocks === next.pastedBlocks && previous.imageAttachments === next.imageAttachments) return;
1923
+ this.#undo.push(clonePromptDraft(previous));
1924
+ if (this.#undo.length > this.limit) this.#undo.shift();
1925
+ this.#redo.length = 0;
1926
+ }
1927
+ undo(current) {
1928
+ const previous = this.#undo.pop();
1929
+ if (previous === void 0) return void 0;
1930
+ this.#redo.push(clonePromptDraft(current));
1931
+ return clonePromptDraft(previous);
1932
+ }
1933
+ redo(current) {
1934
+ const next = this.#redo.pop();
1935
+ if (next === void 0) return void 0;
1936
+ this.#undo.push(clonePromptDraft(current));
1937
+ return clonePromptDraft(next);
1938
+ }
1939
+ reset() {
1940
+ this.#undo.length = 0;
1941
+ this.#redo.length = 0;
1942
+ }
1943
+ };
1944
+ function promptHistoryAction(character, key, platform = process.platform) {
1945
+ const modifier = platform === "darwin" ? key.super : key.ctrl;
1946
+ if (!modifier || character.toLowerCase() !== "z") return null;
1947
+ return key.shift ? "redo" : "undo";
1948
+ }
1949
+ function isCopyShortcut(character, key, platform = process.platform) {
1950
+ return character.toLowerCase() === "c" && (platform === "darwin" ? key.super : key.ctrl);
1951
+ }
1659
1952
  function removeLastCliImageOnBackspace(input, cursor, images) {
1660
1953
  if (input.length === 0 && cursor === 0 && images.length > 0) {
1661
1954
  return { handled: true, images: images.slice(0, -1) };
1662
1955
  }
1663
1956
  return { handled: false, images: [...images] };
1664
1957
  }
1665
- function prepareCliSubmission(input, images, activeSession) {
1958
+ function prepareCliSubmission(input, images) {
1666
1959
  const entered = input.trim();
1667
1960
  if (entered.length === 0 && images.length === 0) return { kind: "empty" };
1668
1961
  if (images.length > 0 && entered.startsWith("/")) {
1669
1962
  return { kind: "error", message: "Image attachments cannot be used with slash commands." };
1670
1963
  }
1671
- if (images.length > 0 && activeSession) {
1672
- return { kind: "error", message: "Images can only be attached to a new prompt." };
1673
- }
1674
1964
  const text = entered || "Analyze the attached image(s).";
1675
1965
  if (images.length === 0) return { kind: "ready", text, displayText: text };
1676
1966
  const content = [{ type: "text", text }, ...images];
@@ -1694,45 +1984,91 @@ function resolvePromptDelivery(activeSession, key, input) {
1694
1984
  }
1695
1985
  return { delivery: promptDelivery(activeSession, key), prompt: input };
1696
1986
  }
1697
- var SinglePendingPrompt = class {
1698
- #value;
1987
+ function cloneQueuedPrompt(prompt) {
1988
+ return {
1989
+ text: prompt.text,
1990
+ displayText: prompt.displayText,
1991
+ ...prompt.content === void 0 ? {} : { content: [...prompt.content] }
1992
+ };
1993
+ }
1994
+ function normalizeQueuedPrompt(prompt) {
1995
+ if (typeof prompt === "string") {
1996
+ const text2 = prompt.trim();
1997
+ return text2.length === 0 ? void 0 : { text: text2, displayText: text2 };
1998
+ }
1999
+ const text = prompt.text.trim();
2000
+ if (text.length === 0) return void 0;
2001
+ const displayText = prompt.displayText.trim() || text;
2002
+ return cloneQueuedPrompt({
2003
+ text,
2004
+ displayText,
2005
+ ...prompt.content === void 0 ? {} : { content: prompt.content }
2006
+ });
2007
+ }
2008
+ function queuedPromptLabel(prompt) {
2009
+ const imageCount = prompt.content?.filter((block) => block.type === "image").length ?? 0;
2010
+ const text = prompt.text.replace(/\s+/gu, " ").trim();
2011
+ if (imageCount === 0) return text;
2012
+ return `${text} \xB7 ${imageCount} ${imageCount === 1 ? "image" : "images"}`;
2013
+ }
2014
+ function restoreQueuedPrompt(prompt) {
2015
+ const imageAttachments = prompt.content?.filter(
2016
+ (block) => block.type === "image"
2017
+ ) ?? [];
2018
+ return {
2019
+ text: prompt.text,
2020
+ cursor: [...prompt.text].length,
2021
+ pastedBlocks: [],
2022
+ imageAttachments
2023
+ };
2024
+ }
2025
+ var PendingPromptQueue = class {
2026
+ #values = [];
1699
2027
  get value() {
1700
- return this.#value;
2028
+ const value = this.#values.at(-1);
2029
+ return value === void 0 ? void 0 : cloneQueuedPrompt(value);
2030
+ }
2031
+ get values() {
2032
+ return this.#values.map(cloneQueuedPrompt);
2033
+ }
2034
+ get size() {
2035
+ return this.#values.length;
1701
2036
  }
1702
2037
  queue(prompt) {
1703
- const value = prompt.trim();
1704
- if (value.length === 0 || this.#value !== void 0) return false;
1705
- this.#value = value;
2038
+ const value = normalizeQueuedPrompt(prompt);
2039
+ if (value === void 0) return false;
2040
+ this.#values.push(value);
1706
2041
  return true;
1707
2042
  }
1708
2043
  cancel() {
1709
- const value = this.#value;
1710
- this.#value = void 0;
1711
- return value;
2044
+ const value = this.#values.pop();
2045
+ return value === void 0 ? void 0 : cloneQueuedPrompt(value);
1712
2046
  }
1713
2047
  take() {
1714
- return this.cancel();
2048
+ const value = this.#values.shift();
2049
+ return value === void 0 ? void 0 : cloneQueuedPrompt(value);
1715
2050
  }
1716
2051
  };
1717
2052
  async function runTerminalSubmissionChain(options) {
1718
- let prompt = options.initialPrompt;
1719
- let initial = true;
2053
+ let prompt = normalizeQueuedPrompt({
2054
+ text: options.initialPrompt,
2055
+ displayText: options.initialDisplayPrompt ?? options.initialPrompt,
2056
+ ...options.initialContent === void 0 ? {} : { content: options.initialContent }
2057
+ });
1720
2058
  while (prompt !== void 0) {
1721
- options.onStart(initial ? options.initialDisplayPrompt ?? prompt : prompt);
1722
- if (initial && options.initialSubmit !== void 0) {
2059
+ options.onStart(prompt.displayText);
2060
+ if (prompt.content === void 0) await submitSafely(options.session, prompt.text, options.report);
2061
+ else {
1723
2062
  try {
1724
- await options.initialSubmit(prompt);
2063
+ await options.session.submit({ text: prompt.text, content: prompt.content });
1725
2064
  } catch (error) {
1726
2065
  safeReport(options.report, safeUiError(error));
1727
2066
  }
1728
- } else {
1729
- await submitSafely(options.session, prompt, options.report);
1730
2067
  }
1731
2068
  options.onFinish();
1732
2069
  if (options.shouldContinue?.() === false) return;
1733
2070
  prompt = options.pending.take();
1734
- if (prompt !== void 0) options.onPendingConsumed();
1735
- initial = false;
2071
+ if (prompt !== void 0) options.onPendingConsumed(options.pending.values);
1736
2072
  }
1737
2073
  }
1738
2074
  function classifyTerminalInput(key) {
@@ -1755,6 +2091,9 @@ function completionKeyAction(key, menuOpen) {
1755
2091
  function slashKeyAction(key, completion) {
1756
2092
  return completionKeyAction(key, completion !== null);
1757
2093
  }
2094
+ function canShowSlashCompletion(_activeSession, input, dismissedInput, blockedByModal) {
2095
+ return dismissedInput !== input && !blockedByModal;
2096
+ }
1758
2097
  function appRuntimeOptions(props, output, onApprovalChange) {
1759
2098
  return {
1760
2099
  workspace: props.workspace,
@@ -1788,7 +2127,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
1788
2127
  const [mentionCandidates, setMentionCandidates] = useState2([]);
1789
2128
  const [mentionSelection, setMentionSelection] = useState2(0);
1790
2129
  const [dismissedMentionInput, setDismissedMentionInput] = useState2();
1791
- const [pendingPrompt, setPendingPrompt] = useState2();
2130
+ const [pendingPrompts, setPendingPrompts] = useState2([]);
1792
2131
  const [revision, setRevision] = useState2(0);
1793
2132
  const [ideContext, setIdeContext] = useState2();
1794
2133
  const [questionIndex, setQuestionIndex] = useState2(0);
@@ -1799,11 +2138,12 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
1799
2138
  const [updateTo, setUpdateTo] = useState2();
1800
2139
  const [transcript, dispatch] = useReducer(transcriptReducer, void 0, createTranscriptState);
1801
2140
  const scrollRef = useRef4(null);
1802
- const taskScrollRef = useRef4(null);
1803
- const taskPanelHovered = useRef4(false);
2141
+ const mainTaskScrollRef = useRef4(null);
2142
+ const subagentTaskScrollRef = useRef4(null);
2143
+ const hoveredTaskTrack = useRef4(null);
1804
2144
  const runtimeRef = useRef4(void 0);
1805
2145
  const pendingPromptRef = useRef4(void 0);
1806
- pendingPromptRef.current ??= new SinglePendingPrompt();
2146
+ pendingPromptRef.current ??= new PendingPromptQueue();
1807
2147
  const closing = useRef4(false);
1808
2148
  const clipboardBusy = useRef4(false);
1809
2149
  const textBuf = useRef4({ pending: "", timer: null });
@@ -1814,8 +2154,9 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
1814
2154
  pastedBlocks,
1815
2155
  imageAttachments
1816
2156
  });
2157
+ const promptEditHistory = useRef4(new PromptEditHistory());
1817
2158
  promptDraftRef.current = { text: input, cursor: promptCursor, pastedBlocks, imageAttachments };
1818
- const commitPromptDraft = (next) => {
2159
+ const commitPromptDraft = (next, recordHistory = true) => {
1819
2160
  const current = promptDraftRef.current;
1820
2161
  const resolved = {
1821
2162
  text: next.text,
@@ -1823,6 +2164,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
1823
2164
  pastedBlocks: next.pastedBlocks ?? current.pastedBlocks,
1824
2165
  imageAttachments: next.imageAttachments ?? current.imageAttachments
1825
2166
  };
2167
+ if (recordHistory) promptEditHistory.current.record(current, resolved);
1826
2168
  promptDraftRef.current = resolved;
1827
2169
  setInput(resolved.text);
1828
2170
  setPromptCursor(resolved.cursor);
@@ -2044,7 +2386,12 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2044
2386
  setCustomQuestionActive(false);
2045
2387
  }, [questions]);
2046
2388
  const derivedSlashCompletion = deriveSlashCompletion(input, promptCursor, slashCandidates, slashSelection);
2047
- const slashCompletion = dismissedSlashInput === input || transcript.active !== void 0 || approval !== void 0 || questions !== void 0 ? null : derivedSlashCompletion;
2389
+ const slashCompletion = canShowSlashCompletion(
2390
+ transcript.active !== void 0,
2391
+ input,
2392
+ dismissedSlashInput,
2393
+ approval !== void 0 || questions !== void 0
2394
+ ) ? derivedSlashCompletion : null;
2048
2395
  const derivedMentionCompletion = slashCompletion === null ? deriveMentionCompletion(input, promptCursor, mentionCandidates, mentionSelection) : null;
2049
2396
  const mentionCompletion = dismissedMentionInput === input || transcript.active !== void 0 || approval !== void 0 || questions !== void 0 ? null : derivedMentionCompletion;
2050
2397
  const completedTokenLength = completedSlashTokenLength(input, slashCandidates, slashCompletion !== null);
@@ -2062,11 +2409,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2062
2409
  setClipboardNotice("Flavor is still starting; try pasting the image again.");
2063
2410
  return;
2064
2411
  }
2065
- if (transcript.active !== void 0) {
2066
- setClipboardNotice("Images can only be attached to a new prompt.");
2067
- return;
2068
- }
2069
- if (imageAttachments.length >= DEFAULT_MAX_IMAGES) {
2412
+ if (promptDraftRef.current.imageAttachments.length >= DEFAULT_MAX_IMAGES) {
2070
2413
  setClipboardNotice(`A prompt can contain at most ${DEFAULT_MAX_IMAGES} images.`);
2071
2414
  return;
2072
2415
  }
@@ -2080,14 +2423,15 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2080
2423
  return;
2081
2424
  }
2082
2425
  const incomingBytes = Buffer.byteLength(attachment.dataBase64, "base64");
2083
- const currentBytes = imageAttachments.reduce((sum, image) => sum + image.bytes, 0);
2426
+ const currentDraft = promptDraftRef.current;
2427
+ const currentBytes = currentDraft.imageAttachments.reduce((sum, image) => sum + image.bytes, 0);
2084
2428
  if (currentBytes + incomingBytes > DEFAULT_MAX_TOTAL_IMAGE_BYTES) {
2085
2429
  throw new Error(`Image attachments exceed the maximum total size of ${DEFAULT_MAX_TOTAL_IMAGE_BYTES} bytes`);
2086
2430
  }
2087
2431
  const [stored] = await new SessionAssetStore({ workspace }).store(active.sessionId, [attachment]);
2088
2432
  if (stored === void 0) throw new Error("Clipboard image could not be stored");
2089
- setImageAttachments((current) => [...current, stored]);
2090
- setClipboardNotice(`Added [Image #${imageAttachments.length + 1}] ${stored.name ?? basename3(stored.source.path)}`);
2433
+ commitPromptDraft({ ...currentDraft, imageAttachments: [...currentDraft.imageAttachments, stored] });
2434
+ setClipboardNotice(`Added [Image #${currentDraft.imageAttachments.length + 1}] ${stored.name ?? basename3(stored.source.path)}`);
2091
2435
  } catch (error) {
2092
2436
  setClipboardNotice(safeUiError(error));
2093
2437
  } finally {
@@ -2097,7 +2441,12 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2097
2441
  use_input_default((character, key, event) => {
2098
2442
  const terminalAction = classifyTerminalInput(key);
2099
2443
  if (terminalAction?.type === "scroll") {
2100
- const scroll = selectWheelScrollTarget(scrollRef.current, taskScrollRef.current, taskPanelHovered.current);
2444
+ const scroll = selectWheelScrollTarget(
2445
+ scrollRef.current,
2446
+ mainTaskScrollRef.current,
2447
+ subagentTaskScrollRef.current,
2448
+ hoveredTaskTrack.current
2449
+ );
2101
2450
  if (scroll !== null) {
2102
2451
  if (terminalAction.rows < 0) scrollUp(scroll, -terminalAction.rows);
2103
2452
  else scrollDown(scroll, terminalAction.rows);
@@ -2110,12 +2459,13 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2110
2459
  return;
2111
2460
  }
2112
2461
  const active = runtimeRef.current;
2113
- if (key.ctrl && character === "c") {
2114
- if (selection.hasSelection()) {
2115
- selection.copySelection();
2116
- } else {
2117
- interrupt();
2118
- }
2462
+ if (isCopyShortcut(character, key)) {
2463
+ if (selection.hasSelection()) selection.copySelection();
2464
+ else if (process.platform !== "darwin") interrupt();
2465
+ return;
2466
+ }
2467
+ if (key.ctrl && character.toLowerCase() === "c") {
2468
+ interrupt();
2119
2469
  return;
2120
2470
  }
2121
2471
  if (shouldReadClipboardImage(character, key, event.keypress.isPasted)) {
@@ -2188,23 +2538,20 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2188
2538
  setPromptCursor(0);
2189
2539
  return;
2190
2540
  }
2191
- if (!key.ctrl && !key.meta && character) setCustomQuestionActive(true);
2541
+ if (!key.ctrl && !key.meta && !key.super && character) setCustomQuestionActive(true);
2192
2542
  else return;
2193
2543
  }
2194
2544
  }
2195
- if (key.escape && transcript.active !== void 0) {
2196
- const restored = pendingPromptRef.current.cancel();
2197
- if (restored !== void 0) {
2198
- setPendingPrompt(void 0);
2199
- setInput(restored);
2200
- setPastedBlocks([]);
2201
- setPromptCursor([...restored].length);
2202
- setSlashSelection(0);
2203
- setDismissedSlashInput(void 0);
2204
- setMentionSelection(0);
2205
- setDismissedMentionInput(void 0);
2206
- return;
2207
- }
2545
+ const historyAction = promptHistoryAction(character, key);
2546
+ if (historyAction !== null) {
2547
+ const draft = promptDraftRef.current;
2548
+ const restored = historyAction === "undo" ? promptEditHistory.current.undo(draft) : promptEditHistory.current.redo(draft);
2549
+ if (restored !== void 0) commitPromptDraft(restored, false);
2550
+ setSlashSelection(0);
2551
+ setDismissedSlashInput(void 0);
2552
+ setMentionSelection(0);
2553
+ setDismissedMentionInput(void 0);
2554
+ return;
2208
2555
  }
2209
2556
  const menuAction = slashKeyAction(key, slashCompletion);
2210
2557
  if (menuAction?.type === "select" && slashCompletion !== null) {
@@ -2215,8 +2562,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2215
2562
  const selected = slashCompletion.items[slashCompletion.selectedIndex];
2216
2563
  if (selected !== void 0) {
2217
2564
  const next = completeSlashSelection(input, promptCursor, selected.name);
2218
- setInput(next.text);
2219
- setPromptCursor(next.cursor);
2565
+ commitPromptDraft(next);
2220
2566
  setDismissedSlashInput(next.text);
2221
2567
  }
2222
2568
  return;
@@ -2239,9 +2585,24 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2239
2585
  setDismissedMentionInput(input);
2240
2586
  return;
2241
2587
  }
2588
+ if (key.escape && transcript.active !== void 0) {
2589
+ const restored = pendingPromptRef.current.cancel();
2590
+ if (restored !== void 0) {
2591
+ setPendingPrompts([...pendingPromptRef.current.values]);
2592
+ const restoredDraft = restoreQueuedPrompt(restored);
2593
+ promptEditHistory.current.reset();
2594
+ commitPromptDraft(restoredDraft, false);
2595
+ setClipboardNotice(restoredDraft.imageAttachments.length === 0 ? void 0 : `Restored ${restoredDraft.imageAttachments.length} pending ${restoredDraft.imageAttachments.length === 1 ? "image" : "images"}.`);
2596
+ setSlashSelection(0);
2597
+ setDismissedSlashInput(void 0);
2598
+ setMentionSelection(0);
2599
+ setDismissedMentionInput(void 0);
2600
+ return;
2601
+ }
2602
+ }
2242
2603
  if (key.return) {
2243
2604
  const images = [...imageAttachments];
2244
- const prepared = prepareCliSubmission(input, images, transcript.active !== void 0);
2605
+ const prepared = prepareCliSubmission(input, images);
2245
2606
  if (prepared.kind === "empty" || active === void 0) return;
2246
2607
  if (prepared.kind === "error") {
2247
2608
  setClipboardNotice(prepared.message);
@@ -2251,8 +2612,12 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2251
2612
  const { delivery, prompt } = resolvePromptDelivery(transcript.active !== void 0, key, submittedText);
2252
2613
  if (!prompt) return;
2253
2614
  if (delivery === "followUp" && transcript.active !== void 0) {
2254
- if (!pendingPromptRef.current.queue(prompt)) return;
2255
- setPendingPrompt(prompt);
2615
+ if (!pendingPromptRef.current.queue({
2616
+ text: prompt,
2617
+ displayText: prepared.content === void 0 ? prompt : prepared.displayText,
2618
+ ...prepared.content === void 0 ? {} : { content: prepared.content }
2619
+ })) return;
2620
+ setPendingPrompts([...pendingPromptRef.current.values]);
2256
2621
  }
2257
2622
  scrollRef.current?.scrollToBottom();
2258
2623
  setHistory((current) => [...current, submittedText].slice(-HISTORY_CAP));
@@ -2261,6 +2626,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2261
2626
  setPastedBlocks([]);
2262
2627
  setImageAttachments([]);
2263
2628
  promptDraftRef.current = { text: "", cursor: 0, pastedBlocks: [], imageAttachments: [] };
2629
+ promptEditHistory.current.reset();
2264
2630
  setClipboardNotice(void 0);
2265
2631
  setPromptCursor(0);
2266
2632
  setSlashSelection(0);
@@ -2273,15 +2639,12 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2273
2639
  initialPrompt: prompt,
2274
2640
  ...prepared.content === void 0 ? {} : {
2275
2641
  initialDisplayPrompt: prepared.displayText,
2276
- initialSubmit: (text) => active.session.submit({
2277
- text,
2278
- content: prepared.content
2279
- })
2642
+ initialContent: prepared.content
2280
2643
  },
2281
2644
  pending: pendingPromptRef.current,
2282
2645
  onStart: (next) => dispatch({ type: "submit", prompt: next }),
2283
2646
  onFinish: () => dispatch({ type: "finish" }),
2284
- onPendingConsumed: () => setPendingPrompt(void 0),
2647
+ onPendingConsumed: (remaining) => setPendingPrompts([...remaining]),
2285
2648
  report: (error) => dispatch({ type: "submit-error", message: error }),
2286
2649
  shouldContinue: () => !closing.current
2287
2650
  });
@@ -2298,8 +2661,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2298
2661
  const draft = promptDraftRef.current;
2299
2662
  const imageEdit = removeLastCliImageOnBackspace(draft.text, draft.cursor, draft.imageAttachments);
2300
2663
  if (imageEdit.handled) {
2301
- setImageAttachments(imageEdit.images);
2302
- promptDraftRef.current = { ...draft, imageAttachments: imageEdit.images };
2664
+ commitPromptDraft({ ...draft, imageAttachments: imageEdit.images });
2303
2665
  setClipboardNotice(imageEdit.images.length === 0 ? "Removed image attachment." : `Removed image attachment; ${imageEdit.images.length} remaining.`);
2304
2666
  return;
2305
2667
  }
@@ -2342,7 +2704,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2342
2704
  setDismissedSlashInput(void 0);
2343
2705
  setMentionSelection(0);
2344
2706
  setDismissedMentionInput(void 0);
2345
- } else if (!key.ctrl && !key.meta && character) {
2707
+ } else if (!key.ctrl && !key.meta && !key.super && character) {
2346
2708
  const draft = promptDraftRef.current;
2347
2709
  const nextPastedBlocks = /[\r\n]/u.test(character) ? [...draft.pastedBlocks, { id: draft.pastedBlocks.length + 1, text: character }] : draft.pastedBlocks;
2348
2710
  commitPromptDraft({
@@ -2388,9 +2750,10 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2388
2750
  ...ideContext === void 0 ? {} : { ideContext },
2389
2751
  completedSlashTokenLength: completedTokenLength,
2390
2752
  scrollRef,
2391
- taskScrollRef,
2392
- onTaskPanelHoverChange: (hovered) => {
2393
- taskPanelHovered.current = hovered;
2753
+ mainTaskScrollRef,
2754
+ subagentTaskScrollRef,
2755
+ onTaskPanelHoverChange: (track) => {
2756
+ hoveredTaskTrack.current = track;
2394
2757
  },
2395
2758
  ...slashCompletion === null ? {} : { completion: slashCompletion },
2396
2759
  ...mentionCompletion === null ? {} : { mentionCompletion, onMentionSelect: selectMention },
@@ -2398,7 +2761,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
2398
2761
  ...questions === void 0 ? {} : { questions },
2399
2762
  memoryReviews,
2400
2763
  memoryAutoDismissSeconds,
2401
- ...pendingPrompt === void 0 ? {} : { pendingPrompt },
2764
+ pendingPrompts,
2402
2765
  questionIndex,
2403
2766
  questionAnswers,
2404
2767
  customQuestionActive
@@ -2511,7 +2874,7 @@ function TerminalLayout({
2511
2874
  columns,
2512
2875
  rows = 24,
2513
2876
  activeSession,
2514
- pendingPrompt,
2877
+ pendingPrompts = [],
2515
2878
  approval,
2516
2879
  questions,
2517
2880
  memoryReviews = [],
@@ -2524,7 +2887,8 @@ function TerminalLayout({
2524
2887
  onMentionSelect,
2525
2888
  completedSlashTokenLength: tokenLength = 0,
2526
2889
  scrollRef,
2527
- taskScrollRef,
2890
+ mainTaskScrollRef,
2891
+ subagentTaskScrollRef,
2528
2892
  onTaskPanelHoverChange,
2529
2893
  onPromptCursorChange,
2530
2894
  ideContext
@@ -2546,7 +2910,7 @@ function TerminalLayout({
2546
2910
  const completedWindow = cliTranscriptWindow(completed);
2547
2911
  const questionRows = questions === void 0 ? 0 : 4 + (questions[questionIndex]?.options.length ?? 0) + questions.length * 2;
2548
2912
  const memoryReviewRows = memoryReviews.length === 0 ? 0 : 5;
2549
- const fixedBottomRows = (approval === void 0 ? 0 : 3) + questionRows + memoryReviewRows + menuRows + (pendingPrompt === void 0 ? 0 : 1) + imageAttachments.length + (clipboardNotice === void 0 ? 0 : 1) + 2;
2913
+ const fixedBottomRows = (approval === void 0 ? 0 : 3) + questionRows + memoryReviewRows + menuRows + (pendingPrompts.length === 0 ? 0 : 1) + imageAttachments.length + (clipboardNotice === void 0 ? 0 : 1) + 2;
2550
2914
  const taskPanelRows = taskPanelViewportRows(rows, fixedBottomRows, activeTaskBlocks.length > 0);
2551
2915
  const availableBottomRows = Math.max(1, rows - taskPanelRows - 1);
2552
2916
  const bottomMaxRows = Math.min(availableBottomRows, Math.max(Math.floor(rows / 2), fixedBottomRows + 1));
@@ -2583,7 +2947,8 @@ function TerminalLayout({
2583
2947
  interactive: activeSession,
2584
2948
  maxHeight: taskPanelRows,
2585
2949
  columns,
2586
- ...taskScrollRef === void 0 ? {} : { scrollRef: taskScrollRef },
2950
+ ...mainTaskScrollRef === void 0 ? {} : { mainScrollRef: mainTaskScrollRef },
2951
+ ...subagentTaskScrollRef === void 0 ? {} : { subagentScrollRef: subagentTaskScrollRef },
2587
2952
  ...onTaskPanelHoverChange === void 0 ? {} : { onHoverChange: onTaskPanelHoverChange }
2588
2953
  }
2589
2954
  ),
@@ -2617,10 +2982,12 @@ function TerminalLayout({
2617
2982
  memoryReviews.length === 0 ? null : /* @__PURE__ */ jsx5(MemoryReviewCards, { reviews: memoryReviews, autoDismissSeconds: memoryAutoDismissSeconds }),
2618
2983
  completion === void 0 ? null : /* @__PURE__ */ jsx5(SlashMenu, { completion }),
2619
2984
  mentionCompletion === void 0 ? null : /* @__PURE__ */ jsx5(MentionMenu, { completion: mentionCompletion, ...onMentionSelect === void 0 ? {} : { onSelect: onMentionSelect } }),
2620
- pendingPrompt === void 0 ? null : /* @__PURE__ */ jsxs4(Text, { color: "yellow", wrap: "truncate-end", children: [
2621
- "Pending \xB7 ",
2622
- pendingPrompt,
2623
- " \xB7 Esc edit"
2985
+ pendingPrompts.length === 0 ? null : /* @__PURE__ */ jsxs4(Text, { color: "yellow", wrap: "truncate-end", children: [
2986
+ "Pending (",
2987
+ pendingPrompts.length,
2988
+ ") \xB7 ",
2989
+ queuedPromptLabel(pendingPrompts.at(-1)),
2990
+ " \xB7 Esc edit latest"
2624
2991
  ] }),
2625
2992
  /* @__PURE__ */ jsx5(Text, { dimColor: true, children: "\u2500".repeat(dividerWidth) }),
2626
2993
  imageAttachments.map((image, index) => /* @__PURE__ */ jsxs4(Text, { color: "cyan", wrap: "truncate-end", children: [
@@ -2645,7 +3012,7 @@ function TerminalLayout({
2645
3012
  /* @__PURE__ */ jsx5(
2646
3013
  FooterStatus,
2647
3014
  {
2648
- hint: activeSession ? "Ctrl+C cancel \xB7 Enter queue \xB7 Esc edit pending \xB7 /steer sends now" : 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" : "Enter send \xB7 Ctrl/Cmd+V image \xB7 \u2191\u2193 history \xB7 Ctrl+C exit",
3015
+ hint: activeSession ? "Ctrl+C cancel \xB7 Enter queue \xB7 Esc edit latest \xB7 / menu \xB7 Ctrl/Cmd+V image" : 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" : "Enter send \xB7 Ctrl/Cmd+V image \xB7 \u2191\u2193 history \xB7 Ctrl+C exit",
2649
3016
  ...ideContext === void 0 ? {} : { ideContext }
2650
3017
  }
2651
3018
  )
@@ -2749,6 +3116,7 @@ function SlashMenu({ completion }) {
2749
3116
  return /* @__PURE__ */ jsxs4(Text, { ...presentation.rowStyle, wrap: "truncate-end", children: [
2750
3117
  presentation.marker,
2751
3118
  /* @__PURE__ */ jsx5(HighlightedName, { name: candidate.name, query: completion.query, matchStyle: presentation.matchStyle }),
3119
+ candidate.kind === "skill" || candidate.kind === "plugin" ? /* @__PURE__ */ jsx5(Text, { color: candidate.kind === "skill" ? "magentaBright" : "cyanBright", children: ` ${candidate.kind}` }) : null,
2752
3120
  candidate.description === void 0 ? null : /* @__PURE__ */ jsx5(Text, { dimColor: true, children: ` ${candidate.description}` })
2753
3121
  ] }, `${candidate.kind}:${candidate.name}`);
2754
3122
  }) });
@@ -2804,8 +3172,10 @@ function jumpScroll(scroll, delta) {
2804
3172
  scroll.scrollTo(Math.max(0, target));
2805
3173
  }
2806
3174
  }
2807
- function selectWheelScrollTarget(transcript, tasks, taskPanelHovered) {
2808
- return taskPanelHovered && tasks !== null ? tasks : transcript;
3175
+ function selectWheelScrollTarget(transcript, mainTasks, subagentTasks, hoveredTrack) {
3176
+ if (hoveredTrack === "main" && mainTasks !== null) return mainTasks;
3177
+ if (hoveredTrack === "subagent" && subagentTasks !== null) return subagentTasks;
3178
+ return transcript;
2809
3179
  }
2810
3180
  function taskPanelViewportRows(rows, reservedBottomRows, hasTasks) {
2811
3181
  if (!hasTasks) return 0;
@@ -3682,12 +4052,14 @@ export {
3682
4052
  FooterStatus,
3683
4053
  HISTORY_CAP,
3684
4054
  MentionMenu,
4055
+ PendingPromptQueue,
4056
+ PromptEditHistory,
3685
4057
  PromptLine,
3686
4058
  SHUTDOWN_TIMEOUT_MS,
3687
- SinglePendingPrompt,
3688
4059
  TerminalLayout,
3689
4060
  appRuntimeOptions,
3690
4061
  boundedCliTurn,
4062
+ canShowSlashCompletion,
3691
4063
  classifyTerminalInput,
3692
4064
  cliTranscriptWindow,
3693
4065
  closeAndDisposeRuntime,
@@ -3695,13 +4067,17 @@ export {
3695
4067
  editPrompt,
3696
4068
  editPromptWithPastedBlocks,
3697
4069
  ideFooterPresentation,
4070
+ isCopyShortcut,
3698
4071
  navigateHistory,
3699
4072
  pastedDraftPresentation,
3700
4073
  prepareCliSubmission,
3701
4074
  promptCursorFromClick,
3702
4075
  promptDelivery,
4076
+ promptHistoryAction,
4077
+ queuedPromptLabel,
3703
4078
  removeLastCliImageOnBackspace,
3704
4079
  resolvePromptDelivery,
4080
+ restoreQueuedPrompt,
3705
4081
  runTerminalSubmissionChain,
3706
4082
  selectWheelScrollTarget,
3707
4083
  shutdownRuntime,