@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.
Files changed (2) hide show
  1. package/dist/cli.mjs +227 -286
  2. 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.77.0" : "1.77.0";
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
- return null;
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
- logVerbose("Brain stream unreachable:", err.message);
21968
- return null;
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 || !brainResult.code) {
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 Brain returned no response. Check your connection or API key."));
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, useCallback, useEffect } from "react";
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 InputBox({ onSubmit, active, placeholder }) {
24143
- const [value, setValue] = useState("");
24144
- useInput((input, key) => {
24145
- if (!active) return;
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 (value.endsWith("\\")) {
24148
- setValue((p) => p.slice(0, -1) + "\n");
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 = value.trim();
24152
- if (text) {
24153
- onSubmit(text);
24154
- setValue("");
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 === "\n") {
24159
- setValue((p) => p + "\n");
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
- setValue("");
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 (input === "") {
24172
- setValue("");
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
- if (input && !key.ctrl && !key.meta) setValue((p) => p + input);
24180
- }, { isActive: active });
24181
- const lines = value.split("\n");
24182
- const empty = value === "";
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(Static, { items: messages, children: (msg) => /* @__PURE__ */ jsx(Box, { marginX: 2, marginBottom: msg.role === "assistant" ? 1 : 0, children: msg.role === "user" ? /* @__PURE__ */ jsxs(Text, { children: [
24228
- /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u276F " }),
24229
- /* @__PURE__ */ jsx(Text, { bold: true, children: msg.text })
24230
- ] }) : msg.role === "info" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: msg.text }) : /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: msg.text }) }, msg.id) }),
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
- loadingLabel
24239
- ] }) }) : null,
24240
- /* @__PURE__ */ jsx(
24241
- InputBox,
24242
- {
24243
- onSubmit: handleSubmit,
24244
- active: !loading,
24245
- placeholder: isFirst ? "What do you want to automate?" : "Ask anything..."
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
- var ReplEngine = class {
24252
- config;
24253
- autoAccept;
24254
- devMode;
24255
- apiKey;
24256
- model;
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 this.config.provider || "gemini";
24309
- }
24310
- updateStatus() {
24311
- const model = this.model.includes("/") ? this.model.split("/").pop() : this.model;
24312
- const cost = this.usage.cost > 0 ? ` \xB7 $${this.usage.cost.toFixed(4)}` : "";
24313
- const tokens = this.usage.totalTokens > 0 ? ` \xB7 ${this.usage.totalTokens.toLocaleString()} tokens` : "";
24314
- this.ui?.setStatus(`${model} \xB7 ${getShellConfig().name} \xB7 ${this.autoAccept ? "auto" : "confirm"}${tokens}${cost}`);
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
- exit() {
24317
- if (this.conversationMessages.length > 1) {
24318
- saveSession(this.sessionId, this.sessionName, this.conversationMessages, this.usage);
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 handleInput(text) {
24323
- if (text === "/" || text === "/help") {
24324
- const cmds = ["/model", "/shell", "/auto", "/clear", "/save", "/sessions", "/memory", "/usage", "exit"];
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
- this.conversationMessages.length = 0;
24330
- this.ui?.addMessage("info", "Cleared.");
24331
- return;
24292
+ conversationMessages.length = 0;
24293
+ return "Cleared.";
24332
24294
  }
24333
24295
  if (text === "/usage") {
24334
- const c = this.usage.cost > 0 ? `$${this.usage.cost.toFixed(4)}` : "$0 (free)";
24335
- this.ui?.addMessage("info", `${this.usage.totalTokens.toLocaleString()} tokens \xB7 ${this.usage.requests} requests \xB7 ${c}`);
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
- this.autoAccept = !this.autoAccept;
24340
- this.ui?.addMessage("info", `Auto-accept: ${this.autoAccept ? "ON" : "OFF"}`);
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
- this.ui?.addMessage("info", models.map((m, i) => `${i + 1}. ${m.name} \u2014 ${m.desc}`).join("\n"));
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
- this.config.model = models[idx].id;
24356
- this.model = models[idx].id;
24357
- writeAiConfig(this.config);
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 mem = loadMemory();
24365
- this.ui?.addMessage("info", mem.facts.length ? mem.facts.map((f, i) => `${i + 1}. ${f}`).join("\n") : "No memories.");
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) this.sessionName = text.slice(5).trim();
24370
- saveSession(this.sessionId, this.sessionName, this.conversationMessages, this.usage);
24371
- this.ui?.addMessage("info", `Saved: ${this.sessionName}`);
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
- this.ui?.addMessage("user", text);
24379
- this.ui?.setLoading(true);
24380
- this.ui?.setStreaming("");
24381
- this.ui?.setLoadingLabel("Thinking");
24382
- try {
24383
- const { expanded } = expandFileRefs(text);
24384
- this.conversationMessages.push({ role: "user", content: expanded });
24385
- await autoCompact(this.conversationMessages);
24386
- const activeModel = readAiConfig().model || this.model;
24387
- const activeKey = readAiConfig().apiKey || this.apiKey;
24388
- const activeProvider = this.resolveProvider(activeKey);
24389
- let fullResponse = "";
24390
- for (let loop = 0; loop < 15; loop++) {
24391
- this.ui?.setLoadingLabel(loop === 0 ? "Thinking" : "Processing");
24392
- fullResponse = "";
24393
- const result = await fetchBrainStream(
24394
- loop === 0 ? expanded : this.conversationMessages[this.conversationMessages.length - 1].content,
24395
- {
24396
- onToken: (delta) => {
24397
- if (delta === "\x1B[RETRY]") {
24398
- fullResponse = "";
24399
- this.ui?.setStreaming("");
24400
- return;
24401
- }
24402
- fullResponse += delta;
24403
- const clean = fullResponse.replace(/<memory>[\s\S]*?<\/memory>/g, "").replace(/<cmd>[\s\S]*?<\/cmd>/g, "").replace(/\n{3,}/g, "\n\n").trim();
24404
- this.ui?.setStreaming(clean);
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
- if (commands.length === 0) {
24433
- if (cleaned) this.ui?.addMessage("assistant", cleaned);
24434
- break;
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
- } catch (err) {
24464
- this.ui?.addMessage("info", `Error: ${err.message}`);
24465
- } finally {
24466
- this.ui?.setLoading(false);
24467
- this.ui?.setStreaming("");
24468
- saveSession(this.sessionId, this.sessionName, this.conversationMessages, this.usage);
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 engine.handleInput(initialPrompt);
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinpath/cli",
3
- "version": "1.77.0",
3
+ "version": "1.79.0",
4
4
  "description": "AI-powered scripting CLI — automate anything from your terminal",
5
5
  "type": "module",
6
6
  "license": "MIT",