@robota-sdk/agent-cli 3.0.0-beta.37 → 3.0.0-beta.39

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/node/bin.cjs CHANGED
@@ -1715,6 +1715,7 @@ var import_ink7 = require("ink");
1715
1715
  var import_react8 = require("react");
1716
1716
  var import_ink4 = require("ink");
1717
1717
  var import_chalk = __toESM(require("chalk"), 1);
1718
+ var import_string_width = __toESM(require("string-width"), 1);
1718
1719
  var import_jsx_runtime4 = require("react/jsx-runtime");
1719
1720
  function filterPrintable(input) {
1720
1721
  if (!input || input.length === 0) return "";
@@ -1724,6 +1725,27 @@ function insertAtCursor(value, cursor, input) {
1724
1725
  const next = value.slice(0, cursor) + input + value.slice(cursor);
1725
1726
  return { value: next, cursor: cursor + input.length };
1726
1727
  }
1728
+ function displayOffset(chars, charIndex, width) {
1729
+ let offset = 0;
1730
+ for (let i = 0; i < charIndex && i < chars.length; i++) {
1731
+ const w = (0, import_string_width.default)(chars[i]);
1732
+ const col = offset % width;
1733
+ if (col + w > width) offset += width - col;
1734
+ offset += w;
1735
+ }
1736
+ return offset;
1737
+ }
1738
+ function charIndexAtDisplayOffset(chars, target, width) {
1739
+ let offset = 0;
1740
+ for (let i = 0; i < chars.length; i++) {
1741
+ if (offset >= target) return i;
1742
+ const w = (0, import_string_width.default)(chars[i]);
1743
+ const col = offset % width;
1744
+ if (col + w > width) offset += width - col;
1745
+ offset += w;
1746
+ }
1747
+ return chars.length;
1748
+ }
1727
1749
  function CjkTextInput({
1728
1750
  value,
1729
1751
  onChange,
@@ -1731,7 +1753,8 @@ function CjkTextInput({
1731
1753
  onPaste,
1732
1754
  placeholder = "",
1733
1755
  focus = true,
1734
- showCursor = true
1756
+ showCursor = true,
1757
+ availableWidth
1735
1758
  }) {
1736
1759
  const valueRef = (0, import_react8.useRef)(value);
1737
1760
  const cursorRef = (0, import_react8.useRef)(value.length);
@@ -1745,7 +1768,22 @@ function CjkTextInput({
1745
1768
  (0, import_ink4.useInput)(
1746
1769
  (input, key) => {
1747
1770
  try {
1748
- if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
1771
+ if (key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
1772
+ return;
1773
+ }
1774
+ if (key.upArrow || key.downArrow) {
1775
+ if (availableWidth && availableWidth > 0) {
1776
+ const chars = [...valueRef.current];
1777
+ const offset = displayOffset(chars, cursorRef.current, availableWidth);
1778
+ const target = key.upArrow ? offset - availableWidth : offset + availableWidth;
1779
+ if (target >= 0) {
1780
+ const newCursor = charIndexAtDisplayOffset(chars, target, availableWidth);
1781
+ if (newCursor !== cursorRef.current) {
1782
+ cursorRef.current = newCursor;
1783
+ forceRender((n) => n + 1);
1784
+ }
1785
+ }
1786
+ }
1749
1787
  return;
1750
1788
  }
1751
1789
  if (key.return) {
@@ -1938,14 +1976,23 @@ function useAutocomplete(value, registry) {
1938
1976
  }
1939
1977
  };
1940
1978
  }
1979
+ var BORDER_HORIZONTAL = 2;
1980
+ var PADDING_LEFT = 1;
1981
+ var PROMPT_WIDTH = 2;
1982
+ var INPUT_AREA_OVERHEAD = BORDER_HORIZONTAL + PADDING_LEFT + PROMPT_WIDTH;
1941
1983
  function InputArea({
1942
1984
  onSubmit,
1985
+ onCancelQueue,
1943
1986
  isDisabled,
1944
1987
  isAborting,
1988
+ pendingPrompt,
1945
1989
  registry
1946
1990
  }) {
1947
1991
  const [value, setValue] = (0, import_react10.useState)("");
1948
1992
  const pasteStore = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
1993
+ const { stdout } = (0, import_ink7.useStdout)();
1994
+ const terminalColumns = stdout?.columns ?? 80;
1995
+ const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
1949
1996
  const pasteIdRef = (0, import_react10.useRef)(0);
1950
1997
  const {
1951
1998
  showPopup,
@@ -2014,6 +2061,14 @@ function InputArea({
2014
2061
  },
2015
2062
  { isActive: showPopup && !isDisabled }
2016
2063
  );
2064
+ (0, import_ink7.useInput)(
2065
+ (_input, key) => {
2066
+ if ((key.backspace || key.delete) && pendingPrompt) {
2067
+ onCancelQueue?.();
2068
+ }
2069
+ },
2070
+ { isActive: !!pendingPrompt }
2071
+ );
2017
2072
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", children: [
2018
2073
  showPopup && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2019
2074
  SlashAutocomplete,
@@ -2028,9 +2083,15 @@ function InputArea({
2028
2083
  import_ink7.Box,
2029
2084
  {
2030
2085
  borderStyle: "single",
2031
- borderColor: isAborting ? "yellow" : isDisabled ? "gray" : "green",
2086
+ borderColor: isAborting ? "yellow" : pendingPrompt ? "cyan" : isDisabled ? "gray" : "green",
2032
2087
  paddingLeft: 1,
2033
- children: isDisabled ? isAborting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", children: " Interrupting..." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
2088
+ children: isAborting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", children: " Interrupting..." }) : pendingPrompt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { color: "cyan", children: [
2089
+ " ",
2090
+ "Queued: ",
2091
+ pendingPrompt.length > 50 ? pendingPrompt.slice(0, 47) + "..." : pendingPrompt,
2092
+ " ",
2093
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: "(Backspace to cancel)" })
2094
+ ] }) : isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
2034
2095
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "green", bold: true, children: "> " }),
2035
2096
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2036
2097
  CjkTextInput,
@@ -2039,7 +2100,8 @@ function InputArea({
2039
2100
  onChange: setValue,
2040
2101
  onSubmit: handleSubmit,
2041
2102
  onPaste: handlePaste,
2042
- placeholder: "Type a message or /help"
2103
+ placeholder: "Type a message or /help",
2104
+ availableWidth
2043
2105
  }
2044
2106
  )
2045
2107
  ] })
@@ -2693,6 +2755,8 @@ function App(props) {
2693
2755
  const [pendingModelId, setPendingModelId] = (0, import_react16.useState)(null);
2694
2756
  const [showPluginTUI, setShowPluginTUI] = (0, import_react16.useState)(false);
2695
2757
  const [isAborting, setIsAborting] = (0, import_react16.useState)(false);
2758
+ const [pendingPrompt, setPendingPrompt] = (0, import_react16.useState)(null);
2759
+ const pendingPromptRef = (0, import_react16.useRef)(null);
2696
2760
  const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
2697
2761
  const handleSlashCommand = useSlashCommands(
2698
2762
  session,
@@ -2705,7 +2769,7 @@ function App(props) {
2705
2769
  pluginCallbacks,
2706
2770
  setShowPluginTUI
2707
2771
  );
2708
- const handleSubmit = useSubmitHandler(
2772
+ const executePrompt = useSubmitHandler(
2709
2773
  session,
2710
2774
  addMessage,
2711
2775
  handleSlashCommand,
@@ -2714,18 +2778,39 @@ function App(props) {
2714
2778
  setContextState,
2715
2779
  registry
2716
2780
  );
2781
+ const handleSubmit = (0, import_react16.useCallback)(
2782
+ async (input) => {
2783
+ if (isThinking) {
2784
+ setPendingPrompt(input);
2785
+ pendingPromptRef.current = input;
2786
+ return;
2787
+ }
2788
+ await executePrompt(input);
2789
+ },
2790
+ [isThinking, executePrompt]
2791
+ );
2717
2792
  (0, import_ink13.useInput)(
2718
2793
  (_input, key) => {
2719
2794
  if (key.escape && isThinking) {
2720
2795
  setIsAborting(true);
2796
+ setPendingPrompt(null);
2797
+ pendingPromptRef.current = null;
2721
2798
  session.abort();
2722
2799
  }
2723
2800
  },
2724
2801
  { isActive: !permissionRequest && !showPluginTUI }
2725
2802
  );
2726
2803
  (0, import_react16.useEffect)(() => {
2727
- if (!isThinking) setIsAborting(false);
2728
- }, [isThinking]);
2804
+ if (!isThinking) {
2805
+ setIsAborting(false);
2806
+ if (pendingPromptRef.current) {
2807
+ const prompt = pendingPromptRef.current;
2808
+ setPendingPrompt(null);
2809
+ pendingPromptRef.current = null;
2810
+ setTimeout(() => executePrompt(prompt), 0);
2811
+ }
2812
+ }
2813
+ }, [isThinking, pendingPrompt, executePrompt]);
2729
2814
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
2730
2815
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2731
2816
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Text, { color: "cyan", bold: true, children: `
@@ -2800,8 +2885,13 @@ function App(props) {
2800
2885
  InputArea,
2801
2886
  {
2802
2887
  onSubmit: handleSubmit,
2803
- isDisabled: isThinking || !!permissionRequest || showPluginTUI,
2888
+ onCancelQueue: () => {
2889
+ setPendingPrompt(null);
2890
+ pendingPromptRef.current = null;
2891
+ },
2892
+ isDisabled: !!permissionRequest || showPluginTUI || isThinking && !!pendingPrompt,
2804
2893
  isAborting,
2894
+ pendingPrompt,
2805
2895
  registry
2806
2896
  }
2807
2897
  ),
package/dist/node/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startCli
4
- } from "./chunk-P323ORQX.js";
4
+ } from "./chunk-GWN5C72P.js";
5
5
 
6
6
  // src/bin.ts
7
7
  process.on("uncaughtException", (err) => {
@@ -149,7 +149,7 @@ var PrintTerminal = class {
149
149
  import { render } from "ink";
150
150
 
151
151
  // src/ui/App.tsx
152
- import { useState as useState10, useRef as useRef8, useEffect as useEffect3 } from "react";
152
+ import { useState as useState10, useRef as useRef8, useEffect as useEffect3, useCallback as useCallback10 } from "react";
153
153
  import { Box as Box11, Text as Text13, useApp, useInput as useInput7 } from "ink";
154
154
  import { getModelName } from "@robota-sdk/agent-core";
155
155
  import { createSystemMessage as createSystemMessage3 } from "@robota-sdk/agent-core";
@@ -1706,12 +1706,13 @@ function StatusBar({
1706
1706
 
1707
1707
  // src/ui/InputArea.tsx
1708
1708
  import React5, { useState as useState5, useCallback as useCallback5, useMemo as useMemo2, useRef as useRef4 } from "react";
1709
- import { Box as Box5, Text as Text7, useInput as useInput2 } from "ink";
1709
+ import { Box as Box5, Text as Text7, useInput as useInput2, useStdout } from "ink";
1710
1710
 
1711
1711
  // src/ui/CjkTextInput.tsx
1712
1712
  import { useRef as useRef3, useState as useState3 } from "react";
1713
1713
  import { Text as Text4, useInput } from "ink";
1714
1714
  import chalk from "chalk";
1715
+ import stringWidth from "string-width";
1715
1716
  import { jsx as jsx3 } from "react/jsx-runtime";
1716
1717
  function filterPrintable(input) {
1717
1718
  if (!input || input.length === 0) return "";
@@ -1721,6 +1722,27 @@ function insertAtCursor(value, cursor, input) {
1721
1722
  const next = value.slice(0, cursor) + input + value.slice(cursor);
1722
1723
  return { value: next, cursor: cursor + input.length };
1723
1724
  }
1725
+ function displayOffset(chars, charIndex, width) {
1726
+ let offset = 0;
1727
+ for (let i = 0; i < charIndex && i < chars.length; i++) {
1728
+ const w = stringWidth(chars[i]);
1729
+ const col = offset % width;
1730
+ if (col + w > width) offset += width - col;
1731
+ offset += w;
1732
+ }
1733
+ return offset;
1734
+ }
1735
+ function charIndexAtDisplayOffset(chars, target, width) {
1736
+ let offset = 0;
1737
+ for (let i = 0; i < chars.length; i++) {
1738
+ if (offset >= target) return i;
1739
+ const w = stringWidth(chars[i]);
1740
+ const col = offset % width;
1741
+ if (col + w > width) offset += width - col;
1742
+ offset += w;
1743
+ }
1744
+ return chars.length;
1745
+ }
1724
1746
  function CjkTextInput({
1725
1747
  value,
1726
1748
  onChange,
@@ -1728,7 +1750,8 @@ function CjkTextInput({
1728
1750
  onPaste,
1729
1751
  placeholder = "",
1730
1752
  focus = true,
1731
- showCursor = true
1753
+ showCursor = true,
1754
+ availableWidth
1732
1755
  }) {
1733
1756
  const valueRef = useRef3(value);
1734
1757
  const cursorRef = useRef3(value.length);
@@ -1742,7 +1765,22 @@ function CjkTextInput({
1742
1765
  useInput(
1743
1766
  (input, key) => {
1744
1767
  try {
1745
- if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
1768
+ if (key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
1769
+ return;
1770
+ }
1771
+ if (key.upArrow || key.downArrow) {
1772
+ if (availableWidth && availableWidth > 0) {
1773
+ const chars = [...valueRef.current];
1774
+ const offset = displayOffset(chars, cursorRef.current, availableWidth);
1775
+ const target = key.upArrow ? offset - availableWidth : offset + availableWidth;
1776
+ if (target >= 0) {
1777
+ const newCursor = charIndexAtDisplayOffset(chars, target, availableWidth);
1778
+ if (newCursor !== cursorRef.current) {
1779
+ cursorRef.current = newCursor;
1780
+ forceRender((n) => n + 1);
1781
+ }
1782
+ }
1783
+ }
1746
1784
  return;
1747
1785
  }
1748
1786
  if (key.return) {
@@ -1935,14 +1973,23 @@ function useAutocomplete(value, registry) {
1935
1973
  }
1936
1974
  };
1937
1975
  }
1976
+ var BORDER_HORIZONTAL = 2;
1977
+ var PADDING_LEFT = 1;
1978
+ var PROMPT_WIDTH = 2;
1979
+ var INPUT_AREA_OVERHEAD = BORDER_HORIZONTAL + PADDING_LEFT + PROMPT_WIDTH;
1938
1980
  function InputArea({
1939
1981
  onSubmit,
1982
+ onCancelQueue,
1940
1983
  isDisabled,
1941
1984
  isAborting,
1985
+ pendingPrompt,
1942
1986
  registry
1943
1987
  }) {
1944
1988
  const [value, setValue] = useState5("");
1945
1989
  const pasteStore = useRef4(/* @__PURE__ */ new Map());
1990
+ const { stdout } = useStdout();
1991
+ const terminalColumns = stdout?.columns ?? 80;
1992
+ const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
1946
1993
  const pasteIdRef = useRef4(0);
1947
1994
  const {
1948
1995
  showPopup,
@@ -2011,6 +2058,14 @@ function InputArea({
2011
2058
  },
2012
2059
  { isActive: showPopup && !isDisabled }
2013
2060
  );
2061
+ useInput2(
2062
+ (_input, key) => {
2063
+ if ((key.backspace || key.delete) && pendingPrompt) {
2064
+ onCancelQueue?.();
2065
+ }
2066
+ },
2067
+ { isActive: !!pendingPrompt }
2068
+ );
2014
2069
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
2015
2070
  showPopup && /* @__PURE__ */ jsx6(
2016
2071
  SlashAutocomplete,
@@ -2025,9 +2080,15 @@ function InputArea({
2025
2080
  Box5,
2026
2081
  {
2027
2082
  borderStyle: "single",
2028
- borderColor: isAborting ? "yellow" : isDisabled ? "gray" : "green",
2083
+ borderColor: isAborting ? "yellow" : pendingPrompt ? "cyan" : isDisabled ? "gray" : "green",
2029
2084
  paddingLeft: 1,
2030
- children: isDisabled ? isAborting ? /* @__PURE__ */ jsx6(Text7, { color: "yellow", children: " Interrupting..." }) : /* @__PURE__ */ jsx6(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ jsxs5(Box5, { children: [
2085
+ children: isAborting ? /* @__PURE__ */ jsx6(Text7, { color: "yellow", children: " Interrupting..." }) : pendingPrompt ? /* @__PURE__ */ jsxs5(Text7, { color: "cyan", children: [
2086
+ " ",
2087
+ "Queued: ",
2088
+ pendingPrompt.length > 50 ? pendingPrompt.slice(0, 47) + "..." : pendingPrompt,
2089
+ " ",
2090
+ /* @__PURE__ */ jsx6(Text7, { dimColor: true, children: "(Backspace to cancel)" })
2091
+ ] }) : isDisabled ? /* @__PURE__ */ jsx6(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ jsxs5(Box5, { children: [
2031
2092
  /* @__PURE__ */ jsx6(Text7, { color: "green", bold: true, children: "> " }),
2032
2093
  /* @__PURE__ */ jsx6(
2033
2094
  CjkTextInput,
@@ -2036,7 +2097,8 @@ function InputArea({
2036
2097
  onChange: setValue,
2037
2098
  onSubmit: handleSubmit,
2038
2099
  onPaste: handlePaste,
2039
- placeholder: "Type a message or /help"
2100
+ placeholder: "Type a message or /help",
2101
+ availableWidth
2040
2102
  }
2041
2103
  )
2042
2104
  ] })
@@ -2690,6 +2752,8 @@ function App(props) {
2690
2752
  const [pendingModelId, setPendingModelId] = useState10(null);
2691
2753
  const [showPluginTUI, setShowPluginTUI] = useState10(false);
2692
2754
  const [isAborting, setIsAborting] = useState10(false);
2755
+ const [pendingPrompt, setPendingPrompt] = useState10(null);
2756
+ const pendingPromptRef = useRef8(null);
2693
2757
  const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
2694
2758
  const handleSlashCommand = useSlashCommands(
2695
2759
  session,
@@ -2702,7 +2766,7 @@ function App(props) {
2702
2766
  pluginCallbacks,
2703
2767
  setShowPluginTUI
2704
2768
  );
2705
- const handleSubmit = useSubmitHandler(
2769
+ const executePrompt = useSubmitHandler(
2706
2770
  session,
2707
2771
  addMessage,
2708
2772
  handleSlashCommand,
@@ -2711,18 +2775,39 @@ function App(props) {
2711
2775
  setContextState,
2712
2776
  registry
2713
2777
  );
2778
+ const handleSubmit = useCallback10(
2779
+ async (input) => {
2780
+ if (isThinking) {
2781
+ setPendingPrompt(input);
2782
+ pendingPromptRef.current = input;
2783
+ return;
2784
+ }
2785
+ await executePrompt(input);
2786
+ },
2787
+ [isThinking, executePrompt]
2788
+ );
2714
2789
  useInput7(
2715
2790
  (_input, key) => {
2716
2791
  if (key.escape && isThinking) {
2717
2792
  setIsAborting(true);
2793
+ setPendingPrompt(null);
2794
+ pendingPromptRef.current = null;
2718
2795
  session.abort();
2719
2796
  }
2720
2797
  },
2721
2798
  { isActive: !permissionRequest && !showPluginTUI }
2722
2799
  );
2723
2800
  useEffect3(() => {
2724
- if (!isThinking) setIsAborting(false);
2725
- }, [isThinking]);
2801
+ if (!isThinking) {
2802
+ setIsAborting(false);
2803
+ if (pendingPromptRef.current) {
2804
+ const prompt = pendingPromptRef.current;
2805
+ setPendingPrompt(null);
2806
+ pendingPromptRef.current = null;
2807
+ setTimeout(() => executePrompt(prompt), 0);
2808
+ }
2809
+ }
2810
+ }, [isThinking, pendingPrompt, executePrompt]);
2726
2811
  return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
2727
2812
  /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2728
2813
  /* @__PURE__ */ jsx13(Text13, { color: "cyan", bold: true, children: `
@@ -2797,8 +2882,13 @@ function App(props) {
2797
2882
  InputArea,
2798
2883
  {
2799
2884
  onSubmit: handleSubmit,
2800
- isDisabled: isThinking || !!permissionRequest || showPluginTUI,
2885
+ onCancelQueue: () => {
2886
+ setPendingPrompt(null);
2887
+ pendingPromptRef.current = null;
2888
+ },
2889
+ isDisabled: !!permissionRequest || showPluginTUI || isThinking && !!pendingPrompt,
2801
2890
  isAborting,
2891
+ pendingPrompt,
2802
2892
  registry
2803
2893
  }
2804
2894
  ),
@@ -1731,6 +1731,7 @@ var import_ink7 = require("ink");
1731
1731
  var import_react8 = require("react");
1732
1732
  var import_ink4 = require("ink");
1733
1733
  var import_chalk = __toESM(require("chalk"), 1);
1734
+ var import_string_width = __toESM(require("string-width"), 1);
1734
1735
  var import_jsx_runtime4 = require("react/jsx-runtime");
1735
1736
  function filterPrintable(input) {
1736
1737
  if (!input || input.length === 0) return "";
@@ -1740,6 +1741,27 @@ function insertAtCursor(value, cursor, input) {
1740
1741
  const next = value.slice(0, cursor) + input + value.slice(cursor);
1741
1742
  return { value: next, cursor: cursor + input.length };
1742
1743
  }
1744
+ function displayOffset(chars, charIndex, width) {
1745
+ let offset = 0;
1746
+ for (let i = 0; i < charIndex && i < chars.length; i++) {
1747
+ const w = (0, import_string_width.default)(chars[i]);
1748
+ const col = offset % width;
1749
+ if (col + w > width) offset += width - col;
1750
+ offset += w;
1751
+ }
1752
+ return offset;
1753
+ }
1754
+ function charIndexAtDisplayOffset(chars, target, width) {
1755
+ let offset = 0;
1756
+ for (let i = 0; i < chars.length; i++) {
1757
+ if (offset >= target) return i;
1758
+ const w = (0, import_string_width.default)(chars[i]);
1759
+ const col = offset % width;
1760
+ if (col + w > width) offset += width - col;
1761
+ offset += w;
1762
+ }
1763
+ return chars.length;
1764
+ }
1743
1765
  function CjkTextInput({
1744
1766
  value,
1745
1767
  onChange,
@@ -1747,7 +1769,8 @@ function CjkTextInput({
1747
1769
  onPaste,
1748
1770
  placeholder = "",
1749
1771
  focus = true,
1750
- showCursor = true
1772
+ showCursor = true,
1773
+ availableWidth
1751
1774
  }) {
1752
1775
  const valueRef = (0, import_react8.useRef)(value);
1753
1776
  const cursorRef = (0, import_react8.useRef)(value.length);
@@ -1761,7 +1784,22 @@ function CjkTextInput({
1761
1784
  (0, import_ink4.useInput)(
1762
1785
  (input, key) => {
1763
1786
  try {
1764
- if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
1787
+ if (key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
1788
+ return;
1789
+ }
1790
+ if (key.upArrow || key.downArrow) {
1791
+ if (availableWidth && availableWidth > 0) {
1792
+ const chars = [...valueRef.current];
1793
+ const offset = displayOffset(chars, cursorRef.current, availableWidth);
1794
+ const target = key.upArrow ? offset - availableWidth : offset + availableWidth;
1795
+ if (target >= 0) {
1796
+ const newCursor = charIndexAtDisplayOffset(chars, target, availableWidth);
1797
+ if (newCursor !== cursorRef.current) {
1798
+ cursorRef.current = newCursor;
1799
+ forceRender((n) => n + 1);
1800
+ }
1801
+ }
1802
+ }
1765
1803
  return;
1766
1804
  }
1767
1805
  if (key.return) {
@@ -1954,14 +1992,23 @@ function useAutocomplete(value, registry) {
1954
1992
  }
1955
1993
  };
1956
1994
  }
1995
+ var BORDER_HORIZONTAL = 2;
1996
+ var PADDING_LEFT = 1;
1997
+ var PROMPT_WIDTH = 2;
1998
+ var INPUT_AREA_OVERHEAD = BORDER_HORIZONTAL + PADDING_LEFT + PROMPT_WIDTH;
1957
1999
  function InputArea({
1958
2000
  onSubmit,
2001
+ onCancelQueue,
1959
2002
  isDisabled,
1960
2003
  isAborting,
2004
+ pendingPrompt,
1961
2005
  registry
1962
2006
  }) {
1963
2007
  const [value, setValue] = (0, import_react10.useState)("");
1964
2008
  const pasteStore = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
2009
+ const { stdout } = (0, import_ink7.useStdout)();
2010
+ const terminalColumns = stdout?.columns ?? 80;
2011
+ const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
1965
2012
  const pasteIdRef = (0, import_react10.useRef)(0);
1966
2013
  const {
1967
2014
  showPopup,
@@ -2030,6 +2077,14 @@ function InputArea({
2030
2077
  },
2031
2078
  { isActive: showPopup && !isDisabled }
2032
2079
  );
2080
+ (0, import_ink7.useInput)(
2081
+ (_input, key) => {
2082
+ if ((key.backspace || key.delete) && pendingPrompt) {
2083
+ onCancelQueue?.();
2084
+ }
2085
+ },
2086
+ { isActive: !!pendingPrompt }
2087
+ );
2033
2088
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", children: [
2034
2089
  showPopup && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2035
2090
  SlashAutocomplete,
@@ -2044,9 +2099,15 @@ function InputArea({
2044
2099
  import_ink7.Box,
2045
2100
  {
2046
2101
  borderStyle: "single",
2047
- borderColor: isAborting ? "yellow" : isDisabled ? "gray" : "green",
2102
+ borderColor: isAborting ? "yellow" : pendingPrompt ? "cyan" : isDisabled ? "gray" : "green",
2048
2103
  paddingLeft: 1,
2049
- children: isDisabled ? isAborting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", children: " Interrupting..." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
2104
+ children: isAborting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", children: " Interrupting..." }) : pendingPrompt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { color: "cyan", children: [
2105
+ " ",
2106
+ "Queued: ",
2107
+ pendingPrompt.length > 50 ? pendingPrompt.slice(0, 47) + "..." : pendingPrompt,
2108
+ " ",
2109
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: "(Backspace to cancel)" })
2110
+ ] }) : isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
2050
2111
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "green", bold: true, children: "> " }),
2051
2112
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2052
2113
  CjkTextInput,
@@ -2055,7 +2116,8 @@ function InputArea({
2055
2116
  onChange: setValue,
2056
2117
  onSubmit: handleSubmit,
2057
2118
  onPaste: handlePaste,
2058
- placeholder: "Type a message or /help"
2119
+ placeholder: "Type a message or /help",
2120
+ availableWidth
2059
2121
  }
2060
2122
  )
2061
2123
  ] })
@@ -2709,6 +2771,8 @@ function App(props) {
2709
2771
  const [pendingModelId, setPendingModelId] = (0, import_react16.useState)(null);
2710
2772
  const [showPluginTUI, setShowPluginTUI] = (0, import_react16.useState)(false);
2711
2773
  const [isAborting, setIsAborting] = (0, import_react16.useState)(false);
2774
+ const [pendingPrompt, setPendingPrompt] = (0, import_react16.useState)(null);
2775
+ const pendingPromptRef = (0, import_react16.useRef)(null);
2712
2776
  const pluginCallbacks = usePluginCallbacks(props.cwd ?? process.cwd());
2713
2777
  const handleSlashCommand = useSlashCommands(
2714
2778
  session,
@@ -2721,7 +2785,7 @@ function App(props) {
2721
2785
  pluginCallbacks,
2722
2786
  setShowPluginTUI
2723
2787
  );
2724
- const handleSubmit = useSubmitHandler(
2788
+ const executePrompt = useSubmitHandler(
2725
2789
  session,
2726
2790
  addMessage,
2727
2791
  handleSlashCommand,
@@ -2730,18 +2794,39 @@ function App(props) {
2730
2794
  setContextState,
2731
2795
  registry
2732
2796
  );
2797
+ const handleSubmit = (0, import_react16.useCallback)(
2798
+ async (input) => {
2799
+ if (isThinking) {
2800
+ setPendingPrompt(input);
2801
+ pendingPromptRef.current = input;
2802
+ return;
2803
+ }
2804
+ await executePrompt(input);
2805
+ },
2806
+ [isThinking, executePrompt]
2807
+ );
2733
2808
  (0, import_ink13.useInput)(
2734
2809
  (_input, key) => {
2735
2810
  if (key.escape && isThinking) {
2736
2811
  setIsAborting(true);
2812
+ setPendingPrompt(null);
2813
+ pendingPromptRef.current = null;
2737
2814
  session.abort();
2738
2815
  }
2739
2816
  },
2740
2817
  { isActive: !permissionRequest && !showPluginTUI }
2741
2818
  );
2742
2819
  (0, import_react16.useEffect)(() => {
2743
- if (!isThinking) setIsAborting(false);
2744
- }, [isThinking]);
2820
+ if (!isThinking) {
2821
+ setIsAborting(false);
2822
+ if (pendingPromptRef.current) {
2823
+ const prompt = pendingPromptRef.current;
2824
+ setPendingPrompt(null);
2825
+ pendingPromptRef.current = null;
2826
+ setTimeout(() => executePrompt(prompt), 0);
2827
+ }
2828
+ }
2829
+ }, [isThinking, pendingPrompt, executePrompt]);
2745
2830
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
2746
2831
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
2747
2832
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Text, { color: "cyan", bold: true, children: `
@@ -2816,8 +2901,13 @@ function App(props) {
2816
2901
  InputArea,
2817
2902
  {
2818
2903
  onSubmit: handleSubmit,
2819
- isDisabled: isThinking || !!permissionRequest || showPluginTUI,
2904
+ onCancelQueue: () => {
2905
+ setPendingPrompt(null);
2906
+ pendingPromptRef.current = null;
2907
+ },
2908
+ isDisabled: !!permissionRequest || showPluginTUI || isThinking && !!pendingPrompt,
2820
2909
  isAborting,
2910
+ pendingPrompt,
2821
2911
  registry
2822
2912
  }
2823
2913
  ),
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startCli
3
- } from "./chunk-P323ORQX.js";
3
+ } from "./chunk-GWN5C72P.js";
4
4
 
5
5
  // src/index.ts
6
6
  import { Session, SessionStore, query, TRUST_TO_MODE } from "@robota-sdk/agent-sdk";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robota-sdk/agent-cli",
3
- "version": "3.0.0-beta.37",
3
+ "version": "3.0.0-beta.39",
4
4
  "description": "AI coding assistant CLI built on Robota SDK",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,8 +35,8 @@
35
35
  "marked-terminal": "^7.3.0",
36
36
  "react": "19.2.4",
37
37
  "string-width": "^8.2.0",
38
- "@robota-sdk/agent-sdk": "3.0.0-beta.33",
39
- "@robota-sdk/agent-core": "3.0.0-beta.33"
38
+ "@robota-sdk/agent-core": "3.0.0-beta.33",
39
+ "@robota-sdk/agent-sdk": "3.0.0-beta.33"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/marked": "^6.0.0",