@ai-setting/roy-agent-cli 1.7.42 → 1.7.45
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/bin/roy-agent.js +817 -211
- package/dist/index.js +817 -211
- package/dist/roy-agent-linux-x64/bin/roy-agent +2 -2
- package/package.json +1 -1
package/dist/bin/roy-agent.js
CHANGED
|
@@ -609,6 +609,7 @@ ${COLORS.system("[已中断]")}
|
|
|
609
609
|
this.emitChunk({
|
|
610
610
|
type: "tool.result",
|
|
611
611
|
toolName: name,
|
|
612
|
+
toolId: payload.id,
|
|
612
613
|
toolResult: payload.result?.output
|
|
613
614
|
});
|
|
614
615
|
}
|
|
@@ -1559,69 +1560,94 @@ var init_theme = __esm(() => {
|
|
|
1559
1560
|
});
|
|
1560
1561
|
|
|
1561
1562
|
// src/tui/StatusBar.tsx
|
|
1563
|
+
import React2 from "react";
|
|
1562
1564
|
import { Box as Box2, Text as Text3 } from "ink";
|
|
1563
1565
|
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
1564
|
-
|
|
1566
|
+
function detectColumns() {
|
|
1567
|
+
const c = process.stdout?.columns;
|
|
1568
|
+
if (typeof c === "number" && c > 0)
|
|
1569
|
+
return c;
|
|
1570
|
+
return 80;
|
|
1571
|
+
}
|
|
1572
|
+
function shortenWorkdir(input) {
|
|
1573
|
+
if (!input)
|
|
1574
|
+
return input;
|
|
1575
|
+
if (input.length <= WORKDIR_TAIL_MAX)
|
|
1576
|
+
return input;
|
|
1577
|
+
const tail = input.slice(input.length - WORKDIR_TAIL_MAX);
|
|
1578
|
+
return `…/${tail}`;
|
|
1579
|
+
}
|
|
1580
|
+
function clipModel(input, max = MODEL_NARROW_MAX) {
|
|
1581
|
+
if (!input)
|
|
1582
|
+
return input;
|
|
1583
|
+
if (input.length <= max)
|
|
1584
|
+
return input;
|
|
1585
|
+
return input.slice(0, max - 1) + "…";
|
|
1586
|
+
}
|
|
1587
|
+
function planSegments(props, columns) {
|
|
1588
|
+
const segs = [];
|
|
1589
|
+
const tier = columns >= 80 ? 4 : columns >= 60 ? 3 : columns >= 40 ? 2 : 1;
|
|
1590
|
+
if (props.model) {
|
|
1591
|
+
const text = tier === 1 ? clipModel(props.model) ?? "" : props.model;
|
|
1592
|
+
segs.push({ text, color: "primary", dimPrefix: "\uD83E\uDD16 " });
|
|
1593
|
+
}
|
|
1594
|
+
if (tier >= 4 || tier === 3) {
|
|
1595
|
+
if (props.workdir) {
|
|
1596
|
+
segs.push({
|
|
1597
|
+
text: shortenWorkdir(props.workdir) ?? "",
|
|
1598
|
+
color: "muted",
|
|
1599
|
+
dimPrefix: "\uD83D\uDCC1 "
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
if (tier >= 4 || tier === 3 || tier === 2) {
|
|
1604
|
+
if (typeof props.tokenCount === "number") {
|
|
1605
|
+
segs.push({ text: `n=${props.tokenCount}`, color: "accent", dimPrefix: "" });
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
if (tier >= 4) {
|
|
1609
|
+
segs.push({ text: "Ctrl+C to exit", color: "muted" });
|
|
1610
|
+
}
|
|
1611
|
+
return segs;
|
|
1612
|
+
}
|
|
1613
|
+
var WORKDIR_TAIL_MAX = 30, MODEL_NARROW_MAX = 24, StatusBar = ({
|
|
1565
1614
|
model,
|
|
1566
1615
|
workdir,
|
|
1567
|
-
tokenCount
|
|
1616
|
+
tokenCount,
|
|
1617
|
+
columns
|
|
1568
1618
|
}) => {
|
|
1569
1619
|
const theme = getTheme();
|
|
1620
|
+
const cols = typeof columns === "number" ? columns : detectColumns();
|
|
1621
|
+
const segs = planSegments({ model, workdir, tokenCount }, cols);
|
|
1622
|
+
if (segs.length === 0) {
|
|
1623
|
+
return /* @__PURE__ */ jsxDEV3(Box2, {
|
|
1624
|
+
paddingX: 1
|
|
1625
|
+
}, undefined, false, undefined, this);
|
|
1626
|
+
}
|
|
1570
1627
|
return /* @__PURE__ */ jsxDEV3(Box2, {
|
|
1571
|
-
borderStyle: "single",
|
|
1572
|
-
borderColor: "gray",
|
|
1573
1628
|
paddingX: 1,
|
|
1574
|
-
|
|
1575
|
-
children:
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
1580
|
-
dimColor: true,
|
|
1581
|
-
children: "\uD83E\uDD16 "
|
|
1582
|
-
}, undefined, false, undefined, this),
|
|
1583
|
-
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
1584
|
-
color: theme.primary,
|
|
1585
|
-
children: model
|
|
1586
|
-
}, undefined, false, undefined, this)
|
|
1587
|
-
]
|
|
1588
|
-
}, undefined, true, undefined, this) : null
|
|
1589
|
-
}, undefined, false, undefined, this),
|
|
1590
|
-
/* @__PURE__ */ jsxDEV3(Box2, {
|
|
1591
|
-
children: workdir ? /* @__PURE__ */ jsxDEV3(Text3, {
|
|
1592
|
-
children: [
|
|
1593
|
-
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
1594
|
-
dimColor: true,
|
|
1595
|
-
children: "\uD83D\uDCC1 "
|
|
1596
|
-
}, undefined, false, undefined, this),
|
|
1597
|
-
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
1598
|
-
children: workdir
|
|
1599
|
-
}, undefined, false, undefined, this)
|
|
1600
|
-
]
|
|
1601
|
-
}, undefined, true, undefined, this) : null
|
|
1602
|
-
}, undefined, false, undefined, this),
|
|
1603
|
-
/* @__PURE__ */ jsxDEV3(Box2, {
|
|
1629
|
+
flexDirection: "row",
|
|
1630
|
+
children: segs.map((seg, i) => {
|
|
1631
|
+
const color = seg.color === "primary" ? theme.primary : seg.color === "accent" ? theme.accent : theme.muted;
|
|
1632
|
+
const isFirst = i === 0;
|
|
1633
|
+
return /* @__PURE__ */ jsxDEV3(React2.Fragment, {
|
|
1604
1634
|
children: [
|
|
1605
|
-
|
|
1606
|
-
children: [
|
|
1607
|
-
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
1608
|
-
dimColor: true,
|
|
1609
|
-
children: "tokens: "
|
|
1610
|
-
}, undefined, false, undefined, this),
|
|
1611
|
-
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
1612
|
-
color: theme.accent,
|
|
1613
|
-
children: tokenCount
|
|
1614
|
-
}, undefined, false, undefined, this)
|
|
1615
|
-
]
|
|
1616
|
-
}, undefined, true, undefined, this) : null,
|
|
1617
|
-
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
1635
|
+
!isFirst ? /* @__PURE__ */ jsxDEV3(Text3, {
|
|
1618
1636
|
dimColor: true,
|
|
1619
|
-
children: "
|
|
1637
|
+
children: " · "
|
|
1638
|
+
}, undefined, false, undefined, this) : null,
|
|
1639
|
+
seg.dimPrefix ? /* @__PURE__ */ jsxDEV3(Text3, {
|
|
1640
|
+
dimColor: true,
|
|
1641
|
+
children: seg.dimPrefix
|
|
1642
|
+
}, undefined, false, undefined, this) : null,
|
|
1643
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
1644
|
+
color,
|
|
1645
|
+
children: seg.text
|
|
1620
1646
|
}, undefined, false, undefined, this)
|
|
1621
1647
|
]
|
|
1622
|
-
},
|
|
1623
|
-
|
|
1624
|
-
}, undefined,
|
|
1648
|
+
}, i, true, undefined, this);
|
|
1649
|
+
})
|
|
1650
|
+
}, undefined, false, undefined, this);
|
|
1625
1651
|
};
|
|
1626
1652
|
var init_StatusBar = __esm(() => {
|
|
1627
1653
|
init_theme();
|
|
@@ -1676,7 +1702,7 @@ __export(exports_repl_ink, {
|
|
|
1676
1702
|
REPLInk: () => REPLInk,
|
|
1677
1703
|
MultilineInput: () => MultilineInput
|
|
1678
1704
|
});
|
|
1679
|
-
import * as
|
|
1705
|
+
import * as React3 from "react";
|
|
1680
1706
|
import { Box as Box3, Text as Text4, Static, useApp, useInput as useInput2 } from "ink";
|
|
1681
1707
|
import { createLogger as createLogger5 } from "@ai-setting/roy-agent-core";
|
|
1682
1708
|
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
@@ -1701,7 +1727,7 @@ function REPLInk(props) {
|
|
|
1701
1727
|
onEscape
|
|
1702
1728
|
} = props;
|
|
1703
1729
|
const { exit: appExit } = useApp();
|
|
1704
|
-
const [messages, setMessages] =
|
|
1730
|
+
const [messages, setMessages] = React3.useState(() => [
|
|
1705
1731
|
withMessageId({
|
|
1706
1732
|
role: "system",
|
|
1707
1733
|
kind: "welcome",
|
|
@@ -1709,47 +1735,47 @@ function REPLInk(props) {
|
|
|
1709
1735
|
}),
|
|
1710
1736
|
...initialMessages.map(withMessageId)
|
|
1711
1737
|
]);
|
|
1712
|
-
const [mode, setMode] =
|
|
1713
|
-
const [statusBarCtx, setStatusBarCtxState] =
|
|
1738
|
+
const [mode, setMode] = React3.useState(initialMode);
|
|
1739
|
+
const [statusBarCtx, setStatusBarCtxState] = React3.useState({
|
|
1714
1740
|
mode: initialMode,
|
|
1715
1741
|
cwd: initialStatusBarCtx.cwd ?? initialContext.cwd,
|
|
1716
1742
|
gitBranch: initialStatusBarCtx.gitBranch,
|
|
1717
1743
|
model: initialStatusBarCtx.model ?? initialContext.model
|
|
1718
1744
|
});
|
|
1719
|
-
const [inputValue, setInputValue] =
|
|
1720
|
-
const [popupIndex, setPopupIndex] =
|
|
1721
|
-
const filteredCmds =
|
|
1745
|
+
const [inputValue, setInputValue] = React3.useState("");
|
|
1746
|
+
const [popupIndex, setPopupIndex] = React3.useState(0);
|
|
1747
|
+
const filteredCmds = React3.useMemo(() => {
|
|
1722
1748
|
if (!/^\/\S*$/.test(inputValue))
|
|
1723
1749
|
return [];
|
|
1724
1750
|
return filterCommands(inputValue);
|
|
1725
1751
|
}, [inputValue]);
|
|
1726
1752
|
const showPopup = filteredCmds.length > 0;
|
|
1727
|
-
|
|
1753
|
+
React3.useEffect(() => {
|
|
1728
1754
|
setPopupIndex(0);
|
|
1729
1755
|
}, [filteredCmds]);
|
|
1730
1756
|
const safePopupIndex = clampSelectedIndex(popupIndex, filteredCmds.length);
|
|
1731
|
-
const handlePopupSelect =
|
|
1757
|
+
const handlePopupSelect = React3.useCallback((cmd) => {
|
|
1732
1758
|
multilineInputRef.current?.setBuffer(cmd.cmd + " ");
|
|
1733
1759
|
setInputValue(cmd.cmd + " ");
|
|
1734
1760
|
}, []);
|
|
1735
|
-
const handlePopupClose =
|
|
1761
|
+
const handlePopupClose = React3.useCallback(() => {
|
|
1736
1762
|
const current = multilineInputRef.current?.getBuffer() ?? "";
|
|
1737
1763
|
const stripped = current.replace(/^\/+/, "");
|
|
1738
1764
|
multilineInputRef.current?.setBuffer(stripped);
|
|
1739
1765
|
setInputValue(stripped);
|
|
1740
1766
|
}, []);
|
|
1741
|
-
const handlePopupIndexChange =
|
|
1767
|
+
const handlePopupIndexChange = React3.useCallback((idx) => {
|
|
1742
1768
|
setPopupIndex(idx);
|
|
1743
1769
|
}, []);
|
|
1744
|
-
const streamingIndexRef =
|
|
1745
|
-
const lastFlushTsRef =
|
|
1770
|
+
const streamingIndexRef = React3.useRef(-1);
|
|
1771
|
+
const lastFlushTsRef = React3.useRef(0);
|
|
1746
1772
|
const STALE_STREAM_THRESHOLD_MS = 1000;
|
|
1747
|
-
const multilineInputRef =
|
|
1748
|
-
const lastEscapeTsRef =
|
|
1749
|
-
const pendingDeltaRef =
|
|
1750
|
-
const throttleTimerRef =
|
|
1751
|
-
const isFirstDeltaInStreamRef =
|
|
1752
|
-
const flushStreamingDelta =
|
|
1773
|
+
const multilineInputRef = React3.useRef(null);
|
|
1774
|
+
const lastEscapeTsRef = React3.useRef(0);
|
|
1775
|
+
const pendingDeltaRef = React3.useRef("");
|
|
1776
|
+
const throttleTimerRef = React3.useRef(null);
|
|
1777
|
+
const isFirstDeltaInStreamRef = React3.useRef(true);
|
|
1778
|
+
const flushStreamingDelta = React3.useCallback(() => {
|
|
1753
1779
|
const delta = pendingDeltaRef.current;
|
|
1754
1780
|
pendingDeltaRef.current = "";
|
|
1755
1781
|
throttleTimerRef.current = null;
|
|
@@ -1778,7 +1804,7 @@ function REPLInk(props) {
|
|
|
1778
1804
|
});
|
|
1779
1805
|
lastFlushTsRef.current = Date.now();
|
|
1780
1806
|
}, []);
|
|
1781
|
-
|
|
1807
|
+
React3.useEffect(() => {
|
|
1782
1808
|
return () => {
|
|
1783
1809
|
if (throttleTimerRef.current !== null) {
|
|
1784
1810
|
clearTimeout(throttleTimerRef.current);
|
|
@@ -1786,8 +1812,8 @@ function REPLInk(props) {
|
|
|
1786
1812
|
}
|
|
1787
1813
|
};
|
|
1788
1814
|
}, []);
|
|
1789
|
-
const apiRef =
|
|
1790
|
-
|
|
1815
|
+
const apiRef = React3.useRef(null);
|
|
1816
|
+
React3.useEffect(() => {
|
|
1791
1817
|
const api = {
|
|
1792
1818
|
appendMessage: (msg) => {
|
|
1793
1819
|
setMessages((msgs) => [...msgs, withMessageId(msg)]);
|
|
@@ -1863,7 +1889,7 @@ function REPLInk(props) {
|
|
|
1863
1889
|
apiRef.current = api;
|
|
1864
1890
|
onReady?.(api);
|
|
1865
1891
|
}, [appExit, onCommand, onReady]);
|
|
1866
|
-
const handleEscapeCascade =
|
|
1892
|
+
const handleEscapeCascade = React3.useCallback(() => {
|
|
1867
1893
|
const now = Date.now();
|
|
1868
1894
|
if (now - lastEscapeTsRef.current < 100) {
|
|
1869
1895
|
return;
|
|
@@ -1907,7 +1933,7 @@ function REPLInk(props) {
|
|
|
1907
1933
|
}
|
|
1908
1934
|
}
|
|
1909
1935
|
});
|
|
1910
|
-
const handleSubmit =
|
|
1936
|
+
const handleSubmit = React3.useCallback(async (value) => {
|
|
1911
1937
|
if (!value || value.trim() === "") {
|
|
1912
1938
|
return;
|
|
1913
1939
|
}
|
|
@@ -1936,7 +1962,7 @@ function REPLInk(props) {
|
|
|
1936
1962
|
]);
|
|
1937
1963
|
}
|
|
1938
1964
|
}, [onCommand, onSubmit]);
|
|
1939
|
-
const staticItems =
|
|
1965
|
+
const staticItems = React3.useMemo(() => {
|
|
1940
1966
|
if (messages.length <= 1)
|
|
1941
1967
|
return [];
|
|
1942
1968
|
return messages.slice(0, -1);
|
|
@@ -1944,8 +1970,8 @@ function REPLInk(props) {
|
|
|
1944
1970
|
const tailMsg = messages.length > 0 ? messages[messages.length - 1] : null;
|
|
1945
1971
|
const terminalWidth = process.stdout.columns ?? 80;
|
|
1946
1972
|
const terminalHeight = process.stdout.rows ?? 24;
|
|
1947
|
-
const dynamicTailBounds =
|
|
1948
|
-
const staticTailBounds =
|
|
1973
|
+
const dynamicTailBounds = React3.useMemo(() => computeDynamicTailBounds(terminalHeight, 12, showPopup), [terminalHeight, showPopup]);
|
|
1974
|
+
const staticTailBounds = React3.useMemo(() => computeDynamicTailBounds(terminalHeight, 12, showPopup), [terminalHeight, showPopup]);
|
|
1949
1975
|
const tailKey = messages.length > 0 ? tailMsg?.id ?? `tail-${messages.length - 1}` : "tail-empty";
|
|
1950
1976
|
const statusBarModel = shortModel(statusBarCtx.model);
|
|
1951
1977
|
const statusBarWorkdir = statusBarCtx.cwd;
|
|
@@ -2012,7 +2038,7 @@ function shortModel(model) {
|
|
|
2012
2038
|
}
|
|
2013
2039
|
async function renderInkREPL(props) {
|
|
2014
2040
|
const ink = await import("ink");
|
|
2015
|
-
const { waitUntilExit } = ink.render(
|
|
2041
|
+
const { waitUntilExit } = ink.render(React3.createElement(REPLInk, props));
|
|
2016
2042
|
await waitUntilExit();
|
|
2017
2043
|
}
|
|
2018
2044
|
var MarkdownBounded, inkLogger, _msgIdCounter = 0, MultilineInput, MessageView;
|
|
@@ -2024,7 +2050,7 @@ var init_repl_ink = __esm(() => {
|
|
|
2024
2050
|
init_Markdown();
|
|
2025
2051
|
init_StatusBar();
|
|
2026
2052
|
init_dynamic_tail();
|
|
2027
|
-
MarkdownBounded =
|
|
2053
|
+
MarkdownBounded = React3.memo(({ text, bounds, width }) => {
|
|
2028
2054
|
const out = renderBoundedAssistant(text, bounds, width);
|
|
2029
2055
|
if (!out) {
|
|
2030
2056
|
return null;
|
|
@@ -2034,16 +2060,16 @@ var init_repl_ink = __esm(() => {
|
|
|
2034
2060
|
}, undefined, false, undefined, this);
|
|
2035
2061
|
});
|
|
2036
2062
|
inkLogger = createLogger5("repl-ink");
|
|
2037
|
-
MultilineInput =
|
|
2063
|
+
MultilineInput = React3.memo(React3.forwardRef(function MultilineInput2(props, ref) {
|
|
2038
2064
|
const { onSubmit, placeholder, popupActive, onChange, onEscape } = props;
|
|
2039
|
-
const [buffer, setBuffer] =
|
|
2040
|
-
const [cursor, setCursor] =
|
|
2041
|
-
|
|
2065
|
+
const [buffer, setBuffer] = React3.useState("");
|
|
2066
|
+
const [cursor, setCursor] = React3.useState(0);
|
|
2067
|
+
React3.useEffect(() => {
|
|
2042
2068
|
if (popupActive || buffer.startsWith("/")) {
|
|
2043
2069
|
onChange?.(buffer);
|
|
2044
2070
|
}
|
|
2045
2071
|
}, [buffer, onChange, popupActive]);
|
|
2046
|
-
|
|
2072
|
+
React3.useImperativeHandle(ref, () => ({
|
|
2047
2073
|
clearBuffer: () => {
|
|
2048
2074
|
setBuffer("");
|
|
2049
2075
|
setCursor(0);
|
|
@@ -2281,7 +2307,7 @@ var init_repl_ink = __esm(() => {
|
|
|
2281
2307
|
})
|
|
2282
2308
|
}, undefined, false, undefined, this);
|
|
2283
2309
|
}));
|
|
2284
|
-
MessageView =
|
|
2310
|
+
MessageView = React3.memo(function MessageView2({
|
|
2285
2311
|
msg,
|
|
2286
2312
|
terminalWidth,
|
|
2287
2313
|
tailBounds
|
|
@@ -9461,7 +9487,7 @@ class CliQuietModeService {
|
|
|
9461
9487
|
// package.json
|
|
9462
9488
|
var package_default = {
|
|
9463
9489
|
name: "@ai-setting/roy-agent-cli",
|
|
9464
|
-
version: "1.7.
|
|
9490
|
+
version: "1.7.45",
|
|
9465
9491
|
type: "module",
|
|
9466
9492
|
description: "CLI for roy-agent - Non-interactive command execution",
|
|
9467
9493
|
main: "./dist/index.js",
|
|
@@ -13591,7 +13617,7 @@ ${chalk7.bold("╰")}${chalk7.dim("─".repeat(49))}${chalk7.bold("╯")}
|
|
|
13591
13617
|
}
|
|
13592
13618
|
function createInteractiveCommand(externalEnvService) {
|
|
13593
13619
|
return {
|
|
13594
|
-
command: "
|
|
13620
|
+
command: "run",
|
|
13595
13621
|
aliases: ["i", "repl"],
|
|
13596
13622
|
describe: "交互式模式 - 多轮对话交互",
|
|
13597
13623
|
builder: (yargs) => yargs.option("session", {
|
|
@@ -13676,7 +13702,7 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
13676
13702
|
configPath: args.config,
|
|
13677
13703
|
plugins: [...componentPluginNames, ...coderPluginNames],
|
|
13678
13704
|
loadPlugins: true,
|
|
13679
|
-
commandName: "
|
|
13705
|
+
commandName: "run"
|
|
13680
13706
|
});
|
|
13681
13707
|
}
|
|
13682
13708
|
const env = envService.getEnvironment();
|
|
@@ -13983,16 +14009,16 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
13983
14009
|
var InteractiveCommand = createInteractiveCommand();
|
|
13984
14010
|
|
|
13985
14011
|
// src/commands/run.ts
|
|
13986
|
-
import
|
|
14012
|
+
import React7 from "react";
|
|
13987
14013
|
import { render } from "ink";
|
|
13988
14014
|
|
|
13989
14015
|
// src/RunTui.tsx
|
|
13990
|
-
import { useState as useState6, useCallback as useCallback4, useRef as
|
|
13991
|
-
import { Box as
|
|
14016
|
+
import { useState as useState6, useCallback as useCallback4, useRef as useRef3, useEffect as useEffect5 } from "react";
|
|
14017
|
+
import { Box as Box7, Text as Text9, useApp as useApp2, useStdout } from "ink";
|
|
13992
14018
|
|
|
13993
14019
|
// src/tui/App.tsx
|
|
13994
14020
|
init_Markdown();
|
|
13995
|
-
import { Box as
|
|
14021
|
+
import { Box as Box5, Static as Static2, Text as Text7 } from "ink";
|
|
13996
14022
|
|
|
13997
14023
|
// src/tui/Spinner.tsx
|
|
13998
14024
|
init_theme();
|
|
@@ -14029,8 +14055,262 @@ var Spinner = ({
|
|
|
14029
14055
|
|
|
14030
14056
|
// src/tui/App.tsx
|
|
14031
14057
|
init_StatusBar();
|
|
14058
|
+
|
|
14059
|
+
// src/tui/ToolCall.tsx
|
|
14060
|
+
import { Box as Box4, Text as Text6 } from "ink";
|
|
14032
14061
|
init_theme();
|
|
14062
|
+
|
|
14063
|
+
// src/tui/tool-call.ts
|
|
14064
|
+
var TOOL_META = {
|
|
14065
|
+
bash: { icon: "❯", label: "Bash", argKeys: ["command", "cmd"] },
|
|
14066
|
+
shell: { icon: "❯", label: "Bash", argKeys: ["command", "cmd"] },
|
|
14067
|
+
echo: { icon: "\uD83D\uDCAC", label: "Echo", argKeys: ["message", "text"] },
|
|
14068
|
+
read_file: {
|
|
14069
|
+
icon: "\uD83D\uDCD6",
|
|
14070
|
+
label: "Read",
|
|
14071
|
+
argKeys: ["file_path", "path", "filePath", "filename"]
|
|
14072
|
+
},
|
|
14073
|
+
write_file: {
|
|
14074
|
+
icon: "\uD83D\uDCDD",
|
|
14075
|
+
label: "Write",
|
|
14076
|
+
argKeys: ["file_path", "path", "filePath", "filename"]
|
|
14077
|
+
},
|
|
14078
|
+
edit_file: {
|
|
14079
|
+
icon: "✏️",
|
|
14080
|
+
label: "Edit",
|
|
14081
|
+
argKeys: ["file_path", "path", "filePath", "filename"]
|
|
14082
|
+
},
|
|
14083
|
+
glob: { icon: "\uD83D\uDD0D", label: "Glob", argKeys: ["pattern"] },
|
|
14084
|
+
grep: { icon: "\uD83D\uDD0E", label: "Grep", argKeys: ["pattern", "query"] },
|
|
14085
|
+
query_background_process: {
|
|
14086
|
+
icon: "\uD83D\uDCE1",
|
|
14087
|
+
label: "Background Process",
|
|
14088
|
+
argKeys: ["id", "process_id"]
|
|
14089
|
+
},
|
|
14090
|
+
understand_image: {
|
|
14091
|
+
icon: "\uD83D\uDDBC️",
|
|
14092
|
+
label: "Understand Image",
|
|
14093
|
+
argKeys: ["image_path", "path", "url"]
|
|
14094
|
+
},
|
|
14095
|
+
delegate_task: {
|
|
14096
|
+
icon: "\uD83E\uDD16",
|
|
14097
|
+
label: "Task",
|
|
14098
|
+
argKeys: ["description", "prompt"]
|
|
14099
|
+
},
|
|
14100
|
+
stop_task: { icon: "\uD83D\uDED1", label: "Stop Task", argKeys: ["task_id", "id"] },
|
|
14101
|
+
task_search: { icon: "\uD83D\uDD0E", label: "Task Search", argKeys: ["query"] },
|
|
14102
|
+
ask_user: { icon: "❓", label: "Ask User", argKeys: ["question"] },
|
|
14103
|
+
workflow_run: {
|
|
14104
|
+
icon: "\uD83D\uDD00",
|
|
14105
|
+
label: "Run Workflow",
|
|
14106
|
+
argKeys: ["workflow", "name", "path"]
|
|
14107
|
+
},
|
|
14108
|
+
web_search: { icon: "\uD83C\uDF10", label: "Web Search", argKeys: ["query"] },
|
|
14109
|
+
webfetch: { icon: "\uD83C\uDF10", label: "Fetch", argKeys: ["url"] },
|
|
14110
|
+
fetch: { icon: "\uD83C\uDF10", label: "Fetch", argKeys: ["url"] },
|
|
14111
|
+
skill: { icon: "\uD83C\uDFAF", label: "Skill", argKeys: ["name"] }
|
|
14112
|
+
};
|
|
14113
|
+
var TOOL_ALIASES = {
|
|
14114
|
+
read: "read_file",
|
|
14115
|
+
write: "write_file",
|
|
14116
|
+
edit: "edit_file",
|
|
14117
|
+
search: "grep",
|
|
14118
|
+
task: "delegate_task",
|
|
14119
|
+
run_terminal_cmd: "bash",
|
|
14120
|
+
terminal: "bash"
|
|
14121
|
+
};
|
|
14122
|
+
function humanizeToolName(name) {
|
|
14123
|
+
if (!name)
|
|
14124
|
+
return "Tool";
|
|
14125
|
+
const spaced = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
|
|
14126
|
+
return spaced.split(/\s+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
14127
|
+
}
|
|
14128
|
+
function firstLine(value, max = 120) {
|
|
14129
|
+
const line = value.split(/\r?\n/)[0]?.trim() ?? "";
|
|
14130
|
+
return line.length > max ? `${line.slice(0, max - 1)}…` : line;
|
|
14131
|
+
}
|
|
14132
|
+
function summarizeArgs(args) {
|
|
14133
|
+
for (const value of Object.values(args)) {
|
|
14134
|
+
if (typeof value === "string" && value.trim())
|
|
14135
|
+
return firstLine(value);
|
|
14136
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
14137
|
+
return String(value);
|
|
14138
|
+
}
|
|
14139
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
14140
|
+
return firstLine(value.map((v) => String(v)).join(" "));
|
|
14141
|
+
}
|
|
14142
|
+
}
|
|
14143
|
+
return "";
|
|
14144
|
+
}
|
|
14145
|
+
function describeToolCall(name, args) {
|
|
14146
|
+
const meta = TOOL_META[name] ?? TOOL_META[TOOL_ALIASES[name] ?? ""];
|
|
14147
|
+
const label = meta?.label ?? humanizeToolName(name);
|
|
14148
|
+
const icon = meta?.icon ?? "⚙";
|
|
14149
|
+
let detail = "";
|
|
14150
|
+
if (args && Object.keys(args).length > 0) {
|
|
14151
|
+
const keys = meta?.argKeys ?? [];
|
|
14152
|
+
for (const key of keys) {
|
|
14153
|
+
const value = args[key];
|
|
14154
|
+
if (typeof value === "string" && value.trim()) {
|
|
14155
|
+
detail = firstLine(value);
|
|
14156
|
+
break;
|
|
14157
|
+
}
|
|
14158
|
+
if (value !== undefined && value !== null && typeof value !== "object") {
|
|
14159
|
+
detail = String(value);
|
|
14160
|
+
break;
|
|
14161
|
+
}
|
|
14162
|
+
}
|
|
14163
|
+
if (!detail)
|
|
14164
|
+
detail = summarizeArgs(args);
|
|
14165
|
+
}
|
|
14166
|
+
return { icon, label, detail };
|
|
14167
|
+
}
|
|
14168
|
+
function stringifyToolOutput(output) {
|
|
14169
|
+
if (output === undefined || output === null)
|
|
14170
|
+
return "";
|
|
14171
|
+
if (typeof output === "string")
|
|
14172
|
+
return output;
|
|
14173
|
+
if (typeof output === "object") {
|
|
14174
|
+
const obj = output;
|
|
14175
|
+
for (const key of ["output", "text", "content", "message"]) {
|
|
14176
|
+
if (typeof obj[key] === "string")
|
|
14177
|
+
return obj[key];
|
|
14178
|
+
}
|
|
14179
|
+
try {
|
|
14180
|
+
return JSON.stringify(output, null, 2);
|
|
14181
|
+
} catch {
|
|
14182
|
+
return String(output);
|
|
14183
|
+
}
|
|
14184
|
+
}
|
|
14185
|
+
return String(output);
|
|
14186
|
+
}
|
|
14187
|
+
function formatToolOutput(output, options = {}) {
|
|
14188
|
+
const { maxLines = 12, maxChars = 200 } = options;
|
|
14189
|
+
const text = stringifyToolOutput(output).replace(/\r\n?/g, `
|
|
14190
|
+
`).replace(/\s+$/, "");
|
|
14191
|
+
if (!text)
|
|
14192
|
+
return "";
|
|
14193
|
+
const lines = text.split(`
|
|
14194
|
+
`);
|
|
14195
|
+
const shown = lines.slice(0, maxLines);
|
|
14196
|
+
const hidden = lines.length - shown.length;
|
|
14197
|
+
const body = shown.map((line) => firstLine(line, maxChars)).join(`
|
|
14198
|
+
`);
|
|
14199
|
+
return hidden > 0 ? `${body}
|
|
14200
|
+
… (+${hidden} more lines)` : body;
|
|
14201
|
+
}
|
|
14202
|
+
function formatDuration(ms) {
|
|
14203
|
+
if (!Number.isFinite(ms) || ms < 0)
|
|
14204
|
+
return "";
|
|
14205
|
+
if (ms < 1000)
|
|
14206
|
+
return `${Math.round(ms)}ms`;
|
|
14207
|
+
const seconds = ms / 1000;
|
|
14208
|
+
if (seconds < 10)
|
|
14209
|
+
return `${seconds.toFixed(1)}s`;
|
|
14210
|
+
if (seconds < 60)
|
|
14211
|
+
return `${Math.round(seconds)}s`;
|
|
14212
|
+
const minutes = Math.floor(seconds / 60);
|
|
14213
|
+
const rest = Math.round(seconds % 60);
|
|
14214
|
+
return `${minutes}m${rest.toString().padStart(2, "0")}s`;
|
|
14215
|
+
}
|
|
14216
|
+
|
|
14217
|
+
// src/tui/ToolCall.tsx
|
|
14033
14218
|
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
14219
|
+
var StatusBadge = ({ info }) => {
|
|
14220
|
+
const theme = getTheme();
|
|
14221
|
+
if (info.status === "running") {
|
|
14222
|
+
return /* @__PURE__ */ jsxDEV6(Spinner, {
|
|
14223
|
+
label: "running"
|
|
14224
|
+
}, undefined, false, undefined, this);
|
|
14225
|
+
}
|
|
14226
|
+
const duration = info.durationMs !== undefined ? ` ${formatDuration(info.durationMs)}` : "";
|
|
14227
|
+
if (info.status === "error") {
|
|
14228
|
+
return /* @__PURE__ */ jsxDEV6(Text6, {
|
|
14229
|
+
color: theme.error,
|
|
14230
|
+
children: [
|
|
14231
|
+
"✗",
|
|
14232
|
+
duration || " failed"
|
|
14233
|
+
]
|
|
14234
|
+
}, undefined, true, undefined, this);
|
|
14235
|
+
}
|
|
14236
|
+
return /* @__PURE__ */ jsxDEV6(Text6, {
|
|
14237
|
+
color: theme.success,
|
|
14238
|
+
children: [
|
|
14239
|
+
"✓",
|
|
14240
|
+
duration
|
|
14241
|
+
]
|
|
14242
|
+
}, undefined, true, undefined, this);
|
|
14243
|
+
};
|
|
14244
|
+
var ToolCall = ({
|
|
14245
|
+
info,
|
|
14246
|
+
showOutput = true
|
|
14247
|
+
}) => {
|
|
14248
|
+
const theme = getTheme();
|
|
14249
|
+
const { icon, label, detail } = describeToolCall(info.name, info.args);
|
|
14250
|
+
const outputLines = showOutput && info.output ? info.output.split(`
|
|
14251
|
+
`) : [];
|
|
14252
|
+
const errorLines = showOutput && info.error ? info.error.split(`
|
|
14253
|
+
`).slice(0, 12) : [];
|
|
14254
|
+
return /* @__PURE__ */ jsxDEV6(Box4, {
|
|
14255
|
+
flexDirection: "column",
|
|
14256
|
+
marginBottom: 1,
|
|
14257
|
+
children: [
|
|
14258
|
+
/* @__PURE__ */ jsxDEV6(Box4, {
|
|
14259
|
+
children: [
|
|
14260
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
14261
|
+
color: theme.tool,
|
|
14262
|
+
children: [
|
|
14263
|
+
icon,
|
|
14264
|
+
" "
|
|
14265
|
+
]
|
|
14266
|
+
}, undefined, true, undefined, this),
|
|
14267
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
14268
|
+
bold: true,
|
|
14269
|
+
color: theme.tool,
|
|
14270
|
+
children: label
|
|
14271
|
+
}, undefined, false, undefined, this),
|
|
14272
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
14273
|
+
children: " "
|
|
14274
|
+
}, undefined, false, undefined, this),
|
|
14275
|
+
/* @__PURE__ */ jsxDEV6(StatusBadge, {
|
|
14276
|
+
info
|
|
14277
|
+
}, undefined, false, undefined, this)
|
|
14278
|
+
]
|
|
14279
|
+
}, undefined, true, undefined, this),
|
|
14280
|
+
detail ? /* @__PURE__ */ jsxDEV6(Box4, {
|
|
14281
|
+
marginLeft: 2,
|
|
14282
|
+
children: /* @__PURE__ */ jsxDEV6(Text6, {
|
|
14283
|
+
dimColor: true,
|
|
14284
|
+
children: detail
|
|
14285
|
+
}, undefined, false, undefined, this)
|
|
14286
|
+
}, undefined, false, undefined, this) : null,
|
|
14287
|
+
outputLines.map((line, i) => /* @__PURE__ */ jsxDEV6(Box4, {
|
|
14288
|
+
marginLeft: 2,
|
|
14289
|
+
children: /* @__PURE__ */ jsxDEV6(Text6, {
|
|
14290
|
+
dimColor: true,
|
|
14291
|
+
children: [
|
|
14292
|
+
i === 0 ? "└ " : " ",
|
|
14293
|
+
line
|
|
14294
|
+
]
|
|
14295
|
+
}, undefined, true, undefined, this)
|
|
14296
|
+
}, `out-${i}`, false, undefined, this)),
|
|
14297
|
+
errorLines.map((line, i) => /* @__PURE__ */ jsxDEV6(Box4, {
|
|
14298
|
+
marginLeft: 2,
|
|
14299
|
+
children: /* @__PURE__ */ jsxDEV6(Text6, {
|
|
14300
|
+
color: theme.error,
|
|
14301
|
+
children: [
|
|
14302
|
+
i === 0 ? "└ " : " ",
|
|
14303
|
+
line
|
|
14304
|
+
]
|
|
14305
|
+
}, undefined, true, undefined, this)
|
|
14306
|
+
}, `err-${i}`, false, undefined, this))
|
|
14307
|
+
]
|
|
14308
|
+
}, undefined, true, undefined, this);
|
|
14309
|
+
};
|
|
14310
|
+
|
|
14311
|
+
// src/tui/App.tsx
|
|
14312
|
+
init_theme();
|
|
14313
|
+
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
14034
14314
|
var ROLE_PREFIX = {
|
|
14035
14315
|
user: "\uD83D\uDC64 You",
|
|
14036
14316
|
assistant: "\uD83E\uDD16 Agent",
|
|
@@ -14039,7 +14319,7 @@ var ROLE_PREFIX = {
|
|
|
14039
14319
|
var RoleLabel = ({ role }) => {
|
|
14040
14320
|
const theme = getTheme();
|
|
14041
14321
|
const roleColor = role === "user" ? theme.user : role === "assistant" ? theme.assistant : theme.tool;
|
|
14042
|
-
return /* @__PURE__ */
|
|
14322
|
+
return /* @__PURE__ */ jsxDEV7(Text7, {
|
|
14043
14323
|
bold: true,
|
|
14044
14324
|
color: roleColor,
|
|
14045
14325
|
children: ROLE_PREFIX[role]
|
|
@@ -14047,16 +14327,16 @@ var RoleLabel = ({ role }) => {
|
|
|
14047
14327
|
};
|
|
14048
14328
|
var HistoryEntry = ({ item }) => {
|
|
14049
14329
|
if (item.role === "user") {
|
|
14050
|
-
return /* @__PURE__ */
|
|
14330
|
+
return /* @__PURE__ */ jsxDEV7(Box5, {
|
|
14051
14331
|
flexDirection: "column",
|
|
14052
14332
|
marginBottom: 1,
|
|
14053
14333
|
children: [
|
|
14054
|
-
/* @__PURE__ */
|
|
14334
|
+
/* @__PURE__ */ jsxDEV7(RoleLabel, {
|
|
14055
14335
|
role: "user"
|
|
14056
14336
|
}, undefined, false, undefined, this),
|
|
14057
|
-
/* @__PURE__ */
|
|
14337
|
+
/* @__PURE__ */ jsxDEV7(Box5, {
|
|
14058
14338
|
marginLeft: 2,
|
|
14059
|
-
children: /* @__PURE__ */
|
|
14339
|
+
children: /* @__PURE__ */ jsxDEV7(Text7, {
|
|
14060
14340
|
children: item.content
|
|
14061
14341
|
}, undefined, false, undefined, this)
|
|
14062
14342
|
}, undefined, false, undefined, this)
|
|
@@ -14064,16 +14344,21 @@ var HistoryEntry = ({ item }) => {
|
|
|
14064
14344
|
}, undefined, true, undefined, this);
|
|
14065
14345
|
}
|
|
14066
14346
|
if (item.role === "tool") {
|
|
14067
|
-
|
|
14347
|
+
if (item.tool) {
|
|
14348
|
+
return /* @__PURE__ */ jsxDEV7(ToolCall, {
|
|
14349
|
+
info: item.tool
|
|
14350
|
+
}, undefined, false, undefined, this);
|
|
14351
|
+
}
|
|
14352
|
+
return /* @__PURE__ */ jsxDEV7(Box5, {
|
|
14068
14353
|
flexDirection: "column",
|
|
14069
14354
|
marginBottom: 1,
|
|
14070
14355
|
children: [
|
|
14071
|
-
/* @__PURE__ */
|
|
14356
|
+
/* @__PURE__ */ jsxDEV7(RoleLabel, {
|
|
14072
14357
|
role: "tool"
|
|
14073
14358
|
}, undefined, false, undefined, this),
|
|
14074
|
-
/* @__PURE__ */
|
|
14359
|
+
/* @__PURE__ */ jsxDEV7(Box5, {
|
|
14075
14360
|
marginLeft: 2,
|
|
14076
|
-
children: /* @__PURE__ */
|
|
14361
|
+
children: /* @__PURE__ */ jsxDEV7(Text7, {
|
|
14077
14362
|
dimColor: true,
|
|
14078
14363
|
children: item.content
|
|
14079
14364
|
}, undefined, false, undefined, this)
|
|
@@ -14081,17 +14366,17 @@ var HistoryEntry = ({ item }) => {
|
|
|
14081
14366
|
]
|
|
14082
14367
|
}, undefined, true, undefined, this);
|
|
14083
14368
|
}
|
|
14084
|
-
return /* @__PURE__ */
|
|
14369
|
+
return /* @__PURE__ */ jsxDEV7(Box5, {
|
|
14085
14370
|
flexDirection: "column",
|
|
14086
14371
|
marginBottom: 1,
|
|
14087
14372
|
children: [
|
|
14088
|
-
/* @__PURE__ */
|
|
14373
|
+
item.continuation ? null : /* @__PURE__ */ jsxDEV7(RoleLabel, {
|
|
14089
14374
|
role: "assistant"
|
|
14090
14375
|
}, undefined, false, undefined, this),
|
|
14091
|
-
/* @__PURE__ */
|
|
14376
|
+
/* @__PURE__ */ jsxDEV7(Box5, {
|
|
14092
14377
|
marginLeft: 2,
|
|
14093
14378
|
flexDirection: "column",
|
|
14094
|
-
children: /* @__PURE__ */
|
|
14379
|
+
children: /* @__PURE__ */ jsxDEV7(Markdown, {
|
|
14095
14380
|
text: item.content
|
|
14096
14381
|
}, undefined, false, undefined, this)
|
|
14097
14382
|
}, undefined, false, undefined, this)
|
|
@@ -14104,66 +14389,69 @@ var App = ({
|
|
|
14104
14389
|
model,
|
|
14105
14390
|
workdir,
|
|
14106
14391
|
streamingText,
|
|
14392
|
+
liveTools,
|
|
14107
14393
|
tokenCount
|
|
14108
14394
|
}) => {
|
|
14109
14395
|
const theme = getTheme();
|
|
14110
|
-
return /* @__PURE__ */
|
|
14396
|
+
return /* @__PURE__ */ jsxDEV7(Box5, {
|
|
14111
14397
|
flexDirection: "column",
|
|
14112
|
-
minHeight: 20,
|
|
14113
14398
|
children: [
|
|
14114
|
-
/* @__PURE__ */
|
|
14399
|
+
/* @__PURE__ */ jsxDEV7(Box5, {
|
|
14115
14400
|
borderStyle: "round",
|
|
14116
14401
|
borderColor: theme.primary,
|
|
14117
14402
|
paddingX: 1,
|
|
14118
14403
|
marginBottom: 1,
|
|
14119
14404
|
children: [
|
|
14120
|
-
/* @__PURE__ */
|
|
14405
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
14121
14406
|
bold: true,
|
|
14122
14407
|
color: theme.primary,
|
|
14123
14408
|
children: "\uD83D\uDE80 Roy Agent"
|
|
14124
14409
|
}, undefined, false, undefined, this),
|
|
14125
|
-
/* @__PURE__ */
|
|
14410
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
14126
14411
|
dimColor: true,
|
|
14127
14412
|
children: " — interactive TUI"
|
|
14128
14413
|
}, undefined, false, undefined, this)
|
|
14129
14414
|
]
|
|
14130
14415
|
}, undefined, true, undefined, this),
|
|
14131
|
-
/* @__PURE__ */
|
|
14416
|
+
/* @__PURE__ */ jsxDEV7(Static2, {
|
|
14132
14417
|
items: history,
|
|
14133
|
-
children: (item, index) => /* @__PURE__ */
|
|
14418
|
+
children: (item, index) => /* @__PURE__ */ jsxDEV7(HistoryEntry, {
|
|
14134
14419
|
item
|
|
14135
14420
|
}, item.id ?? `${item.role}:${index}`, false, undefined, this)
|
|
14136
14421
|
}, undefined, false, undefined, this),
|
|
14137
|
-
status === "thinking" ? /* @__PURE__ */
|
|
14422
|
+
status === "thinking" ? /* @__PURE__ */ jsxDEV7(Box5, {
|
|
14138
14423
|
marginBottom: 1,
|
|
14139
|
-
children: /* @__PURE__ */
|
|
14424
|
+
children: /* @__PURE__ */ jsxDEV7(Spinner, {
|
|
14140
14425
|
label: "Agent is thinking..."
|
|
14141
14426
|
}, undefined, false, undefined, this)
|
|
14142
14427
|
}, undefined, false, undefined, this) : null,
|
|
14143
|
-
status === "streaming" && streamingText ? /* @__PURE__ */
|
|
14428
|
+
status === "streaming" && streamingText ? /* @__PURE__ */ jsxDEV7(Box5, {
|
|
14144
14429
|
flexDirection: "column",
|
|
14145
14430
|
marginBottom: 1,
|
|
14146
14431
|
children: [
|
|
14147
|
-
/* @__PURE__ */
|
|
14432
|
+
/* @__PURE__ */ jsxDEV7(RoleLabel, {
|
|
14148
14433
|
role: "assistant"
|
|
14149
14434
|
}, undefined, false, undefined, this),
|
|
14150
|
-
/* @__PURE__ */
|
|
14435
|
+
/* @__PURE__ */ jsxDEV7(Box5, {
|
|
14151
14436
|
marginLeft: 2,
|
|
14152
|
-
children: /* @__PURE__ */
|
|
14437
|
+
children: /* @__PURE__ */ jsxDEV7(Markdown, {
|
|
14153
14438
|
text: streamingText
|
|
14154
14439
|
}, undefined, false, undefined, this)
|
|
14155
14440
|
}, undefined, false, undefined, this)
|
|
14156
14441
|
]
|
|
14157
|
-
}, undefined, true, undefined, this) : status === "streaming" ? /* @__PURE__ */
|
|
14442
|
+
}, undefined, true, undefined, this) : status === "streaming" ? /* @__PURE__ */ jsxDEV7(Box5, {
|
|
14158
14443
|
marginBottom: 1,
|
|
14159
|
-
children: /* @__PURE__ */
|
|
14444
|
+
children: /* @__PURE__ */ jsxDEV7(Spinner, {
|
|
14160
14445
|
label: "Generating response..."
|
|
14161
14446
|
}, undefined, false, undefined, this)
|
|
14162
14447
|
}, undefined, false, undefined, this) : null,
|
|
14163
|
-
/* @__PURE__ */
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
14448
|
+
liveTools && liveTools.length > 0 ? /* @__PURE__ */ jsxDEV7(Box5, {
|
|
14449
|
+
flexDirection: "column",
|
|
14450
|
+
children: liveTools.map((tool, i) => /* @__PURE__ */ jsxDEV7(ToolCall, {
|
|
14451
|
+
info: tool
|
|
14452
|
+
}, `live-tool-${i}`, false, undefined, this))
|
|
14453
|
+
}, undefined, false, undefined, this) : null,
|
|
14454
|
+
/* @__PURE__ */ jsxDEV7(StatusBar, {
|
|
14167
14455
|
model,
|
|
14168
14456
|
workdir,
|
|
14169
14457
|
tokenCount
|
|
@@ -14177,9 +14465,79 @@ init_Markdown();
|
|
|
14177
14465
|
init_StatusBar();
|
|
14178
14466
|
|
|
14179
14467
|
// src/tui/TextInput.tsx
|
|
14180
|
-
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
14181
|
-
import { Box as
|
|
14182
|
-
|
|
14468
|
+
import { useEffect as useEffect4, useReducer, useState as useState4 } from "react";
|
|
14469
|
+
import { Box as Box6, Text as Text8, useInput as useInput3 } from "ink";
|
|
14470
|
+
|
|
14471
|
+
// src/tui/text-input-editing.ts
|
|
14472
|
+
function clampCursor(value, cursor) {
|
|
14473
|
+
if (!Number.isFinite(cursor))
|
|
14474
|
+
return value.length;
|
|
14475
|
+
return Math.max(0, Math.min(Math.trunc(cursor), value.length));
|
|
14476
|
+
}
|
|
14477
|
+
function insertText(state, text) {
|
|
14478
|
+
const cursor = clampCursor(state.value, state.cursor);
|
|
14479
|
+
const value = state.value.slice(0, cursor) + text + state.value.slice(cursor);
|
|
14480
|
+
return { value, cursor: cursor + text.length };
|
|
14481
|
+
}
|
|
14482
|
+
function deleteBefore(state) {
|
|
14483
|
+
const cursor = clampCursor(state.value, state.cursor);
|
|
14484
|
+
if (cursor === 0)
|
|
14485
|
+
return { value: state.value, cursor };
|
|
14486
|
+
const value = state.value.slice(0, cursor - 1) + state.value.slice(cursor);
|
|
14487
|
+
return { value, cursor: cursor - 1 };
|
|
14488
|
+
}
|
|
14489
|
+
function deleteAt(state) {
|
|
14490
|
+
const { value } = state;
|
|
14491
|
+
const cursor = clampCursor(value, state.cursor);
|
|
14492
|
+
if (cursor >= value.length)
|
|
14493
|
+
return { value, cursor };
|
|
14494
|
+
return { value: value.slice(0, cursor) + value.slice(cursor + 1), cursor };
|
|
14495
|
+
}
|
|
14496
|
+
function moveLeft(state) {
|
|
14497
|
+
return {
|
|
14498
|
+
value: state.value,
|
|
14499
|
+
cursor: Math.max(0, clampCursor(state.value, state.cursor) - 1)
|
|
14500
|
+
};
|
|
14501
|
+
}
|
|
14502
|
+
function moveRight(state) {
|
|
14503
|
+
const cursor = clampCursor(state.value, state.cursor);
|
|
14504
|
+
return {
|
|
14505
|
+
value: state.value,
|
|
14506
|
+
cursor: Math.min(state.value.length, cursor + 1)
|
|
14507
|
+
};
|
|
14508
|
+
}
|
|
14509
|
+
function splitAtCursor(state) {
|
|
14510
|
+
const cursor = clampCursor(state.value, state.cursor);
|
|
14511
|
+
return {
|
|
14512
|
+
before: state.value.slice(0, cursor),
|
|
14513
|
+
after: state.value.slice(cursor),
|
|
14514
|
+
cursor
|
|
14515
|
+
};
|
|
14516
|
+
}
|
|
14517
|
+
function editReducer(state, action) {
|
|
14518
|
+
switch (action.type) {
|
|
14519
|
+
case "insert":
|
|
14520
|
+
return insertText(state, action.text);
|
|
14521
|
+
case "backspace":
|
|
14522
|
+
return deleteBefore(state);
|
|
14523
|
+
case "delete":
|
|
14524
|
+
return deleteAt(state);
|
|
14525
|
+
case "left":
|
|
14526
|
+
return moveLeft(state);
|
|
14527
|
+
case "right":
|
|
14528
|
+
return moveRight(state);
|
|
14529
|
+
case "set":
|
|
14530
|
+
return {
|
|
14531
|
+
value: action.value,
|
|
14532
|
+
cursor: action.cursor ?? action.value.length
|
|
14533
|
+
};
|
|
14534
|
+
case "clear":
|
|
14535
|
+
return { value: "", cursor: 0 };
|
|
14536
|
+
}
|
|
14537
|
+
}
|
|
14538
|
+
|
|
14539
|
+
// src/tui/TextInput.tsx
|
|
14540
|
+
import { jsxDEV as jsxDEV8, Fragment } from "react/jsx-dev-runtime";
|
|
14183
14541
|
var TextInput = ({
|
|
14184
14542
|
label,
|
|
14185
14543
|
prefix,
|
|
@@ -14188,7 +14546,10 @@ var TextInput = ({
|
|
|
14188
14546
|
placeholder,
|
|
14189
14547
|
history = []
|
|
14190
14548
|
}) => {
|
|
14191
|
-
const [value,
|
|
14549
|
+
const [{ value, cursor }, dispatch] = useReducer(editReducer, {
|
|
14550
|
+
value: "",
|
|
14551
|
+
cursor: 0
|
|
14552
|
+
});
|
|
14192
14553
|
const [historyIndex, setHistoryIndex] = useState4(-1);
|
|
14193
14554
|
const [draft, setDraft] = useState4("");
|
|
14194
14555
|
useEffect4(() => {
|
|
@@ -14201,7 +14562,7 @@ var TextInput = ({
|
|
|
14201
14562
|
}
|
|
14202
14563
|
if (key.return) {
|
|
14203
14564
|
const submitted = value;
|
|
14204
|
-
|
|
14565
|
+
dispatch({ type: "clear" });
|
|
14205
14566
|
setHistoryIndex(-1);
|
|
14206
14567
|
setDraft("");
|
|
14207
14568
|
onSubmit(submitted);
|
|
@@ -14211,7 +14572,15 @@ var TextInput = ({
|
|
|
14211
14572
|
if (historyIndex !== -1) {
|
|
14212
14573
|
setHistoryIndex(-1);
|
|
14213
14574
|
}
|
|
14214
|
-
|
|
14575
|
+
dispatch({ type: "backspace" });
|
|
14576
|
+
return;
|
|
14577
|
+
}
|
|
14578
|
+
if (key.leftArrow) {
|
|
14579
|
+
dispatch({ type: "left" });
|
|
14580
|
+
return;
|
|
14581
|
+
}
|
|
14582
|
+
if (key.rightArrow) {
|
|
14583
|
+
dispatch({ type: "right" });
|
|
14215
14584
|
return;
|
|
14216
14585
|
}
|
|
14217
14586
|
if (key.upArrow) {
|
|
@@ -14222,7 +14591,7 @@ var TextInput = ({
|
|
|
14222
14591
|
}
|
|
14223
14592
|
const nextIndex = Math.min(historyIndex + 1, history.length - 1);
|
|
14224
14593
|
setHistoryIndex(nextIndex);
|
|
14225
|
-
|
|
14594
|
+
dispatch({ type: "set", value: history[nextIndex] ?? "" });
|
|
14226
14595
|
return;
|
|
14227
14596
|
}
|
|
14228
14597
|
if (key.downArrow) {
|
|
@@ -14231,10 +14600,10 @@ var TextInput = ({
|
|
|
14231
14600
|
const nextIndex = historyIndex - 1;
|
|
14232
14601
|
if (nextIndex < 0) {
|
|
14233
14602
|
setHistoryIndex(-1);
|
|
14234
|
-
|
|
14603
|
+
dispatch({ type: "set", value: draft });
|
|
14235
14604
|
} else {
|
|
14236
14605
|
setHistoryIndex(nextIndex);
|
|
14237
|
-
|
|
14606
|
+
dispatch({ type: "set", value: history[nextIndex] ?? "" });
|
|
14238
14607
|
}
|
|
14239
14608
|
return;
|
|
14240
14609
|
}
|
|
@@ -14242,12 +14611,13 @@ var TextInput = ({
|
|
|
14242
14611
|
setHistoryIndex(-1);
|
|
14243
14612
|
}
|
|
14244
14613
|
if (input) {
|
|
14245
|
-
|
|
14614
|
+
dispatch({ type: "insert", text: input });
|
|
14246
14615
|
}
|
|
14247
14616
|
});
|
|
14248
|
-
|
|
14617
|
+
const { before, after } = splitAtCursor({ value, cursor });
|
|
14618
|
+
return /* @__PURE__ */ jsxDEV8(Box6, {
|
|
14249
14619
|
children: [
|
|
14250
|
-
/* @__PURE__ */
|
|
14620
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
14251
14621
|
bold: true,
|
|
14252
14622
|
color: "green",
|
|
14253
14623
|
children: [
|
|
@@ -14255,21 +14625,42 @@ var TextInput = ({
|
|
|
14255
14625
|
" "
|
|
14256
14626
|
]
|
|
14257
14627
|
}, undefined, true, undefined, this),
|
|
14258
|
-
/* @__PURE__ */
|
|
14628
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
14259
14629
|
bold: true,
|
|
14260
14630
|
children: [
|
|
14261
14631
|
label,
|
|
14262
14632
|
": "
|
|
14263
14633
|
]
|
|
14264
14634
|
}, undefined, true, undefined, this),
|
|
14265
|
-
/* @__PURE__ */
|
|
14266
|
-
children:
|
|
14635
|
+
value ? /* @__PURE__ */ jsxDEV8(Fragment, {
|
|
14636
|
+
children: [
|
|
14637
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
14638
|
+
children: before
|
|
14639
|
+
}, undefined, false, undefined, this),
|
|
14640
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
14641
|
+
inverse: true,
|
|
14642
|
+
children: "▌"
|
|
14643
|
+
}, undefined, false, undefined, this),
|
|
14644
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
14645
|
+
children: after
|
|
14646
|
+
}, undefined, false, undefined, this)
|
|
14647
|
+
]
|
|
14648
|
+
}, undefined, true, undefined, this) : placeholder ? /* @__PURE__ */ jsxDEV8(Fragment, {
|
|
14649
|
+
children: [
|
|
14650
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
14651
|
+
inverse: true,
|
|
14652
|
+
children: "▌"
|
|
14653
|
+
}, undefined, false, undefined, this),
|
|
14654
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
14655
|
+
dimColor: true,
|
|
14656
|
+
children: placeholder
|
|
14657
|
+
}, undefined, false, undefined, this)
|
|
14658
|
+
]
|
|
14659
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV8(Text8, {
|
|
14660
|
+
inverse: true,
|
|
14661
|
+
children: "▌"
|
|
14267
14662
|
}, undefined, false, undefined, this),
|
|
14268
|
-
|
|
14269
|
-
dimColor: true,
|
|
14270
|
-
children: placeholder
|
|
14271
|
-
}, undefined, false, undefined, this) : null,
|
|
14272
|
-
historyIndex !== -1 ? /* @__PURE__ */ jsxDEV7(Text7, {
|
|
14663
|
+
historyIndex !== -1 ? /* @__PURE__ */ jsxDEV8(Text8, {
|
|
14273
14664
|
dimColor: true,
|
|
14274
14665
|
children: " (history)"
|
|
14275
14666
|
}, undefined, false, undefined, this) : null
|
|
@@ -14282,37 +14673,119 @@ init_theme();
|
|
|
14282
14673
|
init_welcome_card2();
|
|
14283
14674
|
|
|
14284
14675
|
// src/tui/use-streaming-accumulator.ts
|
|
14285
|
-
import { useCallback as useCallback3, useState as useState5 } from "react";
|
|
14286
|
-
|
|
14676
|
+
import { useCallback as useCallback3, useRef as useRef2, useState as useState5 } from "react";
|
|
14677
|
+
|
|
14678
|
+
// src/tui/scrollback.ts
|
|
14679
|
+
var FENCE_RE = /^\s*(```|~~~)/;
|
|
14680
|
+
function lineStartOffset(lines, index) {
|
|
14681
|
+
let off = 0;
|
|
14682
|
+
for (let i = 0;i < index; i++)
|
|
14683
|
+
off += (lines[i] ?? "").length + 1;
|
|
14684
|
+
return off;
|
|
14685
|
+
}
|
|
14686
|
+
function splitStable(text, opts = {}) {
|
|
14687
|
+
if (!text)
|
|
14688
|
+
return { stable: "", tail: "" };
|
|
14689
|
+
if (opts.force)
|
|
14690
|
+
return { stable: text, tail: "" };
|
|
14691
|
+
const lines = text.split(`
|
|
14692
|
+
`);
|
|
14693
|
+
let inFence = false;
|
|
14694
|
+
let boundary = -1;
|
|
14695
|
+
for (let i = 0;i < lines.length; i++) {
|
|
14696
|
+
const line = lines[i] ?? "";
|
|
14697
|
+
const isLast = i === lines.length - 1;
|
|
14698
|
+
const next = lineStartOffset(lines, i) + line.length + 1;
|
|
14699
|
+
if (FENCE_RE.test(line)) {
|
|
14700
|
+
inFence = !inFence;
|
|
14701
|
+
} else if (!inFence && !isLast && line.trim() === "") {
|
|
14702
|
+
boundary = next;
|
|
14703
|
+
}
|
|
14704
|
+
}
|
|
14705
|
+
if (boundary > 0) {
|
|
14706
|
+
return { stable: text.slice(0, boundary), tail: text.slice(boundary) };
|
|
14707
|
+
}
|
|
14708
|
+
const maxTailLines = opts.maxTailLines ?? 0;
|
|
14709
|
+
if (maxTailLines > 0 && !inFence && lines.length > maxTailLines) {
|
|
14710
|
+
const keepFrom = lines.length - 1;
|
|
14711
|
+
const off = lineStartOffset(lines, keepFrom);
|
|
14712
|
+
if (off > 0) {
|
|
14713
|
+
return { stable: text.slice(0, off), tail: text.slice(off) };
|
|
14714
|
+
}
|
|
14715
|
+
}
|
|
14716
|
+
return { stable: "", tail: text };
|
|
14717
|
+
}
|
|
14718
|
+
|
|
14719
|
+
// src/tui/use-streaming-accumulator.ts
|
|
14720
|
+
var DEFAULT_MAX_TAIL_LINES = 24;
|
|
14721
|
+
function useStreamingAccumulator(options = {}) {
|
|
14722
|
+
const maxTailLines = options.maxTailLines ?? DEFAULT_MAX_TAIL_LINES;
|
|
14287
14723
|
const [status, setStatus] = useState5("idle");
|
|
14288
14724
|
const [streamingText, setStreamingText] = useState5("");
|
|
14725
|
+
const pendingRef = useRef2("");
|
|
14726
|
+
const emittedRef = useRef2("");
|
|
14289
14727
|
const start = useCallback3(() => {
|
|
14728
|
+
pendingRef.current = "";
|
|
14729
|
+
emittedRef.current = "";
|
|
14290
14730
|
setStreamingText("");
|
|
14291
14731
|
setStatus("thinking");
|
|
14292
14732
|
}, []);
|
|
14293
14733
|
const append = useCallback3((chunk) => {
|
|
14734
|
+
pendingRef.current += chunk;
|
|
14735
|
+
setStreamingText(pendingRef.current);
|
|
14294
14736
|
setStatus("streaming");
|
|
14295
|
-
setStreamingText((prev) => prev + chunk);
|
|
14296
14737
|
}, []);
|
|
14297
|
-
const
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
setStreamingText((prev) => {
|
|
14301
|
-
snapshot = prev;
|
|
14302
|
-
return "";
|
|
14738
|
+
const drainStable = useCallback3(() => {
|
|
14739
|
+
const { stable, tail } = splitStable(pendingRef.current, {
|
|
14740
|
+
maxTailLines
|
|
14303
14741
|
});
|
|
14304
|
-
|
|
14742
|
+
if (!stable)
|
|
14743
|
+
return "";
|
|
14744
|
+
pendingRef.current = tail;
|
|
14745
|
+
emittedRef.current += stable;
|
|
14746
|
+
setStreamingText(tail);
|
|
14747
|
+
return stable;
|
|
14748
|
+
}, [maxTailLines]);
|
|
14749
|
+
const flushPending = useCallback3(() => {
|
|
14750
|
+
const pending = pendingRef.current;
|
|
14751
|
+
if (!pending)
|
|
14752
|
+
return "";
|
|
14753
|
+
pendingRef.current = "";
|
|
14754
|
+
emittedRef.current += pending;
|
|
14755
|
+
setStreamingText("");
|
|
14756
|
+
return pending;
|
|
14757
|
+
}, []);
|
|
14758
|
+
const finish = useCallback3((finalText) => {
|
|
14759
|
+
const pending = pendingRef.current;
|
|
14760
|
+
pendingRef.current = "";
|
|
14761
|
+
setStreamingText("");
|
|
14762
|
+
setStatus("idle");
|
|
14763
|
+
if (finalText === undefined) {
|
|
14764
|
+
emittedRef.current += pending;
|
|
14765
|
+
return pending;
|
|
14766
|
+
}
|
|
14767
|
+
if (finalText.startsWith(emittedRef.current)) {
|
|
14768
|
+
const suffix = finalText.slice(emittedRef.current.length);
|
|
14769
|
+
emittedRef.current = finalText;
|
|
14770
|
+
return suffix;
|
|
14771
|
+
}
|
|
14772
|
+
const emitted = emittedRef.current;
|
|
14773
|
+
let i = 0;
|
|
14774
|
+
const max = Math.min(emitted.length, finalText.length);
|
|
14775
|
+
while (i < max && emitted.charCodeAt(i) === finalText.charCodeAt(i)) {
|
|
14776
|
+
i++;
|
|
14777
|
+
}
|
|
14778
|
+
emittedRef.current = finalText;
|
|
14779
|
+
return finalText.slice(i);
|
|
14305
14780
|
}, []);
|
|
14306
14781
|
const fail = useCallback3((_err) => {
|
|
14782
|
+
const rest = pendingRef.current;
|
|
14783
|
+
pendingRef.current = "";
|
|
14784
|
+
setStreamingText("");
|
|
14307
14785
|
setStatus("idle");
|
|
14308
|
-
|
|
14309
|
-
setStreamingText((prev) => {
|
|
14310
|
-
snapshot = prev;
|
|
14311
|
-
return "";
|
|
14312
|
-
});
|
|
14313
|
-
return snapshot;
|
|
14786
|
+
return rest;
|
|
14314
14787
|
}, []);
|
|
14315
|
-
return { status, streamingText, start, append, finish, fail };
|
|
14788
|
+
return { status, streamingText, start, append, drainStable, flushPending, finish, fail };
|
|
14316
14789
|
}
|
|
14317
14790
|
|
|
14318
14791
|
// src/RunTui.tsx
|
|
@@ -14391,7 +14864,7 @@ function dispatchSlashCommand(raw, ctx) {
|
|
|
14391
14864
|
}
|
|
14392
14865
|
|
|
14393
14866
|
// src/RunTui.tsx
|
|
14394
|
-
import { jsxDEV as
|
|
14867
|
+
import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
|
|
14395
14868
|
var RunScreen = ({
|
|
14396
14869
|
handleQuery,
|
|
14397
14870
|
streamHandleQuery,
|
|
@@ -14399,6 +14872,8 @@ var RunScreen = ({
|
|
|
14399
14872
|
workdir,
|
|
14400
14873
|
maxLines: initialMaxLines,
|
|
14401
14874
|
markdownEnabled: markdownEnabled2,
|
|
14875
|
+
showToolCalls = true,
|
|
14876
|
+
showToolResults = true,
|
|
14402
14877
|
onExit,
|
|
14403
14878
|
onRegisterHandlers
|
|
14404
14879
|
}) => {
|
|
@@ -14406,14 +14881,22 @@ var RunScreen = ({
|
|
|
14406
14881
|
const [errorMessage, setErrorMessage] = useState6(null);
|
|
14407
14882
|
const [maxLines, setMaxLines] = useState6(initialMaxLines);
|
|
14408
14883
|
const [userHistory, setUserHistory] = useState6([]);
|
|
14409
|
-
const
|
|
14884
|
+
const [liveTools, setLiveTools] = useState6([]);
|
|
14885
|
+
const { stdout } = useStdout();
|
|
14886
|
+
const maxTailLines = Math.max(4, (stdout?.rows ?? 24) - 12);
|
|
14887
|
+
const stream = useStreamingAccumulator({ maxTailLines });
|
|
14410
14888
|
const status = stream.status;
|
|
14411
14889
|
const { exit } = useApp2();
|
|
14412
|
-
const userTurnCountRef =
|
|
14413
|
-
const assistantTurnCountRef =
|
|
14414
|
-
const isProcessingRef =
|
|
14415
|
-
const executeQueryRef =
|
|
14416
|
-
const historyIdRef =
|
|
14890
|
+
const userTurnCountRef = useRef3(0);
|
|
14891
|
+
const assistantTurnCountRef = useRef3(0);
|
|
14892
|
+
const isProcessingRef = useRef3(0);
|
|
14893
|
+
const executeQueryRef = useRef3(null);
|
|
14894
|
+
const historyIdRef = useRef3(0);
|
|
14895
|
+
const liveRef = useRef3([]);
|
|
14896
|
+
const toolSeqRef = useRef3(0);
|
|
14897
|
+
const syncLiveTools = useCallback4(() => {
|
|
14898
|
+
setLiveTools(liveRef.current.map((t) => t.info));
|
|
14899
|
+
}, []);
|
|
14417
14900
|
const width = process.stdout.columns ?? 80;
|
|
14418
14901
|
const doExit = useCallback4(() => {
|
|
14419
14902
|
onExit?.();
|
|
@@ -14422,25 +14905,108 @@ var RunScreen = ({
|
|
|
14422
14905
|
const executeQuery = useCallback4(async (message) => {
|
|
14423
14906
|
isProcessingRef.current += 1;
|
|
14424
14907
|
stream.start();
|
|
14908
|
+
let assistantBlocks = 0;
|
|
14909
|
+
const pushAssistant = (content) => {
|
|
14910
|
+
const id = `h${++historyIdRef.current}`;
|
|
14911
|
+
const continuation = assistantBlocks > 0;
|
|
14912
|
+
assistantBlocks += 1;
|
|
14913
|
+
setHistory((h) => [
|
|
14914
|
+
...h,
|
|
14915
|
+
{ role: "assistant", content, id, continuation }
|
|
14916
|
+
]);
|
|
14917
|
+
};
|
|
14918
|
+
const commitTool = (info) => {
|
|
14919
|
+
const id = `h${++historyIdRef.current}`;
|
|
14920
|
+
setHistory((h) => [
|
|
14921
|
+
...h,
|
|
14922
|
+
{ role: "tool", content: "", tool: info, id }
|
|
14923
|
+
]);
|
|
14924
|
+
};
|
|
14925
|
+
const findLiveIndex = (event) => {
|
|
14926
|
+
if (event.id) {
|
|
14927
|
+
const byId = liveRef.current.findIndex((t) => t.key === event.id);
|
|
14928
|
+
if (byId >= 0)
|
|
14929
|
+
return byId;
|
|
14930
|
+
}
|
|
14931
|
+
return liveRef.current.findIndex((t) => t.info.name === event.name);
|
|
14932
|
+
};
|
|
14933
|
+
const handleToolEvent = (event) => {
|
|
14934
|
+
if (event.kind === "call") {
|
|
14935
|
+
const pending = stream.flushPending();
|
|
14936
|
+
if (pending.trim())
|
|
14937
|
+
pushAssistant(pending);
|
|
14938
|
+
const key = event.id ?? `${event.name}#${++toolSeqRef.current}`;
|
|
14939
|
+
liveRef.current = [
|
|
14940
|
+
...liveRef.current,
|
|
14941
|
+
{
|
|
14942
|
+
key,
|
|
14943
|
+
startedAt: Date.now(),
|
|
14944
|
+
info: { name: event.name, args: event.args, status: "running" }
|
|
14945
|
+
}
|
|
14946
|
+
];
|
|
14947
|
+
syncLiveTools();
|
|
14948
|
+
return;
|
|
14949
|
+
}
|
|
14950
|
+
const idx = findLiveIndex(event);
|
|
14951
|
+
const entry = idx >= 0 ? liveRef.current[idx] : undefined;
|
|
14952
|
+
const durationMs = entry ? Date.now() - entry.startedAt : undefined;
|
|
14953
|
+
const info = event.kind === "error" ? {
|
|
14954
|
+
name: event.name,
|
|
14955
|
+
args: entry?.info.args,
|
|
14956
|
+
status: "error",
|
|
14957
|
+
error: event.error ?? "tool failed",
|
|
14958
|
+
durationMs
|
|
14959
|
+
} : {
|
|
14960
|
+
name: event.name,
|
|
14961
|
+
args: entry?.info.args,
|
|
14962
|
+
status: "completed",
|
|
14963
|
+
output: showToolResults ? formatToolOutput(event.output) : undefined,
|
|
14964
|
+
durationMs
|
|
14965
|
+
};
|
|
14966
|
+
if (idx >= 0) {
|
|
14967
|
+
liveRef.current = liveRef.current.filter((_, i) => i !== idx);
|
|
14968
|
+
syncLiveTools();
|
|
14969
|
+
}
|
|
14970
|
+
commitTool(info);
|
|
14971
|
+
};
|
|
14972
|
+
const settleLiveTools = (status2, error) => {
|
|
14973
|
+
if (liveRef.current.length === 0)
|
|
14974
|
+
return;
|
|
14975
|
+
for (const t of liveRef.current) {
|
|
14976
|
+
commitTool({
|
|
14977
|
+
...t.info,
|
|
14978
|
+
status: status2,
|
|
14979
|
+
...error ? { error } : {},
|
|
14980
|
+
durationMs: Date.now() - t.startedAt
|
|
14981
|
+
});
|
|
14982
|
+
}
|
|
14983
|
+
liveRef.current = [];
|
|
14984
|
+
syncLiveTools();
|
|
14985
|
+
};
|
|
14425
14986
|
try {
|
|
14426
14987
|
let responseText;
|
|
14427
14988
|
if (streamHandleQuery) {
|
|
14428
|
-
responseText = await streamHandleQuery(message, (chunk) =>
|
|
14989
|
+
responseText = await streamHandleQuery(message, (chunk) => {
|
|
14990
|
+
stream.append(chunk);
|
|
14991
|
+
const stable = stream.drainStable();
|
|
14992
|
+
if (stable)
|
|
14993
|
+
pushAssistant(stable);
|
|
14994
|
+
}, showToolCalls ? handleToolEvent : undefined);
|
|
14995
|
+
const tail = stream.finish(responseText);
|
|
14996
|
+
if (tail.trim())
|
|
14997
|
+
pushAssistant(tail);
|
|
14429
14998
|
} else {
|
|
14430
14999
|
responseText = await handleQuery(message);
|
|
15000
|
+
stream.finish();
|
|
15001
|
+
const rendered = markdownEnabled2 ? renderMarkdown(responseText, { width }) : responseText;
|
|
15002
|
+
pushAssistant(truncateForTerminal(rendered, maxLines));
|
|
14431
15003
|
}
|
|
14432
|
-
|
|
14433
|
-
const finalText = truncateForTerminal(rendered, maxLines);
|
|
14434
|
-
stream.finish();
|
|
14435
|
-
const assistantId = `h${++historyIdRef.current}`;
|
|
14436
|
-
setHistory((h) => [
|
|
14437
|
-
...h,
|
|
14438
|
-
{ role: "assistant", content: finalText, id: assistantId }
|
|
14439
|
-
]);
|
|
15004
|
+
settleLiveTools("completed");
|
|
14440
15005
|
assistantTurnCountRef.current += 1;
|
|
14441
15006
|
} catch (err) {
|
|
14442
15007
|
const msg = err instanceof Error ? err.message : String(err);
|
|
14443
15008
|
stream.fail(err instanceof Error ? err : new Error(msg));
|
|
15009
|
+
settleLiveTools("error", msg);
|
|
14444
15010
|
setErrorMessage(msg);
|
|
14445
15011
|
const errorId = `h${++historyIdRef.current}`;
|
|
14446
15012
|
setHistory((h) => [
|
|
@@ -14450,7 +15016,17 @@ var RunScreen = ({
|
|
|
14450
15016
|
} finally {
|
|
14451
15017
|
isProcessingRef.current -= 1;
|
|
14452
15018
|
}
|
|
14453
|
-
}, [
|
|
15019
|
+
}, [
|
|
15020
|
+
handleQuery,
|
|
15021
|
+
markdownEnabled2,
|
|
15022
|
+
maxLines,
|
|
15023
|
+
showToolCalls,
|
|
15024
|
+
showToolResults,
|
|
15025
|
+
stream,
|
|
15026
|
+
streamHandleQuery,
|
|
15027
|
+
syncLiveTools,
|
|
15028
|
+
width
|
|
15029
|
+
]);
|
|
14454
15030
|
useEffect5(() => {
|
|
14455
15031
|
executeQueryRef.current = executeQuery;
|
|
14456
15032
|
}, [executeQuery]);
|
|
@@ -14558,19 +15134,20 @@ var RunScreen = ({
|
|
|
14558
15134
|
const handleCancel = useCallback4(() => {
|
|
14559
15135
|
doExit();
|
|
14560
15136
|
}, [doExit]);
|
|
14561
|
-
return /* @__PURE__ */
|
|
15137
|
+
return /* @__PURE__ */ jsxDEV9(Box7, {
|
|
14562
15138
|
flexDirection: "column",
|
|
14563
15139
|
children: [
|
|
14564
|
-
/* @__PURE__ */
|
|
15140
|
+
/* @__PURE__ */ jsxDEV9(App, {
|
|
14565
15141
|
history,
|
|
14566
15142
|
status,
|
|
14567
15143
|
model,
|
|
14568
15144
|
workdir,
|
|
14569
|
-
streamingText: stream.streamingText
|
|
15145
|
+
streamingText: stream.streamingText,
|
|
15146
|
+
liveTools
|
|
14570
15147
|
}, undefined, false, undefined, this),
|
|
14571
|
-
status === "idle" ? /* @__PURE__ */
|
|
15148
|
+
status === "idle" ? /* @__PURE__ */ jsxDEV9(Box7, {
|
|
14572
15149
|
marginTop: 1,
|
|
14573
|
-
children: /* @__PURE__ */
|
|
15150
|
+
children: /* @__PURE__ */ jsxDEV9(TextInput, {
|
|
14574
15151
|
label: "You",
|
|
14575
15152
|
prefix: "\uD83D\uDC64",
|
|
14576
15153
|
placeholder: 'Type a message, "/help", or "exit"',
|
|
@@ -14579,9 +15156,9 @@ var RunScreen = ({
|
|
|
14579
15156
|
history: userHistory
|
|
14580
15157
|
}, undefined, false, undefined, this)
|
|
14581
15158
|
}, undefined, false, undefined, this) : null,
|
|
14582
|
-
errorMessage ? /* @__PURE__ */
|
|
15159
|
+
errorMessage ? /* @__PURE__ */ jsxDEV9(Box7, {
|
|
14583
15160
|
marginTop: 1,
|
|
14584
|
-
children: /* @__PURE__ */
|
|
15161
|
+
children: /* @__PURE__ */ jsxDEV9(Text9, {
|
|
14585
15162
|
color: "red",
|
|
14586
15163
|
children: [
|
|
14587
15164
|
"⚠ ",
|
|
@@ -14690,7 +15267,7 @@ async function loadHandleQuery(options, hooks) {
|
|
|
14690
15267
|
workDir: options.workdir,
|
|
14691
15268
|
loadPlugins: true,
|
|
14692
15269
|
plugins: options.plugins,
|
|
14693
|
-
commandName: "
|
|
15270
|
+
commandName: "interactive"
|
|
14694
15271
|
});
|
|
14695
15272
|
const env = envService.getEnvironment();
|
|
14696
15273
|
if (!env) {
|
|
@@ -14793,14 +15370,41 @@ async function loadHandleQuery(options, hooks) {
|
|
|
14793
15370
|
};
|
|
14794
15371
|
}
|
|
14795
15372
|
function createStreamHandleQuery(queryExecutor, sessionId, options, agentContext, eventSourceSystemPrompt) {
|
|
14796
|
-
return async (message, onChunk) => {
|
|
15373
|
+
return async (message, onChunk, onTool) => {
|
|
14797
15374
|
queryExecutor.setChunkCallback((event) => {
|
|
14798
|
-
|
|
14799
|
-
|
|
14800
|
-
|
|
14801
|
-
|
|
14802
|
-
|
|
14803
|
-
|
|
15375
|
+
switch (event.type) {
|
|
15376
|
+
case "llm.text":
|
|
15377
|
+
if (event.delta) {
|
|
15378
|
+
onChunk(event.delta);
|
|
15379
|
+
} else if (event.content) {
|
|
15380
|
+
onChunk(event.content);
|
|
15381
|
+
}
|
|
15382
|
+
break;
|
|
15383
|
+
case "tool.call":
|
|
15384
|
+
onTool?.({
|
|
15385
|
+
kind: "call",
|
|
15386
|
+
id: event.toolId,
|
|
15387
|
+
name: event.toolName ?? "tool",
|
|
15388
|
+
args: event.toolArgs
|
|
15389
|
+
});
|
|
15390
|
+
break;
|
|
15391
|
+
case "tool.result":
|
|
15392
|
+
onTool?.({
|
|
15393
|
+
kind: "result",
|
|
15394
|
+
id: event.toolId,
|
|
15395
|
+
name: event.toolName ?? "tool",
|
|
15396
|
+
output: event.toolResult
|
|
15397
|
+
});
|
|
15398
|
+
break;
|
|
15399
|
+
case "tool.error":
|
|
15400
|
+
onTool?.({
|
|
15401
|
+
kind: "error",
|
|
15402
|
+
name: event.toolName ?? "tool",
|
|
15403
|
+
error: event.toolError
|
|
15404
|
+
});
|
|
15405
|
+
break;
|
|
15406
|
+
default:
|
|
15407
|
+
break;
|
|
14804
15408
|
}
|
|
14805
15409
|
});
|
|
14806
15410
|
const mergedContext = {
|
|
@@ -14814,15 +15418,15 @@ function createStreamHandleQuery(queryExecutor, sessionId, options, agentContext
|
|
|
14814
15418
|
};
|
|
14815
15419
|
const result = await queryExecutor.execute(message, sessionId, {
|
|
14816
15420
|
showReasoning: options.reasoning ?? true,
|
|
14817
|
-
showToolCalls:
|
|
14818
|
-
showToolResults:
|
|
15421
|
+
showToolCalls: true,
|
|
15422
|
+
showToolResults: true
|
|
14819
15423
|
}, undefined, mergedContext);
|
|
14820
15424
|
return String(result ?? "");
|
|
14821
15425
|
};
|
|
14822
15426
|
}
|
|
14823
15427
|
function createRunCommand() {
|
|
14824
15428
|
return {
|
|
14825
|
-
command: "
|
|
15429
|
+
command: "interactive",
|
|
14826
15430
|
describe: "Start an interactive conversation with the agent (Ink TUI)",
|
|
14827
15431
|
builder: (yargs) => yargs.option("model", {
|
|
14828
15432
|
alias: "m",
|
|
@@ -14876,7 +15480,7 @@ function createRunCommand() {
|
|
|
14876
15480
|
}).option("tool-results", {
|
|
14877
15481
|
type: "boolean",
|
|
14878
15482
|
describe: "显示工具执行结果",
|
|
14879
|
-
default:
|
|
15483
|
+
default: true
|
|
14880
15484
|
}).option("event-source", {
|
|
14881
15485
|
alias: "es",
|
|
14882
15486
|
type: "array",
|
|
@@ -14935,13 +15539,15 @@ function createRunCommand() {
|
|
|
14935
15539
|
const streamHandleQuery = createStreamHandleQuery(queryExecutor, sessionId, argv, agentContext, eventSourceSystemPrompt);
|
|
14936
15540
|
const stopEventHandler = eventHandler.start();
|
|
14937
15541
|
const stopTaskEventHandler = taskEventHandler.start();
|
|
14938
|
-
const { waitUntilExit } = render(
|
|
15542
|
+
const { waitUntilExit } = render(React7.createElement(RunTui_default, {
|
|
14939
15543
|
handleQuery,
|
|
14940
15544
|
streamHandleQuery,
|
|
14941
15545
|
model: argv.model,
|
|
14942
15546
|
workdir: argv.workdir,
|
|
14943
15547
|
maxLines,
|
|
14944
15548
|
markdownEnabled: argv.markdown !== false,
|
|
15549
|
+
showToolCalls: argv.toolCalls !== false,
|
|
15550
|
+
showToolResults: argv.toolResults !== false,
|
|
14945
15551
|
onRegisterHandlers: (handlers) => {
|
|
14946
15552
|
runState.onNotification = handlers.onNotification;
|
|
14947
15553
|
runState.isIdle = handlers.isIdle;
|
|
@@ -14972,14 +15578,14 @@ function createRunCommand() {
|
|
|
14972
15578
|
var RunCommand = createRunCommand();
|
|
14973
15579
|
|
|
14974
15580
|
// src/commands/chat.ts
|
|
14975
|
-
import
|
|
15581
|
+
import React9 from "react";
|
|
14976
15582
|
import { render as render2 } from "ink";
|
|
14977
15583
|
|
|
14978
15584
|
// src/ChatTui.tsx
|
|
14979
|
-
import { useEffect as useEffect6, useRef as
|
|
14980
|
-
import { Box as
|
|
15585
|
+
import { useEffect as useEffect6, useRef as useRef4, useState as useState7 } from "react";
|
|
15586
|
+
import { Box as Box8, useApp as useApp3 } from "ink";
|
|
14981
15587
|
init_markdown();
|
|
14982
|
-
import { jsxDEV as
|
|
15588
|
+
import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
|
|
14983
15589
|
var ChatScreen = ({
|
|
14984
15590
|
handleQuery,
|
|
14985
15591
|
streamHandleQuery,
|
|
@@ -14992,7 +15598,7 @@ var ChatScreen = ({
|
|
|
14992
15598
|
const [history, setHistory] = useState7([
|
|
14993
15599
|
{ role: "user", content: message, id: "h-init-1" }
|
|
14994
15600
|
]);
|
|
14995
|
-
const historyIdRef =
|
|
15601
|
+
const historyIdRef = useRef4(1);
|
|
14996
15602
|
const stream = useStreamingAccumulator();
|
|
14997
15603
|
const { exit } = useApp3();
|
|
14998
15604
|
const width = process.stdout.columns ?? 80;
|
|
@@ -15035,9 +15641,9 @@ var ChatScreen = ({
|
|
|
15035
15641
|
cancelled = true;
|
|
15036
15642
|
};
|
|
15037
15643
|
}, [handleQuery, streamHandleQuery, message, maxLines, markdownEnabled2, exit, width, stream]);
|
|
15038
|
-
return /* @__PURE__ */
|
|
15644
|
+
return /* @__PURE__ */ jsxDEV10(Box8, {
|
|
15039
15645
|
flexDirection: "column",
|
|
15040
|
-
children: /* @__PURE__ */
|
|
15646
|
+
children: /* @__PURE__ */ jsxDEV10(App, {
|
|
15041
15647
|
history,
|
|
15042
15648
|
status: stream.status,
|
|
15043
15649
|
model,
|
|
@@ -15123,7 +15729,7 @@ function createChatCommand() {
|
|
|
15123
15729
|
}
|
|
15124
15730
|
const maxLines = Number.parseInt(argv.maxLines ?? "500", 10);
|
|
15125
15731
|
const handleQuery = await loadHandleQuery2(argv);
|
|
15126
|
-
const { waitUntilExit } = render2(
|
|
15732
|
+
const { waitUntilExit } = render2(React9.createElement(ChatTui_default, {
|
|
15127
15733
|
handleQuery,
|
|
15128
15734
|
message: argv.message,
|
|
15129
15735
|
model: argv.model,
|
|
@@ -22778,7 +23384,7 @@ function formatDate(date) {
|
|
|
22778
23384
|
const d = typeof date === "string" ? new Date(date) : date;
|
|
22779
23385
|
return d.toLocaleString("zh-CN");
|
|
22780
23386
|
}
|
|
22781
|
-
function
|
|
23387
|
+
function formatDuration2(ms) {
|
|
22782
23388
|
if (ms === undefined || ms === null)
|
|
22783
23389
|
return "-";
|
|
22784
23390
|
if (ms < 1000)
|
|
@@ -22926,7 +23532,7 @@ function renderRunsList(runs, options) {
|
|
|
22926
23532
|
const rows = runs.map((r) => {
|
|
22927
23533
|
const id = truncateVisual3(r.id, ID_WIDTH).padEnd(ID_WIDTH);
|
|
22928
23534
|
const status = statusColor(r.status)(r.status.padEnd(STATUS_WIDTH));
|
|
22929
|
-
const duration =
|
|
23535
|
+
const duration = formatDuration2(r.durationMs).padEnd(DURATION_WIDTH);
|
|
22930
23536
|
const started = formatDate(r.startedAt);
|
|
22931
23537
|
return `${id}${GAP}${status}${GAP}${duration}${GAP}${started}`;
|
|
22932
23538
|
});
|
|
@@ -22954,7 +23560,7 @@ function renderRunDetail(run) {
|
|
|
22954
23560
|
if (run.completedAt) {
|
|
22955
23561
|
lines.push(` ${chalk67.cyan("Completed:")} ${formatDate(run.completedAt)}`);
|
|
22956
23562
|
}
|
|
22957
|
-
lines.push(` ${chalk67.cyan("Duration:")} ${
|
|
23563
|
+
lines.push(` ${chalk67.cyan("Duration:")} ${formatDuration2(run.durationMs)}`);
|
|
22958
23564
|
if (run.error) {
|
|
22959
23565
|
lines.push(chalk67.bold(`
|
|
22960
23566
|
❌ Error
|
|
@@ -23020,7 +23626,7 @@ function renderRunResult(result) {
|
|
|
23020
23626
|
}
|
|
23021
23627
|
lines.push(` Run ID: ${result.runId}`);
|
|
23022
23628
|
if (result.durationMs) {
|
|
23023
|
-
lines.push(` Duration: ${
|
|
23629
|
+
lines.push(` Duration: ${formatDuration2(result.durationMs)}`);
|
|
23024
23630
|
}
|
|
23025
23631
|
if (result.error) {
|
|
23026
23632
|
lines.push(chalk67.red(`
|