@robota-sdk/agent-cli 3.0.0-beta.1 → 3.0.0-beta.11
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 +249 -85
- package/dist/node/bin.js +11 -1
- package/dist/node/{chunk-C56WFH5S.js → chunk-CT2VGJIF.js} +243 -88
- package/dist/node/index.cjs +244 -90
- package/dist/node/index.js +1 -1
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/cli.ts
|
|
2
2
|
import { parseArgs } from "util";
|
|
3
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
3
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2, mkdirSync, writeFileSync, unlinkSync } from "fs";
|
|
4
4
|
import { join as join2, dirname } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import * as readline from "readline";
|
|
@@ -8,30 +8,12 @@ import {
|
|
|
8
8
|
loadConfig,
|
|
9
9
|
loadContext,
|
|
10
10
|
detectProject,
|
|
11
|
-
|
|
11
|
+
createSession as createSession2,
|
|
12
12
|
SessionStore,
|
|
13
|
-
|
|
13
|
+
FileSessionLogger as FileSessionLogger2,
|
|
14
|
+
projectPaths as projectPaths2
|
|
14
15
|
} from "@robota-sdk/agent-sdk";
|
|
15
|
-
|
|
16
|
-
// src/permissions/permission-prompt.ts
|
|
17
|
-
import chalk from "chalk";
|
|
18
|
-
var PERMISSION_OPTIONS = ["Allow", "Deny"];
|
|
19
|
-
var ALLOW_INDEX = 0;
|
|
20
|
-
function formatArgs(toolArgs) {
|
|
21
|
-
const entries = Object.entries(toolArgs);
|
|
22
|
-
if (entries.length === 0) {
|
|
23
|
-
return "(no arguments)";
|
|
24
|
-
}
|
|
25
|
-
return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
|
|
26
|
-
}
|
|
27
|
-
async function promptForApproval(terminal, toolName, toolArgs) {
|
|
28
|
-
terminal.writeLine("");
|
|
29
|
-
terminal.writeLine(chalk.yellow(`[Permission Required] Tool: ${toolName}`));
|
|
30
|
-
terminal.writeLine(chalk.dim(` ${formatArgs(toolArgs)}`));
|
|
31
|
-
terminal.writeLine("");
|
|
32
|
-
const selected = await terminal.select(PERMISSION_OPTIONS, ALLOW_INDEX);
|
|
33
|
-
return selected === ALLOW_INDEX;
|
|
34
|
-
}
|
|
16
|
+
import { promptForApproval } from "@robota-sdk/agent-sdk";
|
|
35
17
|
|
|
36
18
|
// src/ui/render.tsx
|
|
37
19
|
import { render } from "ink";
|
|
@@ -39,7 +21,7 @@ import { render } from "ink";
|
|
|
39
21
|
// src/ui/App.tsx
|
|
40
22
|
import { useState as useState4, useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
41
23
|
import { Box as Box6, Text as Text8, useApp, useInput as useInput4 } from "ink";
|
|
42
|
-
import {
|
|
24
|
+
import { createSession, FileSessionLogger, projectPaths } from "@robota-sdk/agent-sdk";
|
|
43
25
|
|
|
44
26
|
// src/commands/command-registry.ts
|
|
45
27
|
var CommandRegistry = class {
|
|
@@ -101,6 +83,7 @@ function createBuiltinCommands() {
|
|
|
101
83
|
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
102
84
|
{ name: "context", description: "Context window info", source: "builtin" },
|
|
103
85
|
{ name: "permissions", description: "Permission rules", source: "builtin" },
|
|
86
|
+
{ name: "reset", description: "Delete settings and exit", source: "builtin" },
|
|
104
87
|
{ name: "exit", description: "Exit CLI", source: "builtin" }
|
|
105
88
|
];
|
|
106
89
|
}
|
|
@@ -152,7 +135,8 @@ function scanSkillsDir(skillsDir) {
|
|
|
152
135
|
commands.push({
|
|
153
136
|
name: frontmatter?.name ?? entry.name,
|
|
154
137
|
description: frontmatter?.description ?? `Skill: ${entry.name}`,
|
|
155
|
-
source: "skill"
|
|
138
|
+
source: "skill",
|
|
139
|
+
skillContent: content
|
|
156
140
|
});
|
|
157
141
|
}
|
|
158
142
|
return commands;
|
|
@@ -306,7 +290,7 @@ import { Box as Box4, Text as Text6, useInput as useInput2 } from "ink";
|
|
|
306
290
|
import { useRef, useState } from "react";
|
|
307
291
|
import { Text as Text3, useInput, useCursor } from "ink";
|
|
308
292
|
import stringWidth from "string-width";
|
|
309
|
-
import
|
|
293
|
+
import chalk from "chalk";
|
|
310
294
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
311
295
|
function CjkTextInput({
|
|
312
296
|
value,
|
|
@@ -328,71 +312,81 @@ function CjkTextInput({
|
|
|
328
312
|
}
|
|
329
313
|
useInput(
|
|
330
314
|
(input, key) => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (key.return) {
|
|
335
|
-
onSubmit?.(valueRef.current);
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
if (key.leftArrow) {
|
|
339
|
-
if (cursorRef.current > 0) {
|
|
340
|
-
cursorRef.current -= 1;
|
|
341
|
-
forceRender((n) => n + 1);
|
|
315
|
+
try {
|
|
316
|
+
if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
|
|
317
|
+
return;
|
|
342
318
|
}
|
|
343
|
-
return
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (cursorRef.current < valueRef.current.length) {
|
|
347
|
-
cursorRef.current += 1;
|
|
348
|
-
forceRender((n) => n + 1);
|
|
319
|
+
if (key.return) {
|
|
320
|
+
onSubmit?.(valueRef.current);
|
|
321
|
+
return;
|
|
349
322
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
cursorRef.current -= 1;
|
|
357
|
-
valueRef.current = next2;
|
|
358
|
-
onChange(next2);
|
|
323
|
+
if (key.leftArrow) {
|
|
324
|
+
if (cursorRef.current > 0) {
|
|
325
|
+
cursorRef.current -= 1;
|
|
326
|
+
forceRender((n) => n + 1);
|
|
327
|
+
}
|
|
328
|
+
return;
|
|
359
329
|
}
|
|
360
|
-
|
|
330
|
+
if (key.rightArrow) {
|
|
331
|
+
if (cursorRef.current < valueRef.current.length) {
|
|
332
|
+
cursorRef.current += 1;
|
|
333
|
+
forceRender((n) => n + 1);
|
|
334
|
+
}
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (key.backspace || key.delete) {
|
|
338
|
+
if (cursorRef.current > 0) {
|
|
339
|
+
const v2 = valueRef.current;
|
|
340
|
+
const next2 = v2.slice(0, cursorRef.current - 1) + v2.slice(cursorRef.current);
|
|
341
|
+
cursorRef.current -= 1;
|
|
342
|
+
valueRef.current = next2;
|
|
343
|
+
onChange(next2);
|
|
344
|
+
}
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (!input || input.length === 0) return;
|
|
348
|
+
const printable = input.replace(/[\x00-\x1f\x7f]/g, "");
|
|
349
|
+
if (printable.length === 0) return;
|
|
350
|
+
const v = valueRef.current;
|
|
351
|
+
const c = cursorRef.current;
|
|
352
|
+
const next = v.slice(0, c) + printable + v.slice(c);
|
|
353
|
+
cursorRef.current = c + printable.length;
|
|
354
|
+
valueRef.current = next;
|
|
355
|
+
onChange(next);
|
|
356
|
+
} catch {
|
|
361
357
|
}
|
|
362
|
-
const v = valueRef.current;
|
|
363
|
-
const c = cursorRef.current;
|
|
364
|
-
const next = v.slice(0, c) + input + v.slice(c);
|
|
365
|
-
cursorRef.current = c + input.length;
|
|
366
|
-
valueRef.current = next;
|
|
367
|
-
onChange(next);
|
|
368
358
|
},
|
|
369
359
|
{ isActive: focus }
|
|
370
360
|
);
|
|
371
361
|
if (showCursor && focus) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
362
|
+
try {
|
|
363
|
+
const textBeforeCursor = [...valueRef.current].slice(0, cursorRef.current).join("");
|
|
364
|
+
const cursorX = 4 + stringWidth(textBeforeCursor);
|
|
365
|
+
setCursorPosition({ x: cursorX, y: 0 });
|
|
366
|
+
} catch {
|
|
367
|
+
setCursorPosition({ x: 4, y: 0 });
|
|
368
|
+
}
|
|
375
369
|
}
|
|
376
370
|
return /* @__PURE__ */ jsx3(Text3, { children: renderWithCursor(valueRef.current, cursorRef.current, placeholder, showCursor && focus) });
|
|
377
371
|
}
|
|
378
372
|
function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
|
|
379
373
|
if (!showCursor) {
|
|
380
|
-
return value.length > 0 ? value : placeholder ?
|
|
374
|
+
return value.length > 0 ? value : placeholder ? chalk.gray(placeholder) : "";
|
|
381
375
|
}
|
|
382
376
|
if (value.length === 0) {
|
|
383
377
|
if (placeholder.length > 0) {
|
|
384
|
-
return
|
|
378
|
+
return chalk.inverse(placeholder[0]) + chalk.gray(placeholder.slice(1));
|
|
385
379
|
}
|
|
386
|
-
return
|
|
380
|
+
return chalk.inverse(" ");
|
|
387
381
|
}
|
|
388
382
|
const chars = [...value];
|
|
389
383
|
let rendered = "";
|
|
390
384
|
for (let i = 0; i < chars.length; i++) {
|
|
391
385
|
const char = chars[i] ?? "";
|
|
392
|
-
rendered += i === cursorOffset ?
|
|
386
|
+
rendered += i === cursorOffset ? chalk.inverse(char) : char;
|
|
393
387
|
}
|
|
394
388
|
if (cursorOffset >= chars.length) {
|
|
395
|
-
rendered +=
|
|
389
|
+
rendered += chalk.inverse(" ");
|
|
396
390
|
}
|
|
397
391
|
return rendered;
|
|
398
392
|
}
|
|
@@ -607,8 +601,8 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
607
601
|
import React4 from "react";
|
|
608
602
|
import { Box as Box5, Text as Text7, useInput as useInput3 } from "ink";
|
|
609
603
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
610
|
-
var OPTIONS = ["Allow", "Deny"];
|
|
611
|
-
function
|
|
604
|
+
var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
|
|
605
|
+
function formatArgs(args) {
|
|
612
606
|
const entries = Object.entries(args);
|
|
613
607
|
if (entries.length === 0) return "(no arguments)";
|
|
614
608
|
return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
|
|
@@ -623,10 +617,12 @@ function PermissionPrompt({ request }) {
|
|
|
623
617
|
setSelected(0);
|
|
624
618
|
}
|
|
625
619
|
const doResolve = React4.useCallback(
|
|
626
|
-
(
|
|
620
|
+
(index) => {
|
|
627
621
|
if (resolvedRef.current) return;
|
|
628
622
|
resolvedRef.current = true;
|
|
629
|
-
request.resolve(
|
|
623
|
+
if (index === 0) request.resolve(true);
|
|
624
|
+
else if (index === 1) request.resolve("allow-session");
|
|
625
|
+
else request.resolve(false);
|
|
630
626
|
},
|
|
631
627
|
[request]
|
|
632
628
|
);
|
|
@@ -637,11 +633,13 @@ function PermissionPrompt({ request }) {
|
|
|
637
633
|
} else if (key.downArrow || key.rightArrow) {
|
|
638
634
|
setSelected((prev) => prev < OPTIONS.length - 1 ? prev + 1 : prev);
|
|
639
635
|
} else if (key.return) {
|
|
640
|
-
doResolve(selected
|
|
641
|
-
} else if (input === "y" || input === "
|
|
642
|
-
doResolve(
|
|
643
|
-
} else if (input === "
|
|
644
|
-
doResolve(
|
|
636
|
+
doResolve(selected);
|
|
637
|
+
} else if (input === "y" || input === "1") {
|
|
638
|
+
doResolve(0);
|
|
639
|
+
} else if (input === "a" || input === "2") {
|
|
640
|
+
doResolve(1);
|
|
641
|
+
} else if (input === "n" || input === "d" || input === "3") {
|
|
642
|
+
doResolve(2);
|
|
645
643
|
}
|
|
646
644
|
});
|
|
647
645
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
@@ -653,7 +651,7 @@ function PermissionPrompt({ request }) {
|
|
|
653
651
|
] }),
|
|
654
652
|
/* @__PURE__ */ jsxs5(Text7, { dimColor: true, children: [
|
|
655
653
|
" ",
|
|
656
|
-
|
|
654
|
+
formatArgs(request.toolArgs)
|
|
657
655
|
] }),
|
|
658
656
|
/* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsx7(Box5, { marginRight: 2, children: /* @__PURE__ */ jsxs5(Text7, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
659
657
|
i === selected ? "> " : " ",
|
|
@@ -701,11 +699,11 @@ function useSession(props) {
|
|
|
701
699
|
setPermissionRequest({
|
|
702
700
|
toolName: next.toolName,
|
|
703
701
|
toolArgs: next.toolArgs,
|
|
704
|
-
resolve: (
|
|
702
|
+
resolve: (result) => {
|
|
705
703
|
permissionQueueRef.current.shift();
|
|
706
704
|
processingRef.current = false;
|
|
707
705
|
setPermissionRequest(null);
|
|
708
|
-
next.resolve(
|
|
706
|
+
next.resolve(result);
|
|
709
707
|
setTimeout(() => processNextPermission(), 0);
|
|
710
708
|
}
|
|
711
709
|
});
|
|
@@ -721,10 +719,12 @@ function useSession(props) {
|
|
|
721
719
|
const onTextDelta = (delta) => {
|
|
722
720
|
setStreamingText((prev) => prev + delta);
|
|
723
721
|
};
|
|
724
|
-
|
|
722
|
+
const paths = projectPaths(props.cwd ?? process.cwd());
|
|
723
|
+
sessionRef.current = createSession({
|
|
725
724
|
config: props.config,
|
|
726
725
|
context: props.context,
|
|
727
726
|
terminal: NOOP_TERMINAL,
|
|
727
|
+
sessionLogger: new FileSessionLogger(paths.logs),
|
|
728
728
|
projectInfo: props.projectInfo,
|
|
729
729
|
sessionStore: props.sessionStore,
|
|
730
730
|
permissionMode: props.permissionMode,
|
|
@@ -750,6 +750,7 @@ var HELP_TEXT = [
|
|
|
750
750
|
" /compact [instr] \u2014 Compact context (optional focus instructions)",
|
|
751
751
|
" /mode [m] \u2014 Show/change permission mode",
|
|
752
752
|
" /cost \u2014 Show session info",
|
|
753
|
+
" /reset \u2014 Delete settings and exit",
|
|
753
754
|
" /exit \u2014 Exit CLI"
|
|
754
755
|
].join("\n");
|
|
755
756
|
function handleModeCommand(arg, session, addMessage) {
|
|
@@ -795,6 +796,39 @@ async function executeSlashCommand(cmd, parts, session, addMessage, setMessages,
|
|
|
795
796
|
Messages: ${session.getMessageCount()}`
|
|
796
797
|
});
|
|
797
798
|
return true;
|
|
799
|
+
case "permissions": {
|
|
800
|
+
const mode = session.getPermissionMode();
|
|
801
|
+
const sessionAllowed = session.getSessionAllowedTools();
|
|
802
|
+
const lines = [`Permission mode: ${mode}`];
|
|
803
|
+
if (sessionAllowed.length > 0) {
|
|
804
|
+
lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
|
|
805
|
+
} else {
|
|
806
|
+
lines.push("No session-approved tools.");
|
|
807
|
+
}
|
|
808
|
+
addMessage({ role: "system", content: lines.join("\n") });
|
|
809
|
+
return true;
|
|
810
|
+
}
|
|
811
|
+
case "context": {
|
|
812
|
+
const ctx = session.getContextState();
|
|
813
|
+
addMessage({
|
|
814
|
+
role: "system",
|
|
815
|
+
content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
|
|
816
|
+
});
|
|
817
|
+
return true;
|
|
818
|
+
}
|
|
819
|
+
case "reset": {
|
|
820
|
+
const { existsSync: exists, unlinkSync: unlink } = await import("fs");
|
|
821
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
822
|
+
const settingsPath = `${home}/.robota/settings.json`;
|
|
823
|
+
if (exists(settingsPath)) {
|
|
824
|
+
unlink(settingsPath);
|
|
825
|
+
addMessage({ role: "system", content: `Deleted ${settingsPath}. Exiting...` });
|
|
826
|
+
} else {
|
|
827
|
+
addMessage({ role: "system", content: "No user settings found." });
|
|
828
|
+
}
|
|
829
|
+
setTimeout(() => exit(), 500);
|
|
830
|
+
return true;
|
|
831
|
+
}
|
|
798
832
|
case "exit":
|
|
799
833
|
exit();
|
|
800
834
|
return true;
|
|
@@ -835,15 +869,42 @@ function StreamingIndicator({ text }) {
|
|
|
835
869
|
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextPercentage) {
|
|
836
870
|
setIsThinking(true);
|
|
837
871
|
clearStreamingText();
|
|
872
|
+
const historyBefore = session.getHistory().length;
|
|
838
873
|
try {
|
|
839
874
|
const response = await session.run(prompt);
|
|
840
875
|
clearStreamingText();
|
|
876
|
+
const history = session.getHistory();
|
|
877
|
+
const toolLines = [];
|
|
878
|
+
for (let i = historyBefore; i < history.length; i++) {
|
|
879
|
+
const msg = history[i];
|
|
880
|
+
if (msg.role === "assistant" && msg.toolCalls) {
|
|
881
|
+
for (const tc of msg.toolCalls) {
|
|
882
|
+
let value = "";
|
|
883
|
+
try {
|
|
884
|
+
const parsed = JSON.parse(tc.function.arguments);
|
|
885
|
+
const firstVal = Object.values(parsed)[0];
|
|
886
|
+
value = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal);
|
|
887
|
+
} catch {
|
|
888
|
+
value = tc.function.arguments;
|
|
889
|
+
}
|
|
890
|
+
const truncated = value.length > 80 ? value.slice(0, 77) + "..." : value;
|
|
891
|
+
toolLines.push(`${tc.function.name}(${truncated})`);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
if (toolLines.length > 0) {
|
|
896
|
+
addMessage({ role: "tool", content: toolLines.join("\n"), toolName: `${toolLines.length} tools` });
|
|
897
|
+
}
|
|
841
898
|
addMessage({ role: "assistant", content: response || "(empty response)" });
|
|
842
899
|
setContextPercentage(session.getContextState().usedPercentage);
|
|
843
900
|
} catch (err) {
|
|
844
901
|
clearStreamingText();
|
|
845
|
-
|
|
846
|
-
|
|
902
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
903
|
+
addMessage({ role: "system", content: "Cancelled." });
|
|
904
|
+
} else {
|
|
905
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
906
|
+
addMessage({ role: "system", content: `Error: ${errMsg}` });
|
|
907
|
+
}
|
|
847
908
|
} finally {
|
|
848
909
|
setIsThinking(false);
|
|
849
910
|
}
|
|
@@ -854,7 +915,15 @@ function buildSkillPrompt(input, registry) {
|
|
|
854
915
|
const skillCmd = registry.getCommands().find((c) => c.name === cmd && c.source === "skill");
|
|
855
916
|
if (!skillCmd) return null;
|
|
856
917
|
const args = parts.slice(1).join(" ").trim();
|
|
857
|
-
|
|
918
|
+
const userInstruction = args || skillCmd.description;
|
|
919
|
+
if (skillCmd.skillContent) {
|
|
920
|
+
return `<skill name="${cmd}">
|
|
921
|
+
${skillCmd.skillContent}
|
|
922
|
+
</skill>
|
|
923
|
+
|
|
924
|
+
Execute the "${cmd}" skill: ${userInstruction}`;
|
|
925
|
+
}
|
|
926
|
+
return `Use the "${cmd}" skill: ${userInstruction}`;
|
|
858
927
|
}
|
|
859
928
|
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextPercentage, registry) {
|
|
860
929
|
return useCallback2(
|
|
@@ -927,8 +996,9 @@ function App(props) {
|
|
|
927
996
|
useInput4(
|
|
928
997
|
(_input, key) => {
|
|
929
998
|
if (key.ctrl && _input === "c") exit();
|
|
999
|
+
if (key.escape && isThinking) session.abort();
|
|
930
1000
|
},
|
|
931
|
-
{ isActive: !permissionRequest
|
|
1001
|
+
{ isActive: !permissionRequest }
|
|
932
1002
|
);
|
|
933
1003
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
934
1004
|
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
@@ -1048,7 +1118,8 @@ function parseCliArgs() {
|
|
|
1048
1118
|
model: { type: "string" },
|
|
1049
1119
|
"permission-mode": { type: "string" },
|
|
1050
1120
|
"max-turns": { type: "string" },
|
|
1051
|
-
version: { type: "boolean", default: false }
|
|
1121
|
+
version: { type: "boolean", default: false },
|
|
1122
|
+
reset: { type: "boolean", default: false }
|
|
1052
1123
|
}
|
|
1053
1124
|
});
|
|
1054
1125
|
return {
|
|
@@ -1059,7 +1130,8 @@ function parseCliArgs() {
|
|
|
1059
1130
|
model: values["model"],
|
|
1060
1131
|
permissionMode: parsePermissionMode(values["permission-mode"]),
|
|
1061
1132
|
maxTurns: parseMaxTurns(values["max-turns"]),
|
|
1062
|
-
version: values["version"] ?? false
|
|
1133
|
+
version: values["version"] ?? false,
|
|
1134
|
+
reset: values["reset"] ?? false
|
|
1063
1135
|
};
|
|
1064
1136
|
}
|
|
1065
1137
|
var PrintTerminal = class {
|
|
@@ -1110,6 +1182,83 @@ var PrintTerminal = class {
|
|
|
1110
1182
|
} };
|
|
1111
1183
|
}
|
|
1112
1184
|
};
|
|
1185
|
+
function getUserSettingsPath() {
|
|
1186
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
1187
|
+
return join2(home, ".robota", "settings.json");
|
|
1188
|
+
}
|
|
1189
|
+
async function ensureConfig(cwd) {
|
|
1190
|
+
const userPath = getUserSettingsPath();
|
|
1191
|
+
const projectPath = join2(cwd, ".robota", "settings.json");
|
|
1192
|
+
const localPath = join2(cwd, ".robota", "settings.local.json");
|
|
1193
|
+
if (existsSync2(userPath) || existsSync2(projectPath) || existsSync2(localPath)) {
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
process.stdout.write("\n");
|
|
1197
|
+
process.stdout.write(" Welcome to Robota CLI!\n");
|
|
1198
|
+
process.stdout.write(" No configuration found. Let's set up your API key.\n");
|
|
1199
|
+
process.stdout.write("\n");
|
|
1200
|
+
const apiKey = await new Promise((resolve) => {
|
|
1201
|
+
process.stdout.write(" Anthropic API key: ");
|
|
1202
|
+
let input = "";
|
|
1203
|
+
const stdin = process.stdin;
|
|
1204
|
+
const wasRaw = stdin.isRaw;
|
|
1205
|
+
stdin.setRawMode(true);
|
|
1206
|
+
stdin.resume();
|
|
1207
|
+
stdin.setEncoding("utf8");
|
|
1208
|
+
const onData = (data) => {
|
|
1209
|
+
for (const ch of data) {
|
|
1210
|
+
if (ch === "\r" || ch === "\n") {
|
|
1211
|
+
stdin.removeListener("data", onData);
|
|
1212
|
+
stdin.setRawMode(wasRaw ?? false);
|
|
1213
|
+
stdin.pause();
|
|
1214
|
+
process.stdout.write("\n");
|
|
1215
|
+
resolve(input.trim());
|
|
1216
|
+
return;
|
|
1217
|
+
} else if (ch === "\x7F" || ch === "\b") {
|
|
1218
|
+
if (input.length > 0) {
|
|
1219
|
+
input = input.slice(0, -1);
|
|
1220
|
+
process.stdout.write("\b \b");
|
|
1221
|
+
}
|
|
1222
|
+
} else if (ch === "") {
|
|
1223
|
+
process.stdout.write("\n");
|
|
1224
|
+
process.exit(0);
|
|
1225
|
+
} else if (ch.charCodeAt(0) >= 32) {
|
|
1226
|
+
input += ch;
|
|
1227
|
+
process.stdout.write("*");
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
stdin.on("data", onData);
|
|
1232
|
+
});
|
|
1233
|
+
if (!apiKey) {
|
|
1234
|
+
process.stderr.write("\n No API key provided. Exiting.\n");
|
|
1235
|
+
process.exit(1);
|
|
1236
|
+
}
|
|
1237
|
+
const settingsDir = dirname(userPath);
|
|
1238
|
+
mkdirSync(settingsDir, { recursive: true });
|
|
1239
|
+
const settings = {
|
|
1240
|
+
provider: {
|
|
1241
|
+
name: "anthropic",
|
|
1242
|
+
model: "claude-sonnet-4-6",
|
|
1243
|
+
apiKey
|
|
1244
|
+
}
|
|
1245
|
+
};
|
|
1246
|
+
writeFileSync(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1247
|
+
process.stdout.write(`
|
|
1248
|
+
Config saved to ${userPath}
|
|
1249
|
+
|
|
1250
|
+
`);
|
|
1251
|
+
}
|
|
1252
|
+
function resetConfig() {
|
|
1253
|
+
const userPath = getUserSettingsPath();
|
|
1254
|
+
if (existsSync2(userPath)) {
|
|
1255
|
+
unlinkSync(userPath);
|
|
1256
|
+
process.stdout.write(`Deleted ${userPath}
|
|
1257
|
+
`);
|
|
1258
|
+
} else {
|
|
1259
|
+
process.stdout.write("No user settings found.\n");
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1113
1262
|
async function startCli() {
|
|
1114
1263
|
const args = parseCliArgs();
|
|
1115
1264
|
if (args.version) {
|
|
@@ -1117,7 +1266,12 @@ async function startCli() {
|
|
|
1117
1266
|
`);
|
|
1118
1267
|
return;
|
|
1119
1268
|
}
|
|
1269
|
+
if (args.reset) {
|
|
1270
|
+
resetConfig();
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1120
1273
|
const cwd = process.cwd();
|
|
1274
|
+
await ensureConfig(cwd);
|
|
1121
1275
|
const [config, context, projectInfo] = await Promise.all([
|
|
1122
1276
|
loadConfig(cwd),
|
|
1123
1277
|
loadContext(cwd),
|
|
@@ -1134,13 +1288,14 @@ async function startCli() {
|
|
|
1134
1288
|
process.exit(1);
|
|
1135
1289
|
}
|
|
1136
1290
|
const terminal = new PrintTerminal();
|
|
1137
|
-
const
|
|
1291
|
+
const paths = projectPaths2(cwd);
|
|
1292
|
+
const session = createSession2({
|
|
1138
1293
|
config,
|
|
1139
1294
|
context,
|
|
1140
1295
|
terminal,
|
|
1296
|
+
sessionLogger: new FileSessionLogger2(paths.logs),
|
|
1141
1297
|
projectInfo,
|
|
1142
1298
|
permissionMode: args.permissionMode,
|
|
1143
|
-
systemPromptBuilder: buildSystemPrompt,
|
|
1144
1299
|
promptForApproval
|
|
1145
1300
|
});
|
|
1146
1301
|
const response = await session.run(prompt);
|