@robota-sdk/agent-cli 3.0.0-beta.17 → 3.0.0-beta.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/node/bin.cjs +106 -48
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-4WB3L3RU.js → chunk-M723M4M4.js} +103 -45
- package/dist/node/index.cjs +106 -48
- package/dist/node/index.js +1 -1
- package/package.json +3 -3
package/dist/node/bin.cjs
CHANGED
|
@@ -161,11 +161,11 @@ var PrintTerminal = class {
|
|
|
161
161
|
};
|
|
162
162
|
|
|
163
163
|
// src/ui/render.tsx
|
|
164
|
-
var
|
|
164
|
+
var import_ink11 = require("ink");
|
|
165
165
|
|
|
166
166
|
// src/ui/App.tsx
|
|
167
167
|
var import_react6 = require("react");
|
|
168
|
-
var
|
|
168
|
+
var import_ink10 = require("ink");
|
|
169
169
|
|
|
170
170
|
// src/commands/slash-executor.ts
|
|
171
171
|
var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
@@ -1002,8 +1002,39 @@ function parseFirstArgValue(argsJson) {
|
|
|
1002
1002
|
}
|
|
1003
1003
|
}
|
|
1004
1004
|
|
|
1005
|
-
// src/ui/
|
|
1005
|
+
// src/ui/StreamingIndicator.tsx
|
|
1006
|
+
var import_ink9 = require("ink");
|
|
1006
1007
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1008
|
+
function StreamingIndicator({ text, activeTools }) {
|
|
1009
|
+
const hasTools = activeTools.length > 0;
|
|
1010
|
+
const hasText = text.length > 0;
|
|
1011
|
+
if (!hasTools && !hasText) {
|
|
1012
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", children: "Thinking..." });
|
|
1013
|
+
}
|
|
1014
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
|
|
1015
|
+
hasTools && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1016
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "gray", bold: true, children: "Tools:" }),
|
|
1017
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
|
|
1018
|
+
activeTools.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: t.isRunning ? "yellow" : "green", children: [
|
|
1019
|
+
" ",
|
|
1020
|
+
t.isRunning ? "\u27F3" : "\u2713",
|
|
1021
|
+
" ",
|
|
1022
|
+
t.toolName,
|
|
1023
|
+
"(",
|
|
1024
|
+
t.firstArg,
|
|
1025
|
+
")"
|
|
1026
|
+
] }, `${t.toolName}-${i}`))
|
|
1027
|
+
] }),
|
|
1028
|
+
hasText && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1029
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "cyan", bold: true, children: "Robota:" }),
|
|
1030
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
|
|
1031
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
1032
|
+
] })
|
|
1033
|
+
] });
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// src/ui/App.tsx
|
|
1037
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1007
1038
|
var msgIdCounter = 0;
|
|
1008
1039
|
function nextId() {
|
|
1009
1040
|
msgIdCounter += 1;
|
|
@@ -1027,6 +1058,7 @@ var NOOP_TERMINAL = {
|
|
|
1027
1058
|
function useSession(props) {
|
|
1028
1059
|
const [permissionRequest, setPermissionRequest] = (0, import_react6.useState)(null);
|
|
1029
1060
|
const [streamingText, setStreamingText] = (0, import_react6.useState)("");
|
|
1061
|
+
const [activeTools, setActiveTools] = (0, import_react6.useState)([]);
|
|
1030
1062
|
const permissionQueueRef = (0, import_react6.useRef)([]);
|
|
1031
1063
|
const processingRef = (0, import_react6.useRef)(false);
|
|
1032
1064
|
const processNextPermission = (0, import_react6.useCallback)(() => {
|
|
@@ -1060,6 +1092,25 @@ function useSession(props) {
|
|
|
1060
1092
|
const onTextDelta = (delta) => {
|
|
1061
1093
|
setStreamingText((prev) => prev + delta);
|
|
1062
1094
|
};
|
|
1095
|
+
const TOOL_ARG_DISPLAY_MAX = 80;
|
|
1096
|
+
const TOOL_ARG_TRUNCATE_AT = 77;
|
|
1097
|
+
const onToolExecution = (event) => {
|
|
1098
|
+
if (event.type === "start") {
|
|
1099
|
+
let firstArg = "";
|
|
1100
|
+
if (event.toolArgs) {
|
|
1101
|
+
const firstVal = Object.values(event.toolArgs)[0];
|
|
1102
|
+
const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
|
|
1103
|
+
firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_TRUNCATE_AT) + "..." : raw;
|
|
1104
|
+
}
|
|
1105
|
+
setActiveTools((prev) => [...prev, { toolName: event.toolName, firstArg, isRunning: true }]);
|
|
1106
|
+
} else {
|
|
1107
|
+
setActiveTools(
|
|
1108
|
+
(prev) => prev.map(
|
|
1109
|
+
(t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false } : t
|
|
1110
|
+
)
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
};
|
|
1063
1114
|
const paths = (0, import_agent_sdk.projectPaths)(props.cwd ?? process.cwd());
|
|
1064
1115
|
sessionRef.current = (0, import_agent_sdk.createSession)({
|
|
1065
1116
|
config: props.config,
|
|
@@ -1071,11 +1122,15 @@ function useSession(props) {
|
|
|
1071
1122
|
permissionMode: props.permissionMode,
|
|
1072
1123
|
maxTurns: props.maxTurns,
|
|
1073
1124
|
permissionHandler,
|
|
1074
|
-
onTextDelta
|
|
1125
|
+
onTextDelta,
|
|
1126
|
+
onToolExecution
|
|
1075
1127
|
});
|
|
1076
1128
|
}
|
|
1077
|
-
const clearStreamingText = (0, import_react6.useCallback)(() =>
|
|
1078
|
-
|
|
1129
|
+
const clearStreamingText = (0, import_react6.useCallback)(() => {
|
|
1130
|
+
setStreamingText("");
|
|
1131
|
+
setActiveTools([]);
|
|
1132
|
+
}, []);
|
|
1133
|
+
return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText, activeTools };
|
|
1079
1134
|
}
|
|
1080
1135
|
function useMessages() {
|
|
1081
1136
|
const [messages, setMessages] = (0, import_react6.useState)([]);
|
|
@@ -1105,20 +1160,11 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
1105
1160
|
[session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId]
|
|
1106
1161
|
);
|
|
1107
1162
|
}
|
|
1108
|
-
function
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: "cyan", bold: true, children: [
|
|
1112
|
-
"Robota:",
|
|
1113
|
-
" "
|
|
1114
|
-
] }),
|
|
1115
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
|
|
1116
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
1117
|
-
] });
|
|
1118
|
-
}
|
|
1119
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", children: "Thinking..." });
|
|
1163
|
+
function syncContextState(session, setter) {
|
|
1164
|
+
const ctx = session.getContextState();
|
|
1165
|
+
setter({ percentage: ctx.usedPercentage, usedTokens: ctx.usedTokens, maxTokens: ctx.maxTokens });
|
|
1120
1166
|
}
|
|
1121
|
-
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking,
|
|
1167
|
+
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextState) {
|
|
1122
1168
|
setIsThinking(true);
|
|
1123
1169
|
clearStreamingText();
|
|
1124
1170
|
const historyBefore = session.getHistory().length;
|
|
@@ -1134,7 +1180,7 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
1134
1180
|
addMessage({ role: "tool", content: toolLines.join("\n"), toolName: `${toolLines.length} tools` });
|
|
1135
1181
|
}
|
|
1136
1182
|
addMessage({ role: "assistant", content: response || "(empty response)" });
|
|
1137
|
-
|
|
1183
|
+
syncContextState(session, setContextState);
|
|
1138
1184
|
} catch (err) {
|
|
1139
1185
|
clearStreamingText();
|
|
1140
1186
|
if (err instanceof DOMException && err.name === "AbortError") {
|
|
@@ -1163,13 +1209,13 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
1163
1209
|
}
|
|
1164
1210
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
1165
1211
|
}
|
|
1166
|
-
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking,
|
|
1212
|
+
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextState, registry) {
|
|
1167
1213
|
return (0, import_react6.useCallback)(
|
|
1168
1214
|
async (input) => {
|
|
1169
1215
|
if (input.startsWith("/")) {
|
|
1170
1216
|
const handled = await handleSlashCommand(input);
|
|
1171
1217
|
if (handled) {
|
|
1172
|
-
|
|
1218
|
+
syncContextState(session, setContextState);
|
|
1173
1219
|
return;
|
|
1174
1220
|
}
|
|
1175
1221
|
const prompt = buildSkillPrompt(input, registry);
|
|
@@ -1180,7 +1226,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1180
1226
|
addMessage,
|
|
1181
1227
|
clearStreamingText,
|
|
1182
1228
|
setIsThinking,
|
|
1183
|
-
|
|
1229
|
+
setContextState
|
|
1184
1230
|
);
|
|
1185
1231
|
}
|
|
1186
1232
|
addMessage({ role: "user", content: input });
|
|
@@ -1190,7 +1236,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1190
1236
|
addMessage,
|
|
1191
1237
|
clearStreamingText,
|
|
1192
1238
|
setIsThinking,
|
|
1193
|
-
|
|
1239
|
+
setContextState
|
|
1194
1240
|
);
|
|
1195
1241
|
},
|
|
1196
1242
|
[
|
|
@@ -1199,7 +1245,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1199
1245
|
handleSlashCommand,
|
|
1200
1246
|
clearStreamingText,
|
|
1201
1247
|
setIsThinking,
|
|
1202
|
-
|
|
1248
|
+
setContextState,
|
|
1203
1249
|
registry
|
|
1204
1250
|
]
|
|
1205
1251
|
);
|
|
@@ -1215,11 +1261,11 @@ function useCommandRegistry(cwd) {
|
|
|
1215
1261
|
return registryRef.current;
|
|
1216
1262
|
}
|
|
1217
1263
|
function App(props) {
|
|
1218
|
-
const { exit } = (0,
|
|
1219
|
-
const { session, permissionRequest, streamingText, clearStreamingText } = useSession(props);
|
|
1264
|
+
const { exit } = (0, import_ink10.useApp)();
|
|
1265
|
+
const { session, permissionRequest, streamingText, clearStreamingText, activeTools } = useSession(props);
|
|
1220
1266
|
const { messages, setMessages, addMessage } = useMessages();
|
|
1221
1267
|
const [isThinking, setIsThinking] = (0, import_react6.useState)(false);
|
|
1222
|
-
const [
|
|
1268
|
+
const [contextState, setContextState] = (0, import_react6.useState)({ percentage: 0, usedTokens: 0, maxTokens: 0 });
|
|
1223
1269
|
const registry = useCommandRegistry(props.cwd ?? process.cwd());
|
|
1224
1270
|
const pendingModelChangeRef = (0, import_react6.useRef)(null);
|
|
1225
1271
|
const [pendingModelId, setPendingModelId] = (0, import_react6.useState)(null);
|
|
@@ -1230,36 +1276,36 @@ function App(props) {
|
|
|
1230
1276
|
handleSlashCommand,
|
|
1231
1277
|
clearStreamingText,
|
|
1232
1278
|
setIsThinking,
|
|
1233
|
-
|
|
1279
|
+
setContextState,
|
|
1234
1280
|
registry
|
|
1235
1281
|
);
|
|
1236
|
-
(0,
|
|
1282
|
+
(0, import_ink10.useInput)(
|
|
1237
1283
|
(_input, key) => {
|
|
1238
1284
|
if (key.ctrl && _input === "c") exit();
|
|
1239
1285
|
if (key.escape && isThinking) session.abort();
|
|
1240
1286
|
},
|
|
1241
1287
|
{ isActive: !permissionRequest }
|
|
1242
1288
|
);
|
|
1243
|
-
return /* @__PURE__ */ (0,
|
|
1244
|
-
/* @__PURE__ */ (0,
|
|
1245
|
-
/* @__PURE__ */ (0,
|
|
1289
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
|
|
1290
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "cyan", bold: true, children: `
|
|
1246
1292
|
____ ___ ____ ___ _____ _
|
|
1247
1293
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1248
1294
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
1249
1295
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1250
1296
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1251
1297
|
` }),
|
|
1252
|
-
/* @__PURE__ */ (0,
|
|
1298
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Text, { dimColor: true, children: [
|
|
1253
1299
|
" v",
|
|
1254
1300
|
props.version ?? "0.0.0"
|
|
1255
1301
|
] })
|
|
1256
1302
|
] }),
|
|
1257
|
-
/* @__PURE__ */ (0,
|
|
1258
|
-
/* @__PURE__ */ (0,
|
|
1259
|
-
isThinking && /* @__PURE__ */ (0,
|
|
1303
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
1304
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageList, { messages }),
|
|
1305
|
+
isThinking && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
|
|
1260
1306
|
] }),
|
|
1261
|
-
permissionRequest && /* @__PURE__ */ (0,
|
|
1262
|
-
pendingModelId && /* @__PURE__ */ (0,
|
|
1307
|
+
permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PermissionPrompt, { request: permissionRequest }),
|
|
1308
|
+
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1263
1309
|
ConfirmPrompt,
|
|
1264
1310
|
{
|
|
1265
1311
|
message: `Change model to ${(0, import_agent_core3.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
@@ -1281,7 +1327,7 @@ function App(props) {
|
|
|
1281
1327
|
}
|
|
1282
1328
|
}
|
|
1283
1329
|
),
|
|
1284
|
-
/* @__PURE__ */ (0,
|
|
1330
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1285
1331
|
StatusBar,
|
|
1286
1332
|
{
|
|
1287
1333
|
permissionMode: session.getPermissionMode(),
|
|
@@ -1289,12 +1335,12 @@ function App(props) {
|
|
|
1289
1335
|
sessionId: session.getSessionId(),
|
|
1290
1336
|
messageCount: messages.length,
|
|
1291
1337
|
isThinking,
|
|
1292
|
-
contextPercentage,
|
|
1293
|
-
contextUsedTokens:
|
|
1294
|
-
contextMaxTokens:
|
|
1338
|
+
contextPercentage: contextState.percentage,
|
|
1339
|
+
contextUsedTokens: contextState.usedTokens,
|
|
1340
|
+
contextMaxTokens: contextState.maxTokens
|
|
1295
1341
|
}
|
|
1296
1342
|
),
|
|
1297
|
-
/* @__PURE__ */ (0,
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1298
1344
|
InputArea,
|
|
1299
1345
|
{
|
|
1300
1346
|
onSubmit: handleSubmit,
|
|
@@ -1302,12 +1348,12 @@ function App(props) {
|
|
|
1302
1348
|
registry
|
|
1303
1349
|
}
|
|
1304
1350
|
),
|
|
1305
|
-
/* @__PURE__ */ (0,
|
|
1351
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { children: " " })
|
|
1306
1352
|
] });
|
|
1307
1353
|
}
|
|
1308
1354
|
|
|
1309
1355
|
// src/ui/render.tsx
|
|
1310
|
-
var
|
|
1356
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1311
1357
|
function renderApp(options) {
|
|
1312
1358
|
process.on("unhandledRejection", (reason) => {
|
|
1313
1359
|
process.stderr.write(`
|
|
@@ -1318,7 +1364,7 @@ function renderApp(options) {
|
|
|
1318
1364
|
`);
|
|
1319
1365
|
}
|
|
1320
1366
|
});
|
|
1321
|
-
const instance = (0,
|
|
1367
|
+
const instance = (0, import_ink11.render)(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(App, { ...options }), {
|
|
1322
1368
|
exitOnCtrlC: true
|
|
1323
1369
|
});
|
|
1324
1370
|
instance.waitUntilExit().catch((err) => {
|
|
@@ -1332,6 +1378,18 @@ function renderApp(options) {
|
|
|
1332
1378
|
|
|
1333
1379
|
// src/cli.ts
|
|
1334
1380
|
var import_meta = {};
|
|
1381
|
+
function hasValidSettingsFile(filePath) {
|
|
1382
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return false;
|
|
1383
|
+
try {
|
|
1384
|
+
const raw = (0, import_node_fs3.readFileSync)(filePath, "utf8").trim();
|
|
1385
|
+
if (raw.length === 0) return false;
|
|
1386
|
+
const parsed = JSON.parse(raw);
|
|
1387
|
+
const provider = parsed.provider;
|
|
1388
|
+
return !!provider?.apiKey;
|
|
1389
|
+
} catch {
|
|
1390
|
+
return false;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1335
1393
|
function readVersion() {
|
|
1336
1394
|
try {
|
|
1337
1395
|
const thisFile = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
@@ -1356,7 +1414,7 @@ async function ensureConfig(cwd) {
|
|
|
1356
1414
|
const userPath = getUserSettingsPath();
|
|
1357
1415
|
const projectPath = (0, import_node_path3.join)(cwd, ".robota", "settings.json");
|
|
1358
1416
|
const localPath = (0, import_node_path3.join)(cwd, ".robota", "settings.local.json");
|
|
1359
|
-
if ((
|
|
1417
|
+
if (hasValidSettingsFile(userPath) || hasValidSettingsFile(projectPath) || hasValidSettingsFile(localPath)) {
|
|
1360
1418
|
return;
|
|
1361
1419
|
}
|
|
1362
1420
|
process.stdout.write("\n");
|
package/dist/node/bin.js
CHANGED
|
@@ -148,7 +148,7 @@ import { render } from "ink";
|
|
|
148
148
|
|
|
149
149
|
// src/ui/App.tsx
|
|
150
150
|
import { useState as useState5, useCallback as useCallback3, useRef as useRef3 } from "react";
|
|
151
|
-
import { Box as
|
|
151
|
+
import { Box as Box8, Text as Text10, useApp, useInput as useInput5 } from "ink";
|
|
152
152
|
|
|
153
153
|
// src/commands/slash-executor.ts
|
|
154
154
|
var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
@@ -985,8 +985,39 @@ function parseFirstArgValue(argsJson) {
|
|
|
985
985
|
}
|
|
986
986
|
}
|
|
987
987
|
|
|
988
|
-
// src/ui/
|
|
988
|
+
// src/ui/StreamingIndicator.tsx
|
|
989
|
+
import { Box as Box7, Text as Text9 } from "ink";
|
|
989
990
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
991
|
+
function StreamingIndicator({ text, activeTools }) {
|
|
992
|
+
const hasTools = activeTools.length > 0;
|
|
993
|
+
const hasText = text.length > 0;
|
|
994
|
+
if (!hasTools && !hasText) {
|
|
995
|
+
return /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "Thinking..." });
|
|
996
|
+
}
|
|
997
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
998
|
+
hasTools && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, children: [
|
|
999
|
+
/* @__PURE__ */ jsx9(Text9, { color: "gray", bold: true, children: "Tools:" }),
|
|
1000
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
1001
|
+
activeTools.map((t, i) => /* @__PURE__ */ jsxs7(Text9, { color: t.isRunning ? "yellow" : "green", children: [
|
|
1002
|
+
" ",
|
|
1003
|
+
t.isRunning ? "\u27F3" : "\u2713",
|
|
1004
|
+
" ",
|
|
1005
|
+
t.toolName,
|
|
1006
|
+
"(",
|
|
1007
|
+
t.firstArg,
|
|
1008
|
+
")"
|
|
1009
|
+
] }, `${t.toolName}-${i}`))
|
|
1010
|
+
] }),
|
|
1011
|
+
hasText && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, children: [
|
|
1012
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: "Robota:" }),
|
|
1013
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
1014
|
+
/* @__PURE__ */ jsx9(Box7, { marginLeft: 2, children: /* @__PURE__ */ jsx9(Text9, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
1015
|
+
] })
|
|
1016
|
+
] });
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// src/ui/App.tsx
|
|
1020
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
990
1021
|
var msgIdCounter = 0;
|
|
991
1022
|
function nextId() {
|
|
992
1023
|
msgIdCounter += 1;
|
|
@@ -1010,6 +1041,7 @@ var NOOP_TERMINAL = {
|
|
|
1010
1041
|
function useSession(props) {
|
|
1011
1042
|
const [permissionRequest, setPermissionRequest] = useState5(null);
|
|
1012
1043
|
const [streamingText, setStreamingText] = useState5("");
|
|
1044
|
+
const [activeTools, setActiveTools] = useState5([]);
|
|
1013
1045
|
const permissionQueueRef = useRef3([]);
|
|
1014
1046
|
const processingRef = useRef3(false);
|
|
1015
1047
|
const processNextPermission = useCallback3(() => {
|
|
@@ -1043,6 +1075,25 @@ function useSession(props) {
|
|
|
1043
1075
|
const onTextDelta = (delta) => {
|
|
1044
1076
|
setStreamingText((prev) => prev + delta);
|
|
1045
1077
|
};
|
|
1078
|
+
const TOOL_ARG_DISPLAY_MAX = 80;
|
|
1079
|
+
const TOOL_ARG_TRUNCATE_AT = 77;
|
|
1080
|
+
const onToolExecution = (event) => {
|
|
1081
|
+
if (event.type === "start") {
|
|
1082
|
+
let firstArg = "";
|
|
1083
|
+
if (event.toolArgs) {
|
|
1084
|
+
const firstVal = Object.values(event.toolArgs)[0];
|
|
1085
|
+
const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
|
|
1086
|
+
firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_TRUNCATE_AT) + "..." : raw;
|
|
1087
|
+
}
|
|
1088
|
+
setActiveTools((prev) => [...prev, { toolName: event.toolName, firstArg, isRunning: true }]);
|
|
1089
|
+
} else {
|
|
1090
|
+
setActiveTools(
|
|
1091
|
+
(prev) => prev.map(
|
|
1092
|
+
(t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false } : t
|
|
1093
|
+
)
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1046
1097
|
const paths = projectPaths(props.cwd ?? process.cwd());
|
|
1047
1098
|
sessionRef.current = createSession({
|
|
1048
1099
|
config: props.config,
|
|
@@ -1054,11 +1105,15 @@ function useSession(props) {
|
|
|
1054
1105
|
permissionMode: props.permissionMode,
|
|
1055
1106
|
maxTurns: props.maxTurns,
|
|
1056
1107
|
permissionHandler,
|
|
1057
|
-
onTextDelta
|
|
1108
|
+
onTextDelta,
|
|
1109
|
+
onToolExecution
|
|
1058
1110
|
});
|
|
1059
1111
|
}
|
|
1060
|
-
const clearStreamingText = useCallback3(() =>
|
|
1061
|
-
|
|
1112
|
+
const clearStreamingText = useCallback3(() => {
|
|
1113
|
+
setStreamingText("");
|
|
1114
|
+
setActiveTools([]);
|
|
1115
|
+
}, []);
|
|
1116
|
+
return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText, activeTools };
|
|
1062
1117
|
}
|
|
1063
1118
|
function useMessages() {
|
|
1064
1119
|
const [messages, setMessages] = useState5([]);
|
|
@@ -1088,20 +1143,11 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
1088
1143
|
[session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId]
|
|
1089
1144
|
);
|
|
1090
1145
|
}
|
|
1091
|
-
function
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
/* @__PURE__ */ jsxs7(Text9, { color: "cyan", bold: true, children: [
|
|
1095
|
-
"Robota:",
|
|
1096
|
-
" "
|
|
1097
|
-
] }),
|
|
1098
|
-
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
1099
|
-
/* @__PURE__ */ jsx9(Box7, { marginLeft: 2, children: /* @__PURE__ */ jsx9(Text9, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
1100
|
-
] });
|
|
1101
|
-
}
|
|
1102
|
-
return /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "Thinking..." });
|
|
1146
|
+
function syncContextState(session, setter) {
|
|
1147
|
+
const ctx = session.getContextState();
|
|
1148
|
+
setter({ percentage: ctx.usedPercentage, usedTokens: ctx.usedTokens, maxTokens: ctx.maxTokens });
|
|
1103
1149
|
}
|
|
1104
|
-
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking,
|
|
1150
|
+
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextState) {
|
|
1105
1151
|
setIsThinking(true);
|
|
1106
1152
|
clearStreamingText();
|
|
1107
1153
|
const historyBefore = session.getHistory().length;
|
|
@@ -1117,7 +1163,7 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
1117
1163
|
addMessage({ role: "tool", content: toolLines.join("\n"), toolName: `${toolLines.length} tools` });
|
|
1118
1164
|
}
|
|
1119
1165
|
addMessage({ role: "assistant", content: response || "(empty response)" });
|
|
1120
|
-
|
|
1166
|
+
syncContextState(session, setContextState);
|
|
1121
1167
|
} catch (err) {
|
|
1122
1168
|
clearStreamingText();
|
|
1123
1169
|
if (err instanceof DOMException && err.name === "AbortError") {
|
|
@@ -1146,13 +1192,13 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
1146
1192
|
}
|
|
1147
1193
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
1148
1194
|
}
|
|
1149
|
-
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking,
|
|
1195
|
+
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextState, registry) {
|
|
1150
1196
|
return useCallback3(
|
|
1151
1197
|
async (input) => {
|
|
1152
1198
|
if (input.startsWith("/")) {
|
|
1153
1199
|
const handled = await handleSlashCommand(input);
|
|
1154
1200
|
if (handled) {
|
|
1155
|
-
|
|
1201
|
+
syncContextState(session, setContextState);
|
|
1156
1202
|
return;
|
|
1157
1203
|
}
|
|
1158
1204
|
const prompt = buildSkillPrompt(input, registry);
|
|
@@ -1163,7 +1209,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1163
1209
|
addMessage,
|
|
1164
1210
|
clearStreamingText,
|
|
1165
1211
|
setIsThinking,
|
|
1166
|
-
|
|
1212
|
+
setContextState
|
|
1167
1213
|
);
|
|
1168
1214
|
}
|
|
1169
1215
|
addMessage({ role: "user", content: input });
|
|
@@ -1173,7 +1219,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1173
1219
|
addMessage,
|
|
1174
1220
|
clearStreamingText,
|
|
1175
1221
|
setIsThinking,
|
|
1176
|
-
|
|
1222
|
+
setContextState
|
|
1177
1223
|
);
|
|
1178
1224
|
},
|
|
1179
1225
|
[
|
|
@@ -1182,7 +1228,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1182
1228
|
handleSlashCommand,
|
|
1183
1229
|
clearStreamingText,
|
|
1184
1230
|
setIsThinking,
|
|
1185
|
-
|
|
1231
|
+
setContextState,
|
|
1186
1232
|
registry
|
|
1187
1233
|
]
|
|
1188
1234
|
);
|
|
@@ -1199,10 +1245,10 @@ function useCommandRegistry(cwd) {
|
|
|
1199
1245
|
}
|
|
1200
1246
|
function App(props) {
|
|
1201
1247
|
const { exit } = useApp();
|
|
1202
|
-
const { session, permissionRequest, streamingText, clearStreamingText } = useSession(props);
|
|
1248
|
+
const { session, permissionRequest, streamingText, clearStreamingText, activeTools } = useSession(props);
|
|
1203
1249
|
const { messages, setMessages, addMessage } = useMessages();
|
|
1204
1250
|
const [isThinking, setIsThinking] = useState5(false);
|
|
1205
|
-
const [
|
|
1251
|
+
const [contextState, setContextState] = useState5({ percentage: 0, usedTokens: 0, maxTokens: 0 });
|
|
1206
1252
|
const registry = useCommandRegistry(props.cwd ?? process.cwd());
|
|
1207
1253
|
const pendingModelChangeRef = useRef3(null);
|
|
1208
1254
|
const [pendingModelId, setPendingModelId] = useState5(null);
|
|
@@ -1213,7 +1259,7 @@ function App(props) {
|
|
|
1213
1259
|
handleSlashCommand,
|
|
1214
1260
|
clearStreamingText,
|
|
1215
1261
|
setIsThinking,
|
|
1216
|
-
|
|
1262
|
+
setContextState,
|
|
1217
1263
|
registry
|
|
1218
1264
|
);
|
|
1219
1265
|
useInput5(
|
|
@@ -1223,26 +1269,26 @@ function App(props) {
|
|
|
1223
1269
|
},
|
|
1224
1270
|
{ isActive: !permissionRequest }
|
|
1225
1271
|
);
|
|
1226
|
-
return /* @__PURE__ */
|
|
1227
|
-
/* @__PURE__ */
|
|
1228
|
-
/* @__PURE__ */
|
|
1272
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
1273
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
1274
|
+
/* @__PURE__ */ jsx10(Text10, { color: "cyan", bold: true, children: `
|
|
1229
1275
|
____ ___ ____ ___ _____ _
|
|
1230
1276
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1231
1277
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
1232
1278
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1233
1279
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1234
1280
|
` }),
|
|
1235
|
-
/* @__PURE__ */
|
|
1281
|
+
/* @__PURE__ */ jsxs8(Text10, { dimColor: true, children: [
|
|
1236
1282
|
" v",
|
|
1237
1283
|
props.version ?? "0.0.0"
|
|
1238
1284
|
] })
|
|
1239
1285
|
] }),
|
|
1240
|
-
/* @__PURE__ */
|
|
1241
|
-
/* @__PURE__ */
|
|
1242
|
-
isThinking && /* @__PURE__ */
|
|
1286
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
1287
|
+
/* @__PURE__ */ jsx10(MessageList, { messages }),
|
|
1288
|
+
isThinking && /* @__PURE__ */ jsx10(Box8, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx10(StreamingIndicator, { text: streamingText, activeTools }) })
|
|
1243
1289
|
] }),
|
|
1244
|
-
permissionRequest && /* @__PURE__ */
|
|
1245
|
-
pendingModelId && /* @__PURE__ */
|
|
1290
|
+
permissionRequest && /* @__PURE__ */ jsx10(PermissionPrompt, { request: permissionRequest }),
|
|
1291
|
+
pendingModelId && /* @__PURE__ */ jsx10(
|
|
1246
1292
|
ConfirmPrompt,
|
|
1247
1293
|
{
|
|
1248
1294
|
message: `Change model to ${getModelName(pendingModelId)}? This will restart the session.`,
|
|
@@ -1264,7 +1310,7 @@ function App(props) {
|
|
|
1264
1310
|
}
|
|
1265
1311
|
}
|
|
1266
1312
|
),
|
|
1267
|
-
/* @__PURE__ */
|
|
1313
|
+
/* @__PURE__ */ jsx10(
|
|
1268
1314
|
StatusBar,
|
|
1269
1315
|
{
|
|
1270
1316
|
permissionMode: session.getPermissionMode(),
|
|
@@ -1272,12 +1318,12 @@ function App(props) {
|
|
|
1272
1318
|
sessionId: session.getSessionId(),
|
|
1273
1319
|
messageCount: messages.length,
|
|
1274
1320
|
isThinking,
|
|
1275
|
-
contextPercentage,
|
|
1276
|
-
contextUsedTokens:
|
|
1277
|
-
contextMaxTokens:
|
|
1321
|
+
contextPercentage: contextState.percentage,
|
|
1322
|
+
contextUsedTokens: contextState.usedTokens,
|
|
1323
|
+
contextMaxTokens: contextState.maxTokens
|
|
1278
1324
|
}
|
|
1279
1325
|
),
|
|
1280
|
-
/* @__PURE__ */
|
|
1326
|
+
/* @__PURE__ */ jsx10(
|
|
1281
1327
|
InputArea,
|
|
1282
1328
|
{
|
|
1283
1329
|
onSubmit: handleSubmit,
|
|
@@ -1285,12 +1331,12 @@ function App(props) {
|
|
|
1285
1331
|
registry
|
|
1286
1332
|
}
|
|
1287
1333
|
),
|
|
1288
|
-
/* @__PURE__ */
|
|
1334
|
+
/* @__PURE__ */ jsx10(Text10, { children: " " })
|
|
1289
1335
|
] });
|
|
1290
1336
|
}
|
|
1291
1337
|
|
|
1292
1338
|
// src/ui/render.tsx
|
|
1293
|
-
import { jsx as
|
|
1339
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1294
1340
|
function renderApp(options) {
|
|
1295
1341
|
process.on("unhandledRejection", (reason) => {
|
|
1296
1342
|
process.stderr.write(`
|
|
@@ -1301,7 +1347,7 @@ function renderApp(options) {
|
|
|
1301
1347
|
`);
|
|
1302
1348
|
}
|
|
1303
1349
|
});
|
|
1304
|
-
const instance = render(/* @__PURE__ */
|
|
1350
|
+
const instance = render(/* @__PURE__ */ jsx11(App, { ...options }), {
|
|
1305
1351
|
exitOnCtrlC: true
|
|
1306
1352
|
});
|
|
1307
1353
|
instance.waitUntilExit().catch((err) => {
|
|
@@ -1314,6 +1360,18 @@ function renderApp(options) {
|
|
|
1314
1360
|
}
|
|
1315
1361
|
|
|
1316
1362
|
// src/cli.ts
|
|
1363
|
+
function hasValidSettingsFile(filePath) {
|
|
1364
|
+
if (!existsSync3(filePath)) return false;
|
|
1365
|
+
try {
|
|
1366
|
+
const raw = readFileSync3(filePath, "utf8").trim();
|
|
1367
|
+
if (raw.length === 0) return false;
|
|
1368
|
+
const parsed = JSON.parse(raw);
|
|
1369
|
+
const provider = parsed.provider;
|
|
1370
|
+
return !!provider?.apiKey;
|
|
1371
|
+
} catch {
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1317
1375
|
function readVersion() {
|
|
1318
1376
|
try {
|
|
1319
1377
|
const thisFile = fileURLToPath(import.meta.url);
|
|
@@ -1338,7 +1396,7 @@ async function ensureConfig(cwd) {
|
|
|
1338
1396
|
const userPath = getUserSettingsPath();
|
|
1339
1397
|
const projectPath = join3(cwd, ".robota", "settings.json");
|
|
1340
1398
|
const localPath = join3(cwd, ".robota", "settings.local.json");
|
|
1341
|
-
if (
|
|
1399
|
+
if (hasValidSettingsFile(userPath) || hasValidSettingsFile(projectPath) || hasValidSettingsFile(localPath)) {
|
|
1342
1400
|
return;
|
|
1343
1401
|
}
|
|
1344
1402
|
process.stdout.write("\n");
|
package/dist/node/index.cjs
CHANGED
|
@@ -177,11 +177,11 @@ var PrintTerminal = class {
|
|
|
177
177
|
};
|
|
178
178
|
|
|
179
179
|
// src/ui/render.tsx
|
|
180
|
-
var
|
|
180
|
+
var import_ink11 = require("ink");
|
|
181
181
|
|
|
182
182
|
// src/ui/App.tsx
|
|
183
183
|
var import_react6 = require("react");
|
|
184
|
-
var
|
|
184
|
+
var import_ink10 = require("ink");
|
|
185
185
|
|
|
186
186
|
// src/commands/slash-executor.ts
|
|
187
187
|
var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
@@ -1018,8 +1018,39 @@ function parseFirstArgValue(argsJson) {
|
|
|
1018
1018
|
}
|
|
1019
1019
|
}
|
|
1020
1020
|
|
|
1021
|
-
// src/ui/
|
|
1021
|
+
// src/ui/StreamingIndicator.tsx
|
|
1022
|
+
var import_ink9 = require("ink");
|
|
1022
1023
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1024
|
+
function StreamingIndicator({ text, activeTools }) {
|
|
1025
|
+
const hasTools = activeTools.length > 0;
|
|
1026
|
+
const hasText = text.length > 0;
|
|
1027
|
+
if (!hasTools && !hasText) {
|
|
1028
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", children: "Thinking..." });
|
|
1029
|
+
}
|
|
1030
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
|
|
1031
|
+
hasTools && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1032
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "gray", bold: true, children: "Tools:" }),
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
|
|
1034
|
+
activeTools.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: t.isRunning ? "yellow" : "green", children: [
|
|
1035
|
+
" ",
|
|
1036
|
+
t.isRunning ? "\u27F3" : "\u2713",
|
|
1037
|
+
" ",
|
|
1038
|
+
t.toolName,
|
|
1039
|
+
"(",
|
|
1040
|
+
t.firstArg,
|
|
1041
|
+
")"
|
|
1042
|
+
] }, `${t.toolName}-${i}`))
|
|
1043
|
+
] }),
|
|
1044
|
+
hasText && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1045
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "cyan", bold: true, children: "Robota:" }),
|
|
1046
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
|
|
1047
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
1048
|
+
] })
|
|
1049
|
+
] });
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// src/ui/App.tsx
|
|
1053
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1023
1054
|
var msgIdCounter = 0;
|
|
1024
1055
|
function nextId() {
|
|
1025
1056
|
msgIdCounter += 1;
|
|
@@ -1043,6 +1074,7 @@ var NOOP_TERMINAL = {
|
|
|
1043
1074
|
function useSession(props) {
|
|
1044
1075
|
const [permissionRequest, setPermissionRequest] = (0, import_react6.useState)(null);
|
|
1045
1076
|
const [streamingText, setStreamingText] = (0, import_react6.useState)("");
|
|
1077
|
+
const [activeTools, setActiveTools] = (0, import_react6.useState)([]);
|
|
1046
1078
|
const permissionQueueRef = (0, import_react6.useRef)([]);
|
|
1047
1079
|
const processingRef = (0, import_react6.useRef)(false);
|
|
1048
1080
|
const processNextPermission = (0, import_react6.useCallback)(() => {
|
|
@@ -1076,6 +1108,25 @@ function useSession(props) {
|
|
|
1076
1108
|
const onTextDelta = (delta) => {
|
|
1077
1109
|
setStreamingText((prev) => prev + delta);
|
|
1078
1110
|
};
|
|
1111
|
+
const TOOL_ARG_DISPLAY_MAX = 80;
|
|
1112
|
+
const TOOL_ARG_TRUNCATE_AT = 77;
|
|
1113
|
+
const onToolExecution = (event) => {
|
|
1114
|
+
if (event.type === "start") {
|
|
1115
|
+
let firstArg = "";
|
|
1116
|
+
if (event.toolArgs) {
|
|
1117
|
+
const firstVal = Object.values(event.toolArgs)[0];
|
|
1118
|
+
const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
|
|
1119
|
+
firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_TRUNCATE_AT) + "..." : raw;
|
|
1120
|
+
}
|
|
1121
|
+
setActiveTools((prev) => [...prev, { toolName: event.toolName, firstArg, isRunning: true }]);
|
|
1122
|
+
} else {
|
|
1123
|
+
setActiveTools(
|
|
1124
|
+
(prev) => prev.map(
|
|
1125
|
+
(t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false } : t
|
|
1126
|
+
)
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1079
1130
|
const paths = (0, import_agent_sdk.projectPaths)(props.cwd ?? process.cwd());
|
|
1080
1131
|
sessionRef.current = (0, import_agent_sdk.createSession)({
|
|
1081
1132
|
config: props.config,
|
|
@@ -1087,11 +1138,15 @@ function useSession(props) {
|
|
|
1087
1138
|
permissionMode: props.permissionMode,
|
|
1088
1139
|
maxTurns: props.maxTurns,
|
|
1089
1140
|
permissionHandler,
|
|
1090
|
-
onTextDelta
|
|
1141
|
+
onTextDelta,
|
|
1142
|
+
onToolExecution
|
|
1091
1143
|
});
|
|
1092
1144
|
}
|
|
1093
|
-
const clearStreamingText = (0, import_react6.useCallback)(() =>
|
|
1094
|
-
|
|
1145
|
+
const clearStreamingText = (0, import_react6.useCallback)(() => {
|
|
1146
|
+
setStreamingText("");
|
|
1147
|
+
setActiveTools([]);
|
|
1148
|
+
}, []);
|
|
1149
|
+
return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText, activeTools };
|
|
1095
1150
|
}
|
|
1096
1151
|
function useMessages() {
|
|
1097
1152
|
const [messages, setMessages] = (0, import_react6.useState)([]);
|
|
@@ -1121,20 +1176,11 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
1121
1176
|
[session, addMessage, setMessages, exit, registry, pendingModelChangeRef, setPendingModelId]
|
|
1122
1177
|
);
|
|
1123
1178
|
}
|
|
1124
|
-
function
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: "cyan", bold: true, children: [
|
|
1128
|
-
"Robota:",
|
|
1129
|
-
" "
|
|
1130
|
-
] }),
|
|
1131
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
|
|
1132
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
1133
|
-
] });
|
|
1134
|
-
}
|
|
1135
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "yellow", children: "Thinking..." });
|
|
1179
|
+
function syncContextState(session, setter) {
|
|
1180
|
+
const ctx = session.getContextState();
|
|
1181
|
+
setter({ percentage: ctx.usedPercentage, usedTokens: ctx.usedTokens, maxTokens: ctx.maxTokens });
|
|
1136
1182
|
}
|
|
1137
|
-
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking,
|
|
1183
|
+
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextState) {
|
|
1138
1184
|
setIsThinking(true);
|
|
1139
1185
|
clearStreamingText();
|
|
1140
1186
|
const historyBefore = session.getHistory().length;
|
|
@@ -1150,7 +1196,7 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
1150
1196
|
addMessage({ role: "tool", content: toolLines.join("\n"), toolName: `${toolLines.length} tools` });
|
|
1151
1197
|
}
|
|
1152
1198
|
addMessage({ role: "assistant", content: response || "(empty response)" });
|
|
1153
|
-
|
|
1199
|
+
syncContextState(session, setContextState);
|
|
1154
1200
|
} catch (err) {
|
|
1155
1201
|
clearStreamingText();
|
|
1156
1202
|
if (err instanceof DOMException && err.name === "AbortError") {
|
|
@@ -1179,13 +1225,13 @@ Execute the "${cmd}" skill: ${userInstruction}`;
|
|
|
1179
1225
|
}
|
|
1180
1226
|
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
1181
1227
|
}
|
|
1182
|
-
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking,
|
|
1228
|
+
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextState, registry) {
|
|
1183
1229
|
return (0, import_react6.useCallback)(
|
|
1184
1230
|
async (input) => {
|
|
1185
1231
|
if (input.startsWith("/")) {
|
|
1186
1232
|
const handled = await handleSlashCommand(input);
|
|
1187
1233
|
if (handled) {
|
|
1188
|
-
|
|
1234
|
+
syncContextState(session, setContextState);
|
|
1189
1235
|
return;
|
|
1190
1236
|
}
|
|
1191
1237
|
const prompt = buildSkillPrompt(input, registry);
|
|
@@ -1196,7 +1242,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1196
1242
|
addMessage,
|
|
1197
1243
|
clearStreamingText,
|
|
1198
1244
|
setIsThinking,
|
|
1199
|
-
|
|
1245
|
+
setContextState
|
|
1200
1246
|
);
|
|
1201
1247
|
}
|
|
1202
1248
|
addMessage({ role: "user", content: input });
|
|
@@ -1206,7 +1252,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1206
1252
|
addMessage,
|
|
1207
1253
|
clearStreamingText,
|
|
1208
1254
|
setIsThinking,
|
|
1209
|
-
|
|
1255
|
+
setContextState
|
|
1210
1256
|
);
|
|
1211
1257
|
},
|
|
1212
1258
|
[
|
|
@@ -1215,7 +1261,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
1215
1261
|
handleSlashCommand,
|
|
1216
1262
|
clearStreamingText,
|
|
1217
1263
|
setIsThinking,
|
|
1218
|
-
|
|
1264
|
+
setContextState,
|
|
1219
1265
|
registry
|
|
1220
1266
|
]
|
|
1221
1267
|
);
|
|
@@ -1231,11 +1277,11 @@ function useCommandRegistry(cwd) {
|
|
|
1231
1277
|
return registryRef.current;
|
|
1232
1278
|
}
|
|
1233
1279
|
function App(props) {
|
|
1234
|
-
const { exit } = (0,
|
|
1235
|
-
const { session, permissionRequest, streamingText, clearStreamingText } = useSession(props);
|
|
1280
|
+
const { exit } = (0, import_ink10.useApp)();
|
|
1281
|
+
const { session, permissionRequest, streamingText, clearStreamingText, activeTools } = useSession(props);
|
|
1236
1282
|
const { messages, setMessages, addMessage } = useMessages();
|
|
1237
1283
|
const [isThinking, setIsThinking] = (0, import_react6.useState)(false);
|
|
1238
|
-
const [
|
|
1284
|
+
const [contextState, setContextState] = (0, import_react6.useState)({ percentage: 0, usedTokens: 0, maxTokens: 0 });
|
|
1239
1285
|
const registry = useCommandRegistry(props.cwd ?? process.cwd());
|
|
1240
1286
|
const pendingModelChangeRef = (0, import_react6.useRef)(null);
|
|
1241
1287
|
const [pendingModelId, setPendingModelId] = (0, import_react6.useState)(null);
|
|
@@ -1246,36 +1292,36 @@ function App(props) {
|
|
|
1246
1292
|
handleSlashCommand,
|
|
1247
1293
|
clearStreamingText,
|
|
1248
1294
|
setIsThinking,
|
|
1249
|
-
|
|
1295
|
+
setContextState,
|
|
1250
1296
|
registry
|
|
1251
1297
|
);
|
|
1252
|
-
(0,
|
|
1298
|
+
(0, import_ink10.useInput)(
|
|
1253
1299
|
(_input, key) => {
|
|
1254
1300
|
if (key.ctrl && _input === "c") exit();
|
|
1255
1301
|
if (key.escape && isThinking) session.abort();
|
|
1256
1302
|
},
|
|
1257
1303
|
{ isActive: !permissionRequest }
|
|
1258
1304
|
);
|
|
1259
|
-
return /* @__PURE__ */ (0,
|
|
1260
|
-
/* @__PURE__ */ (0,
|
|
1261
|
-
/* @__PURE__ */ (0,
|
|
1305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
|
|
1306
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "cyan", bold: true, children: `
|
|
1262
1308
|
____ ___ ____ ___ _____ _
|
|
1263
1309
|
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1264
1310
|
| |_) | | | | _ \\| | | || | / _ \\
|
|
1265
1311
|
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1266
1312
|
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1267
1313
|
` }),
|
|
1268
|
-
/* @__PURE__ */ (0,
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Text, { dimColor: true, children: [
|
|
1269
1315
|
" v",
|
|
1270
1316
|
props.version ?? "0.0.0"
|
|
1271
1317
|
] })
|
|
1272
1318
|
] }),
|
|
1273
|
-
/* @__PURE__ */ (0,
|
|
1274
|
-
/* @__PURE__ */ (0,
|
|
1275
|
-
isThinking && /* @__PURE__ */ (0,
|
|
1319
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
1320
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageList, { messages }),
|
|
1321
|
+
isThinking && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StreamingIndicator, { text: streamingText, activeTools }) })
|
|
1276
1322
|
] }),
|
|
1277
|
-
permissionRequest && /* @__PURE__ */ (0,
|
|
1278
|
-
pendingModelId && /* @__PURE__ */ (0,
|
|
1323
|
+
permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PermissionPrompt, { request: permissionRequest }),
|
|
1324
|
+
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1279
1325
|
ConfirmPrompt,
|
|
1280
1326
|
{
|
|
1281
1327
|
message: `Change model to ${(0, import_agent_core3.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
@@ -1297,7 +1343,7 @@ function App(props) {
|
|
|
1297
1343
|
}
|
|
1298
1344
|
}
|
|
1299
1345
|
),
|
|
1300
|
-
/* @__PURE__ */ (0,
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1301
1347
|
StatusBar,
|
|
1302
1348
|
{
|
|
1303
1349
|
permissionMode: session.getPermissionMode(),
|
|
@@ -1305,12 +1351,12 @@ function App(props) {
|
|
|
1305
1351
|
sessionId: session.getSessionId(),
|
|
1306
1352
|
messageCount: messages.length,
|
|
1307
1353
|
isThinking,
|
|
1308
|
-
contextPercentage,
|
|
1309
|
-
contextUsedTokens:
|
|
1310
|
-
contextMaxTokens:
|
|
1354
|
+
contextPercentage: contextState.percentage,
|
|
1355
|
+
contextUsedTokens: contextState.usedTokens,
|
|
1356
|
+
contextMaxTokens: contextState.maxTokens
|
|
1311
1357
|
}
|
|
1312
1358
|
),
|
|
1313
|
-
/* @__PURE__ */ (0,
|
|
1359
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1314
1360
|
InputArea,
|
|
1315
1361
|
{
|
|
1316
1362
|
onSubmit: handleSubmit,
|
|
@@ -1318,12 +1364,12 @@ function App(props) {
|
|
|
1318
1364
|
registry
|
|
1319
1365
|
}
|
|
1320
1366
|
),
|
|
1321
|
-
/* @__PURE__ */ (0,
|
|
1367
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { children: " " })
|
|
1322
1368
|
] });
|
|
1323
1369
|
}
|
|
1324
1370
|
|
|
1325
1371
|
// src/ui/render.tsx
|
|
1326
|
-
var
|
|
1372
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1327
1373
|
function renderApp(options) {
|
|
1328
1374
|
process.on("unhandledRejection", (reason) => {
|
|
1329
1375
|
process.stderr.write(`
|
|
@@ -1334,7 +1380,7 @@ function renderApp(options) {
|
|
|
1334
1380
|
`);
|
|
1335
1381
|
}
|
|
1336
1382
|
});
|
|
1337
|
-
const instance = (0,
|
|
1383
|
+
const instance = (0, import_ink11.render)(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(App, { ...options }), {
|
|
1338
1384
|
exitOnCtrlC: true
|
|
1339
1385
|
});
|
|
1340
1386
|
instance.waitUntilExit().catch((err) => {
|
|
@@ -1348,6 +1394,18 @@ function renderApp(options) {
|
|
|
1348
1394
|
|
|
1349
1395
|
// src/cli.ts
|
|
1350
1396
|
var import_meta = {};
|
|
1397
|
+
function hasValidSettingsFile(filePath) {
|
|
1398
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return false;
|
|
1399
|
+
try {
|
|
1400
|
+
const raw = (0, import_node_fs3.readFileSync)(filePath, "utf8").trim();
|
|
1401
|
+
if (raw.length === 0) return false;
|
|
1402
|
+
const parsed = JSON.parse(raw);
|
|
1403
|
+
const provider = parsed.provider;
|
|
1404
|
+
return !!provider?.apiKey;
|
|
1405
|
+
} catch {
|
|
1406
|
+
return false;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1351
1409
|
function readVersion() {
|
|
1352
1410
|
try {
|
|
1353
1411
|
const thisFile = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
@@ -1372,7 +1430,7 @@ async function ensureConfig(cwd) {
|
|
|
1372
1430
|
const userPath = getUserSettingsPath();
|
|
1373
1431
|
const projectPath = (0, import_node_path3.join)(cwd, ".robota", "settings.json");
|
|
1374
1432
|
const localPath = (0, import_node_path3.join)(cwd, ".robota", "settings.local.json");
|
|
1375
|
-
if ((
|
|
1433
|
+
if (hasValidSettingsFile(userPath) || hasValidSettingsFile(projectPath) || hasValidSettingsFile(localPath)) {
|
|
1376
1434
|
return;
|
|
1377
1435
|
}
|
|
1378
1436
|
process.stdout.write("\n");
|
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.18",
|
|
4
4
|
"description": "AI coding assistant CLI built on Robota SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"marked-terminal": "^7.3.0",
|
|
36
36
|
"react": "19.2.4",
|
|
37
37
|
"string-width": "^8.2.0",
|
|
38
|
-
"@robota-sdk/agent-core": "3.0.0-beta.
|
|
39
|
-
"@robota-sdk/agent-sdk": "3.0.0-beta.
|
|
38
|
+
"@robota-sdk/agent-core": "3.0.0-beta.18",
|
|
39
|
+
"@robota-sdk/agent-sdk": "3.0.0-beta.18"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/marked": "^6.0.0",
|