@robota-sdk/agent-cli 3.0.0-beta.7 → 3.0.0-beta.71
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 +414 -114
- package/bin/robota.cjs +47 -0
- package/dist/node/bin.d.ts +2 -1
- package/dist/node/bin.js +57 -10
- package/dist/node/bin.js.map +1 -0
- package/dist/node/child-process-subagent-ipc--Vp2dk1v.js +2 -0
- package/dist/node/child-process-subagent-ipc--Vp2dk1v.js.map +1 -0
- package/dist/node/child-process-subagent-ipc-Aitv2i6E.cjs +1 -0
- package/dist/node/child-process-subagent-ipc-CEy8bLN6.cjs +1 -0
- package/dist/node/child-process-subagent-ipc-DVpVp43R.js +2 -0
- package/dist/node/child-process-subagent-ipc-DVpVp43R.js.map +1 -0
- package/dist/node/cli.cjs +1 -0
- package/dist/node/cli.d.ts +7 -0
- package/dist/node/cli.d.ts.map +1 -0
- package/dist/node/cli.js +2 -0
- package/dist/node/cli.js.map +1 -0
- package/dist/node/constants.cjs +1 -0
- package/dist/node/constants.js +2 -0
- package/dist/node/constants.js.map +1 -0
- package/dist/node/index.cjs +49 -1257
- package/dist/node/index.d.ts +12 -47
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +50 -13
- package/dist/node/index.js.map +1 -0
- package/dist/node/init/init-command.cjs +32 -0
- package/dist/node/init/init-command.js +33 -0
- package/dist/node/init/init-command.js.map +1 -0
- package/dist/node/modes/print-mode.cjs +6 -0
- package/dist/node/modes/print-mode.js +7 -0
- package/dist/node/modes/print-mode.js.map +1 -0
- package/dist/node/modes/shell-exec.cjs +1 -0
- package/dist/node/modes/shell-exec.js +2 -0
- package/dist/node/modes/shell-exec.js.map +1 -0
- package/dist/node/modes/tui-mode.cjs +1 -0
- package/dist/node/modes/tui-mode.js +2 -0
- package/dist/node/modes/tui-mode.js.map +1 -0
- package/dist/node/provider-default-definitions-CKtxv2k0.js +2 -0
- package/dist/node/provider-default-definitions-CKtxv2k0.js.map +1 -0
- package/dist/node/provider-default-definitions-GFiYzACo.cjs +1 -0
- package/dist/node/provider-default-definitions-g0ZUDeii.cjs +1 -0
- package/dist/node/startup/append-system-prompt.cjs +3 -0
- package/dist/node/startup/append-system-prompt.js +4 -0
- package/dist/node/startup/append-system-prompt.js.map +1 -0
- package/dist/node/startup/args-to-options.cjs +1 -0
- package/dist/node/startup/args-to-options.js +2 -0
- package/dist/node/startup/args-to-options.js.map +1 -0
- package/dist/node/startup/command-setup.cjs +1 -0
- package/dist/node/startup/command-setup.d.ts +11 -0
- package/dist/node/startup/command-setup.d.ts.map +1 -0
- package/dist/node/startup/command-setup.js +2 -0
- package/dist/node/startup/command-setup.js.map +1 -0
- package/dist/node/startup/config-phase.cjs +1 -0
- package/dist/node/startup/config-phase.js +2 -0
- package/dist/node/startup/config-phase.js.map +1 -0
- package/dist/node/startup/preflight.cjs +1 -0
- package/dist/node/startup/preflight.js +2 -0
- package/dist/node/startup/preflight.js.map +1 -0
- package/dist/node/startup/provider-setup.cjs +1 -0
- package/dist/node/startup/provider-setup.js +2 -0
- package/dist/node/startup/provider-setup.js.map +1 -0
- package/dist/node/startup/provider-startup.cjs +2 -0
- package/dist/node/startup/provider-startup.js +3 -0
- package/dist/node/startup/provider-startup.js.map +1 -0
- package/dist/node/startup/reset-config.cjs +1 -0
- package/dist/node/startup/reset-config.js +2 -0
- package/dist/node/startup/reset-config.js.map +1 -0
- package/dist/node/startup/session-setup.cjs +1 -0
- package/dist/node/startup/session-setup.js +2 -0
- package/dist/node/startup/session-setup.js.map +1 -0
- package/dist/node/startup/subagent-setup.cjs +1 -0
- package/dist/node/startup/subagent-setup.js +2 -0
- package/dist/node/startup/subagent-setup.js.map +1 -0
- package/dist/node/startup/update-notice.cjs +1 -0
- package/dist/node/startup/update-notice.js +2 -0
- package/dist/node/startup/update-notice.js.map +1 -0
- package/dist/node/startup/version.cjs +1 -0
- package/dist/node/startup/version.js +2 -0
- package/dist/node/startup/version.js.map +1 -0
- package/dist/node/subagents/child-process-subagent-worker.cjs +1 -0
- package/dist/node/subagents/child-process-subagent-worker.d.ts +1 -0
- package/dist/node/subagents/child-process-subagent-worker.js +2 -0
- package/dist/node/subagents/child-process-subagent-worker.js.map +1 -0
- package/dist/node/user-local-direct-command.cjs +1 -0
- package/dist/node/user-local-direct-command.js +2 -0
- package/dist/node/user-local-direct-command.js.map +1 -0
- package/dist/node/utils/cli-args.cjs +35 -0
- package/dist/node/utils/cli-args.js +36 -0
- package/dist/node/utils/cli-args.js.map +1 -0
- package/package.json +52 -16
- package/dist/node/bin.cjs +0 -1240
- package/dist/node/bin.d.cts +0 -1
- package/dist/node/chunk-A2A66S6Q.js +0 -1219
- package/dist/node/index.d.cts +0 -49
package/dist/node/index.cjs
CHANGED
|
@@ -1,1257 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// src/permissions/permission-prompt.ts
|
|
51
|
-
var import_chalk = __toESM(require("chalk"), 1);
|
|
52
|
-
var PERMISSION_OPTIONS = ["Allow", "Deny"];
|
|
53
|
-
var ALLOW_INDEX = 0;
|
|
54
|
-
function formatArgs(toolArgs) {
|
|
55
|
-
const entries = Object.entries(toolArgs);
|
|
56
|
-
if (entries.length === 0) {
|
|
57
|
-
return "(no arguments)";
|
|
58
|
-
}
|
|
59
|
-
return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
|
|
60
|
-
}
|
|
61
|
-
async function promptForApproval(terminal, toolName, toolArgs) {
|
|
62
|
-
terminal.writeLine("");
|
|
63
|
-
terminal.writeLine(import_chalk.default.yellow(`[Permission Required] Tool: ${toolName}`));
|
|
64
|
-
terminal.writeLine(import_chalk.default.dim(` ${formatArgs(toolArgs)}`));
|
|
65
|
-
terminal.writeLine("");
|
|
66
|
-
const selected = await terminal.select(PERMISSION_OPTIONS, ALLOW_INDEX);
|
|
67
|
-
return selected === ALLOW_INDEX;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// src/ui/render.tsx
|
|
71
|
-
var import_ink9 = require("ink");
|
|
72
|
-
|
|
73
|
-
// src/ui/App.tsx
|
|
74
|
-
var import_react5 = require("react");
|
|
75
|
-
var import_ink8 = require("ink");
|
|
76
|
-
var import_agent_sdk = require("@robota-sdk/agent-sdk");
|
|
77
|
-
|
|
78
|
-
// src/commands/command-registry.ts
|
|
79
|
-
var CommandRegistry = class {
|
|
80
|
-
sources = [];
|
|
81
|
-
addSource(source) {
|
|
82
|
-
this.sources.push(source);
|
|
83
|
-
}
|
|
84
|
-
/** Get all commands, optionally filtered by prefix */
|
|
85
|
-
getCommands(filter) {
|
|
86
|
-
const all = [];
|
|
87
|
-
for (const source of this.sources) {
|
|
88
|
-
all.push(...source.getCommands());
|
|
89
|
-
}
|
|
90
|
-
if (!filter) return all;
|
|
91
|
-
const lower = filter.toLowerCase();
|
|
92
|
-
return all.filter((cmd) => cmd.name.toLowerCase().startsWith(lower));
|
|
93
|
-
}
|
|
94
|
-
/** Get subcommands for a specific command */
|
|
95
|
-
getSubcommands(commandName) {
|
|
96
|
-
const lower = commandName.toLowerCase();
|
|
97
|
-
for (const source of this.sources) {
|
|
98
|
-
for (const cmd of source.getCommands()) {
|
|
99
|
-
if (cmd.name.toLowerCase() === lower && cmd.subcommands) {
|
|
100
|
-
return cmd.subcommands;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return [];
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
// src/commands/builtin-source.ts
|
|
109
|
-
function createBuiltinCommands() {
|
|
110
|
-
return [
|
|
111
|
-
{ name: "help", description: "Show available commands", source: "builtin" },
|
|
112
|
-
{ name: "clear", description: "Clear conversation history", source: "builtin" },
|
|
113
|
-
{
|
|
114
|
-
name: "mode",
|
|
115
|
-
description: "Permission mode",
|
|
116
|
-
source: "builtin",
|
|
117
|
-
subcommands: [
|
|
118
|
-
{ name: "plan", description: "Plan only, no execution", source: "builtin" },
|
|
119
|
-
{ name: "default", description: "Ask before risky actions", source: "builtin" },
|
|
120
|
-
{ name: "acceptEdits", description: "Auto-approve file edits", source: "builtin" },
|
|
121
|
-
{ name: "bypassPermissions", description: "Skip all permission checks", source: "builtin" }
|
|
122
|
-
]
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: "model",
|
|
126
|
-
description: "Select AI model",
|
|
127
|
-
source: "builtin",
|
|
128
|
-
subcommands: [
|
|
129
|
-
{ name: "claude-opus-4-6", description: "Opus 4.6 (highest quality)", source: "builtin" },
|
|
130
|
-
{ name: "claude-sonnet-4-6", description: "Sonnet 4.6 (balanced)", source: "builtin" },
|
|
131
|
-
{ name: "claude-haiku-4-5", description: "Haiku 4.5 (fastest)", source: "builtin" }
|
|
132
|
-
]
|
|
133
|
-
},
|
|
134
|
-
{ name: "compact", description: "Compress context window", source: "builtin" },
|
|
135
|
-
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
136
|
-
{ name: "context", description: "Context window info", source: "builtin" },
|
|
137
|
-
{ name: "permissions", description: "Permission rules", source: "builtin" },
|
|
138
|
-
{ name: "exit", description: "Exit CLI", source: "builtin" }
|
|
139
|
-
];
|
|
140
|
-
}
|
|
141
|
-
var BuiltinCommandSource = class {
|
|
142
|
-
name = "builtin";
|
|
143
|
-
commands;
|
|
144
|
-
constructor() {
|
|
145
|
-
this.commands = createBuiltinCommands();
|
|
146
|
-
}
|
|
147
|
-
getCommands() {
|
|
148
|
-
return this.commands;
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
// src/commands/skill-source.ts
|
|
153
|
-
var import_node_fs = require("fs");
|
|
154
|
-
var import_node_path = require("path");
|
|
155
|
-
var import_node_os = require("os");
|
|
156
|
-
function parseFrontmatter(content) {
|
|
157
|
-
const lines = content.split("\n");
|
|
158
|
-
if (lines[0]?.trim() !== "---") return null;
|
|
159
|
-
let name = "";
|
|
160
|
-
let description = "";
|
|
161
|
-
for (let i = 1; i < lines.length; i++) {
|
|
162
|
-
const line = lines[i];
|
|
163
|
-
if (line.trim() === "---") break;
|
|
164
|
-
const nameMatch = line.match(/^name:\s*(.+)/);
|
|
165
|
-
if (nameMatch) {
|
|
166
|
-
name = nameMatch[1].trim();
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
const descMatch = line.match(/^description:\s*(.+)/);
|
|
170
|
-
if (descMatch) {
|
|
171
|
-
description = descMatch[1].trim();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return name ? { name, description } : null;
|
|
175
|
-
}
|
|
176
|
-
function scanSkillsDir(skillsDir) {
|
|
177
|
-
if (!(0, import_node_fs.existsSync)(skillsDir)) return [];
|
|
178
|
-
const commands = [];
|
|
179
|
-
const entries = (0, import_node_fs.readdirSync)(skillsDir, { withFileTypes: true });
|
|
180
|
-
for (const entry of entries) {
|
|
181
|
-
if (!entry.isDirectory()) continue;
|
|
182
|
-
const skillFile = (0, import_node_path.join)(skillsDir, entry.name, "SKILL.md");
|
|
183
|
-
if (!(0, import_node_fs.existsSync)(skillFile)) continue;
|
|
184
|
-
const content = (0, import_node_fs.readFileSync)(skillFile, "utf-8");
|
|
185
|
-
const frontmatter = parseFrontmatter(content);
|
|
186
|
-
commands.push({
|
|
187
|
-
name: frontmatter?.name ?? entry.name,
|
|
188
|
-
description: frontmatter?.description ?? `Skill: ${entry.name}`,
|
|
189
|
-
source: "skill"
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
return commands;
|
|
193
|
-
}
|
|
194
|
-
var SkillCommandSource = class {
|
|
195
|
-
name = "skill";
|
|
196
|
-
cwd;
|
|
197
|
-
cachedCommands = null;
|
|
198
|
-
constructor(cwd) {
|
|
199
|
-
this.cwd = cwd;
|
|
200
|
-
}
|
|
201
|
-
getCommands() {
|
|
202
|
-
if (this.cachedCommands) return this.cachedCommands;
|
|
203
|
-
const projectSkills = scanSkillsDir((0, import_node_path.join)(this.cwd, ".agents", "skills"));
|
|
204
|
-
const userSkills = scanSkillsDir((0, import_node_path.join)((0, import_node_os.homedir)(), ".claude", "skills"));
|
|
205
|
-
const seen = new Set(projectSkills.map((cmd) => cmd.name));
|
|
206
|
-
const merged = [...projectSkills];
|
|
207
|
-
for (const cmd of userSkills) {
|
|
208
|
-
if (!seen.has(cmd.name)) {
|
|
209
|
-
merged.push(cmd);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
this.cachedCommands = merged;
|
|
213
|
-
return this.cachedCommands;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
// src/ui/MessageList.tsx
|
|
218
|
-
var import_ink = require("ink");
|
|
219
|
-
|
|
220
|
-
// src/ui/render-markdown.ts
|
|
221
|
-
var import_marked = require("marked");
|
|
222
|
-
var import_marked_terminal = __toESM(require("marked-terminal"), 1);
|
|
223
|
-
import_marked.marked.setOptions({
|
|
224
|
-
renderer: new import_marked_terminal.default()
|
|
225
|
-
});
|
|
226
|
-
function renderMarkdown(md) {
|
|
227
|
-
const result = import_marked.marked.parse(md);
|
|
228
|
-
return typeof result === "string" ? result.trimEnd() : md;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// src/ui/MessageList.tsx
|
|
232
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
233
|
-
function RoleLabel({ role }) {
|
|
234
|
-
switch (role) {
|
|
235
|
-
case "user":
|
|
236
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "green", bold: true, children: [
|
|
237
|
-
"You:",
|
|
238
|
-
" "
|
|
239
|
-
] });
|
|
240
|
-
case "assistant":
|
|
241
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "cyan", bold: true, children: [
|
|
242
|
-
"Robota:",
|
|
243
|
-
" "
|
|
244
|
-
] });
|
|
245
|
-
case "system":
|
|
246
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "yellow", bold: true, children: [
|
|
247
|
-
"System:",
|
|
248
|
-
" "
|
|
249
|
-
] });
|
|
250
|
-
case "tool":
|
|
251
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "magenta", bold: true, children: [
|
|
252
|
-
"Tool:",
|
|
253
|
-
" "
|
|
254
|
-
] });
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
function MessageItem({ message }) {
|
|
258
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
259
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { children: [
|
|
260
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RoleLabel, { role: message.role }),
|
|
261
|
-
message.toolName && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "magenta", dimColor: true, children: [
|
|
262
|
-
"[",
|
|
263
|
-
message.toolName,
|
|
264
|
-
"]",
|
|
265
|
-
" "
|
|
266
|
-
] })
|
|
267
|
-
] }),
|
|
268
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: " " }),
|
|
269
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { wrap: "wrap", children: message.role === "assistant" ? renderMarkdown(message.content) : message.content }) })
|
|
270
|
-
] });
|
|
271
|
-
}
|
|
272
|
-
function MessageList({ messages }) {
|
|
273
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { flexDirection: "column", children: messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageItem, { message: msg }, msg.id)) });
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// src/ui/StatusBar.tsx
|
|
277
|
-
var import_ink2 = require("ink");
|
|
278
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
279
|
-
var CONTEXT_YELLOW_THRESHOLD = 70;
|
|
280
|
-
var CONTEXT_RED_THRESHOLD = 90;
|
|
281
|
-
function getContextColor(percentage) {
|
|
282
|
-
if (percentage >= CONTEXT_RED_THRESHOLD) return "red";
|
|
283
|
-
if (percentage >= CONTEXT_YELLOW_THRESHOLD) return "yellow";
|
|
284
|
-
return "green";
|
|
285
|
-
}
|
|
286
|
-
function StatusBar({
|
|
287
|
-
permissionMode,
|
|
288
|
-
modelName,
|
|
289
|
-
sessionId: _sessionId,
|
|
290
|
-
messageCount,
|
|
291
|
-
isThinking,
|
|
292
|
-
contextPercentage,
|
|
293
|
-
contextUsedTokens,
|
|
294
|
-
contextMaxTokens
|
|
295
|
-
}) {
|
|
296
|
-
const contextColor = getContextColor(contextPercentage);
|
|
297
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
298
|
-
import_ink2.Box,
|
|
299
|
-
{
|
|
300
|
-
borderStyle: "single",
|
|
301
|
-
borderColor: "gray",
|
|
302
|
-
paddingLeft: 1,
|
|
303
|
-
paddingRight: 1,
|
|
304
|
-
justifyContent: "space-between",
|
|
305
|
-
children: [
|
|
306
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { children: [
|
|
307
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { color: "cyan", bold: true, children: "Mode:" }),
|
|
308
|
-
" ",
|
|
309
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: permissionMode }),
|
|
310
|
-
" | ",
|
|
311
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { dimColor: true, children: modelName }),
|
|
312
|
-
" | ",
|
|
313
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: contextColor, children: [
|
|
314
|
-
"Context: ",
|
|
315
|
-
Math.round(contextPercentage),
|
|
316
|
-
"% (",
|
|
317
|
-
(contextUsedTokens / 1e3).toFixed(1),
|
|
318
|
-
"k/",
|
|
319
|
-
(contextMaxTokens / 1e3).toFixed(0),
|
|
320
|
-
"k)"
|
|
321
|
-
] })
|
|
322
|
-
] }),
|
|
323
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { children: [
|
|
324
|
-
isThinking && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { color: "yellow", children: "Thinking... " }),
|
|
325
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { dimColor: true, children: [
|
|
326
|
-
"msgs: ",
|
|
327
|
-
messageCount
|
|
328
|
-
] })
|
|
329
|
-
] })
|
|
330
|
-
]
|
|
331
|
-
}
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// src/ui/InputArea.tsx
|
|
336
|
-
var import_react3 = __toESM(require("react"), 1);
|
|
337
|
-
var import_ink6 = require("ink");
|
|
338
|
-
|
|
339
|
-
// src/ui/CjkTextInput.tsx
|
|
340
|
-
var import_react = require("react");
|
|
341
|
-
var import_ink3 = require("ink");
|
|
342
|
-
var import_string_width = __toESM(require("string-width"), 1);
|
|
343
|
-
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
344
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
345
|
-
function CjkTextInput({
|
|
346
|
-
value,
|
|
347
|
-
onChange,
|
|
348
|
-
onSubmit,
|
|
349
|
-
placeholder = "",
|
|
350
|
-
focus = true,
|
|
351
|
-
showCursor = true
|
|
352
|
-
}) {
|
|
353
|
-
const valueRef = (0, import_react.useRef)(value);
|
|
354
|
-
const cursorRef = (0, import_react.useRef)(value.length);
|
|
355
|
-
const [, forceRender] = (0, import_react.useState)(0);
|
|
356
|
-
const { setCursorPosition } = (0, import_ink3.useCursor)();
|
|
357
|
-
if (value !== valueRef.current) {
|
|
358
|
-
valueRef.current = value;
|
|
359
|
-
if (cursorRef.current > value.length) {
|
|
360
|
-
cursorRef.current = value.length;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
(0, import_ink3.useInput)(
|
|
364
|
-
(input, key) => {
|
|
365
|
-
if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
if (key.return) {
|
|
369
|
-
onSubmit?.(valueRef.current);
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
if (key.leftArrow) {
|
|
373
|
-
if (cursorRef.current > 0) {
|
|
374
|
-
cursorRef.current -= 1;
|
|
375
|
-
forceRender((n) => n + 1);
|
|
376
|
-
}
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
if (key.rightArrow) {
|
|
380
|
-
if (cursorRef.current < valueRef.current.length) {
|
|
381
|
-
cursorRef.current += 1;
|
|
382
|
-
forceRender((n) => n + 1);
|
|
383
|
-
}
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
if (key.backspace || key.delete) {
|
|
387
|
-
if (cursorRef.current > 0) {
|
|
388
|
-
const v2 = valueRef.current;
|
|
389
|
-
const next2 = v2.slice(0, cursorRef.current - 1) + v2.slice(cursorRef.current);
|
|
390
|
-
cursorRef.current -= 1;
|
|
391
|
-
valueRef.current = next2;
|
|
392
|
-
onChange(next2);
|
|
393
|
-
}
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
const v = valueRef.current;
|
|
397
|
-
const c = cursorRef.current;
|
|
398
|
-
const next = v.slice(0, c) + input + v.slice(c);
|
|
399
|
-
cursorRef.current = c + input.length;
|
|
400
|
-
valueRef.current = next;
|
|
401
|
-
onChange(next);
|
|
402
|
-
},
|
|
403
|
-
{ isActive: focus }
|
|
404
|
-
);
|
|
405
|
-
if (showCursor && focus) {
|
|
406
|
-
const textBeforeCursor = [...valueRef.current].slice(0, cursorRef.current).join("");
|
|
407
|
-
const cursorX = 4 + (0, import_string_width.default)(textBeforeCursor);
|
|
408
|
-
setCursorPosition({ x: cursorX, y: 0 });
|
|
409
|
-
}
|
|
410
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink3.Text, { children: renderWithCursor(valueRef.current, cursorRef.current, placeholder, showCursor && focus) });
|
|
411
|
-
}
|
|
412
|
-
function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
|
|
413
|
-
if (!showCursor) {
|
|
414
|
-
return value.length > 0 ? value : placeholder ? import_chalk2.default.gray(placeholder) : "";
|
|
415
|
-
}
|
|
416
|
-
if (value.length === 0) {
|
|
417
|
-
if (placeholder.length > 0) {
|
|
418
|
-
return import_chalk2.default.inverse(placeholder[0]) + import_chalk2.default.gray(placeholder.slice(1));
|
|
419
|
-
}
|
|
420
|
-
return import_chalk2.default.inverse(" ");
|
|
421
|
-
}
|
|
422
|
-
const chars = [...value];
|
|
423
|
-
let rendered = "";
|
|
424
|
-
for (let i = 0; i < chars.length; i++) {
|
|
425
|
-
const char = chars[i] ?? "";
|
|
426
|
-
rendered += i === cursorOffset ? import_chalk2.default.inverse(char) : char;
|
|
427
|
-
}
|
|
428
|
-
if (cursorOffset >= chars.length) {
|
|
429
|
-
rendered += import_chalk2.default.inverse(" ");
|
|
430
|
-
}
|
|
431
|
-
return rendered;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// src/ui/WaveText.tsx
|
|
435
|
-
var import_react2 = require("react");
|
|
436
|
-
var import_ink4 = require("ink");
|
|
437
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
438
|
-
var WAVE_COLORS = ["#666666", "#888888", "#aaaaaa", "#888888"];
|
|
439
|
-
var INTERVAL_MS = 400;
|
|
440
|
-
var CHARS_PER_GROUP = 4;
|
|
441
|
-
function WaveText({ text }) {
|
|
442
|
-
const [tick, setTick] = (0, import_react2.useState)(0);
|
|
443
|
-
(0, import_react2.useEffect)(() => {
|
|
444
|
-
const timer = setInterval(() => {
|
|
445
|
-
setTick((prev) => prev + 1);
|
|
446
|
-
}, INTERVAL_MS);
|
|
447
|
-
return () => clearInterval(timer);
|
|
448
|
-
}, []);
|
|
449
|
-
const chars = [...text];
|
|
450
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink4.Text, { children: chars.map((char, i) => {
|
|
451
|
-
const group = Math.floor(i / CHARS_PER_GROUP);
|
|
452
|
-
const colorIndex = (tick + group) % WAVE_COLORS.length;
|
|
453
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink4.Text, { color: WAVE_COLORS[colorIndex], children: char }, i);
|
|
454
|
-
}) });
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// src/ui/SlashAutocomplete.tsx
|
|
458
|
-
var import_ink5 = require("ink");
|
|
459
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
460
|
-
var MAX_VISIBLE = 8;
|
|
461
|
-
function CommandRow(props) {
|
|
462
|
-
const { cmd, isSelected, showSlash } = props;
|
|
463
|
-
const prefix = showSlash ? "/" : "";
|
|
464
|
-
const indicator = isSelected ? "\u25B8 " : " ";
|
|
465
|
-
const nameColor = isSelected ? "cyan" : void 0;
|
|
466
|
-
const dimmed = !isSelected;
|
|
467
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink5.Box, { children: [
|
|
468
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_ink5.Text, { color: nameColor, dimColor: dimmed, children: [
|
|
469
|
-
indicator,
|
|
470
|
-
prefix,
|
|
471
|
-
cmd.name
|
|
472
|
-
] }),
|
|
473
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Text, { dimColor: dimmed, children: " " }),
|
|
474
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Text, { color: nameColor, dimColor: dimmed, children: cmd.description })
|
|
475
|
-
] });
|
|
476
|
-
}
|
|
477
|
-
function SlashAutocomplete({
|
|
478
|
-
commands,
|
|
479
|
-
selectedIndex,
|
|
480
|
-
visible,
|
|
481
|
-
isSubcommandMode
|
|
482
|
-
}) {
|
|
483
|
-
if (!visible || commands.length === 0) return null;
|
|
484
|
-
const scrollOffset = computeScrollOffset(selectedIndex, commands.length);
|
|
485
|
-
const visibleCommands = commands.slice(scrollOffset, scrollOffset + MAX_VISIBLE);
|
|
486
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink5.Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: visibleCommands.map((cmd, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
487
|
-
CommandRow,
|
|
488
|
-
{
|
|
489
|
-
cmd,
|
|
490
|
-
isSelected: scrollOffset + i === selectedIndex,
|
|
491
|
-
showSlash: !isSubcommandMode
|
|
492
|
-
},
|
|
493
|
-
cmd.name
|
|
494
|
-
)) });
|
|
495
|
-
}
|
|
496
|
-
function computeScrollOffset(selectedIndex, total) {
|
|
497
|
-
if (total <= MAX_VISIBLE) return 0;
|
|
498
|
-
if (selectedIndex < MAX_VISIBLE) return 0;
|
|
499
|
-
const maxOffset = total - MAX_VISIBLE;
|
|
500
|
-
return Math.min(selectedIndex - MAX_VISIBLE + 1, maxOffset);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// src/ui/InputArea.tsx
|
|
504
|
-
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
505
|
-
function parseSlashInput(value) {
|
|
506
|
-
if (!value.startsWith("/")) return { isSlash: false, parentCommand: "", filter: "" };
|
|
507
|
-
const afterSlash = value.slice(1);
|
|
508
|
-
const spaceIndex = afterSlash.indexOf(" ");
|
|
509
|
-
if (spaceIndex === -1) return { isSlash: true, parentCommand: "", filter: afterSlash };
|
|
510
|
-
const parent = afterSlash.slice(0, spaceIndex);
|
|
511
|
-
const rest = afterSlash.slice(spaceIndex + 1);
|
|
512
|
-
return { isSlash: true, parentCommand: parent, filter: rest };
|
|
513
|
-
}
|
|
514
|
-
function useAutocomplete(value, registry) {
|
|
515
|
-
const [selectedIndex, setSelectedIndex] = (0, import_react3.useState)(0);
|
|
516
|
-
const [dismissed, setDismissed] = (0, import_react3.useState)(false);
|
|
517
|
-
const prevValueRef = import_react3.default.useRef(value);
|
|
518
|
-
if (prevValueRef.current !== value) {
|
|
519
|
-
prevValueRef.current = value;
|
|
520
|
-
if (dismissed) setDismissed(false);
|
|
521
|
-
}
|
|
522
|
-
const parsed = parseSlashInput(value);
|
|
523
|
-
const isSubcommandMode = parsed.isSlash && parsed.parentCommand.length > 0;
|
|
524
|
-
const filteredCommands = (0, import_react3.useMemo)(() => {
|
|
525
|
-
if (!registry || !parsed.isSlash || dismissed) return [];
|
|
526
|
-
if (isSubcommandMode) {
|
|
527
|
-
const subs = registry.getSubcommands(parsed.parentCommand);
|
|
528
|
-
if (subs.length === 0) return [];
|
|
529
|
-
if (!parsed.filter) return subs;
|
|
530
|
-
const lower = parsed.filter.toLowerCase();
|
|
531
|
-
return subs.filter((c) => c.name.toLowerCase().startsWith(lower));
|
|
532
|
-
}
|
|
533
|
-
return registry.getCommands(parsed.filter);
|
|
534
|
-
}, [registry, parsed.isSlash, parsed.parentCommand, parsed.filter, dismissed, isSubcommandMode]);
|
|
535
|
-
const showPopup = parsed.isSlash && filteredCommands.length > 0 && !dismissed;
|
|
536
|
-
if (selectedIndex >= filteredCommands.length && filteredCommands.length > 0) {
|
|
537
|
-
setSelectedIndex(filteredCommands.length - 1);
|
|
538
|
-
}
|
|
539
|
-
return {
|
|
540
|
-
showPopup,
|
|
541
|
-
filteredCommands,
|
|
542
|
-
selectedIndex,
|
|
543
|
-
setSelectedIndex,
|
|
544
|
-
isSubcommandMode,
|
|
545
|
-
setShowPopup: (val) => {
|
|
546
|
-
if (typeof val === "function") {
|
|
547
|
-
setDismissed((prev) => {
|
|
548
|
-
const nextVal = val(!prev);
|
|
549
|
-
return !nextVal;
|
|
550
|
-
});
|
|
551
|
-
} else {
|
|
552
|
-
setDismissed(!val);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
function InputArea({ onSubmit, isDisabled, registry }) {
|
|
558
|
-
const [value, setValue] = (0, import_react3.useState)("");
|
|
559
|
-
const {
|
|
560
|
-
showPopup,
|
|
561
|
-
filteredCommands,
|
|
562
|
-
selectedIndex,
|
|
563
|
-
setSelectedIndex,
|
|
564
|
-
isSubcommandMode,
|
|
565
|
-
setShowPopup
|
|
566
|
-
} = useAutocomplete(value, registry);
|
|
567
|
-
const handleSubmit = (0, import_react3.useCallback)(
|
|
568
|
-
(text) => {
|
|
569
|
-
const trimmed = text.trim();
|
|
570
|
-
if (trimmed.length === 0) return;
|
|
571
|
-
if (showPopup && filteredCommands[selectedIndex]) {
|
|
572
|
-
selectCommand(filteredCommands[selectedIndex]);
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
setValue("");
|
|
576
|
-
onSubmit(trimmed);
|
|
577
|
-
},
|
|
578
|
-
[showPopup, filteredCommands, selectedIndex, onSubmit]
|
|
579
|
-
);
|
|
580
|
-
const selectCommand = (0, import_react3.useCallback)(
|
|
581
|
-
(cmd) => {
|
|
582
|
-
const parsed = parseSlashInput(value);
|
|
583
|
-
if (parsed.parentCommand) {
|
|
584
|
-
const fullCommand = `/${parsed.parentCommand} ${cmd.name}`;
|
|
585
|
-
setValue("");
|
|
586
|
-
onSubmit(fullCommand);
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
if (cmd.subcommands && cmd.subcommands.length > 0) {
|
|
590
|
-
setValue(`/${cmd.name} `);
|
|
591
|
-
setSelectedIndex(0);
|
|
592
|
-
return;
|
|
593
|
-
}
|
|
594
|
-
setValue("");
|
|
595
|
-
onSubmit(`/${cmd.name}`);
|
|
596
|
-
},
|
|
597
|
-
[value, onSubmit, setSelectedIndex]
|
|
598
|
-
);
|
|
599
|
-
(0, import_ink6.useInput)(
|
|
600
|
-
(_input, key) => {
|
|
601
|
-
if (!showPopup) return;
|
|
602
|
-
if (key.upArrow) {
|
|
603
|
-
setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
|
|
604
|
-
} else if (key.downArrow) {
|
|
605
|
-
setSelectedIndex((prev) => prev < filteredCommands.length - 1 ? prev + 1 : 0);
|
|
606
|
-
} else if (key.escape) {
|
|
607
|
-
setShowPopup(false);
|
|
608
|
-
} else if (key.tab) {
|
|
609
|
-
const cmd = filteredCommands[selectedIndex];
|
|
610
|
-
if (cmd) selectCommand(cmd);
|
|
611
|
-
}
|
|
612
|
-
},
|
|
613
|
-
{ isActive: showPopup && !isDisabled }
|
|
614
|
-
);
|
|
615
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_ink6.Box, { flexDirection: "column", children: [
|
|
616
|
-
showPopup && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
617
|
-
SlashAutocomplete,
|
|
618
|
-
{
|
|
619
|
-
commands: filteredCommands,
|
|
620
|
-
selectedIndex,
|
|
621
|
-
visible: showPopup,
|
|
622
|
-
isSubcommandMode
|
|
623
|
-
}
|
|
624
|
-
),
|
|
625
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ink6.Box, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(WaveText, { text: " Waiting for response..." }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_ink6.Box, { children: [
|
|
626
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ink6.Text, { color: "green", bold: true, children: "> " }),
|
|
627
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
628
|
-
CjkTextInput,
|
|
629
|
-
{
|
|
630
|
-
value,
|
|
631
|
-
onChange: setValue,
|
|
632
|
-
onSubmit: handleSubmit,
|
|
633
|
-
placeholder: "Type a message or /help"
|
|
634
|
-
}
|
|
635
|
-
)
|
|
636
|
-
] }) })
|
|
637
|
-
] });
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// src/ui/PermissionPrompt.tsx
|
|
641
|
-
var import_react4 = __toESM(require("react"), 1);
|
|
642
|
-
var import_ink7 = require("ink");
|
|
643
|
-
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
644
|
-
var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
|
|
645
|
-
function formatArgs2(args) {
|
|
646
|
-
const entries = Object.entries(args);
|
|
647
|
-
if (entries.length === 0) return "(no arguments)";
|
|
648
|
-
return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
|
|
649
|
-
}
|
|
650
|
-
function PermissionPrompt({ request }) {
|
|
651
|
-
const [selected, setSelected] = import_react4.default.useState(0);
|
|
652
|
-
const resolvedRef = import_react4.default.useRef(false);
|
|
653
|
-
const prevRequestRef = import_react4.default.useRef(request);
|
|
654
|
-
if (prevRequestRef.current !== request) {
|
|
655
|
-
prevRequestRef.current = request;
|
|
656
|
-
resolvedRef.current = false;
|
|
657
|
-
setSelected(0);
|
|
658
|
-
}
|
|
659
|
-
const doResolve = import_react4.default.useCallback(
|
|
660
|
-
(index) => {
|
|
661
|
-
if (resolvedRef.current) return;
|
|
662
|
-
resolvedRef.current = true;
|
|
663
|
-
if (index === 0) request.resolve(true);
|
|
664
|
-
else if (index === 1) request.resolve("allow-session");
|
|
665
|
-
else request.resolve(false);
|
|
666
|
-
},
|
|
667
|
-
[request]
|
|
668
|
-
);
|
|
669
|
-
(0, import_ink7.useInput)((input, key) => {
|
|
670
|
-
if (resolvedRef.current) return;
|
|
671
|
-
if (key.upArrow || key.leftArrow) {
|
|
672
|
-
setSelected((prev) => prev > 0 ? prev - 1 : prev);
|
|
673
|
-
} else if (key.downArrow || key.rightArrow) {
|
|
674
|
-
setSelected((prev) => prev < OPTIONS.length - 1 ? prev + 1 : prev);
|
|
675
|
-
} else if (key.return) {
|
|
676
|
-
doResolve(selected);
|
|
677
|
-
} else if (input === "y" || input === "1") {
|
|
678
|
-
doResolve(0);
|
|
679
|
-
} else if (input === "a" || input === "2") {
|
|
680
|
-
doResolve(1);
|
|
681
|
-
} else if (input === "n" || input === "d" || input === "3") {
|
|
682
|
-
doResolve(2);
|
|
683
|
-
}
|
|
684
|
-
});
|
|
685
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
686
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "yellow", bold: true, children: "[Permission Required]" }),
|
|
687
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { children: [
|
|
688
|
-
"Tool:",
|
|
689
|
-
" ",
|
|
690
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "cyan", bold: true, children: request.toolName })
|
|
691
|
-
] }),
|
|
692
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { dimColor: true, children: [
|
|
693
|
-
" ",
|
|
694
|
-
formatArgs2(request.toolArgs)
|
|
695
|
-
] }),
|
|
696
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { marginTop: 1, children: OPTIONS.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { marginRight: 2, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
|
|
697
|
-
i === selected ? "> " : " ",
|
|
698
|
-
opt
|
|
699
|
-
] }) }, opt)) }),
|
|
700
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { dimColor: true, children: " left/right to select, Enter to confirm" })
|
|
701
|
-
] });
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// src/ui/App.tsx
|
|
705
|
-
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
706
|
-
var msgIdCounter = 0;
|
|
707
|
-
function nextId() {
|
|
708
|
-
msgIdCounter += 1;
|
|
709
|
-
return `msg_${msgIdCounter}`;
|
|
710
|
-
}
|
|
711
|
-
var NOOP_TERMINAL = {
|
|
712
|
-
write: () => {
|
|
713
|
-
},
|
|
714
|
-
writeLine: () => {
|
|
715
|
-
},
|
|
716
|
-
writeMarkdown: () => {
|
|
717
|
-
},
|
|
718
|
-
writeError: () => {
|
|
719
|
-
},
|
|
720
|
-
prompt: () => Promise.resolve(""),
|
|
721
|
-
select: () => Promise.resolve(0),
|
|
722
|
-
spinner: () => ({ stop: () => {
|
|
723
|
-
}, update: () => {
|
|
724
|
-
} })
|
|
725
|
-
};
|
|
726
|
-
function useSession(props) {
|
|
727
|
-
const [permissionRequest, setPermissionRequest] = (0, import_react5.useState)(null);
|
|
728
|
-
const [streamingText, setStreamingText] = (0, import_react5.useState)("");
|
|
729
|
-
const permissionQueueRef = (0, import_react5.useRef)([]);
|
|
730
|
-
const processingRef = (0, import_react5.useRef)(false);
|
|
731
|
-
const processNextPermission = (0, import_react5.useCallback)(() => {
|
|
732
|
-
if (processingRef.current) return;
|
|
733
|
-
const next = permissionQueueRef.current[0];
|
|
734
|
-
if (!next) {
|
|
735
|
-
setPermissionRequest(null);
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
processingRef.current = true;
|
|
739
|
-
setPermissionRequest({
|
|
740
|
-
toolName: next.toolName,
|
|
741
|
-
toolArgs: next.toolArgs,
|
|
742
|
-
resolve: (result) => {
|
|
743
|
-
permissionQueueRef.current.shift();
|
|
744
|
-
processingRef.current = false;
|
|
745
|
-
setPermissionRequest(null);
|
|
746
|
-
next.resolve(result);
|
|
747
|
-
setTimeout(() => processNextPermission(), 0);
|
|
748
|
-
}
|
|
749
|
-
});
|
|
750
|
-
}, []);
|
|
751
|
-
const sessionRef = (0, import_react5.useRef)(null);
|
|
752
|
-
if (sessionRef.current === null) {
|
|
753
|
-
const permissionHandler = (toolName, toolArgs) => {
|
|
754
|
-
return new Promise((resolve) => {
|
|
755
|
-
permissionQueueRef.current.push({ toolName, toolArgs, resolve });
|
|
756
|
-
processNextPermission();
|
|
757
|
-
});
|
|
758
|
-
};
|
|
759
|
-
const onTextDelta = (delta) => {
|
|
760
|
-
setStreamingText((prev) => prev + delta);
|
|
761
|
-
};
|
|
762
|
-
const paths = (0, import_agent_sdk.projectPaths)(props.cwd ?? process.cwd());
|
|
763
|
-
sessionRef.current = (0, import_agent_sdk.createSession)({
|
|
764
|
-
config: props.config,
|
|
765
|
-
context: props.context,
|
|
766
|
-
terminal: NOOP_TERMINAL,
|
|
767
|
-
sessionLogger: new import_agent_sdk.FileSessionLogger(paths.logs),
|
|
768
|
-
projectInfo: props.projectInfo,
|
|
769
|
-
sessionStore: props.sessionStore,
|
|
770
|
-
permissionMode: props.permissionMode,
|
|
771
|
-
maxTurns: props.maxTurns,
|
|
772
|
-
permissionHandler,
|
|
773
|
-
onTextDelta
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
const clearStreamingText = (0, import_react5.useCallback)(() => setStreamingText(""), []);
|
|
777
|
-
return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText };
|
|
778
|
-
}
|
|
779
|
-
function useMessages() {
|
|
780
|
-
const [messages, setMessages] = (0, import_react5.useState)([]);
|
|
781
|
-
const addMessage = (0, import_react5.useCallback)((msg) => {
|
|
782
|
-
setMessages((prev) => [...prev, { ...msg, id: nextId(), timestamp: /* @__PURE__ */ new Date() }]);
|
|
783
|
-
}, []);
|
|
784
|
-
return { messages, setMessages, addMessage };
|
|
785
|
-
}
|
|
786
|
-
var HELP_TEXT = [
|
|
787
|
-
"Available commands:",
|
|
788
|
-
" /help \u2014 Show this help",
|
|
789
|
-
" /clear \u2014 Clear conversation",
|
|
790
|
-
" /compact [instr] \u2014 Compact context (optional focus instructions)",
|
|
791
|
-
" /mode [m] \u2014 Show/change permission mode",
|
|
792
|
-
" /cost \u2014 Show session info",
|
|
793
|
-
" /exit \u2014 Exit CLI"
|
|
794
|
-
].join("\n");
|
|
795
|
-
function handleModeCommand(arg, session, addMessage) {
|
|
796
|
-
const validModes = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
797
|
-
if (!arg) {
|
|
798
|
-
addMessage({ role: "system", content: `Current mode: ${session.getPermissionMode()}` });
|
|
799
|
-
} else if (validModes.includes(arg)) {
|
|
800
|
-
session.setPermissionMode(arg);
|
|
801
|
-
addMessage({ role: "system", content: `Permission mode set to: ${arg}` });
|
|
802
|
-
} else {
|
|
803
|
-
addMessage({ role: "system", content: `Invalid mode. Valid: ${validModes.join(" | ")}` });
|
|
804
|
-
}
|
|
805
|
-
return true;
|
|
806
|
-
}
|
|
807
|
-
async function executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry) {
|
|
808
|
-
switch (cmd) {
|
|
809
|
-
case "help":
|
|
810
|
-
addMessage({ role: "system", content: HELP_TEXT });
|
|
811
|
-
return true;
|
|
812
|
-
case "clear":
|
|
813
|
-
setMessages([]);
|
|
814
|
-
session.clearHistory();
|
|
815
|
-
addMessage({ role: "system", content: "Conversation cleared." });
|
|
816
|
-
return true;
|
|
817
|
-
case "compact": {
|
|
818
|
-
const instructions = parts.slice(1).join(" ").trim() || void 0;
|
|
819
|
-
const before = session.getContextState().usedPercentage;
|
|
820
|
-
addMessage({ role: "system", content: "Compacting context..." });
|
|
821
|
-
await session.compact(instructions);
|
|
822
|
-
const after = session.getContextState().usedPercentage;
|
|
823
|
-
addMessage({
|
|
824
|
-
role: "system",
|
|
825
|
-
content: `Context compacted: ${Math.round(before)}% -> ${Math.round(after)}%`
|
|
826
|
-
});
|
|
827
|
-
return true;
|
|
828
|
-
}
|
|
829
|
-
case "mode":
|
|
830
|
-
return handleModeCommand(parts[1], session, addMessage);
|
|
831
|
-
case "cost":
|
|
832
|
-
addMessage({
|
|
833
|
-
role: "system",
|
|
834
|
-
content: `Session: ${session.getSessionId()}
|
|
835
|
-
Messages: ${session.getMessageCount()}`
|
|
836
|
-
});
|
|
837
|
-
return true;
|
|
838
|
-
case "permissions": {
|
|
839
|
-
const mode = session.getPermissionMode();
|
|
840
|
-
const sessionAllowed = session.getSessionAllowedTools();
|
|
841
|
-
const lines = [`Permission mode: ${mode}`];
|
|
842
|
-
if (sessionAllowed.length > 0) {
|
|
843
|
-
lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
|
|
844
|
-
} else {
|
|
845
|
-
lines.push("No session-approved tools.");
|
|
846
|
-
}
|
|
847
|
-
addMessage({ role: "system", content: lines.join("\n") });
|
|
848
|
-
return true;
|
|
849
|
-
}
|
|
850
|
-
case "context": {
|
|
851
|
-
const ctx = session.getContextState();
|
|
852
|
-
addMessage({
|
|
853
|
-
role: "system",
|
|
854
|
-
content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
|
|
855
|
-
});
|
|
856
|
-
return true;
|
|
857
|
-
}
|
|
858
|
-
case "exit":
|
|
859
|
-
exit();
|
|
860
|
-
return true;
|
|
861
|
-
default: {
|
|
862
|
-
const skillCmd = registry.getCommands().find((c) => c.name === cmd && c.source === "skill");
|
|
863
|
-
if (skillCmd) {
|
|
864
|
-
addMessage({ role: "system", content: `Invoking skill: ${cmd}` });
|
|
865
|
-
return false;
|
|
866
|
-
}
|
|
867
|
-
addMessage({ role: "system", content: `Unknown command "/${cmd}". Type /help for help.` });
|
|
868
|
-
return true;
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
function useSlashCommands(session, addMessage, setMessages, exit, registry) {
|
|
873
|
-
return (0, import_react5.useCallback)(
|
|
874
|
-
async (input) => {
|
|
875
|
-
const parts = input.slice(1).split(/\s+/);
|
|
876
|
-
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
877
|
-
return executeSlashCommand(cmd, parts, session, addMessage, setMessages, exit, registry);
|
|
878
|
-
},
|
|
879
|
-
[session, addMessage, setMessages, exit, registry]
|
|
880
|
-
);
|
|
881
|
-
}
|
|
882
|
-
function StreamingIndicator({ text }) {
|
|
883
|
-
if (text) {
|
|
884
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
|
|
885
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { color: "cyan", bold: true, children: [
|
|
886
|
-
"Robota:",
|
|
887
|
-
" "
|
|
888
|
-
] }),
|
|
889
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { children: " " }),
|
|
890
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { wrap: "wrap", children: renderMarkdown(text) }) })
|
|
891
|
-
] });
|
|
892
|
-
}
|
|
893
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "yellow", children: "Thinking..." });
|
|
894
|
-
}
|
|
895
|
-
async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextPercentage) {
|
|
896
|
-
setIsThinking(true);
|
|
897
|
-
clearStreamingText();
|
|
898
|
-
const historyBefore = session.getHistory().length;
|
|
899
|
-
try {
|
|
900
|
-
const response = await session.run(prompt);
|
|
901
|
-
clearStreamingText();
|
|
902
|
-
const history = session.getHistory();
|
|
903
|
-
const toolLines = [];
|
|
904
|
-
for (let i = historyBefore; i < history.length; i++) {
|
|
905
|
-
const msg = history[i];
|
|
906
|
-
if (msg.role === "assistant" && msg.toolCalls) {
|
|
907
|
-
for (const tc of msg.toolCalls) {
|
|
908
|
-
let value = "";
|
|
909
|
-
try {
|
|
910
|
-
const parsed = JSON.parse(tc.function.arguments);
|
|
911
|
-
const firstVal = Object.values(parsed)[0];
|
|
912
|
-
value = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal);
|
|
913
|
-
} catch {
|
|
914
|
-
value = tc.function.arguments;
|
|
915
|
-
}
|
|
916
|
-
const truncated = value.length > 80 ? value.slice(0, 77) + "..." : value;
|
|
917
|
-
toolLines.push(`${tc.function.name}(${truncated})`);
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
if (toolLines.length > 0) {
|
|
922
|
-
addMessage({ role: "tool", content: toolLines.join("\n"), toolName: `${toolLines.length} tools` });
|
|
923
|
-
}
|
|
924
|
-
addMessage({ role: "assistant", content: response || "(empty response)" });
|
|
925
|
-
setContextPercentage(session.getContextState().usedPercentage);
|
|
926
|
-
} catch (err) {
|
|
927
|
-
clearStreamingText();
|
|
928
|
-
if (err instanceof DOMException && err.name === "AbortError") {
|
|
929
|
-
addMessage({ role: "system", content: "Cancelled." });
|
|
930
|
-
} else {
|
|
931
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
932
|
-
addMessage({ role: "system", content: `Error: ${errMsg}` });
|
|
933
|
-
}
|
|
934
|
-
} finally {
|
|
935
|
-
setIsThinking(false);
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
function buildSkillPrompt(input, registry) {
|
|
939
|
-
const parts = input.slice(1).split(/\s+/);
|
|
940
|
-
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
941
|
-
const skillCmd = registry.getCommands().find((c) => c.name === cmd && c.source === "skill");
|
|
942
|
-
if (!skillCmd) return null;
|
|
943
|
-
const args = parts.slice(1).join(" ").trim();
|
|
944
|
-
return args ? `Use the "${cmd}" skill: ${args}` : `Use the "${cmd}" skill: ${skillCmd.description}`;
|
|
945
|
-
}
|
|
946
|
-
function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextPercentage, registry) {
|
|
947
|
-
return (0, import_react5.useCallback)(
|
|
948
|
-
async (input) => {
|
|
949
|
-
if (input.startsWith("/")) {
|
|
950
|
-
const handled = await handleSlashCommand(input);
|
|
951
|
-
if (handled) {
|
|
952
|
-
setContextPercentage(session.getContextState().usedPercentage);
|
|
953
|
-
return;
|
|
954
|
-
}
|
|
955
|
-
const prompt = buildSkillPrompt(input, registry);
|
|
956
|
-
if (!prompt) return;
|
|
957
|
-
return runSessionPrompt(
|
|
958
|
-
prompt,
|
|
959
|
-
session,
|
|
960
|
-
addMessage,
|
|
961
|
-
clearStreamingText,
|
|
962
|
-
setIsThinking,
|
|
963
|
-
setContextPercentage
|
|
964
|
-
);
|
|
965
|
-
}
|
|
966
|
-
addMessage({ role: "user", content: input });
|
|
967
|
-
return runSessionPrompt(
|
|
968
|
-
input,
|
|
969
|
-
session,
|
|
970
|
-
addMessage,
|
|
971
|
-
clearStreamingText,
|
|
972
|
-
setIsThinking,
|
|
973
|
-
setContextPercentage
|
|
974
|
-
);
|
|
975
|
-
},
|
|
976
|
-
[
|
|
977
|
-
session,
|
|
978
|
-
addMessage,
|
|
979
|
-
handleSlashCommand,
|
|
980
|
-
clearStreamingText,
|
|
981
|
-
setIsThinking,
|
|
982
|
-
setContextPercentage,
|
|
983
|
-
registry
|
|
984
|
-
]
|
|
985
|
-
);
|
|
986
|
-
}
|
|
987
|
-
function useCommandRegistry(cwd) {
|
|
988
|
-
const registryRef = (0, import_react5.useRef)(null);
|
|
989
|
-
if (registryRef.current === null) {
|
|
990
|
-
const registry = new CommandRegistry();
|
|
991
|
-
registry.addSource(new BuiltinCommandSource());
|
|
992
|
-
registry.addSource(new SkillCommandSource(cwd));
|
|
993
|
-
registryRef.current = registry;
|
|
994
|
-
}
|
|
995
|
-
return registryRef.current;
|
|
996
|
-
}
|
|
997
|
-
function App(props) {
|
|
998
|
-
const { exit } = (0, import_ink8.useApp)();
|
|
999
|
-
const { session, permissionRequest, streamingText, clearStreamingText } = useSession(props);
|
|
1000
|
-
const { messages, setMessages, addMessage } = useMessages();
|
|
1001
|
-
const [isThinking, setIsThinking] = (0, import_react5.useState)(false);
|
|
1002
|
-
const [contextPercentage, setContextPercentage] = (0, import_react5.useState)(0);
|
|
1003
|
-
const registry = useCommandRegistry(props.cwd ?? process.cwd());
|
|
1004
|
-
const handleSlashCommand = useSlashCommands(session, addMessage, setMessages, exit, registry);
|
|
1005
|
-
const handleSubmit = useSubmitHandler(
|
|
1006
|
-
session,
|
|
1007
|
-
addMessage,
|
|
1008
|
-
handleSlashCommand,
|
|
1009
|
-
clearStreamingText,
|
|
1010
|
-
setIsThinking,
|
|
1011
|
-
setContextPercentage,
|
|
1012
|
-
registry
|
|
1013
|
-
);
|
|
1014
|
-
(0, import_ink8.useInput)(
|
|
1015
|
-
(_input, key) => {
|
|
1016
|
-
if (key.ctrl && _input === "c") exit();
|
|
1017
|
-
if (key.escape && isThinking) session.abort();
|
|
1018
|
-
},
|
|
1019
|
-
{ isActive: !permissionRequest }
|
|
1020
|
-
);
|
|
1021
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
|
|
1022
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
1023
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { color: "cyan", bold: true, children: `
|
|
1024
|
-
____ ___ ____ ___ _____ _
|
|
1025
|
-
| _ \\ / _ \\| __ ) / _ \\_ _|/ \\
|
|
1026
|
-
| |_) | | | | _ \\| | | || | / _ \\
|
|
1027
|
-
| _ <| |_| | |_) | |_| || |/ ___ \\
|
|
1028
|
-
|_| \\_\\\\___/|____/ \\___/ |_/_/ \\_\\
|
|
1029
|
-
` }),
|
|
1030
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Text, { dimColor: true, children: [
|
|
1031
|
-
" v",
|
|
1032
|
-
props.version ?? "0.0.0"
|
|
1033
|
-
] })
|
|
1034
|
-
] }),
|
|
1035
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
1036
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MessageList, { messages }),
|
|
1037
|
-
isThinking && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StreamingIndicator, { text: streamingText }) })
|
|
1038
|
-
] }),
|
|
1039
|
-
permissionRequest && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PermissionPrompt, { request: permissionRequest }),
|
|
1040
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1041
|
-
StatusBar,
|
|
1042
|
-
{
|
|
1043
|
-
permissionMode: session.getPermissionMode(),
|
|
1044
|
-
modelName: props.config.provider.model,
|
|
1045
|
-
sessionId: session.getSessionId(),
|
|
1046
|
-
messageCount: messages.length,
|
|
1047
|
-
isThinking,
|
|
1048
|
-
contextPercentage,
|
|
1049
|
-
contextUsedTokens: session.getContextState().usedTokens,
|
|
1050
|
-
contextMaxTokens: session.getContextState().maxTokens
|
|
1051
|
-
}
|
|
1052
|
-
),
|
|
1053
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1054
|
-
InputArea,
|
|
1055
|
-
{
|
|
1056
|
-
onSubmit: handleSubmit,
|
|
1057
|
-
isDisabled: isThinking || !!permissionRequest,
|
|
1058
|
-
registry
|
|
1059
|
-
}
|
|
1060
|
-
)
|
|
1061
|
-
] });
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
// src/ui/render.tsx
|
|
1065
|
-
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1066
|
-
function renderApp(options) {
|
|
1067
|
-
process.on("unhandledRejection", (reason) => {
|
|
1068
|
-
process.stderr.write(`
|
|
1069
|
-
[UNHANDLED REJECTION] ${reason}
|
|
1070
|
-
`);
|
|
1071
|
-
if (reason instanceof Error) {
|
|
1072
|
-
process.stderr.write(`${reason.stack}
|
|
1073
|
-
`);
|
|
1074
|
-
}
|
|
1075
|
-
});
|
|
1076
|
-
const instance = (0, import_ink9.render)(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(App, { ...options }), {
|
|
1077
|
-
exitOnCtrlC: true
|
|
1078
|
-
});
|
|
1079
|
-
instance.waitUntilExit().catch((err) => {
|
|
1080
|
-
if (err) {
|
|
1081
|
-
process.stderr.write(`
|
|
1082
|
-
[EXIT ERROR] ${err}
|
|
1083
|
-
`);
|
|
1084
|
-
}
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
// src/cli.ts
|
|
1089
|
-
var import_meta = {};
|
|
1090
|
-
var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
1091
|
-
function readVersion() {
|
|
1092
|
-
try {
|
|
1093
|
-
const thisFile = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
1094
|
-
const dir = (0, import_node_path2.dirname)(thisFile);
|
|
1095
|
-
const candidates = [(0, import_node_path2.join)(dir, "..", "..", "package.json"), (0, import_node_path2.join)(dir, "..", "package.json")];
|
|
1096
|
-
for (const pkgPath of candidates) {
|
|
1097
|
-
try {
|
|
1098
|
-
const raw = (0, import_node_fs2.readFileSync)(pkgPath, "utf-8");
|
|
1099
|
-
const pkg = JSON.parse(raw);
|
|
1100
|
-
if (pkg.version !== void 0 && pkg.name !== void 0) {
|
|
1101
|
-
return pkg.version;
|
|
1102
|
-
}
|
|
1103
|
-
} catch {
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
return "0.0.0";
|
|
1107
|
-
} catch {
|
|
1108
|
-
return "0.0.0";
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
function parsePermissionMode(raw) {
|
|
1112
|
-
if (raw === void 0) return void 0;
|
|
1113
|
-
if (!VALID_MODES.includes(raw)) {
|
|
1114
|
-
process.stderr.write(`Invalid --permission-mode "${raw}". Valid: ${VALID_MODES.join(" | ")}
|
|
1115
|
-
`);
|
|
1116
|
-
process.exit(1);
|
|
1117
|
-
}
|
|
1118
|
-
return raw;
|
|
1119
|
-
}
|
|
1120
|
-
function parseMaxTurns(raw) {
|
|
1121
|
-
if (raw === void 0) return void 0;
|
|
1122
|
-
const n = parseInt(raw, 10);
|
|
1123
|
-
if (isNaN(n) || n <= 0) {
|
|
1124
|
-
process.stderr.write(`Invalid --max-turns "${raw}". Must be a positive integer.
|
|
1125
|
-
`);
|
|
1126
|
-
process.exit(1);
|
|
1127
|
-
}
|
|
1128
|
-
return n;
|
|
1129
|
-
}
|
|
1130
|
-
function parseCliArgs() {
|
|
1131
|
-
const { values, positionals } = (0, import_node_util.parseArgs)({
|
|
1132
|
-
allowPositionals: true,
|
|
1133
|
-
options: {
|
|
1134
|
-
p: { type: "boolean", short: "p", default: false },
|
|
1135
|
-
c: { type: "boolean", short: "c", default: false },
|
|
1136
|
-
r: { type: "string", short: "r" },
|
|
1137
|
-
model: { type: "string" },
|
|
1138
|
-
"permission-mode": { type: "string" },
|
|
1139
|
-
"max-turns": { type: "string" },
|
|
1140
|
-
version: { type: "boolean", default: false }
|
|
1141
|
-
}
|
|
1142
|
-
});
|
|
1143
|
-
return {
|
|
1144
|
-
positional: positionals,
|
|
1145
|
-
printMode: values["p"] ?? false,
|
|
1146
|
-
continueMode: values["c"] ?? false,
|
|
1147
|
-
resumeId: values["r"],
|
|
1148
|
-
model: values["model"],
|
|
1149
|
-
permissionMode: parsePermissionMode(values["permission-mode"]),
|
|
1150
|
-
maxTurns: parseMaxTurns(values["max-turns"]),
|
|
1151
|
-
version: values["version"] ?? false
|
|
1152
|
-
};
|
|
1153
|
-
}
|
|
1154
|
-
var PrintTerminal = class {
|
|
1155
|
-
write(text) {
|
|
1156
|
-
process.stdout.write(text);
|
|
1157
|
-
}
|
|
1158
|
-
writeLine(text) {
|
|
1159
|
-
process.stdout.write(text + "\n");
|
|
1160
|
-
}
|
|
1161
|
-
writeMarkdown(md) {
|
|
1162
|
-
process.stdout.write(md);
|
|
1163
|
-
}
|
|
1164
|
-
writeError(text) {
|
|
1165
|
-
process.stderr.write(text + "\n");
|
|
1166
|
-
}
|
|
1167
|
-
prompt(question) {
|
|
1168
|
-
return new Promise((resolve) => {
|
|
1169
|
-
const rl = readline.createInterface({
|
|
1170
|
-
input: process.stdin,
|
|
1171
|
-
output: process.stdout,
|
|
1172
|
-
terminal: false,
|
|
1173
|
-
historySize: 0
|
|
1174
|
-
});
|
|
1175
|
-
rl.question(question, (answer) => {
|
|
1176
|
-
rl.close();
|
|
1177
|
-
resolve(answer);
|
|
1178
|
-
});
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
async select(options, initialIndex = 0) {
|
|
1182
|
-
for (let i = 0; i < options.length; i++) {
|
|
1183
|
-
const marker = i === initialIndex ? ">" : " ";
|
|
1184
|
-
process.stdout.write(` ${marker} ${i + 1}) ${options[i]}
|
|
1185
|
-
`);
|
|
1186
|
-
}
|
|
1187
|
-
const answer = await this.prompt(
|
|
1188
|
-
` Choose [1-${options.length}] (default: ${options[initialIndex]}): `
|
|
1189
|
-
);
|
|
1190
|
-
const trimmed = answer.trim().toLowerCase();
|
|
1191
|
-
if (trimmed === "") return initialIndex;
|
|
1192
|
-
const num = parseInt(trimmed, 10);
|
|
1193
|
-
if (!isNaN(num) && num >= 1 && num <= options.length) return num - 1;
|
|
1194
|
-
return initialIndex;
|
|
1195
|
-
}
|
|
1196
|
-
spinner(_message) {
|
|
1197
|
-
return { stop() {
|
|
1198
|
-
}, update() {
|
|
1199
|
-
} };
|
|
1200
|
-
}
|
|
1201
|
-
};
|
|
1202
|
-
async function startCli() {
|
|
1203
|
-
const args = parseCliArgs();
|
|
1204
|
-
if (args.version) {
|
|
1205
|
-
process.stdout.write(`robota ${readVersion()}
|
|
1206
|
-
`);
|
|
1207
|
-
return;
|
|
1208
|
-
}
|
|
1209
|
-
const cwd = process.cwd();
|
|
1210
|
-
const [config, context, projectInfo] = await Promise.all([
|
|
1211
|
-
(0, import_agent_sdk2.loadConfig)(cwd),
|
|
1212
|
-
(0, import_agent_sdk2.loadContext)(cwd),
|
|
1213
|
-
(0, import_agent_sdk2.detectProject)(cwd)
|
|
1214
|
-
]);
|
|
1215
|
-
if (args.model !== void 0) {
|
|
1216
|
-
config.provider.model = args.model;
|
|
1217
|
-
}
|
|
1218
|
-
const sessionStore = new import_agent_sdk2.SessionStore();
|
|
1219
|
-
if (args.printMode) {
|
|
1220
|
-
const prompt = args.positional.join(" ").trim();
|
|
1221
|
-
if (prompt.length === 0) {
|
|
1222
|
-
process.stderr.write("Print mode (-p) requires a prompt argument.\n");
|
|
1223
|
-
process.exit(1);
|
|
1224
|
-
}
|
|
1225
|
-
const terminal = new PrintTerminal();
|
|
1226
|
-
const paths = (0, import_agent_sdk2.projectPaths)(cwd);
|
|
1227
|
-
const session = (0, import_agent_sdk2.createSession)({
|
|
1228
|
-
config,
|
|
1229
|
-
context,
|
|
1230
|
-
terminal,
|
|
1231
|
-
sessionLogger: new import_agent_sdk2.FileSessionLogger(paths.logs),
|
|
1232
|
-
projectInfo,
|
|
1233
|
-
permissionMode: args.permissionMode,
|
|
1234
|
-
promptForApproval
|
|
1235
|
-
});
|
|
1236
|
-
const response = await session.run(prompt);
|
|
1237
|
-
process.stdout.write(response + "\n");
|
|
1238
|
-
return;
|
|
1239
|
-
}
|
|
1240
|
-
renderApp({
|
|
1241
|
-
config,
|
|
1242
|
-
context,
|
|
1243
|
-
projectInfo,
|
|
1244
|
-
sessionStore,
|
|
1245
|
-
permissionMode: args.permissionMode,
|
|
1246
|
-
maxTurns: args.maxTurns,
|
|
1247
|
-
version: readVersion()
|
|
1248
|
-
});
|
|
1249
|
-
}
|
|
1250
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1251
|
-
0 && (module.exports = {
|
|
1252
|
-
Session,
|
|
1253
|
-
SessionStore,
|
|
1254
|
-
TRUST_TO_MODE,
|
|
1255
|
-
query,
|
|
1256
|
-
startCli
|
|
1257
|
-
});
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`node:child_process`),t=require(`@robota-sdk/agent-transport/headless`),n=require(`@robota-sdk/agent-framework`),r=require(`node:util`),i=require(`@robota-sdk/agent-core`),a=require(`@robota-sdk/agent-provider`),o=require(`@robota-sdk/agent-command`),s=require(`@robota-sdk/agent-transport/tui`),c=require(`@robota-sdk/agent-transport`),l=require(`@robota-sdk/agent-executor`),u=require(`@robota-sdk/agent-subagent-runner`),d=require(`node:fs`),f=require(`node:path`);const p=[`plan`,`default`,`acceptEdits`,`bypassPermissions`],m=[`text`,`json`,`stream-json`];function h(){return`
|
|
2
|
+
Usage: robota [options] [-p <prompt>]
|
|
3
|
+
|
|
4
|
+
Options:
|
|
5
|
+
-p <prompt> Run in print (headless) mode with the given prompt
|
|
6
|
+
--output-format <format> Output format: text | json | stream-json (default: text)
|
|
7
|
+
--system-prompt <text> Override the system prompt for this session
|
|
8
|
+
--append-system-prompt <t> Append text to the system prompt
|
|
9
|
+
--language <lang> Language preference (e.g. ko, en)
|
|
10
|
+
--no-session-persistence Disable session persistence for this run
|
|
11
|
+
--permission-mode <mode> Permission mode: plan | default | acceptEdits | bypassPermissions
|
|
12
|
+
--max-turns <n> Maximum agent turns before stopping
|
|
13
|
+
-c, --continue Continue the most recent session
|
|
14
|
+
-r, --resume <id> Resume a session by ID or name
|
|
15
|
+
-n, --name <name> Name for the new session
|
|
16
|
+
--fork-session Fork the current session into a new independent session
|
|
17
|
+
--task-file <path> Read a task prompt from file and append it to the system prompt
|
|
18
|
+
--bare Print mode: output raw text only, no formatting wrapper
|
|
19
|
+
--configure Run interactive provider configuration
|
|
20
|
+
--configure-provider <n> Configure a specific provider
|
|
21
|
+
--dry-run Plan-only run: show what the agent would do without modifying files
|
|
22
|
+
--check-update Check for CLI updates
|
|
23
|
+
--version Show version number
|
|
24
|
+
-h, --help Show this help message
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
robota init Initialize AGENTS.md and .robota/settings.json
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
robota Start interactive TUI session
|
|
31
|
+
robota init Initialize project files
|
|
32
|
+
robota -p "Hello" Print mode: send prompt and exit
|
|
33
|
+
robota -p "Hello" --output-format json
|
|
34
|
+
robota -p "Review this diff" --bare Raw output for shell pipelines
|
|
35
|
+
robota --task-file task.md Run task from file (appended to system prompt)
|
|
36
|
+
robota --dry-run "Refactor the auth module" Show plan without modifying files
|
|
37
|
+
robota --continue Resume the last session
|
|
38
|
+
`}function g(e){if(e!==void 0){if(!m.includes(e))throw Error(`Invalid --output-format "${e}". Valid: ${m.join(` | `)}`);return e}}function _(e){if(e!==void 0){if(!p.includes(e))throw Error(`Invalid --permission-mode "${e}". Valid: ${p.join(` | `)}`);return e}}function v(e){if(e===void 0)return;let t=parseInt(e,10);if(isNaN(t)||t<=0)throw Error(`Invalid --max-turns "${e}". Must be a positive integer.`);return t}const y={allowPositionals:!0,options:{help:{type:`boolean`,short:`h`,default:!1},p:{type:`boolean`,short:`p`,default:!1},continue:{type:`boolean`,short:`c`,default:!1},resume:{type:`string`,short:`r`},language:{type:`string`},"permission-mode":{type:`string`},"max-turns":{type:`string`},"fork-session":{type:`boolean`,default:!1},name:{type:`string`,short:`n`},"output-format":{type:`string`},format:{type:`string`},summary:{type:`string`},source:{type:`string`},"system-prompt":{type:`string`},"append-system-prompt":{type:`string`},"task-file":{type:`string`},version:{type:`boolean`,default:!1},reset:{type:`boolean`,default:!1},bare:{type:`boolean`,default:!1},"allowed-tools":{type:`string`},"denied-tools":{type:`string`},model:{type:`string`},"no-session-persistence":{type:`boolean`,default:!1},"json-schema":{type:`string`},configure:{type:`boolean`,default:!1},"configure-provider":{type:`string`},provider:{type:`string`},type:{type:`string`},"base-url":{type:`string`},"api-key":{type:`string`},"api-key-env":{type:`string`},"set-current":{type:`boolean`,default:!1},"settings-scope":{type:`string`},"check-update":{type:`boolean`,default:!1},"disable-update-check":{type:`boolean`,default:!1},"dry-run":{type:`boolean`,default:!1},yes:{type:`boolean`,short:`y`,default:!1}}};function b(e,t){return{positional:t,help:e.help??!1,printMode:e.p??!1,continueMode:e.continue??!1,resumeId:e.resume,language:e.language,permissionMode:_(e[`permission-mode`]),maxTurns:v(e[`max-turns`]),forkSession:e[`fork-session`]??!1,sessionName:e.name,outputFormat:g(e[`output-format`]),format:e.format,summary:e.summary,source:e.source,systemPrompt:e[`system-prompt`],appendSystemPrompt:e[`append-system-prompt`],taskFile:e[`task-file`],version:e.version??!1,reset:e.reset??!1,bare:e.bare??!1,allowedTools:e[`allowed-tools`],deniedTools:e[`denied-tools`],model:e.model,noSessionPersistence:e[`no-session-persistence`]??!1,jsonSchema:e[`json-schema`],configure:e.configure??!1,configureProvider:e[`configure-provider`],provider:e.provider,providerType:e.type,baseURL:e[`base-url`],apiKey:e[`api-key`],apiKeyEnv:e[`api-key-env`],setCurrent:e[`set-current`]??!1,settingsScope:e[`settings-scope`],checkUpdate:e[`check-update`]??!1,disableUpdateCheck:e[`disable-update-check`]??!1,dryRun:e[`dry-run`]??!1,yes:e.yes??!1}}function x(){let{values:e,positionals:t}=(0,r.parseArgs)(y);return b(e,t)}function S(e){if(e===void 0||e===`user`||e===`project-local`)return e;throw Error(`Invalid --settings-scope "${e}". Valid: user | project-local`)}function C(e,t,r,i=(0,a.createDefaultProviderDefinitions)()){let o=(0,n.resolveSettingsPathForScope)(e,S(t.settingsScope));return t.configureProvider?((0,n.applyProviderConfiguration)(o,E(t),{providerDefinitions:i}),r.writeLine(`Provider profile saved to ${o}`),!t.printMode&&t.positional.length===0):t.provider&&t.setCurrent?((0,n.applyProviderSwitch)(t.settingsScope===void 0?(0,n.resolveProviderSettingsWriteTargetPath)(e):o,t.provider,{knownProviders:(0,n.readMergedProviderSettings)(e).providers}),r.writeLine(`Current provider set to ${t.provider}`),!t.printMode&&t.positional.length===0):!1}async function w(e,t,n,r,i=(0,a.createDefaultProviderDefinitions)(),s){await(0,o.ensureProviderConfig)(e,{provider:t.provider,settingsScope:S(t.settingsScope)},n,r,i,{formatError:D,isInteractive:s===void 0?()=>process.stdin.isTTY===!0&&process.stdout.isTTY===!0:()=>s})}async function T(e,t,n,r,i=(0,a.createDefaultProviderDefinitions)()){await(0,o.runProviderStartupSetup)(e,{settingsScope:S(t.settingsScope)},n,r,i)}function E(e){let t=e.providerType??e.configureProvider;if(!e.configureProvider||!t)throw Error(`--configure-provider requires a provider profile and --type`);return{profile:e.configureProvider,type:t,...e.model!==void 0&&{model:e.model},...e.apiKey!==void 0&&{apiKey:e.apiKey},...e.apiKeyEnv!==void 0&&{apiKeyEnv:e.apiKeyEnv},...e.baseURL!==void 0&&{baseURL:e.baseURL},setCurrent:e.setCurrent}}function D(e=(0,a.createDefaultProviderDefinitions)()){return[`No provider configuration found.`,"Run `robota --configure` in an interactive terminal, or configure a provider:",`Supported providers: ${(0,i.formatSupportedProviderTypes)(e)}`,...e.map(O)].join(`
|
|
39
|
+
`)}function O(e){return` ${[`robota --configure-provider ${e.type}`,`--type ${e.type}`,...e.defaults?.baseURL===void 0?[]:[`--base-url <url>`],`--model <model>`,...e.requiresApiKey===!0?[`--api-key-env <ENV_NAME>`]:[],`--set-current`].join(` `)}`}async function k(e,t,n){if(e.positional[0]!==`user-local`)return!1;let r=await(0,o.executeUserLocalDirectCommand)({cwd:t,argv:e.positional.slice(1),format:e.format,summary:e.summary,source:e.source}),i=r.message.trimEnd();if(!r.success)throw Error(i);return n.writeLine(i),!0}function A(e){let t=(0,d.readFileSync)(e,`utf-8`);return JSON.parse(t)}function j(e,t){return new Date(t).getTime()-new Date(e).getTime()}function M(e){let t=[],n=0,r=0;for(;r<e.length;){let i=e[r];if(!i){r++;continue}if(i.category===`chat`&&i.type===`user`){n++;let a=i.timestamp,o=!1,s=null,c=r+1;for(;c<e.length;){let r=e[c];if(!r){c++;continue}if(r.category===`chat`&&r.type===`user`)break;if(r.category===`event`&&r.type===`tool-start`){o?s!==null&&t.push(N(`llm_between_tools`,`tool-end`,`tool-start`,s,r.timestamp,n)):(t.push(N(`user_to_first_tool`,`user`,`tool-start`,a,r.timestamp,n)),o=!0),s=null,c++;continue}if(r.category===`event`&&r.type===`tool-end`){let i=e[c-1];i&&i.category===`event`&&i.type===`tool-start`&&t.push(N(`tool_exec`,`tool-start`,`tool-end`,i.timestamp,r.timestamp,n)),s=r.timestamp,c++;continue}if(r.category===`event`&&r.type===`tool-summary`){s!==null&&t.push(N(`llm_final_response`,`tool-end`,`tool-summary`,s,r.timestamp,n)),c++;continue}if(r.category===`chat`&&r.type===`assistant`){o?s!==null&&t.push(N(`llm_final_response`,`tool-end`,`assistant`,s,r.timestamp,n)):t.push(N(`user_to_assistant`,`user`,`assistant`,a,r.timestamp,n)),c++;break}c++}r=c}else r++}return t}function N(e,t,n,r,i,a){return{kind:e,fromType:t,toType:n,fromTimestamp:r,toTimestamp:i,durationMs:j(r,i),turnIndex:a}}function P(e){let t=e.filter(e=>e.kind===`user_to_first_tool`||e.kind===`user_to_assistant`||e.kind===`llm_between_tools`||e.kind===`llm_final_response`),n=e.filter(e=>e.kind===`tool_exec`),r=e.filter(e=>e.kind===`user_to_assistant`),i=e=>e.length?Math.round(e.reduce((e,t)=>e+t.durationMs,0)/e.length):0,a=e=>e.length?Math.max(...e.map(e=>e.durationMs)):0;return{llmWaitMs:{avg:i(t),max:a(t),total:t.reduce((e,t)=>e+t.durationMs,0),count:t.length},toolExecMs:{avg:i(n),max:a(n),median:(e=>{if(!e.length)return 0;let t=[...e].sort((e,t)=>e.durationMs-t.durationMs),n=Math.floor(t.length/2);return t.length%2==0?Math.round(((t[n-1]?.durationMs??0)+(t[n]?.durationMs??0))/2):t[n]?.durationMs??0})(n),count:n.length},userToAssistantMs:{avg:i(r),max:a(r),count:r.length}}}function F(e){let t=M(e.history??[]),n=t.filter(e=>e.durationMs>=1e4);return{sessionId:e.id,cwd:e.cwd,createdAt:e.createdAt,totalIntervals:t.length,intervals:t,slowIntervals:n,stats:P(t)}}function I(e){return e>=1e3?`${(e/1e3).toFixed(1)}s`:`${e}ms`}function L(e){return new Date(e).toLocaleString(`sv-SE`,{timeZoneName:`short`}).slice(0,16)}function R(e){return{user_to_first_tool:`user → tool-start`,user_to_assistant:`user → assistant`,tool_exec:`tool-start → tool-end`,llm_between_tools:`tool-end → tool-start`,llm_final_response:`tool-end → assistant/summary`}[e.kind]??e.kind}function z(e){let{stats:t}=e,n=t.llmWaitMs.total+t.toolExecMs.avg*t.toolExecMs.count;if(n===0)return`Verdict: No timing data available.`;let r=Math.round(t.llmWaitMs.total/n*100);return`Verdict: LLM API wait ${r}% | Code processing ${100-r}%`}function B(e){let t=[],{stats:n}=e;if(t.push(`Session: ${e.sessionId}`),t.push(`Created: ${L(e.createdAt)} | cwd: ${e.cwd}`),t.push(``),t.push(`Timing Summary:`),n.llmWaitMs.count>0&&t.push(` LLM API wait ${I(n.llmWaitMs.avg).padStart(8)} avg | ${I(n.llmWaitMs.max).padStart(8)} max`),n.toolExecMs.count>0&&t.push(` Tool execution ${I(n.toolExecMs.avg).padStart(8)} avg | ${I(n.toolExecMs.median).padStart(8)} median`),n.userToAssistantMs.count>0&&t.push(` user → assistant ${I(n.userToAssistantMs.avg).padStart(8)} avg`),n.llmWaitMs.count===0&&n.toolExecMs.count===0&&t.push(` (no intervals computed — session may have no history)`),e.slowIntervals.length>0){t.push(``),t.push(`Slow intervals (>10s):`);for(let n of e.slowIntervals)t.push(` turn ${n.turnIndex} ${R(n).padEnd(32)} ${I(n.durationMs).padStart(8)}`)}return t.push(``),t.push(z(e)),t.join(`
|
|
40
|
+
`)}function V(e){let t=[];return t.push(`Analyzed ${e.sessionCount} sessions (${L(e.fromDate)} ~ ${L(e.toDate)})`),t.push(` Avg LLM response: ${I(e.avgLlmResponseMs)}`),t.push(` Avg tool exec: ${I(e.avgToolExecMs)}`),e.maxSingleDelayMs>0&&t.push(` Max single delay: ${I(e.maxSingleDelayMs)} (${e.maxSingleDelaySession}, turn ${e.maxSingleDelayTurn}, ${e.maxSingleDelayKind})`),t.join(`
|
|
41
|
+
`)}function H(e){let t,n;for(let r=0;r<e.length;r++)if(e[r]===`--last`&&e[r+1]){let n=parseInt(e[r+1],10);!isNaN(n)&&n>0&&(t=n),r++}else e[r]===`--session`&&e[r+1]&&(n=e[r+1],r++);return{last:t,sessionId:n}}function U(e){try{return(0,d.readdirSync)(e).filter(e=>e.endsWith(`.json`)).map(t=>(0,f.join)(e,t)).sort()}catch{return[]}}function W(e){let t=e.flatMap(e=>e.intervals.filter(e=>e.kind===`user_to_first_tool`||e.kind===`user_to_assistant`||e.kind===`llm_between_tools`||e.kind===`llm_final_response`)),n=e.flatMap(e=>e.intervals.filter(e=>e.kind===`tool_exec`)),r=t.length?Math.round(t.reduce((e,t)=>e+t.durationMs,0)/t.length):0,i=n.length?Math.round(n.reduce((e,t)=>e+t.durationMs,0)/n.length):0,a=0,o=``,s=0,c=``;for(let t of e)for(let e of t.intervals)e.durationMs>a&&(a=e.durationMs,o=t.sessionId,s=e.turnIndex,c=e.kind);let l=e.map(e=>e.createdAt).sort();return{sessionCount:e.length,fromDate:l[0]??``,toDate:l[l.length-1]??``,avgLlmResponseMs:r,avgToolExecMs:i,maxSingleDelayMs:a,maxSingleDelaySession:o,maxSingleDelayTurn:s,maxSingleDelayKind:c}}async function G(e){let t=H(e),r=(0,n.userPaths)().sessions,i=U(r);if(i.length===0&&(process.stderr.write(`No session files found in ${r}\n`),process.exit(1)),t.sessionId!==void 0){let e=i.find(e=>e.includes(t.sessionId));e||(process.stderr.write(`Session not found: ${t.sessionId}\n`),process.exit(1));let n=F(A(e));process.stdout.write(B(n)+`
|
|
42
|
+
`);return}if(t.last!==void 0){let e=i.slice(-t.last),n=[];for(let t of e)try{n.push(F(A(t)))}catch{}n.length===0&&(process.stderr.write(`No valid sessions found.
|
|
43
|
+
`),process.exit(1));let r=W(n);process.stdout.write(V(r)+`
|
|
44
|
+
`);return}let a=i[i.length-1];a||(process.stderr.write(`No sessions found.
|
|
45
|
+
`),process.exit(1));let o=F(A(a));process.stdout.write(B(o)+`
|
|
46
|
+
`)}const K=()=>(0,n.readPackageVersion)(require(`url`).pathToFileURL(__filename).href);function q(e){let t=(0,n.resetUserConfig)();t.deleted?e.writeLine(`Deleted ${t.path}`):e.writeLine(`No user settings found.`)}function J(e,t,r,i){let s={settings:{read:()=>(0,n.readSettings)((0,n.getUserSettingsPath)()),write:e=>(0,n.writeSettings)((0,n.getUserSettingsPath)(),e)},plugin:(0,o.createDefaultPluginCommandAdapter)(e)},c=r.providerDefinitions??(0,a.createDefaultProviderDefinitions)();return{commandHostAdapters:s,providerDefinitions:c,commandModules:[...(0,o.createDefaultCommandModules)({cwd:e,providerDefinitions:c,providerSettingsAdapter:{readMergedSettings:()=>(0,n.readMergedProviderSettings)(e),readTargetSettings:()=>(0,n.readSettings)((0,n.resolveProviderSettingsWriteTargetPath)(e)),writeTargetSettings:t=>(0,n.writeSettings)((0,n.resolveProviderSettingsWriteTargetPath)(e),t)}}),...r.commandModules??[]],startupUpdateNoticePromise:(0,n.shouldRunStartupCliUpdateCheck)(t)?(0,n.getStartupCliUpdateNotice)({currentVersion:i}):void 0}}function Y(e,t){let n=(0,d.readFileSync)((0,f.resolve)(e,t),`utf8`).trim();if(n.length===0)throw Error(`Task file is empty: ${t}`);return`Task file (${t}):\n${n}`}function X(e,t){let n=[];if(t.appendSystemPrompt&&n.push(t.appendSystemPrompt),t.taskFile)try{n.push(Y(e,t.taskFile))}catch(e){process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}return t.jsonSchema&&n.push(`Respond with valid JSON only, matching this JSON schema:\n${t.jsonSchema}`),n.length>0?n.join(`
|
|
47
|
+
|
|
48
|
+
`):void 0}async function Z(e,n,r,i,a,o,s,c){let l=n.positional.join(` `).trim();if(!l&&!process.stdin.isTTY){let e=[];for await(let t of process.stdin)e.push(t);l=Buffer.concat(e).toString(`utf-8`).trim()}l||(process.stderr.write(`Print mode (-p) requires a prompt argument.
|
|
49
|
+
`),process.exit(1));let u=X(e,n),d=new t.HeadlessInteractionChannel({cwd:e,provider:r,outputFormat:n.outputFormat??`text`,permissionMode:n.permissionMode??`bypassPermissions`,maxTurns:n.maxTurns,sessionStore:n.noSessionPersistence?void 0:i,sessionName:n.sessionName,bare:n.bare||void 0,allowedTools:n.allowedTools?n.allowedTools.split(`,`).map(e=>e.trim()).filter(e=>e.length>0):void 0,appendSystemPrompt:u,...n.systemPrompt?{systemPrompt:n.systemPrompt}:{},backgroundTaskRunners:a,subagentRunnerFactory:o,commandModules:s,commandHostAdapters:c});await d.run(l),process.exit(d.getExitCode())}async function Q(r={}){let i;try{i=x()}catch(e){process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}let a=K();if(i.help){process.stdout.write(h());return}if(i.version){process.stdout.write(`robota ${a}\n`);return}if(i.checkUpdate){let e=await(0,n.checkForCliUpdate)({currentVersion:a,force:!0}),t=(0,n.formatCliUpdateCheckMessage)(e);e.status===`error`&&(process.stderr.write(`${t}\n`),process.exit(1)),process.stdout.write(`${t}\n`);return}let d=process.cwd(),f=new t.PrintTerminal;if(i.reset){q(f);return}if(i.positional[0]===`session`&&i.positional[1]===`analyze`){await G(process.argv.slice(4));return}try{if(await k(i,d,f))return}catch(e){f.writeError(e instanceof Error?e.message:String(e)),process.exit(1)}let{commandHostAdapters:p,providerDefinitions:m,commandModules:g,startupUpdateNoticePromise:_}=J(d,i,r,a);if(i.configure){await T(d,i,t.promptInput,f,m);return}if(C(d,i,f,m))return;try{await w(d,i,t.promptInput,f,m)}catch(e){process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}let v=i.provider?{providerOverride:i.provider,providerDefinitions:m}:{providerDefinitions:m},y=(0,n.readProviderSettings)(d,v),b=i.model??y.model,S=(0,n.createProviderFromSettings)(d,i.model,v),E=(0,l.createDefaultBackgroundTaskRunners)(),D=(0,n.projectPaths)(d),O=(0,u.createChildProcessSubagentRunnerFactory)({workerPath:(0,u.getDefaultSubagentWorkerPath)(),providerConfig:{...y,model:b},logsDir:D.logs}),A=(0,n.createProjectSessionStore)(d),j,M=!1;if(i.continueMode?j=(0,n.resolveLatestSessionId)(A,d):i.resumeId!==void 0&&(i.resumeId===``?M=!0:(j=(0,n.resolveSessionIdByIdOrName)(A,i.resumeId),j===void 0&&(process.stderr.write(`Session not found: ${i.resumeId}\n`),process.exit(1)))),i.printMode){await Z(d,i,S,A,E,O,g,p);return}await(0,s.renderApp)({cwd:d,provider:S,providerOverride:i.provider,providerType:y.name,modelId:b,language:i.language,permissionMode:i.permissionMode,maxTurns:i.maxTurns,version:a,sessionStore:i.noSessionPersistence?void 0:A,resumeSessionId:j,showSessionPickerOnStart:M,forkSession:i.forkSession,sessionName:i.sessionName,backgroundTaskRunners:E,subagentRunnerFactory:O,commandModules:g,commandHostAdapters:p,shellExec:t=>(0,e.execSync)(t,{timeout:5e3,encoding:`utf-8`,stdio:`pipe`}).trimEnd(),startupUpdateNotice:_?_.then(e=>e?(0,n.formatCliUpdateNotice)(e):void 0):void 0,transportRegistry:(0,c.createDefaultTransportRegistry)(),cliAdapter:(0,s.createDefaultTuiCliAdapter)({providerDefinitions:m,reloadPluginCommandSource:o.reloadPluginCommandSource}),reloadPluginCommandSource:o.reloadPluginCommandSource,agentName:`robota-cli`}),process.exit(0)}exports.startCli=Q;
|