@robinpath/cli 1.77.0 → 1.79.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 +227 -286
- 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.79.0" : "1.79.0";
|
|
18602
18602
|
var FLAG_QUIET = false;
|
|
18603
18603
|
var FLAG_VERBOSE = false;
|
|
18604
18604
|
var FLAG_AUTO_ACCEPT = false;
|
|
@@ -21904,7 +21904,8 @@ async function fetchBrainStream(prompt, { onToken, conversationHistory, provider
|
|
|
21904
21904
|
});
|
|
21905
21905
|
if (!response.ok) {
|
|
21906
21906
|
logVerbose("Brain stream returned", response.status);
|
|
21907
|
-
|
|
21907
|
+
const errorHint = response.status === 401 ? "Invalid API key." : response.status === 429 ? "Rate limited. Wait a moment and try again." : response.status >= 500 ? "Brain server error. Try again." : `Brain returned HTTP ${response.status}.`;
|
|
21908
|
+
return { code: "", sources: [], context: {}, validation: null, usage: null, error: errorHint };
|
|
21908
21909
|
}
|
|
21909
21910
|
let fullText = "";
|
|
21910
21911
|
let metadata = null;
|
|
@@ -21964,8 +21965,19 @@ async function fetchBrainStream(prompt, { onToken, conversationHistory, provider
|
|
|
21964
21965
|
usage: doneData?.usage || null
|
|
21965
21966
|
};
|
|
21966
21967
|
} catch (err) {
|
|
21967
|
-
|
|
21968
|
-
|
|
21968
|
+
const msg = err.message || "";
|
|
21969
|
+
logVerbose("Brain stream unreachable:", msg);
|
|
21970
|
+
let errorHint;
|
|
21971
|
+
if (msg.includes("fetch failed") || msg.includes("ENOTFOUND") || msg.includes("ECONNREFUSED") || msg.includes("NetworkError") || msg.includes("getaddrinfo")) {
|
|
21972
|
+
errorHint = "No internet connection. Check your network and try again.";
|
|
21973
|
+
} else if (msg.includes("abort") || msg.includes("timeout") || msg.includes("TimeoutError")) {
|
|
21974
|
+
errorHint = "Request timed out. The server might be slow \u2014 try again.";
|
|
21975
|
+
} else if (msg.includes("CERT") || msg.includes("SSL") || msg.includes("certificate")) {
|
|
21976
|
+
errorHint = "SSL/certificate error. Check your network or proxy settings.";
|
|
21977
|
+
} else {
|
|
21978
|
+
errorHint = `Connection failed: ${msg.slice(0, 100)}`;
|
|
21979
|
+
}
|
|
21980
|
+
return { code: "", sources: [], context: {}, validation: null, usage: null, error: errorHint };
|
|
21969
21981
|
}
|
|
21970
21982
|
}
|
|
21971
21983
|
async function resolveBrainModules(prompt) {
|
|
@@ -23941,9 +23953,20 @@ ${readFileSync9(rpJson, "utf-8")}
|
|
|
23941
23953
|
if (pending.length > 0 && !insideMemory && !insideCmd) {
|
|
23942
23954
|
process.stdout.write(pending);
|
|
23943
23955
|
}
|
|
23944
|
-
if (!brainResult
|
|
23956
|
+
if (!brainResult) {
|
|
23957
|
+
spinner.stop();
|
|
23958
|
+
log(color.red("\n No internet connection. Check your network and try again."));
|
|
23959
|
+
break;
|
|
23960
|
+
}
|
|
23961
|
+
if (brainResult.error) {
|
|
23962
|
+
spinner.stop();
|
|
23963
|
+
log(color.red(`
|
|
23964
|
+
${brainResult.error}`));
|
|
23965
|
+
break;
|
|
23966
|
+
}
|
|
23967
|
+
if (!brainResult.code) {
|
|
23945
23968
|
spinner.stop();
|
|
23946
|
-
log(color.red("\n
|
|
23969
|
+
log(color.red("\n No response from AI. Try again."));
|
|
23947
23970
|
break;
|
|
23948
23971
|
}
|
|
23949
23972
|
if (brainResult.usage) {
|
|
@@ -24132,89 +24155,72 @@ ${resultSummary}`
|
|
|
24132
24155
|
}
|
|
24133
24156
|
|
|
24134
24157
|
// src/ink-repl.tsx
|
|
24135
|
-
import { useState,
|
|
24158
|
+
import { useState, useEffect } from "react";
|
|
24136
24159
|
import { render, Box, Text, Static, useInput, useApp } from "ink";
|
|
24137
24160
|
import InkSpinner from "ink-spinner";
|
|
24138
24161
|
import { platform as platform7 } from "node:os";
|
|
24139
24162
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
24140
24163
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
24141
24164
|
var nextId = 0;
|
|
24142
|
-
function
|
|
24143
|
-
const [
|
|
24144
|
-
|
|
24145
|
-
|
|
24165
|
+
function ChatApp({ onMessage }) {
|
|
24166
|
+
const [input, setInput] = useState("");
|
|
24167
|
+
const [messages, setMessages] = useState([]);
|
|
24168
|
+
const [streaming, setStreaming] = useState("");
|
|
24169
|
+
const [loading, setLoading] = useState(false);
|
|
24170
|
+
const { exit } = useApp();
|
|
24171
|
+
useEffect(() => {
|
|
24172
|
+
global.__rpUI = {
|
|
24173
|
+
setStreaming,
|
|
24174
|
+
setLoading,
|
|
24175
|
+
addMessage: (text) => setMessages((prev) => [...prev, { id: ++nextId, text }])
|
|
24176
|
+
};
|
|
24177
|
+
}, []);
|
|
24178
|
+
useInput((character, key) => {
|
|
24179
|
+
if (loading) return;
|
|
24146
24180
|
if (key.return) {
|
|
24147
|
-
if (
|
|
24148
|
-
|
|
24181
|
+
if (!input.trim()) return;
|
|
24182
|
+
if (input.endsWith("\\")) {
|
|
24183
|
+
setInput((prev) => prev.slice(0, -1) + "\n");
|
|
24149
24184
|
return;
|
|
24150
24185
|
}
|
|
24151
|
-
const text =
|
|
24152
|
-
|
|
24153
|
-
|
|
24154
|
-
|
|
24186
|
+
const text = input.trim();
|
|
24187
|
+
setInput("");
|
|
24188
|
+
if (text === "exit" || text === "quit") {
|
|
24189
|
+
exit();
|
|
24190
|
+
return;
|
|
24155
24191
|
}
|
|
24192
|
+
setMessages((prev) => [...prev, { id: ++nextId, text: `\u276F ${text}` }]);
|
|
24193
|
+
setLoading(true);
|
|
24194
|
+
setStreaming("");
|
|
24195
|
+
onMessage(text).then((response) => {
|
|
24196
|
+
if (response) {
|
|
24197
|
+
setMessages((prev) => [...prev, { id: ++nextId, text: response }]);
|
|
24198
|
+
}
|
|
24199
|
+
setLoading(false);
|
|
24200
|
+
setStreaming("");
|
|
24201
|
+
}).catch((err) => {
|
|
24202
|
+
setMessages((prev) => [...prev, { id: ++nextId, text: `Error: ${err.message}` }]);
|
|
24203
|
+
setLoading(false);
|
|
24204
|
+
setStreaming("");
|
|
24205
|
+
});
|
|
24156
24206
|
return;
|
|
24157
24207
|
}
|
|
24158
|
-
if (input
|
|
24159
|
-
|
|
24208
|
+
if (input.length > 0 && (key.backspace || key.delete)) {
|
|
24209
|
+
setInput((prev) => prev.slice(0, -1));
|
|
24160
24210
|
return;
|
|
24161
24211
|
}
|
|
24162
24212
|
if (key.escape) {
|
|
24163
|
-
|
|
24164
|
-
return;
|
|
24165
|
-
}
|
|
24166
|
-
if (key.backspace || key.delete) {
|
|
24167
|
-
setValue((p) => p.slice(0, -1));
|
|
24213
|
+
setInput("");
|
|
24168
24214
|
return;
|
|
24169
24215
|
}
|
|
24170
24216
|
if (key.tab) return;
|
|
24171
|
-
if (
|
|
24172
|
-
|
|
24173
|
-
return;
|
|
24174
|
-
}
|
|
24175
|
-
if (input === "") {
|
|
24176
|
-
setValue((p) => p.replace(/\S+\s*$/, ""));
|
|
24177
|
-
return;
|
|
24217
|
+
if (character && !key.ctrl && !key.meta) {
|
|
24218
|
+
setInput((prev) => prev + character);
|
|
24178
24219
|
}
|
|
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: [
|
|
24220
|
+
});
|
|
24221
|
+
const lines = input.split("\n");
|
|
24222
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
|
|
24223
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
24218
24224
|
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u25C6" }),
|
|
24219
24225
|
" ",
|
|
24220
24226
|
/* @__PURE__ */ jsx(Text, { bold: true, children: "RobinPath" }),
|
|
@@ -24223,261 +24229,196 @@ function App({ engine }) {
|
|
|
24223
24229
|
"v",
|
|
24224
24230
|
CLI_VERSION
|
|
24225
24231
|
] })
|
|
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: [
|
|
24232
|
+
] }),
|
|
24233
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
24234
|
+
/* @__PURE__ */ jsx(Static, { items: messages, children: (msg) => /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: msg.text }, msg.id) }),
|
|
24235
|
+
loading && streaming ? /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: streaming }) : null,
|
|
24236
|
+
loading && !streaming ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
24236
24237
|
/* @__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
|
|
24238
|
+
" Thinking"
|
|
24239
|
+
] }) : null,
|
|
24240
|
+
!loading ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
24241
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u276F " }),
|
|
24242
|
+
input === "" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: messages.length === 0 ? "What do you want to automate?" : "Ask anything..." }) : /* @__PURE__ */ jsxs(Text, { children: [
|
|
24243
|
+
input,
|
|
24244
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u258E" })
|
|
24245
|
+
] })
|
|
24246
|
+
] }) }) : null
|
|
24249
24247
|
] });
|
|
24250
24248
|
}
|
|
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) {
|
|
24249
|
+
async function startInkREPL(initialPrompt, resumeSessionId, opts = {}) {
|
|
24250
|
+
const config = readAiConfig();
|
|
24251
|
+
let autoAccept = opts.autoAccept || false;
|
|
24252
|
+
const devMode = opts.devMode || false;
|
|
24253
|
+
if (devMode) setFlags({ verbose: true });
|
|
24254
|
+
const resolveProvider = (key) => {
|
|
24304
24255
|
if (!key) return "gemini";
|
|
24305
24256
|
if (key.startsWith("sk-or-")) return "openrouter";
|
|
24306
24257
|
if (key.startsWith("sk-ant-")) return "anthropic";
|
|
24307
24258
|
if (key.startsWith("sk-")) return "openai";
|
|
24308
|
-
return
|
|
24309
|
-
}
|
|
24310
|
-
|
|
24311
|
-
|
|
24312
|
-
|
|
24313
|
-
|
|
24314
|
-
|
|
24259
|
+
return config.provider || "gemini";
|
|
24260
|
+
};
|
|
24261
|
+
const apiKey = config.apiKey || null;
|
|
24262
|
+
const model = apiKey ? config.model || "anthropic/claude-sonnet-4.6" : "robinpath-default";
|
|
24263
|
+
const cliContext = {
|
|
24264
|
+
platform: platform7(),
|
|
24265
|
+
shell: getShellConfig().name,
|
|
24266
|
+
cwd: process.cwd(),
|
|
24267
|
+
cliVersion: CLI_VERSION,
|
|
24268
|
+
nativeModules: getNativeModules().map((m) => m.name),
|
|
24269
|
+
installedModules: Object.keys(readModulesManifest())
|
|
24270
|
+
};
|
|
24271
|
+
let sessionId = resumeSessionId || randomUUID4().slice(0, 8);
|
|
24272
|
+
let sessionName = `session-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
24273
|
+
const usage = createUsageTracker();
|
|
24274
|
+
const conversationMessages = [];
|
|
24275
|
+
const mem = buildMemoryContext();
|
|
24276
|
+
if (mem.trim()) {
|
|
24277
|
+
conversationMessages.push({ role: "user", content: `[Context] ${mem.trim()}` });
|
|
24278
|
+
conversationMessages.push({ role: "assistant", content: "Preferences loaded." });
|
|
24315
24279
|
}
|
|
24316
|
-
|
|
24317
|
-
|
|
24318
|
-
|
|
24280
|
+
if (resumeSessionId) {
|
|
24281
|
+
const session = loadSession(resumeSessionId);
|
|
24282
|
+
if (session) {
|
|
24283
|
+
sessionName = session.name;
|
|
24284
|
+
for (const msg of session.messages) conversationMessages.push(msg);
|
|
24285
|
+
if (session.usage) Object.assign(usage, session.usage);
|
|
24319
24286
|
}
|
|
24320
|
-
this.ui?.exit();
|
|
24321
24287
|
}
|
|
24322
|
-
async
|
|
24323
|
-
|
|
24324
|
-
|
|
24325
|
-
this.ui?.addMessage("info", cmds.join(" "));
|
|
24326
|
-
return;
|
|
24327
|
-
}
|
|
24288
|
+
async function handleMessage(text) {
|
|
24289
|
+
const ui = global.__rpUI;
|
|
24290
|
+
if (text === "/" || text === "/help") return "/model /auto /clear /save /usage /memory exit";
|
|
24328
24291
|
if (text === "/clear") {
|
|
24329
|
-
|
|
24330
|
-
|
|
24331
|
-
return;
|
|
24292
|
+
conversationMessages.length = 0;
|
|
24293
|
+
return "Cleared.";
|
|
24332
24294
|
}
|
|
24333
24295
|
if (text === "/usage") {
|
|
24334
|
-
const c =
|
|
24335
|
-
|
|
24336
|
-
return;
|
|
24296
|
+
const c = usage.cost > 0 ? `$${usage.cost.toFixed(4)}` : "$0 (free)";
|
|
24297
|
+
return `${usage.totalTokens.toLocaleString()} tokens \xB7 ${usage.requests} requests \xB7 ${c}`;
|
|
24337
24298
|
}
|
|
24338
24299
|
if (text === "/auto") {
|
|
24339
|
-
|
|
24340
|
-
|
|
24341
|
-
this.updateStatus();
|
|
24342
|
-
return;
|
|
24300
|
+
autoAccept = !autoAccept;
|
|
24301
|
+
return `Auto-accept: ${autoAccept ? "ON" : "OFF"}`;
|
|
24343
24302
|
}
|
|
24344
24303
|
if (text === "/model") {
|
|
24345
24304
|
const hasKey = !!readAiConfig().apiKey;
|
|
24346
24305
|
const models = hasKey ? AI_MODELS : AI_MODELS.filter((m) => !m.requiresKey);
|
|
24347
|
-
|
|
24348
|
-
return;
|
|
24306
|
+
return models.map((m, i) => `${i + 1}. ${m.name} \u2014 ${m.desc}`).join("\n");
|
|
24349
24307
|
}
|
|
24350
24308
|
if (text.match(/^\/model \d+$/)) {
|
|
24351
24309
|
const hasKey = !!readAiConfig().apiKey;
|
|
24352
24310
|
const models = hasKey ? AI_MODELS : AI_MODELS.filter((m) => !m.requiresKey);
|
|
24353
24311
|
const idx = parseInt(text.split(" ")[1], 10) - 1;
|
|
24354
24312
|
if (idx >= 0 && idx < models.length) {
|
|
24355
|
-
|
|
24356
|
-
|
|
24357
|
-
|
|
24358
|
-
this.ui?.addMessage("info", `Model: ${models[idx].id}`);
|
|
24359
|
-
this.updateStatus();
|
|
24313
|
+
config.model = models[idx].id;
|
|
24314
|
+
writeAiConfig(config);
|
|
24315
|
+
return `Model: ${models[idx].id}`;
|
|
24360
24316
|
}
|
|
24361
|
-
return;
|
|
24317
|
+
return "Invalid number.";
|
|
24362
24318
|
}
|
|
24363
24319
|
if (text === "/memory") {
|
|
24364
|
-
const
|
|
24365
|
-
|
|
24366
|
-
return;
|
|
24320
|
+
const m = loadMemory();
|
|
24321
|
+
return m.facts.length ? m.facts.map((f, i) => `${i + 1}. ${f}`).join("\n") : "No memories.";
|
|
24367
24322
|
}
|
|
24368
24323
|
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;
|
|
24324
|
+
if (text.length > 5) sessionName = text.slice(5).trim();
|
|
24325
|
+
saveSession(sessionId, sessionName, conversationMessages, usage);
|
|
24326
|
+
return `Saved: ${sessionName}`;
|
|
24377
24327
|
}
|
|
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 });
|
|
24328
|
+
if (text.startsWith("/")) return `Unknown: ${text}. Type / for help.`;
|
|
24329
|
+
const { expanded } = expandFileRefs(text);
|
|
24330
|
+
conversationMessages.push({ role: "user", content: expanded });
|
|
24331
|
+
await autoCompact(conversationMessages);
|
|
24332
|
+
const activeModel = readAiConfig().model || model;
|
|
24333
|
+
const activeKey = readAiConfig().apiKey || apiKey;
|
|
24334
|
+
const activeProvider = resolveProvider(activeKey);
|
|
24335
|
+
let finalResponse = "";
|
|
24336
|
+
for (let loop = 0; loop < 15; loop++) {
|
|
24337
|
+
let fullText = "";
|
|
24338
|
+
const result = await fetchBrainStream(
|
|
24339
|
+
loop === 0 ? expanded : conversationMessages[conversationMessages.length - 1].content,
|
|
24340
|
+
{
|
|
24341
|
+
onToken: (delta) => {
|
|
24342
|
+
if (delta === "\x1B[RETRY]") {
|
|
24343
|
+
fullText = "";
|
|
24344
|
+
ui?.setStreaming("");
|
|
24345
|
+
return;
|
|
24346
|
+
}
|
|
24347
|
+
fullText += delta;
|
|
24348
|
+
const clean = fullText.replace(/<memory>[\s\S]*?<\/memory>/g, "").replace(/<cmd>[\s\S]*?<\/cmd>/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
24349
|
+
ui?.setStreaming(clean);
|
|
24350
|
+
},
|
|
24351
|
+
conversationHistory: conversationMessages.slice(0, -1),
|
|
24352
|
+
provider: activeProvider,
|
|
24353
|
+
model: activeModel,
|
|
24354
|
+
apiKey: activeKey,
|
|
24355
|
+
cliContext
|
|
24431
24356
|
}
|
|
24432
|
-
|
|
24433
|
-
|
|
24434
|
-
|
|
24357
|
+
);
|
|
24358
|
+
if (!result) {
|
|
24359
|
+
finalResponse = "No internet connection. Check your network and try again.";
|
|
24360
|
+
break;
|
|
24361
|
+
}
|
|
24362
|
+
if (result.error) {
|
|
24363
|
+
finalResponse = result.error;
|
|
24364
|
+
break;
|
|
24365
|
+
}
|
|
24366
|
+
if (!result.code) {
|
|
24367
|
+
finalResponse = fullText || "No response from AI. Try again.";
|
|
24368
|
+
break;
|
|
24369
|
+
}
|
|
24370
|
+
if (result.usage) {
|
|
24371
|
+
const pt2 = result.usage.prompt_tokens || 0;
|
|
24372
|
+
const ct2 = result.usage.completion_tokens || 0;
|
|
24373
|
+
usage.promptTokens += pt2;
|
|
24374
|
+
usage.completionTokens += ct2;
|
|
24375
|
+
usage.totalTokens += pt2 + ct2;
|
|
24376
|
+
usage.requests++;
|
|
24377
|
+
usage.cost += estimateCost(activeModel, pt2, ct2);
|
|
24378
|
+
}
|
|
24379
|
+
const { cleaned } = extractMemoryTags(stripCommandTags(result.code));
|
|
24380
|
+
const commands = extractCommands(result.code);
|
|
24381
|
+
if (cleaned) conversationMessages.push({ role: "assistant", content: cleaned });
|
|
24382
|
+
if (commands.length === 0) {
|
|
24383
|
+
finalResponse = cleaned || fullText;
|
|
24384
|
+
break;
|
|
24385
|
+
}
|
|
24386
|
+
if (cleaned) ui?.addMessage(cleaned);
|
|
24387
|
+
for (const cmd of commands) {
|
|
24388
|
+
const preview = cmd.split("\n")[0].slice(0, 80);
|
|
24389
|
+
ui?.addMessage(`$ ${preview}${cmd.includes("\n") ? " ..." : ""}`);
|
|
24390
|
+
const r = await executeShellCommand(cmd);
|
|
24391
|
+
if (r.exitCode === 0 && r.stdout?.trim()) {
|
|
24392
|
+
ui?.addMessage(r.stdout.trim().split("\n").slice(0, 5).join("\n"));
|
|
24393
|
+
} else if (r.exitCode !== 0) {
|
|
24394
|
+
ui?.addMessage(`exit ${r.exitCode}: ${(r.stderr || "").slice(0, 100)}`);
|
|
24435
24395
|
}
|
|
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
24396
|
}
|
|
24463
|
-
|
|
24464
|
-
|
|
24465
|
-
|
|
24466
|
-
|
|
24467
|
-
|
|
24468
|
-
|
|
24397
|
+
const summary = commands.map((cmd, i) => `$ ${cmd}
|
|
24398
|
+
(executed)`).join("\n");
|
|
24399
|
+
conversationMessages.push({ role: "user", content: `[Results]
|
|
24400
|
+
${summary}` });
|
|
24401
|
+
ui?.setStreaming("");
|
|
24402
|
+
finalResponse = "";
|
|
24469
24403
|
}
|
|
24404
|
+
saveSession(sessionId, sessionName, conversationMessages, usage);
|
|
24405
|
+
return finalResponse;
|
|
24470
24406
|
}
|
|
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();
|
|
24407
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx(ChatApp, { onMessage: handleMessage }));
|
|
24477
24408
|
if (initialPrompt) {
|
|
24478
|
-
await
|
|
24409
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
24410
|
+
const ui = global.__rpUI;
|
|
24411
|
+
ui?.addMessage(`\u276F ${initialPrompt}`);
|
|
24412
|
+
ui?.setLoading(true);
|
|
24413
|
+
try {
|
|
24414
|
+
const response = await handleMessage(initialPrompt);
|
|
24415
|
+
if (response) ui?.addMessage(response);
|
|
24416
|
+
} finally {
|
|
24417
|
+
ui?.setLoading(false);
|
|
24418
|
+
}
|
|
24479
24419
|
}
|
|
24480
24420
|
await waitUntilExit();
|
|
24421
|
+
saveSession(sessionId, sessionName, conversationMessages, usage);
|
|
24481
24422
|
}
|
|
24482
24423
|
|
|
24483
24424
|
// src/commands-modules.ts
|