@robinpath/cli 1.77.0 → 1.78.0
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/cli.mjs +191 -281
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -18598,7 +18598,7 @@ function getNativeModules() {
|
|
|
18598
18598
|
import { join as join3, basename as basename2 } from "node:path";
|
|
18599
18599
|
import { homedir as homedir2, platform as platform2 } from "node:os";
|
|
18600
18600
|
import { existsSync as existsSync2 } from "node:fs";
|
|
18601
|
-
var CLI_VERSION = true ? "1.
|
|
18601
|
+
var CLI_VERSION = true ? "1.78.0" : "1.78.0";
|
|
18602
18602
|
var FLAG_QUIET = false;
|
|
18603
18603
|
var FLAG_VERBOSE = false;
|
|
18604
18604
|
var FLAG_AUTO_ACCEPT = false;
|
|
@@ -24132,89 +24132,72 @@ ${resultSummary}`
|
|
|
24132
24132
|
}
|
|
24133
24133
|
|
|
24134
24134
|
// src/ink-repl.tsx
|
|
24135
|
-
import { useState,
|
|
24135
|
+
import { useState, useEffect } from "react";
|
|
24136
24136
|
import { render, Box, Text, Static, useInput, useApp } from "ink";
|
|
24137
24137
|
import InkSpinner from "ink-spinner";
|
|
24138
24138
|
import { platform as platform7 } from "node:os";
|
|
24139
24139
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
24140
24140
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
24141
24141
|
var nextId = 0;
|
|
24142
|
-
function
|
|
24143
|
-
const [
|
|
24144
|
-
|
|
24145
|
-
|
|
24142
|
+
function ChatApp({ onMessage }) {
|
|
24143
|
+
const [input, setInput] = useState("");
|
|
24144
|
+
const [messages, setMessages] = useState([]);
|
|
24145
|
+
const [streaming, setStreaming] = useState("");
|
|
24146
|
+
const [loading, setLoading] = useState(false);
|
|
24147
|
+
const { exit } = useApp();
|
|
24148
|
+
useEffect(() => {
|
|
24149
|
+
global.__rpUI = {
|
|
24150
|
+
setStreaming,
|
|
24151
|
+
setLoading,
|
|
24152
|
+
addMessage: (text) => setMessages((prev) => [...prev, { id: ++nextId, text }])
|
|
24153
|
+
};
|
|
24154
|
+
}, []);
|
|
24155
|
+
useInput((character, key) => {
|
|
24156
|
+
if (loading) return;
|
|
24146
24157
|
if (key.return) {
|
|
24147
|
-
if (
|
|
24148
|
-
|
|
24158
|
+
if (!input.trim()) return;
|
|
24159
|
+
if (input.endsWith("\\")) {
|
|
24160
|
+
setInput((prev) => prev.slice(0, -1) + "\n");
|
|
24149
24161
|
return;
|
|
24150
24162
|
}
|
|
24151
|
-
const text =
|
|
24152
|
-
|
|
24153
|
-
|
|
24154
|
-
|
|
24163
|
+
const text = input.trim();
|
|
24164
|
+
setInput("");
|
|
24165
|
+
if (text === "exit" || text === "quit") {
|
|
24166
|
+
exit();
|
|
24167
|
+
return;
|
|
24155
24168
|
}
|
|
24169
|
+
setMessages((prev) => [...prev, { id: ++nextId, text: `\u276F ${text}` }]);
|
|
24170
|
+
setLoading(true);
|
|
24171
|
+
setStreaming("");
|
|
24172
|
+
onMessage(text).then((response) => {
|
|
24173
|
+
if (response) {
|
|
24174
|
+
setMessages((prev) => [...prev, { id: ++nextId, text: response }]);
|
|
24175
|
+
}
|
|
24176
|
+
setLoading(false);
|
|
24177
|
+
setStreaming("");
|
|
24178
|
+
}).catch((err) => {
|
|
24179
|
+
setMessages((prev) => [...prev, { id: ++nextId, text: `Error: ${err.message}` }]);
|
|
24180
|
+
setLoading(false);
|
|
24181
|
+
setStreaming("");
|
|
24182
|
+
});
|
|
24156
24183
|
return;
|
|
24157
24184
|
}
|
|
24158
|
-
if (input
|
|
24159
|
-
|
|
24185
|
+
if (input.length > 0 && (key.backspace || key.delete)) {
|
|
24186
|
+
setInput((prev) => prev.slice(0, -1));
|
|
24160
24187
|
return;
|
|
24161
24188
|
}
|
|
24162
24189
|
if (key.escape) {
|
|
24163
|
-
|
|
24164
|
-
return;
|
|
24165
|
-
}
|
|
24166
|
-
if (key.backspace || key.delete) {
|
|
24167
|
-
setValue((p) => p.slice(0, -1));
|
|
24190
|
+
setInput("");
|
|
24168
24191
|
return;
|
|
24169
24192
|
}
|
|
24170
24193
|
if (key.tab) return;
|
|
24171
|
-
if (
|
|
24172
|
-
|
|
24173
|
-
return;
|
|
24174
|
-
}
|
|
24175
|
-
if (input === "") {
|
|
24176
|
-
setValue((p) => p.replace(/\S+\s*$/, ""));
|
|
24177
|
-
return;
|
|
24194
|
+
if (character && !key.ctrl && !key.meta) {
|
|
24195
|
+
setInput((prev) => prev + character);
|
|
24178
24196
|
}
|
|
24179
|
-
|
|
24180
|
-
|
|
24181
|
-
|
|
24182
|
-
|
|
24183
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
24184
|
-
/* @__PURE__ */ jsx(Box, { borderStyle: "round", borderColor: active ? "cyan" : "gray", flexDirection: "column", paddingX: 1, marginX: 1, children: empty ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: placeholder }) : lines.map((line, i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
24185
|
-
line,
|
|
24186
|
-
i === lines.length - 1 && active ? /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u2588" }) : null
|
|
24187
|
-
] }, i)) }),
|
|
24188
|
-
/* @__PURE__ */ jsx(Box, { marginX: 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "enter send \xB7 \\ newline \xB7 esc clear \xB7 / commands" }) })
|
|
24189
|
-
] });
|
|
24190
|
-
}
|
|
24191
|
-
function App({ engine }) {
|
|
24192
|
-
const [messages, setMessages] = useState([]);
|
|
24193
|
-
const [streaming, setStreaming] = useState("");
|
|
24194
|
-
const [loading, setLoading] = useState(false);
|
|
24195
|
-
const [loadingLabel, setLoadingLabel] = useState("Thinking");
|
|
24196
|
-
const [status, setStatus] = useState("");
|
|
24197
|
-
const { exit } = useApp();
|
|
24198
|
-
useEffect(() => {
|
|
24199
|
-
engine.ui = {
|
|
24200
|
-
addMessage: (role, text) => setMessages((p) => [...p, { id: ++nextId, role, text }]),
|
|
24201
|
-
setStreaming,
|
|
24202
|
-
setLoading,
|
|
24203
|
-
setLoadingLabel,
|
|
24204
|
-
setStatus,
|
|
24205
|
-
exit
|
|
24206
|
-
};
|
|
24207
|
-
}, []);
|
|
24208
|
-
const handleSubmit = useCallback(async (text) => {
|
|
24209
|
-
if (text === "exit" || text === "quit") {
|
|
24210
|
-
engine.exit();
|
|
24211
|
-
return;
|
|
24212
|
-
}
|
|
24213
|
-
await engine.handleInput(text);
|
|
24214
|
-
}, [engine]);
|
|
24215
|
-
const isFirst = messages.length === 0;
|
|
24216
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
24217
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, marginBottom: 1, marginX: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
24197
|
+
});
|
|
24198
|
+
const lines = input.split("\n");
|
|
24199
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
|
|
24200
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
24218
24201
|
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u25C6" }),
|
|
24219
24202
|
" ",
|
|
24220
24203
|
/* @__PURE__ */ jsx(Text, { bold: true, children: "RobinPath" }),
|
|
@@ -24223,261 +24206,188 @@ function App({ engine }) {
|
|
|
24223
24206
|
"v",
|
|
24224
24207
|
CLI_VERSION
|
|
24225
24208
|
] })
|
|
24226
|
-
] })
|
|
24227
|
-
/* @__PURE__ */ jsx(
|
|
24228
|
-
|
|
24229
|
-
|
|
24230
|
-
|
|
24231
|
-
loading && streaming ? /* @__PURE__ */ jsx(Box, { marginX: 2, marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { wrap: "wrap", children: [
|
|
24232
|
-
streaming,
|
|
24233
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u258D" })
|
|
24234
|
-
] }) }) : null,
|
|
24235
|
-
loading && !streaming ? /* @__PURE__ */ jsx(Box, { marginX: 2, marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
24209
|
+
] }),
|
|
24210
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
24211
|
+
/* @__PURE__ */ jsx(Static, { items: messages, children: (msg) => /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: msg.text }, msg.id) }),
|
|
24212
|
+
loading && streaming ? /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: streaming }) : null,
|
|
24213
|
+
loading && !streaming ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
24236
24214
|
/* @__PURE__ */ jsx(InkSpinner, { type: "dots" }),
|
|
24237
|
-
" "
|
|
24238
|
-
|
|
24239
|
-
|
|
24240
|
-
|
|
24241
|
-
|
|
24242
|
-
|
|
24243
|
-
|
|
24244
|
-
|
|
24245
|
-
|
|
24246
|
-
}
|
|
24247
|
-
),
|
|
24248
|
-
status ? /* @__PURE__ */ jsx(Box, { marginX: 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: status }) }) : null
|
|
24215
|
+
" Thinking"
|
|
24216
|
+
] }) : null,
|
|
24217
|
+
!loading ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
24218
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u276F " }),
|
|
24219
|
+
input === "" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: messages.length === 0 ? "What do you want to automate?" : "Ask anything..." }) : /* @__PURE__ */ jsxs(Text, { children: [
|
|
24220
|
+
input,
|
|
24221
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u258E" })
|
|
24222
|
+
] })
|
|
24223
|
+
] }) }) : null
|
|
24249
24224
|
] });
|
|
24250
24225
|
}
|
|
24251
|
-
|
|
24252
|
-
config;
|
|
24253
|
-
autoAccept;
|
|
24254
|
-
devMode;
|
|
24255
|
-
|
|
24256
|
-
|
|
24257
|
-
provider;
|
|
24258
|
-
sessionId;
|
|
24259
|
-
sessionName;
|
|
24260
|
-
usage;
|
|
24261
|
-
conversationMessages;
|
|
24262
|
-
cliContext;
|
|
24263
|
-
ui = null;
|
|
24264
|
-
constructor(resumeSessionId, opts) {
|
|
24265
|
-
this.config = readAiConfig();
|
|
24266
|
-
this.autoAccept = opts.autoAccept || false;
|
|
24267
|
-
this.devMode = opts.devMode || false;
|
|
24268
|
-
if (this.devMode) setFlags({ verbose: true });
|
|
24269
|
-
this.apiKey = this.config.apiKey || null;
|
|
24270
|
-
this.provider = this.resolveProvider(this.apiKey);
|
|
24271
|
-
this.model = this.apiKey ? this.config.model || "anthropic/claude-sonnet-4.6" : "robinpath-default";
|
|
24272
|
-
this.sessionId = resumeSessionId || randomUUID4().slice(0, 8);
|
|
24273
|
-
this.sessionName = `session-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
24274
|
-
this.usage = createUsageTracker();
|
|
24275
|
-
this.conversationMessages = [];
|
|
24276
|
-
this.cliContext = {
|
|
24277
|
-
platform: platform7(),
|
|
24278
|
-
shell: getShellConfig().name,
|
|
24279
|
-
cwd: process.cwd(),
|
|
24280
|
-
cliVersion: CLI_VERSION,
|
|
24281
|
-
nativeModules: getNativeModules().map((m) => m.name),
|
|
24282
|
-
installedModules: Object.keys(readModulesManifest())
|
|
24283
|
-
};
|
|
24284
|
-
const mem = buildMemoryContext();
|
|
24285
|
-
if (mem.trim()) {
|
|
24286
|
-
this.conversationMessages.push({ role: "user", content: `[Context] ${mem.trim()}` });
|
|
24287
|
-
this.conversationMessages.push({ role: "assistant", content: "Preferences loaded." });
|
|
24288
|
-
}
|
|
24289
|
-
if (resumeSessionId) {
|
|
24290
|
-
const session = loadSession(resumeSessionId);
|
|
24291
|
-
if (session) {
|
|
24292
|
-
this.sessionName = session.name;
|
|
24293
|
-
for (const msg of session.messages) this.conversationMessages.push(msg);
|
|
24294
|
-
if (session.usage) {
|
|
24295
|
-
this.usage.promptTokens = session.usage.promptTokens || 0;
|
|
24296
|
-
this.usage.completionTokens = session.usage.completionTokens || 0;
|
|
24297
|
-
this.usage.totalTokens = session.usage.totalTokens || 0;
|
|
24298
|
-
this.usage.requests = session.usage.requests || 0;
|
|
24299
|
-
}
|
|
24300
|
-
}
|
|
24301
|
-
}
|
|
24302
|
-
}
|
|
24303
|
-
resolveProvider(key) {
|
|
24226
|
+
async function startInkREPL(initialPrompt, resumeSessionId, opts = {}) {
|
|
24227
|
+
const config = readAiConfig();
|
|
24228
|
+
let autoAccept = opts.autoAccept || false;
|
|
24229
|
+
const devMode = opts.devMode || false;
|
|
24230
|
+
if (devMode) setFlags({ verbose: true });
|
|
24231
|
+
const resolveProvider = (key) => {
|
|
24304
24232
|
if (!key) return "gemini";
|
|
24305
24233
|
if (key.startsWith("sk-or-")) return "openrouter";
|
|
24306
24234
|
if (key.startsWith("sk-ant-")) return "anthropic";
|
|
24307
24235
|
if (key.startsWith("sk-")) return "openai";
|
|
24308
|
-
return
|
|
24309
|
-
}
|
|
24310
|
-
|
|
24311
|
-
|
|
24312
|
-
|
|
24313
|
-
|
|
24314
|
-
|
|
24236
|
+
return config.provider || "gemini";
|
|
24237
|
+
};
|
|
24238
|
+
const apiKey = config.apiKey || null;
|
|
24239
|
+
const model = apiKey ? config.model || "anthropic/claude-sonnet-4.6" : "robinpath-default";
|
|
24240
|
+
const cliContext = {
|
|
24241
|
+
platform: platform7(),
|
|
24242
|
+
shell: getShellConfig().name,
|
|
24243
|
+
cwd: process.cwd(),
|
|
24244
|
+
cliVersion: CLI_VERSION,
|
|
24245
|
+
nativeModules: getNativeModules().map((m) => m.name),
|
|
24246
|
+
installedModules: Object.keys(readModulesManifest())
|
|
24247
|
+
};
|
|
24248
|
+
let sessionId = resumeSessionId || randomUUID4().slice(0, 8);
|
|
24249
|
+
let sessionName = `session-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
24250
|
+
const usage = createUsageTracker();
|
|
24251
|
+
const conversationMessages = [];
|
|
24252
|
+
const mem = buildMemoryContext();
|
|
24253
|
+
if (mem.trim()) {
|
|
24254
|
+
conversationMessages.push({ role: "user", content: `[Context] ${mem.trim()}` });
|
|
24255
|
+
conversationMessages.push({ role: "assistant", content: "Preferences loaded." });
|
|
24315
24256
|
}
|
|
24316
|
-
|
|
24317
|
-
|
|
24318
|
-
|
|
24257
|
+
if (resumeSessionId) {
|
|
24258
|
+
const session = loadSession(resumeSessionId);
|
|
24259
|
+
if (session) {
|
|
24260
|
+
sessionName = session.name;
|
|
24261
|
+
for (const msg of session.messages) conversationMessages.push(msg);
|
|
24262
|
+
if (session.usage) Object.assign(usage, session.usage);
|
|
24319
24263
|
}
|
|
24320
|
-
this.ui?.exit();
|
|
24321
24264
|
}
|
|
24322
|
-
async
|
|
24323
|
-
|
|
24324
|
-
|
|
24325
|
-
this.ui?.addMessage("info", cmds.join(" "));
|
|
24326
|
-
return;
|
|
24327
|
-
}
|
|
24265
|
+
async function handleMessage(text) {
|
|
24266
|
+
const ui = global.__rpUI;
|
|
24267
|
+
if (text === "/" || text === "/help") return "/model /auto /clear /save /usage /memory exit";
|
|
24328
24268
|
if (text === "/clear") {
|
|
24329
|
-
|
|
24330
|
-
|
|
24331
|
-
return;
|
|
24269
|
+
conversationMessages.length = 0;
|
|
24270
|
+
return "Cleared.";
|
|
24332
24271
|
}
|
|
24333
24272
|
if (text === "/usage") {
|
|
24334
|
-
const c =
|
|
24335
|
-
|
|
24336
|
-
return;
|
|
24273
|
+
const c = usage.cost > 0 ? `$${usage.cost.toFixed(4)}` : "$0 (free)";
|
|
24274
|
+
return `${usage.totalTokens.toLocaleString()} tokens \xB7 ${usage.requests} requests \xB7 ${c}`;
|
|
24337
24275
|
}
|
|
24338
24276
|
if (text === "/auto") {
|
|
24339
|
-
|
|
24340
|
-
|
|
24341
|
-
this.updateStatus();
|
|
24342
|
-
return;
|
|
24277
|
+
autoAccept = !autoAccept;
|
|
24278
|
+
return `Auto-accept: ${autoAccept ? "ON" : "OFF"}`;
|
|
24343
24279
|
}
|
|
24344
24280
|
if (text === "/model") {
|
|
24345
24281
|
const hasKey = !!readAiConfig().apiKey;
|
|
24346
24282
|
const models = hasKey ? AI_MODELS : AI_MODELS.filter((m) => !m.requiresKey);
|
|
24347
|
-
|
|
24348
|
-
return;
|
|
24283
|
+
return models.map((m, i) => `${i + 1}. ${m.name} \u2014 ${m.desc}`).join("\n");
|
|
24349
24284
|
}
|
|
24350
24285
|
if (text.match(/^\/model \d+$/)) {
|
|
24351
24286
|
const hasKey = !!readAiConfig().apiKey;
|
|
24352
24287
|
const models = hasKey ? AI_MODELS : AI_MODELS.filter((m) => !m.requiresKey);
|
|
24353
24288
|
const idx = parseInt(text.split(" ")[1], 10) - 1;
|
|
24354
24289
|
if (idx >= 0 && idx < models.length) {
|
|
24355
|
-
|
|
24356
|
-
|
|
24357
|
-
|
|
24358
|
-
this.ui?.addMessage("info", `Model: ${models[idx].id}`);
|
|
24359
|
-
this.updateStatus();
|
|
24290
|
+
config.model = models[idx].id;
|
|
24291
|
+
writeAiConfig(config);
|
|
24292
|
+
return `Model: ${models[idx].id}`;
|
|
24360
24293
|
}
|
|
24361
|
-
return;
|
|
24294
|
+
return "Invalid number.";
|
|
24362
24295
|
}
|
|
24363
24296
|
if (text === "/memory") {
|
|
24364
|
-
const
|
|
24365
|
-
|
|
24366
|
-
return;
|
|
24297
|
+
const m = loadMemory();
|
|
24298
|
+
return m.facts.length ? m.facts.map((f, i) => `${i + 1}. ${f}`).join("\n") : "No memories.";
|
|
24367
24299
|
}
|
|
24368
24300
|
if (text.startsWith("/save")) {
|
|
24369
|
-
if (text.length > 5)
|
|
24370
|
-
saveSession(
|
|
24371
|
-
|
|
24372
|
-
return;
|
|
24373
|
-
}
|
|
24374
|
-
if (text.startsWith("/")) {
|
|
24375
|
-
this.ui?.addMessage("info", `Unknown: ${text}. Type / for help.`);
|
|
24376
|
-
return;
|
|
24301
|
+
if (text.length > 5) sessionName = text.slice(5).trim();
|
|
24302
|
+
saveSession(sessionId, sessionName, conversationMessages, usage);
|
|
24303
|
+
return `Saved: ${sessionName}`;
|
|
24377
24304
|
}
|
|
24378
|
-
|
|
24379
|
-
|
|
24380
|
-
|
|
24381
|
-
|
|
24382
|
-
|
|
24383
|
-
|
|
24384
|
-
|
|
24385
|
-
|
|
24386
|
-
|
|
24387
|
-
|
|
24388
|
-
const
|
|
24389
|
-
|
|
24390
|
-
|
|
24391
|
-
|
|
24392
|
-
|
|
24393
|
-
|
|
24394
|
-
|
|
24395
|
-
|
|
24396
|
-
|
|
24397
|
-
|
|
24398
|
-
|
|
24399
|
-
|
|
24400
|
-
|
|
24401
|
-
|
|
24402
|
-
|
|
24403
|
-
|
|
24404
|
-
|
|
24405
|
-
|
|
24406
|
-
conversationHistory: this.conversationMessages.slice(0, -1),
|
|
24407
|
-
provider: activeProvider,
|
|
24408
|
-
model: activeModel,
|
|
24409
|
-
apiKey: activeKey,
|
|
24410
|
-
cliContext: this.cliContext
|
|
24411
|
-
}
|
|
24412
|
-
);
|
|
24413
|
-
if (!result || !result.code) {
|
|
24414
|
-
this.ui?.addMessage("assistant", fullResponse || "No response. Check connection or API key.");
|
|
24415
|
-
break;
|
|
24416
|
-
}
|
|
24417
|
-
if (result.usage) {
|
|
24418
|
-
const pt2 = result.usage.prompt_tokens || 0;
|
|
24419
|
-
const ct2 = result.usage.completion_tokens || 0;
|
|
24420
|
-
this.usage.promptTokens += pt2;
|
|
24421
|
-
this.usage.completionTokens += ct2;
|
|
24422
|
-
this.usage.totalTokens += pt2 + ct2;
|
|
24423
|
-
this.usage.requests++;
|
|
24424
|
-
this.usage.cost += estimateCost(activeModel, pt2, ct2);
|
|
24425
|
-
this.updateStatus();
|
|
24426
|
-
}
|
|
24427
|
-
const { cleaned } = extractMemoryTags(stripCommandTags(result.code));
|
|
24428
|
-
const commands = extractCommands(result.code);
|
|
24429
|
-
if (cleaned) {
|
|
24430
|
-
this.conversationMessages.push({ role: "assistant", content: cleaned });
|
|
24305
|
+
if (text.startsWith("/")) return `Unknown: ${text}. Type / for help.`;
|
|
24306
|
+
const { expanded } = expandFileRefs(text);
|
|
24307
|
+
conversationMessages.push({ role: "user", content: expanded });
|
|
24308
|
+
await autoCompact(conversationMessages);
|
|
24309
|
+
const activeModel = readAiConfig().model || model;
|
|
24310
|
+
const activeKey = readAiConfig().apiKey || apiKey;
|
|
24311
|
+
const activeProvider = resolveProvider(activeKey);
|
|
24312
|
+
let finalResponse = "";
|
|
24313
|
+
for (let loop = 0; loop < 15; loop++) {
|
|
24314
|
+
let fullText = "";
|
|
24315
|
+
const result = await fetchBrainStream(
|
|
24316
|
+
loop === 0 ? expanded : conversationMessages[conversationMessages.length - 1].content,
|
|
24317
|
+
{
|
|
24318
|
+
onToken: (delta) => {
|
|
24319
|
+
if (delta === "\x1B[RETRY]") {
|
|
24320
|
+
fullText = "";
|
|
24321
|
+
ui?.setStreaming("");
|
|
24322
|
+
return;
|
|
24323
|
+
}
|
|
24324
|
+
fullText += delta;
|
|
24325
|
+
const clean = fullText.replace(/<memory>[\s\S]*?<\/memory>/g, "").replace(/<cmd>[\s\S]*?<\/cmd>/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
24326
|
+
ui?.setStreaming(clean);
|
|
24327
|
+
},
|
|
24328
|
+
conversationHistory: conversationMessages.slice(0, -1),
|
|
24329
|
+
provider: activeProvider,
|
|
24330
|
+
model: activeModel,
|
|
24331
|
+
apiKey: activeKey,
|
|
24332
|
+
cliContext
|
|
24431
24333
|
}
|
|
24432
|
-
|
|
24433
|
-
|
|
24434
|
-
|
|
24334
|
+
);
|
|
24335
|
+
if (!result || !result.code) {
|
|
24336
|
+
finalResponse = fullText || "No response.";
|
|
24337
|
+
break;
|
|
24338
|
+
}
|
|
24339
|
+
if (result.usage) {
|
|
24340
|
+
const pt2 = result.usage.prompt_tokens || 0;
|
|
24341
|
+
const ct2 = result.usage.completion_tokens || 0;
|
|
24342
|
+
usage.promptTokens += pt2;
|
|
24343
|
+
usage.completionTokens += ct2;
|
|
24344
|
+
usage.totalTokens += pt2 + ct2;
|
|
24345
|
+
usage.requests++;
|
|
24346
|
+
usage.cost += estimateCost(activeModel, pt2, ct2);
|
|
24347
|
+
}
|
|
24348
|
+
const { cleaned } = extractMemoryTags(stripCommandTags(result.code));
|
|
24349
|
+
const commands = extractCommands(result.code);
|
|
24350
|
+
if (cleaned) conversationMessages.push({ role: "assistant", content: cleaned });
|
|
24351
|
+
if (commands.length === 0) {
|
|
24352
|
+
finalResponse = cleaned || fullText;
|
|
24353
|
+
break;
|
|
24354
|
+
}
|
|
24355
|
+
if (cleaned) ui?.addMessage(cleaned);
|
|
24356
|
+
for (const cmd of commands) {
|
|
24357
|
+
const preview = cmd.split("\n")[0].slice(0, 80);
|
|
24358
|
+
ui?.addMessage(`$ ${preview}${cmd.includes("\n") ? " ..." : ""}`);
|
|
24359
|
+
const r = await executeShellCommand(cmd);
|
|
24360
|
+
if (r.exitCode === 0 && r.stdout?.trim()) {
|
|
24361
|
+
ui?.addMessage(r.stdout.trim().split("\n").slice(0, 5).join("\n"));
|
|
24362
|
+
} else if (r.exitCode !== 0) {
|
|
24363
|
+
ui?.addMessage(`exit ${r.exitCode}: ${(r.stderr || "").slice(0, 100)}`);
|
|
24435
24364
|
}
|
|
24436
|
-
if (cleaned) this.ui?.addMessage("assistant", cleaned);
|
|
24437
|
-
const cmdResults = [];
|
|
24438
|
-
for (const cmd of commands) {
|
|
24439
|
-
this.ui?.addMessage("info", `$ ${cmd.split("\n")[0]}${cmd.includes("\n") ? ` (+${cmd.split("\n").length - 1} lines)` : ""}`);
|
|
24440
|
-
const r = await executeShellCommand(cmd);
|
|
24441
|
-
if (r.exitCode === 0 && r.stdout?.trim()) {
|
|
24442
|
-
this.ui?.addMessage("info", r.stdout.trim().split("\n").slice(0, 5).join("\n"));
|
|
24443
|
-
} else if (r.exitCode !== 0) {
|
|
24444
|
-
this.ui?.addMessage("info", `exit ${r.exitCode}: ${(r.stderr || "").slice(0, 100)}`);
|
|
24445
|
-
}
|
|
24446
|
-
cmdResults.push({ command: cmd, stdout: r.stdout || "", stderr: r.stderr || "", exitCode: r.exitCode });
|
|
24447
|
-
}
|
|
24448
|
-
const summary = cmdResults.map((r) => {
|
|
24449
|
-
let o = `$ ${r.command}
|
|
24450
|
-
`;
|
|
24451
|
-
if (r.exitCode === 0) o += r.stdout || "(no output)";
|
|
24452
|
-
else {
|
|
24453
|
-
o += `Exit: ${r.exitCode}
|
|
24454
|
-
`;
|
|
24455
|
-
if (r.stderr) o += r.stderr;
|
|
24456
|
-
}
|
|
24457
|
-
return o;
|
|
24458
|
-
}).join("\n\n");
|
|
24459
|
-
this.conversationMessages.push({ role: "user", content: `[Command results]
|
|
24460
|
-
${summary}` });
|
|
24461
|
-
this.ui?.setStreaming("");
|
|
24462
24365
|
}
|
|
24463
|
-
|
|
24464
|
-
|
|
24465
|
-
|
|
24466
|
-
|
|
24467
|
-
|
|
24468
|
-
|
|
24366
|
+
const summary = commands.map((cmd, i) => `$ ${cmd}
|
|
24367
|
+
(executed)`).join("\n");
|
|
24368
|
+
conversationMessages.push({ role: "user", content: `[Results]
|
|
24369
|
+
${summary}` });
|
|
24370
|
+
ui?.setStreaming("");
|
|
24371
|
+
finalResponse = "";
|
|
24469
24372
|
}
|
|
24373
|
+
saveSession(sessionId, sessionName, conversationMessages, usage);
|
|
24374
|
+
return finalResponse;
|
|
24470
24375
|
}
|
|
24471
|
-
};
|
|
24472
|
-
async function startInkREPL(initialPrompt, resumeSessionId, opts = {}) {
|
|
24473
|
-
const engine = new ReplEngine(resumeSessionId, opts);
|
|
24474
|
-
const { waitUntilExit } = render(/* @__PURE__ */ jsx(App, { engine }));
|
|
24475
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
24476
|
-
engine.updateStatus();
|
|
24376
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx(ChatApp, { onMessage: handleMessage }));
|
|
24477
24377
|
if (initialPrompt) {
|
|
24478
|
-
await
|
|
24378
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
24379
|
+
const ui = global.__rpUI;
|
|
24380
|
+
ui?.addMessage(`\u276F ${initialPrompt}`);
|
|
24381
|
+
ui?.setLoading(true);
|
|
24382
|
+
try {
|
|
24383
|
+
const response = await handleMessage(initialPrompt);
|
|
24384
|
+
if (response) ui?.addMessage(response);
|
|
24385
|
+
} finally {
|
|
24386
|
+
ui?.setLoading(false);
|
|
24387
|
+
}
|
|
24479
24388
|
}
|
|
24480
24389
|
await waitUntilExit();
|
|
24390
|
+
saveSession(sessionId, sessionName, conversationMessages, usage);
|
|
24481
24391
|
}
|
|
24482
24392
|
|
|
24483
24393
|
// src/commands-modules.ts
|