@robota-sdk/agent-cli 3.0.0-beta.44 → 3.0.0-beta.46
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/README.md +30 -0
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-Y6VSMUKG.js → chunk-L5G6WFOL.js} +291 -67
- package/dist/node/index.cjs +290 -66
- package/dist/node/index.js +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -181,6 +181,34 @@ After the Edit tool runs, a `DiffBlock` component renders the change inline:
|
|
|
181
181
|
|
|
182
182
|
Removed lines appear in red with `-`, added lines in green with `+`. Diffs longer than 10 lines show the first 8 + a `... and N more lines` summary.
|
|
183
183
|
|
|
184
|
+
## Session Management
|
|
185
|
+
|
|
186
|
+
The CLI supports continuing, resuming, forking, and naming sessions.
|
|
187
|
+
|
|
188
|
+
### CLI Flags
|
|
189
|
+
|
|
190
|
+
| Flag | Description |
|
|
191
|
+
| --------------------- | ------------------------------------------------ |
|
|
192
|
+
| `-c`, `--continue` | Continue the most recent session |
|
|
193
|
+
| `-r`, `--resume <id>` | Resume a specific session by ID |
|
|
194
|
+
| `--fork-session <id>` | Fork a session (new session with copied history) |
|
|
195
|
+
| `--name <name>` | Assign a name to the session at startup |
|
|
196
|
+
|
|
197
|
+
### TUI Commands
|
|
198
|
+
|
|
199
|
+
| Command | Description |
|
|
200
|
+
| ---------------- | ----------------------------------- |
|
|
201
|
+
| `/resume` | List recent sessions and resume one |
|
|
202
|
+
| `/rename <name>` | Rename the current session |
|
|
203
|
+
|
|
204
|
+
### Session Name Display
|
|
205
|
+
|
|
206
|
+
When a session has a name, it appears in three places:
|
|
207
|
+
|
|
208
|
+
- **Input border** — session name shown in the input area border
|
|
209
|
+
- **Terminal title** — updated via ANSI escape sequences
|
|
210
|
+
- **StatusBar** — displayed alongside mode, model, and context usage
|
|
211
|
+
|
|
184
212
|
## Slash Commands
|
|
185
213
|
|
|
186
214
|
| Command | Description |
|
|
@@ -195,6 +223,8 @@ Removed lines appear in red with `-`, added lines in green with `+`. Diffs longe
|
|
|
195
223
|
| `/context` | Context window details |
|
|
196
224
|
| `/permissions` | Show permission rules |
|
|
197
225
|
| `/plugin [subcommand]` | Plugin management TUI |
|
|
226
|
+
| `/resume` | List recent sessions and resume one |
|
|
227
|
+
| `/rename <name>` | Rename the current session |
|
|
198
228
|
| `/exit` | Exit CLI |
|
|
199
229
|
|
|
200
230
|
Typing `/` triggers an autocomplete popup with arrow-key navigation, Tab completion, and Esc to dismiss. Commands with subcommands (e.g., `/mode`, `/model`) show a nested submenu. Skill commands discovered from `.agents/skills/` and `.claude/commands/` appear alongside built-in commands.
|
package/dist/node/bin.js
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync as readFileSync3, existsSync as existsSync3, mkdirSync as
|
|
|
3
3
|
import { join as join5, dirname as dirname2 } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { InteractiveSession as InteractiveSession2 } from "@robota-sdk/agent-sdk";
|
|
6
|
+
import { SessionStore } from "@robota-sdk/agent-sessions";
|
|
6
7
|
|
|
7
8
|
// src/utils/cli-args.ts
|
|
8
9
|
import { parseArgs } from "util";
|
|
@@ -31,12 +32,14 @@ function parseCliArgs() {
|
|
|
31
32
|
allowPositionals: true,
|
|
32
33
|
options: {
|
|
33
34
|
p: { type: "boolean", short: "p", default: false },
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
continue: { type: "boolean", short: "c", default: false },
|
|
36
|
+
resume: { type: "string", short: "r" },
|
|
36
37
|
model: { type: "string" },
|
|
37
38
|
language: { type: "string" },
|
|
38
39
|
"permission-mode": { type: "string" },
|
|
39
40
|
"max-turns": { type: "string" },
|
|
41
|
+
"fork-session": { type: "boolean", default: false },
|
|
42
|
+
name: { type: "string", short: "n" },
|
|
40
43
|
version: { type: "boolean", default: false },
|
|
41
44
|
reset: { type: "boolean", default: false }
|
|
42
45
|
}
|
|
@@ -44,12 +47,14 @@ function parseCliArgs() {
|
|
|
44
47
|
return {
|
|
45
48
|
positional: positionals,
|
|
46
49
|
printMode: values["p"] ?? false,
|
|
47
|
-
continueMode: values["
|
|
48
|
-
resumeId: values["
|
|
50
|
+
continueMode: values["continue"] ?? false,
|
|
51
|
+
resumeId: values["resume"],
|
|
49
52
|
model: values["model"],
|
|
50
53
|
language: values["language"],
|
|
51
54
|
permissionMode: parsePermissionMode(values["permission-mode"]),
|
|
52
55
|
maxTurns: parseMaxTurns(values["max-turns"]),
|
|
56
|
+
forkSession: values["fork-session"] ?? false,
|
|
57
|
+
sessionName: values["name"],
|
|
53
58
|
version: values["version"] ?? false,
|
|
54
59
|
reset: values["reset"] ?? false
|
|
55
60
|
};
|
|
@@ -133,8 +138,8 @@ function createProviderFromSettings(cwd, modelOverride) {
|
|
|
133
138
|
import { render } from "ink";
|
|
134
139
|
|
|
135
140
|
// src/ui/App.tsx
|
|
136
|
-
import { useState as
|
|
137
|
-
import { Box as
|
|
141
|
+
import { useState as useState10, useRef as useRef8, useEffect as useEffect4 } from "react";
|
|
142
|
+
import { Box as Box12, Text as Text14, useApp, useInput as useInput8 } from "ink";
|
|
138
143
|
import { getModelName, createSystemMessage as createSystemMessage2, messageToHistoryEntry as messageToHistoryEntry2 } from "@robota-sdk/agent-core";
|
|
139
144
|
|
|
140
145
|
// src/ui/hooks/useInteractiveSession.ts
|
|
@@ -258,7 +263,11 @@ function initializeSession(props, permissionHandler) {
|
|
|
258
263
|
provider: props.provider,
|
|
259
264
|
permissionMode: props.permissionMode,
|
|
260
265
|
maxTurns: props.maxTurns,
|
|
261
|
-
permissionHandler
|
|
266
|
+
permissionHandler,
|
|
267
|
+
sessionStore: props.sessionStore,
|
|
268
|
+
resumeSessionId: props.resumeSessionId,
|
|
269
|
+
forkSession: props.forkSession,
|
|
270
|
+
sessionName: props.sessionName
|
|
262
271
|
});
|
|
263
272
|
const registry = new CommandRegistry();
|
|
264
273
|
registry.addSource(new BuiltinCommandSource());
|
|
@@ -313,6 +322,12 @@ function useInteractiveSession(props) {
|
|
|
313
322
|
}
|
|
314
323
|
const { interactiveSession, registry, manager } = stateRef.current;
|
|
315
324
|
manager.onChange = () => forceRender((n) => n + 1);
|
|
325
|
+
if (manager.history.length === 0) {
|
|
326
|
+
const restored = interactiveSession.getFullHistory();
|
|
327
|
+
if (restored.length > 0) {
|
|
328
|
+
manager.syncHistory(restored);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
316
331
|
useEffect(() => {
|
|
317
332
|
interactiveSession.on("text_delta", manager.onTextDelta);
|
|
318
333
|
interactiveSession.on("tool_start", manager.onToolStart);
|
|
@@ -329,6 +344,10 @@ function useInteractiveSession(props) {
|
|
|
329
344
|
usedTokens: ctx.usedTokens,
|
|
330
345
|
maxTokens: ctx.maxTokens
|
|
331
346
|
});
|
|
347
|
+
const restored = interactiveSession.getFullHistory();
|
|
348
|
+
if (restored.length > 0) {
|
|
349
|
+
manager.syncHistory(restored);
|
|
350
|
+
}
|
|
332
351
|
clearInterval(initCheck);
|
|
333
352
|
} catch {
|
|
334
353
|
}
|
|
@@ -372,6 +391,14 @@ function useInteractiveSession(props) {
|
|
|
372
391
|
effects._resetRequested = true;
|
|
373
392
|
return;
|
|
374
393
|
}
|
|
394
|
+
if (result.data?.triggerResumePicker) {
|
|
395
|
+
effects._triggerResumePicker = true;
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (result.data?.name) {
|
|
399
|
+
effects._sessionName = result.data.name;
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
375
402
|
const ctx = interactiveSession.getContextState();
|
|
376
403
|
manager.setContextState({
|
|
377
404
|
percentage: ctx.usedPercentage,
|
|
@@ -764,7 +791,7 @@ function MessageList({ history }) {
|
|
|
764
791
|
// src/ui/StatusBar.tsx
|
|
765
792
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
766
793
|
import { formatTokenCount } from "@robota-sdk/agent-core";
|
|
767
|
-
import { jsx as jsx2, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
794
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
768
795
|
var CONTEXT_YELLOW_THRESHOLD = 70;
|
|
769
796
|
var CONTEXT_RED_THRESHOLD = 90;
|
|
770
797
|
function getContextColor(percentage) {
|
|
@@ -780,7 +807,8 @@ function StatusBar({
|
|
|
780
807
|
isThinking,
|
|
781
808
|
contextPercentage,
|
|
782
809
|
contextUsedTokens,
|
|
783
|
-
contextMaxTokens
|
|
810
|
+
contextMaxTokens,
|
|
811
|
+
sessionName
|
|
784
812
|
}) {
|
|
785
813
|
const contextColor = getContextColor(contextPercentage);
|
|
786
814
|
return /* @__PURE__ */ jsxs3(
|
|
@@ -796,6 +824,10 @@ function StatusBar({
|
|
|
796
824
|
/* @__PURE__ */ jsx2(Text3, { color: "cyan", bold: true, children: "Mode:" }),
|
|
797
825
|
" ",
|
|
798
826
|
/* @__PURE__ */ jsx2(Text3, { children: permissionMode }),
|
|
827
|
+
sessionName && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
828
|
+
" | ",
|
|
829
|
+
/* @__PURE__ */ jsx2(Text3, { color: "magenta", children: sessionName })
|
|
830
|
+
] }),
|
|
799
831
|
" | ",
|
|
800
832
|
/* @__PURE__ */ jsx2(Text3, { dimColor: true, children: modelName }),
|
|
801
833
|
" | ",
|
|
@@ -1137,7 +1169,8 @@ function InputArea({
|
|
|
1137
1169
|
isDisabled,
|
|
1138
1170
|
isAborting,
|
|
1139
1171
|
pendingPrompt,
|
|
1140
|
-
registry
|
|
1172
|
+
registry,
|
|
1173
|
+
sessionName
|
|
1141
1174
|
}) {
|
|
1142
1175
|
const [value, setValue] = useState4("");
|
|
1143
1176
|
const pasteStore = useRef3(/* @__PURE__ */ new Map());
|
|
@@ -1220,6 +1253,17 @@ function InputArea({
|
|
|
1220
1253
|
},
|
|
1221
1254
|
{ isActive: !!pendingPrompt }
|
|
1222
1255
|
);
|
|
1256
|
+
const borderColor = isAborting ? "yellow" : pendingPrompt ? "cyan" : isDisabled ? "gray" : "green";
|
|
1257
|
+
const innerWidth = Math.max(1, terminalColumns - BORDER_HORIZONTAL);
|
|
1258
|
+
const topBorder = (() => {
|
|
1259
|
+
if (sessionName) {
|
|
1260
|
+
const label = ` "${sessionName}" `;
|
|
1261
|
+
const rightPad = 2;
|
|
1262
|
+
const leftLen = Math.max(0, innerWidth - label.length - rightPad);
|
|
1263
|
+
return { left: "\u250C" + "\u2500".repeat(leftLen), label, right: "\u2500".repeat(rightPad) + "\u2510" };
|
|
1264
|
+
}
|
|
1265
|
+
return { left: "\u250C" + "\u2500".repeat(innerWidth), label: "", right: "\u2510" };
|
|
1266
|
+
})();
|
|
1223
1267
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
1224
1268
|
showPopup && /* @__PURE__ */ jsx6(
|
|
1225
1269
|
SlashAutocomplete,
|
|
@@ -1230,34 +1274,31 @@ function InputArea({
|
|
|
1230
1274
|
isSubcommandMode
|
|
1231
1275
|
}
|
|
1232
1276
|
),
|
|
1233
|
-
/* @__PURE__ */
|
|
1234
|
-
|
|
1235
|
-
{
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
] })
|
|
1259
|
-
}
|
|
1260
|
-
)
|
|
1277
|
+
/* @__PURE__ */ jsxs5(Text7, { color: borderColor, children: [
|
|
1278
|
+
topBorder.left,
|
|
1279
|
+
topBorder.label ? /* @__PURE__ */ jsx6(Text7, { backgroundColor: borderColor, color: "black", bold: true, children: topBorder.label }) : null,
|
|
1280
|
+
topBorder.right
|
|
1281
|
+
] }),
|
|
1282
|
+
/* @__PURE__ */ jsx6(Box5, { borderStyle: "single", borderTop: false, borderColor, paddingLeft: 1, children: isAborting ? /* @__PURE__ */ jsx6(Text7, { color: "yellow", children: " Interrupting..." }) : pendingPrompt ? /* @__PURE__ */ jsxs5(Text7, { color: "cyan", children: [
|
|
1283
|
+
" ",
|
|
1284
|
+
"Queued: ",
|
|
1285
|
+
pendingPrompt.length > 50 ? pendingPrompt.slice(0, 47) + "..." : pendingPrompt,
|
|
1286
|
+
" ",
|
|
1287
|
+
/* @__PURE__ */ jsx6(Text7, { dimColor: true, children: "(Backspace to cancel)" })
|
|
1288
|
+
] }) : isDisabled ? /* @__PURE__ */ jsx6(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
1289
|
+
/* @__PURE__ */ jsx6(Text7, { color: "green", bold: true, children: "> " }),
|
|
1290
|
+
/* @__PURE__ */ jsx6(
|
|
1291
|
+
CjkTextInput,
|
|
1292
|
+
{
|
|
1293
|
+
value,
|
|
1294
|
+
onChange: setValue,
|
|
1295
|
+
onSubmit: handleSubmit,
|
|
1296
|
+
onPaste: handlePaste,
|
|
1297
|
+
placeholder: "Type a message or /help",
|
|
1298
|
+
availableWidth
|
|
1299
|
+
}
|
|
1300
|
+
)
|
|
1301
|
+
] }) })
|
|
1261
1302
|
] });
|
|
1262
1303
|
}
|
|
1263
1304
|
|
|
@@ -1370,7 +1411,7 @@ function PermissionPrompt({ request }) {
|
|
|
1370
1411
|
|
|
1371
1412
|
// src/ui/StreamingIndicator.tsx
|
|
1372
1413
|
import { Box as Box8, Text as Text10 } from "ink";
|
|
1373
|
-
import { Fragment as
|
|
1414
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1374
1415
|
function getToolStyle(t) {
|
|
1375
1416
|
if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
|
|
1376
1417
|
if (t.result === "error") return { color: "red", icon: "\u2717", strikethrough: true };
|
|
@@ -1381,7 +1422,7 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
1381
1422
|
const hasTools = activeTools.length > 0;
|
|
1382
1423
|
const hasText = text.length > 0;
|
|
1383
1424
|
if (!hasTools && !hasText) {
|
|
1384
|
-
return /* @__PURE__ */ jsx9(
|
|
1425
|
+
return /* @__PURE__ */ jsx9(Fragment3, {});
|
|
1385
1426
|
}
|
|
1386
1427
|
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
1387
1428
|
hasTools && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
|
|
@@ -1862,10 +1903,90 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
1862
1903
|
);
|
|
1863
1904
|
}
|
|
1864
1905
|
|
|
1865
|
-
// src/ui/
|
|
1906
|
+
// src/ui/ListPicker.tsx
|
|
1907
|
+
import { useState as useState9, useRef as useRef7 } from "react";
|
|
1908
|
+
import { Box as Box11, Text as Text13, useInput as useInput7 } from "ink";
|
|
1866
1909
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1910
|
+
var DEFAULT_MAX_VISIBLE = 3;
|
|
1911
|
+
function ListPicker({
|
|
1912
|
+
items,
|
|
1913
|
+
renderItem,
|
|
1914
|
+
onSelect,
|
|
1915
|
+
onCancel,
|
|
1916
|
+
maxVisible = DEFAULT_MAX_VISIBLE
|
|
1917
|
+
}) {
|
|
1918
|
+
const [selectedIndex, setSelectedIndex] = useState9(0);
|
|
1919
|
+
const [scrollOffset, setScrollOffset] = useState9(0);
|
|
1920
|
+
const selectedRef = useRef7(0);
|
|
1921
|
+
const resolvedRef = useRef7(false);
|
|
1922
|
+
useInput7((_input, key) => {
|
|
1923
|
+
if (resolvedRef.current) return;
|
|
1924
|
+
if (key.escape) {
|
|
1925
|
+
resolvedRef.current = true;
|
|
1926
|
+
onCancel();
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
if (items.length === 0) return;
|
|
1930
|
+
if (key.upArrow) {
|
|
1931
|
+
const next = selectedRef.current > 0 ? selectedRef.current - 1 : selectedRef.current;
|
|
1932
|
+
selectedRef.current = next;
|
|
1933
|
+
setSelectedIndex(next);
|
|
1934
|
+
if (next < scrollOffset) {
|
|
1935
|
+
setScrollOffset(next);
|
|
1936
|
+
}
|
|
1937
|
+
} else if (key.downArrow) {
|
|
1938
|
+
const next = selectedRef.current < items.length - 1 ? selectedRef.current + 1 : selectedRef.current;
|
|
1939
|
+
selectedRef.current = next;
|
|
1940
|
+
setSelectedIndex(next);
|
|
1941
|
+
if (next >= scrollOffset + maxVisible) {
|
|
1942
|
+
setScrollOffset(next - maxVisible + 1);
|
|
1943
|
+
}
|
|
1944
|
+
} else if (key.return) {
|
|
1945
|
+
const item = items[selectedRef.current];
|
|
1946
|
+
if (item !== void 0) {
|
|
1947
|
+
resolvedRef.current = true;
|
|
1948
|
+
onSelect(item);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
});
|
|
1952
|
+
if (items.length === 0) {
|
|
1953
|
+
return /* @__PURE__ */ jsx13(Box11, {});
|
|
1954
|
+
}
|
|
1955
|
+
const visibleItems = items.slice(scrollOffset, scrollOffset + maxVisible);
|
|
1956
|
+
const hasMore = scrollOffset + maxVisible < items.length;
|
|
1957
|
+
const hasLess = scrollOffset > 0;
|
|
1958
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
1959
|
+
hasLess && /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
|
|
1960
|
+
" \u2191 ",
|
|
1961
|
+
scrollOffset,
|
|
1962
|
+
" more above"
|
|
1963
|
+
] }),
|
|
1964
|
+
visibleItems.map((item, index) => /* @__PURE__ */ jsx13(Box11, { marginBottom: 1, children: renderItem(item, scrollOffset + index === selectedIndex) }, scrollOffset + index)),
|
|
1965
|
+
hasMore && /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
|
|
1966
|
+
" \u2193 ",
|
|
1967
|
+
items.length - scrollOffset - maxVisible,
|
|
1968
|
+
" more below"
|
|
1969
|
+
] })
|
|
1970
|
+
] });
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
// src/ui/App.tsx
|
|
1974
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1867
1975
|
var EXIT_DELAY_MS = 500;
|
|
1976
|
+
var SESSION_ID_DISPLAY_LENGTH = 8;
|
|
1868
1977
|
function App(props) {
|
|
1978
|
+
const [activeSessionId, setActiveSessionId] = useState10(props.resumeSessionId);
|
|
1979
|
+
return /* @__PURE__ */ jsx14(
|
|
1980
|
+
AppInner,
|
|
1981
|
+
{
|
|
1982
|
+
...props,
|
|
1983
|
+
resumeSessionId: activeSessionId,
|
|
1984
|
+
onSessionSwitch: (sessionId) => setActiveSessionId(sessionId)
|
|
1985
|
+
},
|
|
1986
|
+
activeSessionId ?? "__new__"
|
|
1987
|
+
);
|
|
1988
|
+
}
|
|
1989
|
+
function AppInner(props) {
|
|
1869
1990
|
const { exit } = useApp();
|
|
1870
1991
|
const cwd = props.cwd;
|
|
1871
1992
|
const {
|
|
@@ -1887,12 +2008,28 @@ function App(props) {
|
|
|
1887
2008
|
cwd,
|
|
1888
2009
|
provider: props.provider,
|
|
1889
2010
|
permissionMode: props.permissionMode,
|
|
1890
|
-
maxTurns: props.maxTurns
|
|
2011
|
+
maxTurns: props.maxTurns,
|
|
2012
|
+
sessionStore: props.sessionStore,
|
|
2013
|
+
resumeSessionId: props.resumeSessionId,
|
|
2014
|
+
forkSession: props.forkSession,
|
|
2015
|
+
sessionName: props.sessionName
|
|
1891
2016
|
});
|
|
1892
2017
|
const pluginCallbacks = usePluginCallbacks(cwd);
|
|
1893
|
-
const [pendingModelId, setPendingModelId] =
|
|
1894
|
-
const pendingModelChangeRef =
|
|
1895
|
-
const [showPluginTUI, setShowPluginTUI] =
|
|
2018
|
+
const [pendingModelId, setPendingModelId] = useState10(null);
|
|
2019
|
+
const pendingModelChangeRef = useRef8(null);
|
|
2020
|
+
const [showPluginTUI, setShowPluginTUI] = useState10(false);
|
|
2021
|
+
const [showSessionPicker, setShowSessionPicker] = useState10(
|
|
2022
|
+
props.resumeSessionId === "__picker__"
|
|
2023
|
+
);
|
|
2024
|
+
const [sessionName, setSessionName] = useState10(props.sessionName);
|
|
2025
|
+
useEffect4(() => {
|
|
2026
|
+
const name = interactiveSession?.getName?.();
|
|
2027
|
+
if (name && !sessionName) setSessionName(name);
|
|
2028
|
+
}, [interactiveSession, sessionName]);
|
|
2029
|
+
useEffect4(() => {
|
|
2030
|
+
const title = sessionName ? `Robota \u2014 ${sessionName}` : "Robota";
|
|
2031
|
+
process.stdout.write(`\x1B]0;${title}\x07`);
|
|
2032
|
+
}, [sessionName]);
|
|
1896
2033
|
const handleSubmit = async (input) => {
|
|
1897
2034
|
await baseHandleSubmit(input);
|
|
1898
2035
|
const sideEffects = interactiveSession;
|
|
@@ -1937,14 +2074,26 @@ function App(props) {
|
|
|
1937
2074
|
setShowPluginTUI(true);
|
|
1938
2075
|
return;
|
|
1939
2076
|
}
|
|
2077
|
+
if (sideEffects._triggerResumePicker) {
|
|
2078
|
+
delete sideEffects._triggerResumePicker;
|
|
2079
|
+
setShowSessionPicker(true);
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
if (sideEffects._sessionName) {
|
|
2083
|
+
const name = sideEffects._sessionName;
|
|
2084
|
+
delete sideEffects._sessionName;
|
|
2085
|
+
interactiveSession.setName(name);
|
|
2086
|
+
setSessionName(name);
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
1940
2089
|
};
|
|
1941
|
-
|
|
2090
|
+
useInput8(
|
|
1942
2091
|
(_input, key) => {
|
|
1943
2092
|
if (key.escape && isThinking) {
|
|
1944
2093
|
handleAbort();
|
|
1945
2094
|
}
|
|
1946
2095
|
},
|
|
1947
|
-
{ isActive: !permissionRequest && !showPluginTUI }
|
|
2096
|
+
{ isActive: !permissionRequest && !showPluginTUI && !showSessionPicker }
|
|
1948
2097
|
);
|
|
1949
2098
|
let permissionMode = props.permissionMode ?? "default";
|
|
1950
2099
|
let sessionId = "";
|
|
@@ -1954,26 +2103,26 @@ function App(props) {
|
|
|
1954
2103
|
sessionId = session.getSessionId();
|
|
1955
2104
|
} catch {
|
|
1956
2105
|
}
|
|
1957
|
-
return /* @__PURE__ */
|
|
1958
|
-
/* @__PURE__ */
|
|
1959
|
-
/* @__PURE__ */
|
|
2106
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
2107
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
2108
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", bold: true, children: `
|
|
1960
2109
|
____ ___ ____ ___ _____ _
|
|
1961
2110
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1962
2111
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
1963
2112
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1964
2113
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1965
2114
|
` }),
|
|
1966
|
-
/* @__PURE__ */
|
|
2115
|
+
/* @__PURE__ */ jsxs12(Text14, { dimColor: true, children: [
|
|
1967
2116
|
" v",
|
|
1968
2117
|
props.version ?? "0.0.0"
|
|
1969
2118
|
] })
|
|
1970
2119
|
] }),
|
|
1971
|
-
/* @__PURE__ */
|
|
1972
|
-
/* @__PURE__ */
|
|
1973
|
-
(isThinking || activeTools.length > 0) && /* @__PURE__ */
|
|
2120
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
2121
|
+
/* @__PURE__ */ jsx14(MessageList, { history }),
|
|
2122
|
+
(isThinking || activeTools.length > 0) && /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx14(StreamingIndicator, { text: streamingText, activeTools }) })
|
|
1974
2123
|
] }),
|
|
1975
|
-
permissionRequest && /* @__PURE__ */
|
|
1976
|
-
pendingModelId && /* @__PURE__ */
|
|
2124
|
+
permissionRequest && /* @__PURE__ */ jsx14(PermissionPrompt, { request: permissionRequest }),
|
|
2125
|
+
pendingModelId && /* @__PURE__ */ jsx14(
|
|
1977
2126
|
ConfirmPrompt,
|
|
1978
2127
|
{
|
|
1979
2128
|
message: `Change model to ${getModelName(pendingModelId)}? This will restart the session.`,
|
|
@@ -2007,7 +2156,7 @@ function App(props) {
|
|
|
2007
2156
|
}
|
|
2008
2157
|
}
|
|
2009
2158
|
),
|
|
2010
|
-
showPluginTUI && /* @__PURE__ */
|
|
2159
|
+
showPluginTUI && /* @__PURE__ */ jsx14(
|
|
2011
2160
|
PluginTUI,
|
|
2012
2161
|
{
|
|
2013
2162
|
callbacks: pluginCallbacks,
|
|
@@ -2015,7 +2164,52 @@ function App(props) {
|
|
|
2015
2164
|
addMessage: (msg) => addEntry(messageToHistoryEntry2(createSystemMessage2(msg.content)))
|
|
2016
2165
|
}
|
|
2017
2166
|
),
|
|
2018
|
-
/* @__PURE__ */
|
|
2167
|
+
showSessionPicker && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
2168
|
+
/* @__PURE__ */ jsx14(Text14, { bold: true, color: "cyan", children: "Select a session to resume (ESC to cancel):" }),
|
|
2169
|
+
/* @__PURE__ */ jsx14(
|
|
2170
|
+
ListPicker,
|
|
2171
|
+
{
|
|
2172
|
+
items: (props.sessionStore?.list() ?? []).filter((s) => s.cwd === props.cwd),
|
|
2173
|
+
renderItem: (session, isSelected) => {
|
|
2174
|
+
const lastMsg = session.messages.slice().reverse().find((m) => {
|
|
2175
|
+
const msg = m;
|
|
2176
|
+
return msg.role === "assistant" && msg.content;
|
|
2177
|
+
});
|
|
2178
|
+
const rawPreview = lastMsg?.content?.replace(/[\n\r]+/g, " ").trim() ?? "";
|
|
2179
|
+
const preview = rawPreview ? rawPreview.slice(0, 60) + (rawPreview.length > 60 ? "..." : "") : "";
|
|
2180
|
+
return /* @__PURE__ */ jsxs12(Text14, { children: [
|
|
2181
|
+
isSelected ? "> " : " ",
|
|
2182
|
+
/* @__PURE__ */ jsx14(Text14, { bold: true, children: session.name ?? session.id.slice(0, SESSION_ID_DISPLAY_LENGTH) }),
|
|
2183
|
+
" ",
|
|
2184
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: new Date(session.updatedAt).toLocaleString(void 0, {
|
|
2185
|
+
month: "short",
|
|
2186
|
+
day: "numeric",
|
|
2187
|
+
hour: "2-digit",
|
|
2188
|
+
minute: "2-digit"
|
|
2189
|
+
}) }),
|
|
2190
|
+
" ",
|
|
2191
|
+
/* @__PURE__ */ jsxs12(Text14, { dimColor: true, children: [
|
|
2192
|
+
"msgs: ",
|
|
2193
|
+
session.messages.length
|
|
2194
|
+
] }),
|
|
2195
|
+
preview ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
2196
|
+
"\n ",
|
|
2197
|
+
/* @__PURE__ */ jsx14(Text14, { color: "gray", children: preview })
|
|
2198
|
+
] }) : null
|
|
2199
|
+
] });
|
|
2200
|
+
},
|
|
2201
|
+
onSelect: (session) => {
|
|
2202
|
+
setShowSessionPicker(false);
|
|
2203
|
+
props.onSessionSwitch(session.id);
|
|
2204
|
+
},
|
|
2205
|
+
onCancel: () => {
|
|
2206
|
+
setShowSessionPicker(false);
|
|
2207
|
+
addEntry(messageToHistoryEntry2(createSystemMessage2("Session resume cancelled.")));
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
)
|
|
2211
|
+
] }),
|
|
2212
|
+
/* @__PURE__ */ jsx14(
|
|
2019
2213
|
StatusBar,
|
|
2020
2214
|
{
|
|
2021
2215
|
permissionMode,
|
|
@@ -2025,26 +2219,28 @@ function App(props) {
|
|
|
2025
2219
|
isThinking,
|
|
2026
2220
|
contextPercentage: contextState.percentage,
|
|
2027
2221
|
contextUsedTokens: contextState.usedTokens,
|
|
2028
|
-
contextMaxTokens: contextState.maxTokens
|
|
2222
|
+
contextMaxTokens: contextState.maxTokens,
|
|
2223
|
+
sessionName
|
|
2029
2224
|
}
|
|
2030
2225
|
),
|
|
2031
|
-
/* @__PURE__ */
|
|
2226
|
+
/* @__PURE__ */ jsx14(
|
|
2032
2227
|
InputArea,
|
|
2033
2228
|
{
|
|
2034
2229
|
onSubmit: handleSubmit,
|
|
2035
2230
|
onCancelQueue: handleCancelQueue,
|
|
2036
|
-
isDisabled: !!permissionRequest || showPluginTUI || isThinking && !!pendingPrompt,
|
|
2231
|
+
isDisabled: !!permissionRequest || showPluginTUI || showSessionPicker || isThinking && !!pendingPrompt,
|
|
2037
2232
|
isAborting,
|
|
2038
2233
|
pendingPrompt,
|
|
2039
|
-
registry
|
|
2234
|
+
registry,
|
|
2235
|
+
sessionName
|
|
2040
2236
|
}
|
|
2041
2237
|
),
|
|
2042
|
-
/* @__PURE__ */
|
|
2238
|
+
/* @__PURE__ */ jsx14(Text14, { children: " " })
|
|
2043
2239
|
] });
|
|
2044
2240
|
}
|
|
2045
2241
|
|
|
2046
2242
|
// src/ui/render.tsx
|
|
2047
|
-
import { jsx as
|
|
2243
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
2048
2244
|
function renderApp(options) {
|
|
2049
2245
|
process.on("unhandledRejection", (reason) => {
|
|
2050
2246
|
process.stderr.write(`
|
|
@@ -2058,7 +2254,7 @@ function renderApp(options) {
|
|
|
2058
2254
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
2059
2255
|
process.stdout.write("\x1B[?2004h");
|
|
2060
2256
|
}
|
|
2061
|
-
const instance = render(/* @__PURE__ */
|
|
2257
|
+
const instance = render(/* @__PURE__ */ jsx15(App, { ...options }), {
|
|
2062
2258
|
exitOnCtrlC: true
|
|
2063
2259
|
});
|
|
2064
2260
|
instance.waitUntilExit().then(() => {
|
|
@@ -2227,6 +2423,28 @@ async function startCli() {
|
|
|
2227
2423
|
const providerSettings = readProviderSettings(cwd);
|
|
2228
2424
|
const modelId = args.model ?? providerSettings.model;
|
|
2229
2425
|
const provider = createProviderFromSettings(cwd, args.model);
|
|
2426
|
+
const sessionStore = new SessionStore();
|
|
2427
|
+
let resumeSessionId;
|
|
2428
|
+
if (args.continueMode) {
|
|
2429
|
+
const sessions = sessionStore.list().filter((s) => s.cwd === cwd);
|
|
2430
|
+
if (sessions.length > 0) {
|
|
2431
|
+
resumeSessionId = sessions[0].id;
|
|
2432
|
+
}
|
|
2433
|
+
} else if (args.resumeId !== void 0) {
|
|
2434
|
+
if (args.resumeId === "") {
|
|
2435
|
+
resumeSessionId = "__picker__";
|
|
2436
|
+
} else {
|
|
2437
|
+
const sessions = sessionStore.list();
|
|
2438
|
+
const match = sessions.find((s) => s.id === args.resumeId || s.name === args.resumeId);
|
|
2439
|
+
if (match) {
|
|
2440
|
+
resumeSessionId = match.id;
|
|
2441
|
+
} else {
|
|
2442
|
+
process.stderr.write(`Session not found: ${args.resumeId}
|
|
2443
|
+
`);
|
|
2444
|
+
process.exit(1);
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2230
2448
|
if (args.printMode) {
|
|
2231
2449
|
const prompt = args.positional.join(" ").trim();
|
|
2232
2450
|
if (prompt.length === 0) {
|
|
@@ -2237,7 +2455,9 @@ async function startCli() {
|
|
|
2237
2455
|
cwd,
|
|
2238
2456
|
provider,
|
|
2239
2457
|
permissionMode: args.permissionMode ?? "bypassPermissions",
|
|
2240
|
-
maxTurns: args.maxTurns
|
|
2458
|
+
maxTurns: args.maxTurns,
|
|
2459
|
+
sessionStore,
|
|
2460
|
+
sessionName: args.sessionName
|
|
2241
2461
|
});
|
|
2242
2462
|
await new Promise((resolve, reject) => {
|
|
2243
2463
|
session.on("complete", (result) => {
|
|
@@ -2260,7 +2480,11 @@ async function startCli() {
|
|
|
2260
2480
|
language: args.language,
|
|
2261
2481
|
permissionMode: args.permissionMode,
|
|
2262
2482
|
maxTurns: args.maxTurns,
|
|
2263
|
-
version: readVersion()
|
|
2483
|
+
version: readVersion(),
|
|
2484
|
+
sessionStore,
|
|
2485
|
+
resumeSessionId,
|
|
2486
|
+
forkSession: args.forkSession,
|
|
2487
|
+
sessionName: args.sessionName
|
|
2264
2488
|
});
|
|
2265
2489
|
}
|
|
2266
2490
|
|
package/dist/node/index.cjs
CHANGED
|
@@ -39,6 +39,7 @@ var import_node_fs3 = require("fs");
|
|
|
39
39
|
var import_node_path5 = require("path");
|
|
40
40
|
var import_node_url = require("url");
|
|
41
41
|
var import_agent_sdk3 = require("@robota-sdk/agent-sdk");
|
|
42
|
+
var import_agent_sessions = require("@robota-sdk/agent-sessions");
|
|
42
43
|
|
|
43
44
|
// src/utils/cli-args.ts
|
|
44
45
|
var import_node_util = require("util");
|
|
@@ -67,12 +68,14 @@ function parseCliArgs() {
|
|
|
67
68
|
allowPositionals: true,
|
|
68
69
|
options: {
|
|
69
70
|
p: { type: "boolean", short: "p", default: false },
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
continue: { type: "boolean", short: "c", default: false },
|
|
72
|
+
resume: { type: "string", short: "r" },
|
|
72
73
|
model: { type: "string" },
|
|
73
74
|
language: { type: "string" },
|
|
74
75
|
"permission-mode": { type: "string" },
|
|
75
76
|
"max-turns": { type: "string" },
|
|
77
|
+
"fork-session": { type: "boolean", default: false },
|
|
78
|
+
name: { type: "string", short: "n" },
|
|
76
79
|
version: { type: "boolean", default: false },
|
|
77
80
|
reset: { type: "boolean", default: false }
|
|
78
81
|
}
|
|
@@ -80,12 +83,14 @@ function parseCliArgs() {
|
|
|
80
83
|
return {
|
|
81
84
|
positional: positionals,
|
|
82
85
|
printMode: values["p"] ?? false,
|
|
83
|
-
continueMode: values["
|
|
84
|
-
resumeId: values["
|
|
86
|
+
continueMode: values["continue"] ?? false,
|
|
87
|
+
resumeId: values["resume"],
|
|
85
88
|
model: values["model"],
|
|
86
89
|
language: values["language"],
|
|
87
90
|
permissionMode: parsePermissionMode(values["permission-mode"]),
|
|
88
91
|
maxTurns: parseMaxTurns(values["max-turns"]),
|
|
92
|
+
forkSession: values["fork-session"] ?? false,
|
|
93
|
+
sessionName: values["name"],
|
|
89
94
|
version: values["version"] ?? false,
|
|
90
95
|
reset: values["reset"] ?? false
|
|
91
96
|
};
|
|
@@ -166,11 +171,11 @@ function createProviderFromSettings(cwd, modelOverride) {
|
|
|
166
171
|
}
|
|
167
172
|
|
|
168
173
|
// src/ui/render.tsx
|
|
169
|
-
var
|
|
174
|
+
var import_ink15 = require("ink");
|
|
170
175
|
|
|
171
176
|
// src/ui/App.tsx
|
|
172
|
-
var
|
|
173
|
-
var
|
|
177
|
+
var import_react13 = require("react");
|
|
178
|
+
var import_ink14 = require("ink");
|
|
174
179
|
var import_agent_core4 = require("@robota-sdk/agent-core");
|
|
175
180
|
|
|
176
181
|
// src/ui/hooks/useInteractiveSession.ts
|
|
@@ -286,7 +291,11 @@ function initializeSession(props, permissionHandler) {
|
|
|
286
291
|
provider: props.provider,
|
|
287
292
|
permissionMode: props.permissionMode,
|
|
288
293
|
maxTurns: props.maxTurns,
|
|
289
|
-
permissionHandler
|
|
294
|
+
permissionHandler,
|
|
295
|
+
sessionStore: props.sessionStore,
|
|
296
|
+
resumeSessionId: props.resumeSessionId,
|
|
297
|
+
forkSession: props.forkSession,
|
|
298
|
+
sessionName: props.sessionName
|
|
290
299
|
});
|
|
291
300
|
const registry = new import_agent_sdk.CommandRegistry();
|
|
292
301
|
registry.addSource(new import_agent_sdk.BuiltinCommandSource());
|
|
@@ -341,6 +350,12 @@ function useInteractiveSession(props) {
|
|
|
341
350
|
}
|
|
342
351
|
const { interactiveSession, registry, manager } = stateRef.current;
|
|
343
352
|
manager.onChange = () => forceRender((n) => n + 1);
|
|
353
|
+
if (manager.history.length === 0) {
|
|
354
|
+
const restored = interactiveSession.getFullHistory();
|
|
355
|
+
if (restored.length > 0) {
|
|
356
|
+
manager.syncHistory(restored);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
344
359
|
(0, import_react.useEffect)(() => {
|
|
345
360
|
interactiveSession.on("text_delta", manager.onTextDelta);
|
|
346
361
|
interactiveSession.on("tool_start", manager.onToolStart);
|
|
@@ -357,6 +372,10 @@ function useInteractiveSession(props) {
|
|
|
357
372
|
usedTokens: ctx.usedTokens,
|
|
358
373
|
maxTokens: ctx.maxTokens
|
|
359
374
|
});
|
|
375
|
+
const restored = interactiveSession.getFullHistory();
|
|
376
|
+
if (restored.length > 0) {
|
|
377
|
+
manager.syncHistory(restored);
|
|
378
|
+
}
|
|
360
379
|
clearInterval(initCheck);
|
|
361
380
|
} catch {
|
|
362
381
|
}
|
|
@@ -400,6 +419,14 @@ function useInteractiveSession(props) {
|
|
|
400
419
|
effects._resetRequested = true;
|
|
401
420
|
return;
|
|
402
421
|
}
|
|
422
|
+
if (result.data?.triggerResumePicker) {
|
|
423
|
+
effects._triggerResumePicker = true;
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (result.data?.name) {
|
|
427
|
+
effects._sessionName = result.data.name;
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
403
430
|
const ctx = interactiveSession.getContextState();
|
|
404
431
|
manager.setContextState({
|
|
405
432
|
percentage: ctx.usedPercentage,
|
|
@@ -803,7 +830,8 @@ function StatusBar({
|
|
|
803
830
|
isThinking,
|
|
804
831
|
contextPercentage,
|
|
805
832
|
contextUsedTokens,
|
|
806
|
-
contextMaxTokens
|
|
833
|
+
contextMaxTokens,
|
|
834
|
+
sessionName
|
|
807
835
|
}) {
|
|
808
836
|
const contextColor = getContextColor(contextPercentage);
|
|
809
837
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
@@ -819,6 +847,10 @@ function StatusBar({
|
|
|
819
847
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { color: "cyan", bold: true, children: "Mode:" }),
|
|
820
848
|
" ",
|
|
821
849
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { children: permissionMode }),
|
|
850
|
+
sessionName && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
851
|
+
" | ",
|
|
852
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { color: "magenta", children: sessionName })
|
|
853
|
+
] }),
|
|
822
854
|
" | ",
|
|
823
855
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { dimColor: true, children: modelName }),
|
|
824
856
|
" | ",
|
|
@@ -1160,7 +1192,8 @@ function InputArea({
|
|
|
1160
1192
|
isDisabled,
|
|
1161
1193
|
isAborting,
|
|
1162
1194
|
pendingPrompt,
|
|
1163
|
-
registry
|
|
1195
|
+
registry,
|
|
1196
|
+
sessionName
|
|
1164
1197
|
}) {
|
|
1165
1198
|
const [value, setValue] = (0, import_react6.useState)("");
|
|
1166
1199
|
const pasteStore = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
|
|
@@ -1243,6 +1276,17 @@ function InputArea({
|
|
|
1243
1276
|
},
|
|
1244
1277
|
{ isActive: !!pendingPrompt }
|
|
1245
1278
|
);
|
|
1279
|
+
const borderColor = isAborting ? "yellow" : pendingPrompt ? "cyan" : isDisabled ? "gray" : "green";
|
|
1280
|
+
const innerWidth = Math.max(1, terminalColumns - BORDER_HORIZONTAL);
|
|
1281
|
+
const topBorder = (() => {
|
|
1282
|
+
if (sessionName) {
|
|
1283
|
+
const label = ` "${sessionName}" `;
|
|
1284
|
+
const rightPad = 2;
|
|
1285
|
+
const leftLen = Math.max(0, innerWidth - label.length - rightPad);
|
|
1286
|
+
return { left: "\u250C" + "\u2500".repeat(leftLen), label, right: "\u2500".repeat(rightPad) + "\u2510" };
|
|
1287
|
+
}
|
|
1288
|
+
return { left: "\u250C" + "\u2500".repeat(innerWidth), label: "", right: "\u2510" };
|
|
1289
|
+
})();
|
|
1246
1290
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", children: [
|
|
1247
1291
|
showPopup && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1248
1292
|
SlashAutocomplete,
|
|
@@ -1253,34 +1297,31 @@ function InputArea({
|
|
|
1253
1297
|
isSubcommandMode
|
|
1254
1298
|
}
|
|
1255
1299
|
),
|
|
1256
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.
|
|
1257
|
-
|
|
1258
|
-
{
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
] })
|
|
1282
|
-
}
|
|
1283
|
-
)
|
|
1300
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { color: borderColor, children: [
|
|
1301
|
+
topBorder.left,
|
|
1302
|
+
topBorder.label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { backgroundColor: borderColor, color: "black", bold: true, children: topBorder.label }) : null,
|
|
1303
|
+
topBorder.right
|
|
1304
|
+
] }),
|
|
1305
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { borderStyle: "single", borderTop: false, borderColor, paddingLeft: 1, 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: [
|
|
1306
|
+
" ",
|
|
1307
|
+
"Queued: ",
|
|
1308
|
+
pendingPrompt.length > 50 ? pendingPrompt.slice(0, 47) + "..." : pendingPrompt,
|
|
1309
|
+
" ",
|
|
1310
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: "(Backspace to cancel)" })
|
|
1311
|
+
] }) : 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: [
|
|
1312
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "green", bold: true, children: "> " }),
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1314
|
+
CjkTextInput,
|
|
1315
|
+
{
|
|
1316
|
+
value,
|
|
1317
|
+
onChange: setValue,
|
|
1318
|
+
onSubmit: handleSubmit,
|
|
1319
|
+
onPaste: handlePaste,
|
|
1320
|
+
placeholder: "Type a message or /help",
|
|
1321
|
+
availableWidth
|
|
1322
|
+
}
|
|
1323
|
+
)
|
|
1324
|
+
] }) })
|
|
1284
1325
|
] });
|
|
1285
1326
|
}
|
|
1286
1327
|
|
|
@@ -1885,11 +1926,91 @@ function PluginTUI({ callbacks, onClose, addMessage }) {
|
|
|
1885
1926
|
);
|
|
1886
1927
|
}
|
|
1887
1928
|
|
|
1888
|
-
// src/ui/
|
|
1929
|
+
// src/ui/ListPicker.tsx
|
|
1930
|
+
var import_react12 = require("react");
|
|
1931
|
+
var import_ink13 = require("ink");
|
|
1889
1932
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1933
|
+
var DEFAULT_MAX_VISIBLE = 3;
|
|
1934
|
+
function ListPicker({
|
|
1935
|
+
items,
|
|
1936
|
+
renderItem,
|
|
1937
|
+
onSelect,
|
|
1938
|
+
onCancel,
|
|
1939
|
+
maxVisible = DEFAULT_MAX_VISIBLE
|
|
1940
|
+
}) {
|
|
1941
|
+
const [selectedIndex, setSelectedIndex] = (0, import_react12.useState)(0);
|
|
1942
|
+
const [scrollOffset, setScrollOffset] = (0, import_react12.useState)(0);
|
|
1943
|
+
const selectedRef = (0, import_react12.useRef)(0);
|
|
1944
|
+
const resolvedRef = (0, import_react12.useRef)(false);
|
|
1945
|
+
(0, import_ink13.useInput)((_input, key) => {
|
|
1946
|
+
if (resolvedRef.current) return;
|
|
1947
|
+
if (key.escape) {
|
|
1948
|
+
resolvedRef.current = true;
|
|
1949
|
+
onCancel();
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1952
|
+
if (items.length === 0) return;
|
|
1953
|
+
if (key.upArrow) {
|
|
1954
|
+
const next = selectedRef.current > 0 ? selectedRef.current - 1 : selectedRef.current;
|
|
1955
|
+
selectedRef.current = next;
|
|
1956
|
+
setSelectedIndex(next);
|
|
1957
|
+
if (next < scrollOffset) {
|
|
1958
|
+
setScrollOffset(next);
|
|
1959
|
+
}
|
|
1960
|
+
} else if (key.downArrow) {
|
|
1961
|
+
const next = selectedRef.current < items.length - 1 ? selectedRef.current + 1 : selectedRef.current;
|
|
1962
|
+
selectedRef.current = next;
|
|
1963
|
+
setSelectedIndex(next);
|
|
1964
|
+
if (next >= scrollOffset + maxVisible) {
|
|
1965
|
+
setScrollOffset(next - maxVisible + 1);
|
|
1966
|
+
}
|
|
1967
|
+
} else if (key.return) {
|
|
1968
|
+
const item = items[selectedRef.current];
|
|
1969
|
+
if (item !== void 0) {
|
|
1970
|
+
resolvedRef.current = true;
|
|
1971
|
+
onSelect(item);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
});
|
|
1975
|
+
if (items.length === 0) {
|
|
1976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, {});
|
|
1977
|
+
}
|
|
1978
|
+
const visibleItems = items.slice(scrollOffset, scrollOffset + maxVisible);
|
|
1979
|
+
const hasMore = scrollOffset + maxVisible < items.length;
|
|
1980
|
+
const hasLess = scrollOffset > 0;
|
|
1981
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Box, { flexDirection: "column", children: [
|
|
1982
|
+
hasLess && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Text, { dimColor: true, children: [
|
|
1983
|
+
" \u2191 ",
|
|
1984
|
+
scrollOffset,
|
|
1985
|
+
" more above"
|
|
1986
|
+
] }),
|
|
1987
|
+
visibleItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink13.Box, { marginBottom: 1, children: renderItem(item, scrollOffset + index === selectedIndex) }, scrollOffset + index)),
|
|
1988
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink13.Text, { dimColor: true, children: [
|
|
1989
|
+
" \u2193 ",
|
|
1990
|
+
items.length - scrollOffset - maxVisible,
|
|
1991
|
+
" more below"
|
|
1992
|
+
] })
|
|
1993
|
+
] });
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
// src/ui/App.tsx
|
|
1997
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1890
1998
|
var EXIT_DELAY_MS = 500;
|
|
1999
|
+
var SESSION_ID_DISPLAY_LENGTH = 8;
|
|
1891
2000
|
function App(props) {
|
|
1892
|
-
const
|
|
2001
|
+
const [activeSessionId, setActiveSessionId] = (0, import_react13.useState)(props.resumeSessionId);
|
|
2002
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2003
|
+
AppInner,
|
|
2004
|
+
{
|
|
2005
|
+
...props,
|
|
2006
|
+
resumeSessionId: activeSessionId,
|
|
2007
|
+
onSessionSwitch: (sessionId) => setActiveSessionId(sessionId)
|
|
2008
|
+
},
|
|
2009
|
+
activeSessionId ?? "__new__"
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
2012
|
+
function AppInner(props) {
|
|
2013
|
+
const { exit } = (0, import_ink14.useApp)();
|
|
1893
2014
|
const cwd = props.cwd;
|
|
1894
2015
|
const {
|
|
1895
2016
|
interactiveSession,
|
|
@@ -1910,12 +2031,28 @@ function App(props) {
|
|
|
1910
2031
|
cwd,
|
|
1911
2032
|
provider: props.provider,
|
|
1912
2033
|
permissionMode: props.permissionMode,
|
|
1913
|
-
maxTurns: props.maxTurns
|
|
2034
|
+
maxTurns: props.maxTurns,
|
|
2035
|
+
sessionStore: props.sessionStore,
|
|
2036
|
+
resumeSessionId: props.resumeSessionId,
|
|
2037
|
+
forkSession: props.forkSession,
|
|
2038
|
+
sessionName: props.sessionName
|
|
1914
2039
|
});
|
|
1915
2040
|
const pluginCallbacks = usePluginCallbacks(cwd);
|
|
1916
|
-
const [pendingModelId, setPendingModelId] = (0,
|
|
1917
|
-
const pendingModelChangeRef = (0,
|
|
1918
|
-
const [showPluginTUI, setShowPluginTUI] = (0,
|
|
2041
|
+
const [pendingModelId, setPendingModelId] = (0, import_react13.useState)(null);
|
|
2042
|
+
const pendingModelChangeRef = (0, import_react13.useRef)(null);
|
|
2043
|
+
const [showPluginTUI, setShowPluginTUI] = (0, import_react13.useState)(false);
|
|
2044
|
+
const [showSessionPicker, setShowSessionPicker] = (0, import_react13.useState)(
|
|
2045
|
+
props.resumeSessionId === "__picker__"
|
|
2046
|
+
);
|
|
2047
|
+
const [sessionName, setSessionName] = (0, import_react13.useState)(props.sessionName);
|
|
2048
|
+
(0, import_react13.useEffect)(() => {
|
|
2049
|
+
const name = interactiveSession?.getName?.();
|
|
2050
|
+
if (name && !sessionName) setSessionName(name);
|
|
2051
|
+
}, [interactiveSession, sessionName]);
|
|
2052
|
+
(0, import_react13.useEffect)(() => {
|
|
2053
|
+
const title = sessionName ? `Robota \u2014 ${sessionName}` : "Robota";
|
|
2054
|
+
process.stdout.write(`\x1B]0;${title}\x07`);
|
|
2055
|
+
}, [sessionName]);
|
|
1919
2056
|
const handleSubmit = async (input) => {
|
|
1920
2057
|
await baseHandleSubmit(input);
|
|
1921
2058
|
const sideEffects = interactiveSession;
|
|
@@ -1960,14 +2097,26 @@ function App(props) {
|
|
|
1960
2097
|
setShowPluginTUI(true);
|
|
1961
2098
|
return;
|
|
1962
2099
|
}
|
|
2100
|
+
if (sideEffects._triggerResumePicker) {
|
|
2101
|
+
delete sideEffects._triggerResumePicker;
|
|
2102
|
+
setShowSessionPicker(true);
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2105
|
+
if (sideEffects._sessionName) {
|
|
2106
|
+
const name = sideEffects._sessionName;
|
|
2107
|
+
delete sideEffects._sessionName;
|
|
2108
|
+
interactiveSession.setName(name);
|
|
2109
|
+
setSessionName(name);
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
1963
2112
|
};
|
|
1964
|
-
(0,
|
|
2113
|
+
(0, import_ink14.useInput)(
|
|
1965
2114
|
(_input, key) => {
|
|
1966
2115
|
if (key.escape && isThinking) {
|
|
1967
2116
|
handleAbort();
|
|
1968
2117
|
}
|
|
1969
2118
|
},
|
|
1970
|
-
{ isActive: !permissionRequest && !showPluginTUI }
|
|
2119
|
+
{ isActive: !permissionRequest && !showPluginTUI && !showSessionPicker }
|
|
1971
2120
|
);
|
|
1972
2121
|
let permissionMode = props.permissionMode ?? "default";
|
|
1973
2122
|
let sessionId = "";
|
|
@@ -1977,26 +2126,26 @@ function App(props) {
|
|
|
1977
2126
|
sessionId = session.getSessionId();
|
|
1978
2127
|
} catch {
|
|
1979
2128
|
}
|
|
1980
|
-
return /* @__PURE__ */ (0,
|
|
1981
|
-
/* @__PURE__ */ (0,
|
|
1982
|
-
/* @__PURE__ */ (0,
|
|
2129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", children: [
|
|
2130
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
2131
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { color: "cyan", bold: true, children: `
|
|
1983
2132
|
____ ___ ____ ___ _____ _
|
|
1984
2133
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1985
2134
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
1986
2135
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1987
2136
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1988
2137
|
` }),
|
|
1989
|
-
/* @__PURE__ */ (0,
|
|
2138
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { dimColor: true, children: [
|
|
1990
2139
|
" v",
|
|
1991
2140
|
props.version ?? "0.0.0"
|
|
1992
2141
|
] })
|
|
1993
2142
|
] }),
|
|
1994
|
-
/* @__PURE__ */ (0,
|
|
1995
|
-
/* @__PURE__ */ (0,
|
|
1996
|
-
(isThinking || activeTools.length > 0) && /* @__PURE__ */ (0,
|
|
2143
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
2144
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MessageList, { history }),
|
|
2145
|
+
(isThinking || activeTools.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
|
|
1997
2146
|
] }),
|
|
1998
|
-
permissionRequest && /* @__PURE__ */ (0,
|
|
1999
|
-
pendingModelId && /* @__PURE__ */ (0,
|
|
2147
|
+
permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PermissionPrompt, { request: permissionRequest }),
|
|
2148
|
+
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2000
2149
|
ConfirmPrompt,
|
|
2001
2150
|
{
|
|
2002
2151
|
message: `Change model to ${(0, import_agent_core4.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
@@ -2030,7 +2179,7 @@ function App(props) {
|
|
|
2030
2179
|
}
|
|
2031
2180
|
}
|
|
2032
2181
|
),
|
|
2033
|
-
showPluginTUI && /* @__PURE__ */ (0,
|
|
2182
|
+
showPluginTUI && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2034
2183
|
PluginTUI,
|
|
2035
2184
|
{
|
|
2036
2185
|
callbacks: pluginCallbacks,
|
|
@@ -2038,7 +2187,52 @@ function App(props) {
|
|
|
2038
2187
|
addMessage: (msg) => addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(msg.content)))
|
|
2039
2188
|
}
|
|
2040
2189
|
),
|
|
2041
|
-
/* @__PURE__ */ (0,
|
|
2190
|
+
showSessionPicker && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
2191
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { bold: true, color: "cyan", children: "Select a session to resume (ESC to cancel):" }),
|
|
2192
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2193
|
+
ListPicker,
|
|
2194
|
+
{
|
|
2195
|
+
items: (props.sessionStore?.list() ?? []).filter((s) => s.cwd === props.cwd),
|
|
2196
|
+
renderItem: (session, isSelected) => {
|
|
2197
|
+
const lastMsg = session.messages.slice().reverse().find((m) => {
|
|
2198
|
+
const msg = m;
|
|
2199
|
+
return msg.role === "assistant" && msg.content;
|
|
2200
|
+
});
|
|
2201
|
+
const rawPreview = lastMsg?.content?.replace(/[\n\r]+/g, " ").trim() ?? "";
|
|
2202
|
+
const preview = rawPreview ? rawPreview.slice(0, 60) + (rawPreview.length > 60 ? "..." : "") : "";
|
|
2203
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { children: [
|
|
2204
|
+
isSelected ? "> " : " ",
|
|
2205
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { bold: true, children: session.name ?? session.id.slice(0, SESSION_ID_DISPLAY_LENGTH) }),
|
|
2206
|
+
" ",
|
|
2207
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { dimColor: true, children: new Date(session.updatedAt).toLocaleString(void 0, {
|
|
2208
|
+
month: "short",
|
|
2209
|
+
day: "numeric",
|
|
2210
|
+
hour: "2-digit",
|
|
2211
|
+
minute: "2-digit"
|
|
2212
|
+
}) }),
|
|
2213
|
+
" ",
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { dimColor: true, children: [
|
|
2215
|
+
"msgs: ",
|
|
2216
|
+
session.messages.length
|
|
2217
|
+
] }),
|
|
2218
|
+
preview ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
2219
|
+
"\n ",
|
|
2220
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { color: "gray", children: preview })
|
|
2221
|
+
] }) : null
|
|
2222
|
+
] });
|
|
2223
|
+
},
|
|
2224
|
+
onSelect: (session) => {
|
|
2225
|
+
setShowSessionPicker(false);
|
|
2226
|
+
props.onSessionSwitch(session.id);
|
|
2227
|
+
},
|
|
2228
|
+
onCancel: () => {
|
|
2229
|
+
setShowSessionPicker(false);
|
|
2230
|
+
addEntry((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("Session resume cancelled.")));
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
)
|
|
2234
|
+
] }),
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2042
2236
|
StatusBar,
|
|
2043
2237
|
{
|
|
2044
2238
|
permissionMode,
|
|
@@ -2048,26 +2242,28 @@ function App(props) {
|
|
|
2048
2242
|
isThinking,
|
|
2049
2243
|
contextPercentage: contextState.percentage,
|
|
2050
2244
|
contextUsedTokens: contextState.usedTokens,
|
|
2051
|
-
contextMaxTokens: contextState.maxTokens
|
|
2245
|
+
contextMaxTokens: contextState.maxTokens,
|
|
2246
|
+
sessionName
|
|
2052
2247
|
}
|
|
2053
2248
|
),
|
|
2054
|
-
/* @__PURE__ */ (0,
|
|
2249
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2055
2250
|
InputArea,
|
|
2056
2251
|
{
|
|
2057
2252
|
onSubmit: handleSubmit,
|
|
2058
2253
|
onCancelQueue: handleCancelQueue,
|
|
2059
|
-
isDisabled: !!permissionRequest || showPluginTUI || isThinking && !!pendingPrompt,
|
|
2254
|
+
isDisabled: !!permissionRequest || showPluginTUI || showSessionPicker || isThinking && !!pendingPrompt,
|
|
2060
2255
|
isAborting,
|
|
2061
2256
|
pendingPrompt,
|
|
2062
|
-
registry
|
|
2257
|
+
registry,
|
|
2258
|
+
sessionName
|
|
2063
2259
|
}
|
|
2064
2260
|
),
|
|
2065
|
-
/* @__PURE__ */ (0,
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { children: " " })
|
|
2066
2262
|
] });
|
|
2067
2263
|
}
|
|
2068
2264
|
|
|
2069
2265
|
// src/ui/render.tsx
|
|
2070
|
-
var
|
|
2266
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2071
2267
|
function renderApp(options) {
|
|
2072
2268
|
process.on("unhandledRejection", (reason) => {
|
|
2073
2269
|
process.stderr.write(`
|
|
@@ -2081,7 +2277,7 @@ function renderApp(options) {
|
|
|
2081
2277
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
2082
2278
|
process.stdout.write("\x1B[?2004h");
|
|
2083
2279
|
}
|
|
2084
|
-
const instance = (0,
|
|
2280
|
+
const instance = (0, import_ink15.render)(/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(App, { ...options }), {
|
|
2085
2281
|
exitOnCtrlC: true
|
|
2086
2282
|
});
|
|
2087
2283
|
instance.waitUntilExit().then(() => {
|
|
@@ -2251,6 +2447,28 @@ async function startCli() {
|
|
|
2251
2447
|
const providerSettings = readProviderSettings(cwd);
|
|
2252
2448
|
const modelId = args.model ?? providerSettings.model;
|
|
2253
2449
|
const provider = createProviderFromSettings(cwd, args.model);
|
|
2450
|
+
const sessionStore = new import_agent_sessions.SessionStore();
|
|
2451
|
+
let resumeSessionId;
|
|
2452
|
+
if (args.continueMode) {
|
|
2453
|
+
const sessions = sessionStore.list().filter((s) => s.cwd === cwd);
|
|
2454
|
+
if (sessions.length > 0) {
|
|
2455
|
+
resumeSessionId = sessions[0].id;
|
|
2456
|
+
}
|
|
2457
|
+
} else if (args.resumeId !== void 0) {
|
|
2458
|
+
if (args.resumeId === "") {
|
|
2459
|
+
resumeSessionId = "__picker__";
|
|
2460
|
+
} else {
|
|
2461
|
+
const sessions = sessionStore.list();
|
|
2462
|
+
const match = sessions.find((s) => s.id === args.resumeId || s.name === args.resumeId);
|
|
2463
|
+
if (match) {
|
|
2464
|
+
resumeSessionId = match.id;
|
|
2465
|
+
} else {
|
|
2466
|
+
process.stderr.write(`Session not found: ${args.resumeId}
|
|
2467
|
+
`);
|
|
2468
|
+
process.exit(1);
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2254
2472
|
if (args.printMode) {
|
|
2255
2473
|
const prompt = args.positional.join(" ").trim();
|
|
2256
2474
|
if (prompt.length === 0) {
|
|
@@ -2261,7 +2479,9 @@ async function startCli() {
|
|
|
2261
2479
|
cwd,
|
|
2262
2480
|
provider,
|
|
2263
2481
|
permissionMode: args.permissionMode ?? "bypassPermissions",
|
|
2264
|
-
maxTurns: args.maxTurns
|
|
2482
|
+
maxTurns: args.maxTurns,
|
|
2483
|
+
sessionStore,
|
|
2484
|
+
sessionName: args.sessionName
|
|
2265
2485
|
});
|
|
2266
2486
|
await new Promise((resolve, reject) => {
|
|
2267
2487
|
session.on("complete", (result) => {
|
|
@@ -2284,7 +2504,11 @@ async function startCli() {
|
|
|
2284
2504
|
language: args.language,
|
|
2285
2505
|
permissionMode: args.permissionMode,
|
|
2286
2506
|
maxTurns: args.maxTurns,
|
|
2287
|
-
version: readVersion()
|
|
2507
|
+
version: readVersion(),
|
|
2508
|
+
sessionStore,
|
|
2509
|
+
resumeSessionId,
|
|
2510
|
+
forkSession: args.forkSession,
|
|
2511
|
+
sessionName: args.sessionName
|
|
2288
2512
|
});
|
|
2289
2513
|
}
|
|
2290
2514
|
// Annotate the CommonJS export names for ESM import in node:
|
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.46",
|
|
4
4
|
"description": "AI coding assistant CLI built on Robota SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"dist"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"@robota-sdk/agent-sessions": "3.0.0-beta.46",
|
|
28
29
|
"chalk": "^5.3.0",
|
|
29
30
|
"cli-highlight": "^2.1.0",
|
|
30
31
|
"ink": "^6.8.0",
|
|
@@ -35,9 +36,9 @@
|
|
|
35
36
|
"marked-terminal": "^7.3.0",
|
|
36
37
|
"react": "19.2.4",
|
|
37
38
|
"string-width": "^8.2.0",
|
|
38
|
-
"@robota-sdk/agent-core": "3.0.0-beta.
|
|
39
|
-
"@robota-sdk/agent-sdk": "3.0.0-beta.
|
|
40
|
-
"@robota-sdk/agent-provider-anthropic": "3.0.0-beta.
|
|
39
|
+
"@robota-sdk/agent-core": "3.0.0-beta.46",
|
|
40
|
+
"@robota-sdk/agent-sdk": "3.0.0-beta.46",
|
|
41
|
+
"@robota-sdk/agent-provider-anthropic": "3.0.0-beta.46"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/marked": "^6.0.0",
|