@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 +99 -9
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-P323ORQX.js → chunk-GWN5C72P.js} +101 -11
- package/dist/node/index.cjs +99 -9
- package/dist/node/index.js +1 -1
- package/package.json +3 -3
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.
|
|
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:
|
|
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
|
|
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)
|
|
2728
|
-
|
|
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
|
-
|
|
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
|
@@ -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.
|
|
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:
|
|
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
|
|
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)
|
|
2725
|
-
|
|
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
|
-
|
|
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
|
),
|
package/dist/node/index.cjs
CHANGED
|
@@ -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.
|
|
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:
|
|
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
|
|
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)
|
|
2744
|
-
|
|
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
|
-
|
|
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
|
),
|
package/dist/node/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-cli",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
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-
|
|
39
|
-
"@robota-sdk/agent-
|
|
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",
|