@robinpath/cli 1.76.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.
Files changed (2) hide show
  1. package/dist/cli.mjs +292 -497
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -18561,7 +18561,7 @@ var init_modules = __esm({
18561
18561
  });
18562
18562
 
18563
18563
  // src/index.ts
18564
- import { readFileSync as readFileSync15, existsSync as existsSync16 } from "node:fs";
18564
+ import { readFileSync as readFileSync14, existsSync as existsSync15 } from "node:fs";
18565
18565
  import { resolve as resolve12, extname as extname5, basename as basename8 } from "node:path";
18566
18566
 
18567
18567
  // src/runtime.ts
@@ -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.76.0" : "1.76.0";
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,113 +24132,97 @@ ${resultSummary}`
24132
24132
  }
24133
24133
 
24134
24134
  // src/ink-repl.tsx
24135
- import { useState } from "react";
24136
- import { render, Box, Text, useInput, useApp } from "ink";
24137
- import { homedir as homedir8, platform as platform7 } from "node:os";
24135
+ import { useState, useEffect } from "react";
24136
+ import { render, Box, Text, Static, useInput, useApp } from "ink";
24137
+ import InkSpinner from "ink-spinner";
24138
+ import { platform as platform7 } from "node:os";
24138
24139
  import { randomUUID as randomUUID4 } from "node:crypto";
24139
- import { readdirSync as readdirSync6, statSync as statSync6 } from "node:fs";
24140
- import { join as join12 } from "node:path";
24141
24140
  import { jsx, jsxs } from "react/jsx-runtime";
24142
- function InputPrompt({ placeholder, onSubmit, onExit }) {
24143
- const [value, setValue] = useState("");
24141
+ var nextId = 0;
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);
24144
24147
  const { exit } = useApp();
24145
- useInput((input, key) => {
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 (value.endsWith("\\")) {
24148
- setValue((p) => p.slice(0, -1) + "\n");
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 = value.trim();
24152
- if (text) {
24163
+ const text = input.trim();
24164
+ setInput("");
24165
+ if (text === "exit" || text === "quit") {
24153
24166
  exit();
24154
- onSubmit(text);
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 === "\n") {
24159
- setValue((p) => p + "\n");
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
- setValue("");
24164
- return;
24165
- }
24166
- if (input === "") {
24167
- if (!value) {
24168
- exit();
24169
- onExit();
24170
- } else setValue("");
24171
- return;
24172
- }
24173
- if (key.backspace || key.delete) {
24174
- setValue((p) => p.slice(0, -1));
24190
+ setInput("");
24175
24191
  return;
24176
24192
  }
24177
24193
  if (key.tab) return;
24178
- if (input === "") {
24179
- setValue("");
24180
- return;
24181
- }
24182
- if (input === "") {
24183
- setValue((p) => p.replace(/\S+\s*$/, ""));
24184
- return;
24194
+ if (character && !key.ctrl && !key.meta) {
24195
+ setInput((prev) => prev + character);
24185
24196
  }
24186
- if (input && !key.ctrl && !key.meta) setValue((p) => p + input);
24187
24197
  });
24188
- const lines = value.split("\n");
24189
- const empty = value === "";
24190
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
24191
- /* @__PURE__ */ jsx(Box, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, marginX: 1, children: empty ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: placeholder }) : lines.map((line, i) => /* @__PURE__ */ jsxs(Text, { children: [
24192
- line,
24193
- i === lines.length - 1 ? /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u2588" }) : null
24194
- ] }, i)) }),
24195
- /* @__PURE__ */ jsx(Box, { marginX: 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "enter send \xB7 \\ newline \xB7 esc clear \xB7 / commands" }) })
24198
+ const lines = input.split("\n");
24199
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
24200
+ /* @__PURE__ */ jsxs(Text, { children: [
24201
+ /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u25C6" }),
24202
+ " ",
24203
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "RobinPath" }),
24204
+ " ",
24205
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
24206
+ "v",
24207
+ CLI_VERSION
24208
+ ] })
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: [
24214
+ /* @__PURE__ */ jsx(InkSpinner, { type: "dots" }),
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
24196
24224
  ] });
24197
24225
  }
24198
- function collectInkInput(placeholder) {
24199
- if (!process.stdin.isTTY) {
24200
- return Promise.resolve(null);
24201
- }
24202
- return new Promise((resolve13) => {
24203
- let resolved = false;
24204
- const instance = render(
24205
- /* @__PURE__ */ jsx(
24206
- InputPrompt,
24207
- {
24208
- placeholder,
24209
- onSubmit: (v) => {
24210
- if (!resolved) {
24211
- resolved = true;
24212
- instance.clear();
24213
- instance.unmount();
24214
- resolve13(v);
24215
- }
24216
- },
24217
- onExit: () => {
24218
- if (!resolved) {
24219
- resolved = true;
24220
- instance.clear();
24221
- instance.unmount();
24222
- resolve13(null);
24223
- }
24224
- }
24225
- }
24226
- )
24227
- );
24228
- instance.waitUntilExit().then(() => {
24229
- if (!resolved) {
24230
- resolved = true;
24231
- resolve13(null);
24232
- }
24233
- });
24234
- });
24235
- }
24236
- function printBanner(modelShort, modeStr, cwdShort, shellName) {
24237
- log("");
24238
- log(` ${color.cyan("\u25C6")} ${color.bold("RobinPath")} ${color.dim("v" + CLI_VERSION)}`);
24239
- log(color.dim(` ${modelShort} \xB7 ${shellName} \xB7 ${modeStr}`));
24240
- log("");
24241
- }
24242
24226
  async function startInkREPL(initialPrompt, resumeSessionId, opts = {}) {
24243
24227
  const config = readAiConfig();
24244
24228
  let autoAccept = opts.autoAccept || false;
@@ -24252,9 +24236,7 @@ async function startInkREPL(initialPrompt, resumeSessionId, opts = {}) {
24252
24236
  return config.provider || "gemini";
24253
24237
  };
24254
24238
  const apiKey = config.apiKey || null;
24255
- const provider = resolveProvider(apiKey);
24256
24239
  const model = apiKey ? config.model || "anthropic/claude-sonnet-4.6" : "robinpath-default";
24257
- const modelShort = model === "robinpath-default" ? "gemini-2.0-flash (free)" : model.includes("/") ? model.split("/").pop() : model;
24258
24240
  const cliContext = {
24259
24241
  platform: platform7(),
24260
24242
  shell: getShellConfig().name,
@@ -24267,348 +24249,161 @@ async function startInkREPL(initialPrompt, resumeSessionId, opts = {}) {
24267
24249
  let sessionName = `session-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
24268
24250
  const usage = createUsageTracker();
24269
24251
  const conversationMessages = [];
24270
- const history = [];
24271
- const memContext = buildMemoryContext();
24272
- if (memContext.trim()) {
24273
- conversationMessages.push({ role: "user", content: `[Context] ${memContext.trim()}` });
24274
- conversationMessages.push({ role: "assistant", content: "Got it, I have your preferences loaded." });
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." });
24275
24256
  }
24276
24257
  if (resumeSessionId) {
24277
24258
  const session = loadSession(resumeSessionId);
24278
24259
  if (session) {
24279
24260
  sessionName = session.name;
24280
24261
  for (const msg of session.messages) conversationMessages.push(msg);
24281
- if (session.usage) {
24282
- usage.promptTokens = session.usage.promptTokens || 0;
24283
- usage.completionTokens = session.usage.completionTokens || 0;
24284
- usage.totalTokens = session.usage.totalTokens || 0;
24285
- usage.requests = session.usage.requests || 0;
24286
- }
24287
- log(color.green(` Resumed: ${sessionName} (${session.messages.length} msgs)`));
24288
- }
24289
- }
24290
- const modeStr = devMode ? "dev" : autoAccept ? "auto" : "confirm";
24291
- const cwdShort = process.cwd().replace(homedir8(), "~");
24292
- printBanner(modelShort, modeStr, cwdShort, getShellConfig().name);
24293
- try {
24294
- const entries = readdirSync6(process.cwd()).filter((e) => !e.startsWith("."));
24295
- let rpCount = 0, dirCount = 0;
24296
- for (const e of entries.slice(0, 100)) {
24297
- try {
24298
- const s = statSync6(join12(process.cwd(), e));
24299
- if (s.isDirectory() && !["node_modules", "__pycache__", "dist", "build"].includes(e)) dirCount++;
24300
- else if (e.endsWith(".rp") || e.endsWith(".robin")) rpCount++;
24301
- } catch {
24302
- }
24262
+ if (session.usage) Object.assign(usage, session.usage);
24303
24263
  }
24304
- if (rpCount > 0 || dirCount > 0) log(color.dim(` ${rpCount} .rp file(s), ${dirCount} dir(s)`));
24305
- } catch {
24306
24264
  }
24307
- let isFirst = !resumeSessionId && !initialPrompt;
24308
- while (true) {
24309
- let trimmed;
24310
- if (initialPrompt) {
24311
- trimmed = initialPrompt.trim();
24312
- initialPrompt = null;
24313
- log(color.cyan(" \u276F ") + trimmed);
24314
- } else {
24315
- const input = await collectInkInput(
24316
- isFirst ? "What do you want to automate?" : "Ask anything..."
24317
- );
24318
- isFirst = false;
24319
- if (input === null) {
24320
- exitWithSave();
24321
- break;
24322
- }
24323
- trimmed = input.trim();
24324
- if (!trimmed) continue;
24325
- log(color.cyan(" \u276F ") + color.bold(trimmed));
24326
- }
24327
- if (trimmed === "/") {
24328
- log("");
24329
- for (const [cmd, desc] of Object.entries(SLASH_CMDS)) {
24330
- log(` ${color.cyan(cmd.padEnd(14))} ${color.dim(desc)}`);
24331
- }
24332
- log("");
24333
- continue;
24334
- }
24335
- if (trimmed === "exit" || trimmed === "quit") {
24336
- exitWithSave();
24337
- break;
24265
+ async function handleMessage(text) {
24266
+ const ui = global.__rpUI;
24267
+ if (text === "/" || text === "/help") return "/model /auto /clear /save /usage /memory exit";
24268
+ if (text === "/clear") {
24269
+ conversationMessages.length = 0;
24270
+ return "Cleared.";
24338
24271
  }
24339
- if (trimmed === "/help") {
24340
- log("");
24341
- for (const [cmd, desc] of Object.entries(SLASH_CMDS)) {
24342
- log(` ${color.cyan(cmd.padEnd(14))} ${color.dim(desc)}`);
24343
- }
24344
- log("");
24345
- continue;
24272
+ if (text === "/usage") {
24273
+ const c = usage.cost > 0 ? `$${usage.cost.toFixed(4)}` : "$0 (free)";
24274
+ return `${usage.totalTokens.toLocaleString()} tokens \xB7 ${usage.requests} requests \xB7 ${c}`;
24346
24275
  }
24347
- if (trimmed === "/clear") {
24348
- conversationMessages.length = 0;
24349
- log(color.green(" Cleared."));
24350
- continue;
24276
+ if (text === "/auto") {
24277
+ autoAccept = !autoAccept;
24278
+ return `Auto-accept: ${autoAccept ? "ON" : "OFF"}`;
24351
24279
  }
24352
- if (trimmed === "/usage") {
24353
- const cost = usage.cost > 0 ? `$${usage.cost.toFixed(4)}` : "$0.00 (free)";
24354
- log(` ${usage.totalTokens.toLocaleString()} tokens \xB7 ${usage.requests} requests \xB7 ${cost}`);
24355
- continue;
24280
+ if (text === "/model") {
24281
+ const hasKey = !!readAiConfig().apiKey;
24282
+ const models = hasKey ? AI_MODELS : AI_MODELS.filter((m) => !m.requiresKey);
24283
+ return models.map((m, i) => `${i + 1}. ${m.name} \u2014 ${m.desc}`).join("\n");
24356
24284
  }
24357
- if (trimmed === "/model") {
24285
+ if (text.match(/^\/model \d+$/)) {
24358
24286
  const hasKey = !!readAiConfig().apiKey;
24359
24287
  const models = hasKey ? AI_MODELS : AI_MODELS.filter((m) => !m.requiresKey);
24360
- const cur = readAiConfig().model || model;
24361
- log("");
24362
- let lastGroup = "";
24363
- for (let i = 0; i < models.length; i++) {
24364
- const m = models[i];
24365
- if (m.group !== lastGroup) {
24366
- log(color.dim(` \u2500\u2500 ${m.group} \u2500\u2500`));
24367
- lastGroup = m.group;
24368
- }
24369
- const mark = m.id === cur ? color.green(" \u2713") : "";
24370
- log(` ${color.cyan(String(i + 1))}. ${m.name} ${color.dim("\u2014 " + m.desc)}${mark}`);
24371
- }
24372
- log("");
24373
- const answer = await collectInkInput("Enter number...");
24374
- if (answer) {
24375
- const idx = parseInt(answer, 10) - 1;
24376
- if (idx >= 0 && idx < models.length) {
24377
- config.model = models[idx].id;
24378
- writeAiConfig(config);
24379
- log(color.green(` Model: ${models[idx].id}`));
24380
- }
24288
+ const idx = parseInt(text.split(" ")[1], 10) - 1;
24289
+ if (idx >= 0 && idx < models.length) {
24290
+ config.model = models[idx].id;
24291
+ writeAiConfig(config);
24292
+ return `Model: ${models[idx].id}`;
24381
24293
  }
24382
- continue;
24294
+ return "Invalid number.";
24383
24295
  }
24384
- if (trimmed === "/auto" || trimmed.startsWith("/auto ")) {
24385
- const arg = trimmed.slice(5).trim().toLowerCase();
24386
- if (arg === "on") autoAccept = true;
24387
- else if (arg === "off") autoAccept = false;
24388
- else autoAccept = !autoAccept;
24389
- log(` Auto-accept: ${autoAccept ? color.green("ON") : color.yellow("OFF")}`);
24390
- continue;
24391
- }
24392
- if (trimmed === "/memory") {
24393
- const mem = loadMemory();
24394
- if (mem.facts.length === 0) log(color.dim(" No memories."));
24395
- else mem.facts.forEach((f, i) => log(` ${i + 1}. ${f}`));
24396
- continue;
24397
- }
24398
- if (trimmed.startsWith("/remember ")) {
24399
- addMemoryFact(trimmed.slice(10).trim());
24400
- log(color.green(" Remembered."));
24401
- continue;
24296
+ if (text === "/memory") {
24297
+ const m = loadMemory();
24298
+ return m.facts.length ? m.facts.map((f, i) => `${i + 1}. ${f}`).join("\n") : "No memories.";
24402
24299
  }
24403
- if (trimmed.startsWith("/forget ")) {
24404
- removeMemoryFact(parseInt(trimmed.slice(8).trim(), 10) - 1);
24405
- log(color.green(" Forgot."));
24406
- continue;
24407
- }
24408
- if (trimmed === "/save" || trimmed.startsWith("/save ")) {
24409
- if (trimmed.length > 5) sessionName = trimmed.slice(5).trim();
24300
+ if (text.startsWith("/save")) {
24301
+ if (text.length > 5) sessionName = text.slice(5).trim();
24410
24302
  saveSession(sessionId, sessionName, conversationMessages, usage);
24411
- log(color.green(` Saved: ${sessionName}`));
24412
- continue;
24303
+ return `Saved: ${sessionName}`;
24413
24304
  }
24414
- if (trimmed === "/sessions") {
24415
- const sessions = listSessions();
24416
- if (sessions.length === 0) log(color.dim(" No sessions."));
24417
- else sessions.forEach((s) => log(` ${color.cyan(s.id)} ${s.name} ${color.dim(`${s.messages} msgs`)}`));
24418
- continue;
24419
- }
24420
- if (trimmed === "/shell") {
24421
- const shells = getAvailableShells();
24422
- shells.forEach((s) => {
24423
- const mark = s.current ? color.green(" \u2713") : s.available ? "" : color.dim(" (not found)");
24424
- log(` ${s.available ? color.cyan(s.name) : color.dim(s.name)}${mark}`);
24425
- });
24426
- continue;
24427
- }
24428
- if (trimmed.startsWith("/shell ")) {
24429
- setShellOverride(trimmed.slice(7).trim());
24430
- cliContext.shell = getShellConfig().name;
24431
- log(` Shell: ${color.cyan(getShellConfig().name)}`);
24432
- continue;
24433
- }
24434
- if (trimmed.startsWith("/")) {
24435
- log(color.dim(` Unknown: ${trimmed}. Type / for commands.`));
24436
- continue;
24437
- }
24438
- const { expanded } = expandFileRefs(trimmed);
24305
+ if (text.startsWith("/")) return `Unknown: ${text}. Type / for help.`;
24306
+ const { expanded } = expandFileRefs(text);
24439
24307
  conversationMessages.push({ role: "user", content: expanded });
24440
24308
  await autoCompact(conversationMessages);
24441
24309
  const activeModel = readAiConfig().model || model;
24442
24310
  const activeKey = readAiConfig().apiKey || apiKey;
24443
24311
  const activeProvider = resolveProvider(activeKey);
24444
- let spinner = createSpinner("Thinking");
24445
- try {
24446
- for (let loop = 0; loop < 15; loop++) {
24447
- let pending = "";
24448
- let insideMemory = false;
24449
- let insideCmd = false;
24450
- const result = await fetchBrainStream(
24451
- loop === 0 ? expanded : conversationMessages[conversationMessages.length - 1].content,
24452
- {
24453
- onToken: (delta) => {
24454
- spinner.stop();
24455
- if (delta === "\x1B[RETRY]") {
24456
- pending = "";
24457
- insideMemory = false;
24458
- insideCmd = false;
24459
- spinner = createSpinner("Retrying");
24460
- return;
24461
- }
24462
- pending += delta;
24463
- while (true) {
24464
- if (insideMemory) {
24465
- const ci2 = pending.indexOf("</memory>");
24466
- if (ci2 === -1) break;
24467
- const fact = pending.slice(0, ci2).trim();
24468
- if (fact.length > 3 && fact.length < 300) addMemoryFact(fact);
24469
- pending = pending.slice(ci2 + 9);
24470
- insideMemory = false;
24471
- continue;
24472
- }
24473
- if (insideCmd) {
24474
- const ci2 = pending.indexOf("</cmd>");
24475
- if (ci2 === -1) break;
24476
- pending = pending.slice(ci2 + 6);
24477
- insideCmd = false;
24478
- continue;
24479
- }
24480
- const mi = pending.indexOf("<memory>");
24481
- const ci = pending.indexOf("<cmd>");
24482
- if (mi === -1 && ci === -1) {
24483
- const lt2 = pending.lastIndexOf("<");
24484
- if (lt2 !== -1 && lt2 > pending.length - 9) {
24485
- if (lt2 > 0) {
24486
- process.stdout.write(pending.slice(0, lt2).replace(/\n{3,}/g, "\n\n"));
24487
- pending = pending.slice(lt2);
24488
- }
24489
- } else {
24490
- process.stdout.write(pending.replace(/\n{3,}/g, "\n\n"));
24491
- pending = "";
24492
- }
24493
- break;
24494
- }
24495
- const first = mi === -1 ? ci : ci === -1 ? mi : Math.min(mi, ci);
24496
- if (first > 0) process.stdout.write(pending.slice(0, first).replace(/\n{3,}/g, "\n\n"));
24497
- if (first === mi) {
24498
- pending = pending.slice(first + 8);
24499
- insideMemory = true;
24500
- } else {
24501
- pending = pending.slice(first + 5);
24502
- insideCmd = true;
24503
- }
24504
- }
24505
- },
24506
- conversationHistory: conversationMessages.slice(0, -1),
24507
- provider: activeProvider,
24508
- model: activeModel,
24509
- apiKey: activeKey,
24510
- cliContext
24511
- }
24512
- );
24513
- if (pending && !insideMemory && !insideCmd) process.stdout.write(pending);
24514
- if (!result || !result.code) {
24515
- spinner.stop();
24516
- log(color.red("\n No response."));
24517
- break;
24518
- }
24519
- if (result.usage) {
24520
- const pt2 = result.usage.prompt_tokens || 0;
24521
- const ct2 = result.usage.completion_tokens || 0;
24522
- usage.promptTokens += pt2;
24523
- usage.completionTokens += ct2;
24524
- usage.totalTokens += pt2 + ct2;
24525
- usage.requests++;
24526
- usage.cost += estimateCost(activeModel, pt2, ct2);
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
24527
24333
  }
24528
- const commands = extractCommands(result.code);
24529
- const { cleaned } = extractMemoryTags(stripCommandTags(result.code));
24530
- process.stdout.write("\n");
24531
- if (cleaned) conversationMessages.push({ role: "assistant", content: cleaned });
24532
- if (commands.length === 0) break;
24533
- const cmdResults = [];
24534
- for (const cmd of commands) {
24535
- const decision = await confirmCommand(cmd, autoAccept);
24536
- if (decision === "no") {
24537
- cmdResults.push({ command: cmd, stdout: "", stderr: "(skipped)", exitCode: -1 });
24538
- continue;
24539
- }
24540
- if (decision === "auto") {
24541
- autoAccept = true;
24542
- log(color.green(" Auto-accept ON"));
24543
- }
24544
- const r = await executeShellCommand(cmd);
24545
- if (r.exitCode !== 0) log(color.red(` exit ${r.exitCode}: ${(r.stderr || "").slice(0, 80)}`));
24546
- cmdResults.push({ command: cmd, stdout: r.stdout || "", stderr: r.stderr || "", exitCode: r.exitCode });
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)}`);
24547
24364
  }
24548
- const summary = cmdResults.map((r) => {
24549
- let o = `$ ${r.command}
24550
- `;
24551
- if (r.exitCode === 0) o += r.stdout || "(no output)";
24552
- else {
24553
- o += `Exit: ${r.exitCode}
24554
- `;
24555
- if (r.stderr) o += r.stderr;
24556
- }
24557
- return o;
24558
- }).join("\n\n");
24559
- conversationMessages.push({ role: "user", content: `[Command results]
24560
- ${summary}` });
24561
- spinner = createSpinner("Processing");
24562
24365
  }
24563
- } catch (err) {
24564
- spinner.stop();
24565
- log(color.red(` Error: ${err.message}`));
24566
- }
24567
- log("");
24568
- if (usage.cost > 0) log(color.dim(` $${usage.cost.toFixed(4)} \xB7 ${usage.totalTokens.toLocaleString()} tokens`));
24569
- }
24570
- function exitWithSave() {
24571
- if (conversationMessages.length > 1) {
24572
- saveSession(sessionId, sessionName, conversationMessages, usage);
24573
- log(color.dim(` Session saved: ${sessionId}`));
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 = "";
24372
+ }
24373
+ saveSession(sessionId, sessionName, conversationMessages, usage);
24374
+ return finalResponse;
24375
+ }
24376
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx(ChatApp, { onMessage: handleMessage }));
24377
+ if (initialPrompt) {
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);
24574
24387
  }
24575
- log(color.dim(" Goodbye!"));
24576
- process.exit(0);
24577
24388
  }
24578
- process.on("SIGINT", () => {
24579
- log("");
24580
- exitWithSave();
24581
- });
24389
+ await waitUntilExit();
24390
+ saveSession(sessionId, sessionName, conversationMessages, usage);
24582
24391
  }
24583
- var SLASH_CMDS = {
24584
- "/help": "Show commands",
24585
- "/model": "Switch AI model",
24586
- "/shell": "Switch shell",
24587
- "/auto": "Toggle auto-accept",
24588
- "/clear": "Clear conversation",
24589
- "/save": "Save session",
24590
- "/sessions": "List sessions",
24591
- "/memory": "Show memory",
24592
- "/remember": "Save a fact",
24593
- "/forget": "Remove a memory",
24594
- "/usage": "Token usage & cost",
24595
- "exit": "Quit"
24596
- };
24597
24392
 
24598
24393
  // src/commands-modules.ts
24599
24394
  import { createInterface as createInterface3 } from "node:readline";
24600
24395
  import {
24601
- readFileSync as readFileSync11,
24602
- existsSync as existsSync12,
24396
+ readFileSync as readFileSync10,
24397
+ existsSync as existsSync11,
24603
24398
  mkdirSync as mkdirSync6,
24604
24399
  copyFileSync as copyFileSync2,
24605
24400
  rmSync as rmSync2,
24606
24401
  writeFileSync as writeFileSync6,
24607
- readdirSync as readdirSync7,
24608
- statSync as statSync7,
24402
+ readdirSync as readdirSync6,
24403
+ statSync as statSync6,
24609
24404
  unlinkSync as unlinkSync5
24610
24405
  } from "node:fs";
24611
- import { resolve as resolve8, join as join13, dirname as dirname4, basename as basename4 } from "node:path";
24406
+ import { resolve as resolve8, join as join12, dirname as dirname4, basename as basename4 } from "node:path";
24612
24407
  import { execSync as execSync2 } from "node:child_process";
24613
24408
  import { homedir as homedir9, platform as platform8, tmpdir as tmpdir3 } from "node:os";
24614
24409
  import { createHash as createHash3 } from "node:crypto";
@@ -24699,17 +24494,17 @@ async function handleAdd(args) {
24699
24494
  process.exit(1);
24700
24495
  }
24701
24496
  const integrity = "sha256-" + createHash3("sha256").update(tarballBuffer).digest("hex");
24702
- if (!existsSync12(CACHE_DIR)) {
24497
+ if (!existsSync11(CACHE_DIR)) {
24703
24498
  mkdirSync6(CACHE_DIR, { recursive: true });
24704
24499
  }
24705
- const cacheFile = join13(CACHE_DIR, `${scope}-${name}-${resolvedVersion}.tar.gz`);
24500
+ const cacheFile = join12(CACHE_DIR, `${scope}-${name}-${resolvedVersion}.tar.gz`);
24706
24501
  writeFileSync6(cacheFile, tarballBuffer);
24707
24502
  const modDir = getModulePath(fullName);
24708
- if (existsSync12(modDir)) {
24503
+ if (existsSync11(modDir)) {
24709
24504
  rmSync2(modDir, { recursive: true, force: true });
24710
24505
  }
24711
24506
  mkdirSync6(modDir, { recursive: true });
24712
- const tmpFile = join13(tmpdir3(), `robinpath-add-${Date.now()}.tar.gz`);
24507
+ const tmpFile = join12(tmpdir3(), `robinpath-add-${Date.now()}.tar.gz`);
24713
24508
  writeFileSync6(tmpFile, tarballBuffer);
24714
24509
  try {
24715
24510
  execSync2(`tar xzf "${toTarPath(tmpFile)}" --strip-components=1 -C "${toTarPath(modDir)}"`, { stdio: "pipe" });
@@ -24726,15 +24521,15 @@ async function handleAdd(args) {
24726
24521
  unlinkSync5(tmpFile);
24727
24522
  } catch {
24728
24523
  }
24729
- const distDir = join13(modDir, "dist");
24730
- const srcDir = join13(modDir, "src");
24731
- if (!existsSync12(distDir) && existsSync12(srcDir) && existsSync12(join13(srcDir, "index.ts"))) {
24524
+ const distDir = join12(modDir, "dist");
24525
+ const srcDir = join12(modDir, "src");
24526
+ if (!existsSync11(distDir) && existsSync11(srcDir) && existsSync11(join12(srcDir, "index.ts"))) {
24732
24527
  log(color.dim(" Compiling module..."));
24733
24528
  mkdirSync6(distDir, { recursive: true });
24734
- const tsFiles = readdirSync7(srcDir).filter((f) => f.endsWith(".ts"));
24529
+ const tsFiles = readdirSync6(srcDir).filter((f) => f.endsWith(".ts"));
24735
24530
  for (const file of tsFiles) {
24736
- const srcFile = join13(srcDir, file);
24737
- const outFile = join13(distDir, file.replace(".ts", ".js"));
24531
+ const srcFile = join12(srcDir, file);
24532
+ const outFile = join12(distDir, file.replace(".ts", ".js"));
24738
24533
  try {
24739
24534
  const stripScript = `
24740
24535
  const fs = require('fs');
@@ -24750,17 +24545,17 @@ async function handleAdd(args) {
24750
24545
  }
24751
24546
  }
24752
24547
  let installedVersion = resolvedVersion;
24753
- const pkgJsonPath = join13(modDir, "package.json");
24754
- if (existsSync12(pkgJsonPath)) {
24548
+ const pkgJsonPath = join12(modDir, "package.json");
24549
+ if (existsSync11(pkgJsonPath)) {
24755
24550
  try {
24756
- const pkg = JSON.parse(readFileSync11(pkgJsonPath, "utf-8"));
24551
+ const pkg = JSON.parse(readFileSync10(pkgJsonPath, "utf-8"));
24757
24552
  installedVersion = pkg.version || installedVersion;
24758
24553
  } catch {
24759
24554
  }
24760
24555
  }
24761
- if (existsSync12(pkgJsonPath)) {
24556
+ if (existsSync11(pkgJsonPath)) {
24762
24557
  try {
24763
- const pkg = JSON.parse(readFileSync11(pkgJsonPath, "utf-8"));
24558
+ const pkg = JSON.parse(readFileSync10(pkgJsonPath, "utf-8"));
24764
24559
  const depends = pkg.robinpath?.depends || [];
24765
24560
  for (const dep of depends) {
24766
24561
  if (!manifest[dep]) {
@@ -24779,9 +24574,9 @@ async function handleAdd(args) {
24779
24574
  };
24780
24575
  writeModulesManifest(updatedManifest);
24781
24576
  const projectFile = resolve8("robinpath.json");
24782
- if (existsSync12(projectFile)) {
24577
+ if (existsSync11(projectFile)) {
24783
24578
  try {
24784
- const config = JSON.parse(readFileSync11(projectFile, "utf-8"));
24579
+ const config = JSON.parse(readFileSync10(projectFile, "utf-8"));
24785
24580
  if (!config.modules) config.modules = {};
24786
24581
  config.modules[fullName] = `^${installedVersion}`;
24787
24582
  writeFileSync6(projectFile, JSON.stringify(config, null, 2) + "\n", "utf-8");
@@ -24809,12 +24604,12 @@ async function handleRemove(args) {
24809
24604
  process.exit(1);
24810
24605
  }
24811
24606
  const modDir = getModulePath(fullName);
24812
- if (existsSync12(modDir)) {
24607
+ if (existsSync11(modDir)) {
24813
24608
  rmSync2(modDir, { recursive: true, force: true });
24814
24609
  }
24815
24610
  const scopeDir = dirname4(modDir);
24816
24611
  try {
24817
- const remaining = readdirSync7(scopeDir);
24612
+ const remaining = readdirSync6(scopeDir);
24818
24613
  if (remaining.length === 0) {
24819
24614
  rmSync2(scopeDir, { recursive: true, force: true });
24820
24615
  }
@@ -24823,9 +24618,9 @@ async function handleRemove(args) {
24823
24618
  delete manifest[fullName];
24824
24619
  writeModulesManifest(manifest);
24825
24620
  const projectFile = resolve8("robinpath.json");
24826
- if (existsSync12(projectFile)) {
24621
+ if (existsSync11(projectFile)) {
24827
24622
  try {
24828
- const config = JSON.parse(readFileSync11(projectFile, "utf-8"));
24623
+ const config = JSON.parse(readFileSync10(projectFile, "utf-8"));
24829
24624
  if (config.modules && config.modules[fullName]) {
24830
24625
  delete config.modules[fullName];
24831
24626
  writeFileSync6(projectFile, JSON.stringify(config, null, 2) + "\n", "utf-8");
@@ -24998,14 +24793,14 @@ async function handleModulesInit() {
24998
24793
  const targetDir = resolve8(moduleName);
24999
24794
  log("");
25000
24795
  log(`Creating ${color.cyan(fullName)}...`);
25001
- if (existsSync12(targetDir)) {
24796
+ if (existsSync11(targetDir)) {
25002
24797
  console.error(color.red("Error:") + ` Directory already exists: ${moduleName}/`);
25003
24798
  process.exit(1);
25004
24799
  }
25005
- mkdirSync6(join13(targetDir, "src"), { recursive: true });
25006
- mkdirSync6(join13(targetDir, "tests"), { recursive: true });
24800
+ mkdirSync6(join12(targetDir, "src"), { recursive: true });
24801
+ mkdirSync6(join12(targetDir, "tests"), { recursive: true });
25007
24802
  writeFileSync6(
25008
- join13(targetDir, "package.json"),
24803
+ join12(targetDir, "package.json"),
25009
24804
  JSON.stringify(
25010
24805
  {
25011
24806
  name: fullName,
@@ -25029,7 +24824,7 @@ async function handleModulesInit() {
25029
24824
  "utf-8"
25030
24825
  );
25031
24826
  writeFileSync6(
25032
- join13(targetDir, "src", "index.ts"),
24827
+ join12(targetDir, "src", "index.ts"),
25033
24828
  `import type { ModuleAdapter } from "@wiredwp/robinpath";
25034
24829
  import {
25035
24830
  ${pascalName}Functions,
@@ -25051,7 +24846,7 @@ export { ${pascalName}Module };
25051
24846
  "utf-8"
25052
24847
  );
25053
24848
  writeFileSync6(
25054
- join13(targetDir, "src", `${moduleName}.ts`),
24849
+ join12(targetDir, "src", `${moduleName}.ts`),
25055
24850
  `import type {
25056
24851
  BuiltinHandler,
25057
24852
  FunctionMetadata,
@@ -25122,7 +24917,7 @@ export const ${pascalName}ModuleMetadata: ModuleMetadata = {
25122
24917
  "utf-8"
25123
24918
  );
25124
24919
  writeFileSync6(
25125
- join13(targetDir, "tsconfig.json"),
24920
+ join12(targetDir, "tsconfig.json"),
25126
24921
  JSON.stringify(
25127
24922
  {
25128
24923
  compilerOptions: {
@@ -25146,7 +24941,7 @@ export const ${pascalName}ModuleMetadata: ModuleMetadata = {
25146
24941
  "utf-8"
25147
24942
  );
25148
24943
  writeFileSync6(
25149
- join13(targetDir, "tests", `${moduleName}.test.rp`),
24944
+ join12(targetDir, "tests", `${moduleName}.test.rp`),
25150
24945
  `# ${displayName} module tests
25151
24946
  # Run: robinpath test tests/
25152
24947
 
@@ -25165,7 +24960,7 @@ enddo
25165
24960
  "utf-8"
25166
24961
  );
25167
24962
  writeFileSync6(
25168
- join13(targetDir, "README.md"),
24963
+ join12(targetDir, "README.md"),
25169
24964
  `# ${fullName}
25170
24965
 
25171
24966
  ${description}
@@ -25209,7 +25004,7 @@ ${license}
25209
25004
  "utf-8"
25210
25005
  );
25211
25006
  writeFileSync6(
25212
- join13(targetDir, ".gitignore"),
25007
+ join12(targetDir, ".gitignore"),
25213
25008
  `node_modules/
25214
25009
  dist/
25215
25010
  *.tgz
@@ -25239,14 +25034,14 @@ dist/
25239
25034
  async function handlePack(args) {
25240
25035
  const targetArg = args.find((a) => !a.startsWith("-")) || ".";
25241
25036
  const targetDir = resolve8(targetArg);
25242
- const pkgPath = join13(targetDir, "package.json");
25243
- if (!existsSync12(pkgPath)) {
25037
+ const pkgPath = join12(targetDir, "package.json");
25038
+ if (!existsSync11(pkgPath)) {
25244
25039
  console.error(color.red("Error:") + ` No package.json found in ${targetDir}`);
25245
25040
  process.exit(2);
25246
25041
  }
25247
25042
  let pkg;
25248
25043
  try {
25249
- pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
25044
+ pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
25250
25045
  } catch (err) {
25251
25046
  console.error(color.red("Error:") + ` Invalid package.json: ${err.message}`);
25252
25047
  process.exit(2);
@@ -25267,12 +25062,12 @@ async function handlePack(args) {
25267
25062
  { stdio: "pipe" }
25268
25063
  );
25269
25064
  } catch (err) {
25270
- if (!existsSync12(outputPath)) {
25065
+ if (!existsSync11(outputPath)) {
25271
25066
  console.error(color.red("Error:") + ` Failed to create tarball: ${err.message}`);
25272
25067
  process.exit(1);
25273
25068
  }
25274
25069
  }
25275
- const size = statSync7(outputPath).size;
25070
+ const size = statSync6(outputPath).size;
25276
25071
  log(color.green("Created") + ` ${outputFile} (${(size / 1024).toFixed(1)}KB)`);
25277
25072
  }
25278
25073
  function formatCompactNumber(n) {
@@ -25421,9 +25216,9 @@ async function handleInfo(args) {
25421
25216
  path: getModulePath(packageName)
25422
25217
  };
25423
25218
  try {
25424
- const pkgPath = join13(getModulePath(packageName), "package.json");
25425
- if (existsSync12(pkgPath)) {
25426
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
25219
+ const pkgPath = join12(getModulePath(packageName), "package.json");
25220
+ if (existsSync11(pkgPath)) {
25221
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
25427
25222
  if (pkg.description) entry.description = pkg.description;
25428
25223
  if (pkg.keywords) entry.keywords = pkg.keywords;
25429
25224
  }
@@ -25447,9 +25242,9 @@ async function handleInfo(args) {
25447
25242
  modules_manifest: MODULES_MANIFEST,
25448
25243
  cache: CACHE_DIR,
25449
25244
  auth: getAuthPath(),
25450
- history: join13(homedir9(), ".robinpath", "history"),
25451
- env: join13(homedir9(), ".robinpath", "env"),
25452
- docs: join13(getRobinPathHome(), "DOCUMENTATION.md")
25245
+ history: join12(homedir9(), ".robinpath", "history"),
25246
+ env: join12(homedir9(), ".robinpath", "env"),
25247
+ docs: join12(getRobinPathHome(), "DOCUMENTATION.md")
25453
25248
  },
25454
25249
  native_modules: modulesInfo,
25455
25250
  installed_modules: installedModulesInfo,
@@ -25838,14 +25633,14 @@ async function handleInfo(args) {
25838
25633
  }
25839
25634
 
25840
25635
  // src/commands-project.ts
25841
- import { readFileSync as readFileSync12, existsSync as existsSync13, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, readdirSync as readdirSync8, statSync as statSync8, rmSync as rmSync3, chmodSync as chmodSync3 } from "node:fs";
25842
- import { resolve as resolve9, join as join14, basename as basename5 } from "node:path";
25636
+ import { readFileSync as readFileSync11, existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, readdirSync as readdirSync7, statSync as statSync7, rmSync as rmSync3, chmodSync as chmodSync3 } from "node:fs";
25637
+ import { resolve as resolve9, join as join13, basename as basename5 } from "node:path";
25843
25638
  import { createInterface as createInterface4 } from "node:readline";
25844
25639
  import { platform as platform9 } from "node:os";
25845
25640
  var PLATFORM_URL3 = process.env.ROBINPATH_PLATFORM_URL || "https://api.robinpath.com";
25846
25641
  async function handleInit(args) {
25847
25642
  const projectFile = resolve9("robinpath.json");
25848
- if (existsSync13(projectFile) && !args.includes("--force")) {
25643
+ if (existsSync12(projectFile) && !args.includes("--force")) {
25849
25644
  console.error(color.red("Error:") + " robinpath.json already exists. Use --force to overwrite.");
25850
25645
  process.exit(1);
25851
25646
  }
@@ -25876,7 +25671,7 @@ async function handleInit(args) {
25876
25671
  };
25877
25672
  writeFileSync7(projectFile, JSON.stringify(config, null, 2) + "\n", "utf-8");
25878
25673
  const mainPath = resolve9(mainFile);
25879
- if (!existsSync13(mainPath)) {
25674
+ if (!existsSync12(mainPath)) {
25880
25675
  writeFileSync7(
25881
25676
  mainPath,
25882
25677
  `# ${projectName}
@@ -25887,7 +25682,7 @@ log "Hello from RobinPath!"
25887
25682
  "utf-8"
25888
25683
  );
25889
25684
  }
25890
- if (!existsSync13(resolve9(".env"))) {
25685
+ if (!existsSync12(resolve9(".env"))) {
25891
25686
  writeFileSync7(
25892
25687
  resolve9(".env"),
25893
25688
  `# Add your secrets here
@@ -25897,7 +25692,7 @@ log "Hello from RobinPath!"
25897
25692
  "utf-8"
25898
25693
  );
25899
25694
  }
25900
- if (!existsSync13(resolve9(".gitignore"))) {
25695
+ if (!existsSync12(resolve9(".gitignore"))) {
25901
25696
  writeFileSync7(
25902
25697
  resolve9(".gitignore"),
25903
25698
  `.env
@@ -25910,7 +25705,7 @@ node_modules/
25910
25705
  log("");
25911
25706
  log(color.green("Created project:"));
25912
25707
  log(` robinpath.json`);
25913
- if (!existsSync13(mainPath)) log(` ${mainFile}`);
25708
+ if (!existsSync12(mainPath)) log(` ${mainFile}`);
25914
25709
  log(` .env`);
25915
25710
  log(` .gitignore`);
25916
25711
  log("");
@@ -25919,13 +25714,13 @@ node_modules/
25919
25714
  }
25920
25715
  async function handleProjectInstall() {
25921
25716
  const projectFile = resolve9("robinpath.json");
25922
- if (!existsSync13(projectFile)) {
25717
+ if (!existsSync12(projectFile)) {
25923
25718
  handleInstall();
25924
25719
  return;
25925
25720
  }
25926
25721
  let config;
25927
25722
  try {
25928
- config = JSON.parse(readFileSync12(projectFile, "utf-8"));
25723
+ config = JSON.parse(readFileSync11(projectFile, "utf-8"));
25929
25724
  } catch (err) {
25930
25725
  console.error(color.red("Error:") + ` Invalid robinpath.json: ${err.message}`);
25931
25726
  process.exit(2);
@@ -25996,7 +25791,7 @@ async function handleDoctor() {
25996
25791
  const installDir = getInstallDir();
25997
25792
  const isWindows = platform9() === "win32";
25998
25793
  const binaryName = isWindows ? "robinpath.exe" : "robinpath";
25999
- if (existsSync13(join14(installDir, binaryName))) {
25794
+ if (existsSync12(join13(installDir, binaryName))) {
26000
25795
  log(color.green(" \u2713") + ` Installed: ${installDir}`);
26001
25796
  } else {
26002
25797
  log(color.yellow(" !") + ` Not installed to PATH. Run ${color.cyan("robinpath install")}`);
@@ -26023,21 +25818,21 @@ async function handleDoctor() {
26023
25818
  log(color.green(" \u2713") + ` ${moduleCount} module${moduleCount !== 1 ? "s" : ""} installed`);
26024
25819
  for (const [name, info] of Object.entries(manifest)) {
26025
25820
  const modDir = getModulePath(name);
26026
- const pkgPath = join14(modDir, "package.json");
26027
- if (!existsSync13(modDir)) {
25821
+ const pkgPath = join13(modDir, "package.json");
25822
+ if (!existsSync12(modDir)) {
26028
25823
  log(color.red(" \u2717") + ` ${name}: directory missing`);
26029
25824
  issues++;
26030
- } else if (!existsSync13(pkgPath)) {
25825
+ } else if (!existsSync12(pkgPath)) {
26031
25826
  log(color.red(" \u2717") + ` ${name}: package.json missing`);
26032
25827
  issues++;
26033
25828
  } else {
26034
25829
  let entryPoint = "dist/index.js";
26035
25830
  try {
26036
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
25831
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
26037
25832
  if (pkg.main) entryPoint = pkg.main;
26038
25833
  } catch {
26039
25834
  }
26040
- if (!existsSync13(join14(modDir, entryPoint))) {
25835
+ if (!existsSync12(join13(modDir, entryPoint))) {
26041
25836
  log(color.red(" \u2717") + ` ${name}: entry point ${entryPoint} missing`);
26042
25837
  issues++;
26043
25838
  }
@@ -26047,9 +25842,9 @@ async function handleDoctor() {
26047
25842
  log(color.dim(" -") + ` No modules installed`);
26048
25843
  }
26049
25844
  const projectFile = resolve9("robinpath.json");
26050
- if (existsSync13(projectFile)) {
25845
+ if (existsSync12(projectFile)) {
26051
25846
  try {
26052
- const config = JSON.parse(readFileSync12(projectFile, "utf-8"));
25847
+ const config = JSON.parse(readFileSync11(projectFile, "utf-8"));
26053
25848
  log(color.green(" \u2713") + ` Project: ${config.name || "unnamed"} v${config.version || "?"}`);
26054
25849
  const projectModules = Object.keys(config.modules || {});
26055
25850
  for (const mod of projectModules) {
@@ -26063,12 +25858,12 @@ async function handleDoctor() {
26063
25858
  issues++;
26064
25859
  }
26065
25860
  }
26066
- if (existsSync13(CACHE_DIR)) {
25861
+ if (existsSync12(CACHE_DIR)) {
26067
25862
  try {
26068
- const cacheFiles = readdirSync8(CACHE_DIR);
25863
+ const cacheFiles = readdirSync7(CACHE_DIR);
26069
25864
  const cacheSize = cacheFiles.reduce((total, f) => {
26070
25865
  try {
26071
- return total + statSync8(join14(CACHE_DIR, f)).size;
25866
+ return total + statSync7(join13(CACHE_DIR, f)).size;
26072
25867
  } catch {
26073
25868
  return total;
26074
25869
  }
@@ -26086,12 +25881,12 @@ async function handleDoctor() {
26086
25881
  log("");
26087
25882
  }
26088
25883
  async function handleEnv(args) {
26089
- const envPath = join14(getRobinPathHome(), "env");
25884
+ const envPath = join13(getRobinPathHome(), "env");
26090
25885
  const sub = args[0];
26091
25886
  function readEnvFile() {
26092
25887
  try {
26093
- if (!existsSync13(envPath)) return {};
26094
- const lines = readFileSync12(envPath, "utf-8").split("\n");
25888
+ if (!existsSync12(envPath)) return {};
25889
+ const lines = readFileSync11(envPath, "utf-8").split("\n");
26095
25890
  const env = {};
26096
25891
  for (const line of lines) {
26097
25892
  const trimmed = line.trim();
@@ -26108,7 +25903,7 @@ async function handleEnv(args) {
26108
25903
  }
26109
25904
  function writeEnvFile(env) {
26110
25905
  const dir = getRobinPathHome();
26111
- if (!existsSync13(dir)) mkdirSync7(dir, { recursive: true });
25906
+ if (!existsSync12(dir)) mkdirSync7(dir, { recursive: true });
26112
25907
  const content = Object.entries(env).map(([k2, v]) => `${k2}=${v}`).join("\n") + "\n";
26113
25908
  writeFileSync7(envPath, content, "utf-8");
26114
25909
  if (platform9() !== "win32") {
@@ -26172,12 +25967,12 @@ async function handleEnv(args) {
26172
25967
  async function handleCache(args) {
26173
25968
  const sub = args[0];
26174
25969
  if (sub === "list") {
26175
- if (!existsSync13(CACHE_DIR)) {
25970
+ if (!existsSync12(CACHE_DIR)) {
26176
25971
  log("Cache is empty.");
26177
25972
  return;
26178
25973
  }
26179
25974
  try {
26180
- const files = readdirSync8(CACHE_DIR);
25975
+ const files = readdirSync7(CACHE_DIR);
26181
25976
  if (files.length === 0) {
26182
25977
  log("Cache is empty.");
26183
25978
  return;
@@ -26187,7 +25982,7 @@ async function handleCache(args) {
26187
25982
  log(color.dim(" " + "\u2500".repeat(50)));
26188
25983
  let totalSize = 0;
26189
25984
  for (const file of files) {
26190
- const size = statSync8(join14(CACHE_DIR, file)).size;
25985
+ const size = statSync7(join13(CACHE_DIR, file)).size;
26191
25986
  totalSize += size;
26192
25987
  log(` ${file.padEnd(45)} ${color.dim((size / 1024).toFixed(1) + "KB")}`);
26193
25988
  }
@@ -26203,15 +25998,15 @@ async function handleCache(args) {
26203
25998
  process.exit(1);
26204
25999
  }
26205
26000
  } else if (sub === "clean") {
26206
- if (!existsSync13(CACHE_DIR)) {
26001
+ if (!existsSync12(CACHE_DIR)) {
26207
26002
  log("Cache is already empty.");
26208
26003
  return;
26209
26004
  }
26210
26005
  try {
26211
- const files = readdirSync8(CACHE_DIR);
26006
+ const files = readdirSync7(CACHE_DIR);
26212
26007
  let totalSize = 0;
26213
26008
  for (const file of files) {
26214
- totalSize += statSync8(join14(CACHE_DIR, file)).size;
26009
+ totalSize += statSync7(join13(CACHE_DIR, file)).size;
26215
26010
  }
26216
26011
  rmSync3(CACHE_DIR, { recursive: true, force: true });
26217
26012
  log(
@@ -26326,8 +26121,8 @@ async function handleDeprecate(args) {
26326
26121
  }
26327
26122
 
26328
26123
  // src/commands-snippets.ts
26329
- import { readFileSync as readFileSync13, existsSync as existsSync14, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "node:fs";
26330
- import { resolve as resolve10, basename as basename6, extname as extname4, join as join15 } from "node:path";
26124
+ import { readFileSync as readFileSync12, existsSync as existsSync13, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "node:fs";
26125
+ import { resolve as resolve10, basename as basename6, extname as extname4, join as join14 } from "node:path";
26331
26126
  import { homedir as homedir10, platform as platform10 } from "node:os";
26332
26127
  import { createInterface as createInterface5 } from "node:readline";
26333
26128
  var PLATFORM_URL4 = process.env.ROBINPATH_PLATFORM_URL || "https://api.robinpath.com";
@@ -26563,11 +26358,11 @@ async function snippetCreate(args) {
26563
26358
  defaultName = "untitled";
26564
26359
  } else {
26565
26360
  const filePath = resolve10(fileArg);
26566
- if (!existsSync14(filePath)) {
26361
+ if (!existsSync13(filePath)) {
26567
26362
  console.error(color.red("Error:") + ` File not found: ${fileArg}`);
26568
26363
  process.exit(1);
26569
26364
  }
26570
- code = readFileSync13(filePath, "utf-8");
26365
+ code = readFileSync12(filePath, "utf-8");
26571
26366
  defaultName = basename6(filePath, extname4(filePath));
26572
26367
  }
26573
26368
  if (!code || !code.trim()) {
@@ -26589,8 +26384,8 @@ async function snippetCreate(args) {
26589
26384
  if (flags.version) payload.version = flags.version;
26590
26385
  if (flags.readme) {
26591
26386
  const readmePath = resolve10(flags.readme);
26592
- if (existsSync14(readmePath)) {
26593
- payload.readme = readFileSync13(readmePath, "utf-8");
26387
+ if (existsSync13(readmePath)) {
26388
+ payload.readme = readFileSync12(readmePath, "utf-8");
26594
26389
  }
26595
26390
  }
26596
26391
  try {
@@ -26673,12 +26468,12 @@ async function snippetInit(args) {
26673
26468
  code = codeLines.join("\n");
26674
26469
  } else {
26675
26470
  const filePath = await ask("File path", "");
26676
- if (!filePath || !existsSync14(resolve10(filePath))) {
26471
+ if (!filePath || !existsSync13(resolve10(filePath))) {
26677
26472
  console.error(color.red("Error:") + " File not found.");
26678
26473
  rl.close();
26679
26474
  process.exit(1);
26680
26475
  }
26681
- code = readFileSync13(resolve10(filePath), "utf-8");
26476
+ code = readFileSync12(resolve10(filePath), "utf-8");
26682
26477
  }
26683
26478
  rl.close();
26684
26479
  if (!code.trim()) {
@@ -26835,16 +26630,16 @@ async function snippetUpdate(args) {
26835
26630
  payload.tags = flags.tags.split(",").map((t) => t.trim()).filter(Boolean);
26836
26631
  if (flags.code) {
26837
26632
  const codePath = resolve10(flags.code);
26838
- if (!existsSync14(codePath)) {
26633
+ if (!existsSync13(codePath)) {
26839
26634
  console.error(color.red("Error:") + ` Code file not found: ${flags.code}`);
26840
26635
  process.exit(1);
26841
26636
  }
26842
- payload.code = readFileSync13(codePath, "utf-8");
26637
+ payload.code = readFileSync12(codePath, "utf-8");
26843
26638
  }
26844
26639
  if (flags.readme) {
26845
26640
  const readmePath = resolve10(flags.readme);
26846
- if (existsSync14(readmePath)) {
26847
- payload.readme = readFileSync13(readmePath, "utf-8");
26641
+ if (existsSync13(readmePath)) {
26642
+ payload.readme = readFileSync12(readmePath, "utf-8");
26848
26643
  }
26849
26644
  }
26850
26645
  if (Object.keys(payload).length === 0) {
@@ -27220,16 +27015,16 @@ async function snippetCopy(args) {
27220
27015
  process.exit(1);
27221
27016
  }
27222
27017
  }
27223
- var SNIPPET_CACHE_DIR = join15(homedir10(), ".robinpath", "cache", "snippets");
27018
+ var SNIPPET_CACHE_DIR = join14(homedir10(), ".robinpath", "cache", "snippets");
27224
27019
  var SNIPPET_CACHE_TTL = 5 * 60 * 1e3;
27225
27020
  function getSnippetCachePath(id) {
27226
- return join15(SNIPPET_CACHE_DIR, `${id}.json`);
27021
+ return join14(SNIPPET_CACHE_DIR, `${id}.json`);
27227
27022
  }
27228
27023
  function readSnippetCache(id) {
27229
27024
  try {
27230
27025
  const cachePath = getSnippetCachePath(id);
27231
- if (!existsSync14(cachePath)) return null;
27232
- const raw = JSON.parse(readFileSync13(cachePath, "utf-8"));
27026
+ if (!existsSync13(cachePath)) return null;
27027
+ const raw = JSON.parse(readFileSync12(cachePath, "utf-8"));
27233
27028
  if (Date.now() - (raw._cachedAt || 0) > SNIPPET_CACHE_TTL) return null;
27234
27029
  return raw;
27235
27030
  } catch {
@@ -27238,7 +27033,7 @@ function readSnippetCache(id) {
27238
27033
  }
27239
27034
  function writeSnippetCache(id, data) {
27240
27035
  try {
27241
- if (!existsSync14(SNIPPET_CACHE_DIR)) {
27036
+ if (!existsSync13(SNIPPET_CACHE_DIR)) {
27242
27037
  mkdirSync8(SNIPPET_CACHE_DIR, { recursive: true });
27243
27038
  }
27244
27039
  writeFileSync8(getSnippetCachePath(id), JSON.stringify({ ...data, _cachedAt: Date.now() }), "utf-8");
@@ -27352,11 +27147,11 @@ async function snippetPush(args) {
27352
27147
  }
27353
27148
  id = await resolveSnippetId(id);
27354
27149
  const filePath = resolve10(fileArg);
27355
- if (!existsSync14(filePath)) {
27150
+ if (!existsSync13(filePath)) {
27356
27151
  console.error(color.red("Error:") + ` File not found: ${fileArg}`);
27357
27152
  process.exit(1);
27358
27153
  }
27359
- const code = readFileSync13(filePath, "utf-8");
27154
+ const code = readFileSync12(filePath, "utf-8");
27360
27155
  if (!code.trim()) {
27361
27156
  console.error(color.red("Error:") + " File is empty.");
27362
27157
  process.exit(1);
@@ -27440,11 +27235,11 @@ async function snippetDiff(args) {
27440
27235
  }
27441
27236
  id = await resolveSnippetId(id);
27442
27237
  const filePath = resolve10(fileArg);
27443
- if (!existsSync14(filePath)) {
27238
+ if (!existsSync13(filePath)) {
27444
27239
  console.error(color.red("Error:") + ` File not found: ${fileArg}`);
27445
27240
  process.exit(1);
27446
27241
  }
27447
- const localCode = readFileSync13(filePath, "utf-8");
27242
+ const localCode = readFileSync12(filePath, "utf-8");
27448
27243
  try {
27449
27244
  const res = await fetchSnippet(id);
27450
27245
  if (!res.ok) {
@@ -27564,13 +27359,13 @@ async function snippetImport(args) {
27564
27359
  process.exit(2);
27565
27360
  }
27566
27361
  const filePath = resolve10(fileArg);
27567
- if (!existsSync14(filePath)) {
27362
+ if (!existsSync13(filePath)) {
27568
27363
  console.error(color.red("Error:") + ` File not found: ${fileArg}`);
27569
27364
  process.exit(1);
27570
27365
  }
27571
27366
  let importData;
27572
27367
  try {
27573
- importData = JSON.parse(readFileSync13(filePath, "utf-8"));
27368
+ importData = JSON.parse(readFileSync12(filePath, "utf-8"));
27574
27369
  } catch {
27575
27370
  console.error(color.red("Error:") + " Invalid JSON file.");
27576
27371
  process.exit(1);
@@ -27637,8 +27432,8 @@ async function snippetImport(args) {
27637
27432
 
27638
27433
  // src/commands-cloud.ts
27639
27434
  import { createServer as createServer4 } from "node:http";
27640
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, unlinkSync as unlinkSync6, existsSync as existsSync15 } from "node:fs";
27641
- import { resolve as resolve11, join as join16, dirname as dirname5, basename as basename7 } from "node:path";
27435
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, unlinkSync as unlinkSync6, existsSync as existsSync14 } from "node:fs";
27436
+ import { resolve as resolve11, join as join15, dirname as dirname5, basename as basename7 } from "node:path";
27642
27437
  import { execSync as execSync3 } from "node:child_process";
27643
27438
  import { tmpdir as tmpdir4, hostname as hostname3 } from "node:os";
27644
27439
  var CLOUD_URL2 = process.env.ROBINPATH_CLOUD_URL || "https://dev.robinpath.com";
@@ -27774,14 +27569,14 @@ async function handlePublish(args) {
27774
27569
  const isDryRun = args.includes("--dry-run");
27775
27570
  const targetArg = args.find((a) => !a.startsWith("-") && !a.startsWith("--org")) || ".";
27776
27571
  const targetDir = resolve11(targetArg);
27777
- const pkgPath = join16(targetDir, "package.json");
27778
- if (!existsSync15(pkgPath)) {
27572
+ const pkgPath = join15(targetDir, "package.json");
27573
+ if (!existsSync14(pkgPath)) {
27779
27574
  console.error(color.red("Error:") + ` No package.json found in ${targetDir}`);
27780
27575
  process.exit(2);
27781
27576
  }
27782
27577
  let pkg;
27783
27578
  try {
27784
- pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
27579
+ pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
27785
27580
  } catch (err) {
27786
27581
  console.error(color.red("Error:") + ` Invalid package.json: ${err.message}`);
27787
27582
  process.exit(2);
@@ -27825,7 +27620,7 @@ async function handlePublish(args) {
27825
27620
  scope = emailPrefix;
27826
27621
  name = pkg.name;
27827
27622
  }
27828
- const tmpFile = join16(tmpdir4(), `robinpath-publish-${Date.now()}.tar.gz`);
27623
+ const tmpFile = join15(tmpdir4(), `robinpath-publish-${Date.now()}.tar.gz`);
27829
27624
  const parentDir = dirname5(targetDir);
27830
27625
  const dirName = basename7(targetDir);
27831
27626
  log(`Packing @${scope}/${name}@${pkg.version} (${visibility})...`);
@@ -27842,7 +27637,7 @@ async function handlePublish(args) {
27842
27637
  console.error(color.red("Error:") + ` Failed to create tarball: ${err.message}`);
27843
27638
  process.exit(1);
27844
27639
  }
27845
- const tarball = readFileSync14(tmpFile);
27640
+ const tarball = readFileSync13(tmpFile);
27846
27641
  const maxSize = 50 * 1024 * 1024;
27847
27642
  if (tarball.length > maxSize) {
27848
27643
  unlinkSync6(tmpFile);
@@ -28154,7 +27949,7 @@ async function main() {
28154
27949
  return;
28155
27950
  }
28156
27951
  if (command === "install") {
28157
- existsSync16(resolve12("robinpath.json")) ? await handleProjectInstall() : handleInstall();
27952
+ existsSync15(resolve12("robinpath.json")) ? await handleProjectInstall() : handleInstall();
28158
27953
  return;
28159
27954
  }
28160
27955
  if (command === "uninstall") {
@@ -28273,7 +28068,7 @@ async function main() {
28273
28068
  }
28274
28069
  process.exit(2);
28275
28070
  }
28276
- const script = readFileSync15(filePath, "utf-8");
28071
+ const script = readFileSync14(filePath, "utf-8");
28277
28072
  const hasWatch = args.includes("--watch");
28278
28073
  const hasShortWatch = args.includes("-w") && command !== "fmt";
28279
28074
  if (hasWatch || hasShortWatch) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinpath/cli",
3
- "version": "1.76.0",
3
+ "version": "1.78.0",
4
4
  "description": "AI-powered scripting CLI — automate anything from your terminal",
5
5
  "type": "module",
6
6
  "license": "MIT",