@robinpath/cli 2.8.0 → 3.0.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 +68 -12
  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 ? "2.8.0" : "2.8.0";
18601
+ var CLI_VERSION = true ? "3.0.0" : "3.0.0";
18602
18602
  var FLAG_QUIET = false;
18603
18603
  var FLAG_VERBOSE = false;
18604
18604
  var FLAG_AUTO_ACCEPT = false;
@@ -24134,7 +24134,7 @@ ${resultSummary}`
24134
24134
 
24135
24135
  // src/ink-repl.tsx
24136
24136
  import { useState, useCallback, useEffect, useMemo } from "react";
24137
- import { render, Box as Box2, Text as Text2, Static, useInput, useApp } from "ink";
24137
+ import { render, Box as Box2, Text as Text2, useInput, useApp } from "ink";
24138
24138
  import InkSpinner from "ink-spinner";
24139
24139
 
24140
24140
  // src/ui/Markdown.tsx
@@ -24276,8 +24276,10 @@ var COMMANDS = {
24276
24276
  "/shell": "Switch shell",
24277
24277
  "/help": "All commands"
24278
24278
  };
24279
- function InputArea({ onSubmit, placeholder, statusText }) {
24279
+ function InputArea({ onSubmit, placeholder, statusText, history }) {
24280
24280
  const [value, setValue] = useState("");
24281
+ const [historyIdx, setHistoryIdx] = useState(-1);
24282
+ const [savedInput, setSavedInput] = useState("");
24281
24283
  const { exit } = useApp();
24282
24284
  const matchingCommands = useMemo(() => {
24283
24285
  if (!value.startsWith("/")) return [];
@@ -24347,6 +24349,24 @@ function InputArea({ onSubmit, placeholder, statusText }) {
24347
24349
  }
24348
24350
  return;
24349
24351
  }
24352
+ if (key.upArrow && history && history.length > 0) {
24353
+ if (historyIdx === -1) setSavedInput(value);
24354
+ const newIdx = Math.min(historyIdx + 1, history.length - 1);
24355
+ setHistoryIdx(newIdx);
24356
+ setValue(history[history.length - 1 - newIdx]);
24357
+ return;
24358
+ }
24359
+ if (key.downArrow && historyIdx >= 0) {
24360
+ const newIdx = historyIdx - 1;
24361
+ if (newIdx < 0) {
24362
+ setHistoryIdx(-1);
24363
+ setValue(savedInput);
24364
+ } else {
24365
+ setHistoryIdx(newIdx);
24366
+ setValue(history[history.length - 1 - newIdx]);
24367
+ }
24368
+ return;
24369
+ }
24350
24370
  if (ch === "") {
24351
24371
  setValue("");
24352
24372
  return;
@@ -24355,7 +24375,10 @@ function InputArea({ onSubmit, placeholder, statusText }) {
24355
24375
  setValue((p) => p.replace(/\S+\s*$/, ""));
24356
24376
  return;
24357
24377
  }
24358
- if (ch && !key.ctrl && !key.meta) setValue((p) => p + ch);
24378
+ if (ch && !key.ctrl && !key.meta) {
24379
+ setValue((p) => p + ch);
24380
+ setHistoryIdx(-1);
24381
+ }
24359
24382
  });
24360
24383
  const lines = value.split("\n");
24361
24384
  const empty = value === "";
@@ -24503,13 +24526,22 @@ function ChatApp({ engine }) {
24503
24526
  const [loading, setLoading] = useState(false);
24504
24527
  const [status, setStatus] = useState("");
24505
24528
  const [showModelPicker, setShowModelPicker] = useState(false);
24529
+ const [inputHistory, setInputHistory] = useState([]);
24530
+ const [responseTime, setResponseTime] = useState("");
24531
+ useInput((ch, key) => {
24532
+ if (loading && (key.escape || ch === "")) {
24533
+ engine.cancel();
24534
+ }
24535
+ }, { isActive: loading });
24506
24536
  useEffect(() => {
24507
24537
  engine.ui = {
24508
24538
  setStreaming,
24509
24539
  setLoading,
24510
24540
  setStatus,
24511
24541
  setShowModelPicker,
24512
- addMessage: (text, dim) => setMessages((p) => [...p, { id: ++nextId, text, dim }])
24542
+ addMessage: (text, dim) => setMessages((p) => [...p, { id: ++nextId, text, dim }]),
24543
+ clearMessages: () => setMessages([]),
24544
+ setResponseTime
24513
24545
  };
24514
24546
  engine.updateStatus();
24515
24547
  }, []);
@@ -24520,13 +24552,16 @@ function ChatApp({ engine }) {
24520
24552
  }
24521
24553
  if (text.startsWith("/")) {
24522
24554
  const result = await engine.handleSlashCommand(text);
24523
- if (result) setMessages((p) => [...p, { id: ++nextId, text: result, dim: true }]);
24555
+ if (result && result.trim()) setMessages((p) => [...p, { id: ++nextId, text: result, dim: true }]);
24524
24556
  engine.updateStatus();
24525
24557
  return;
24526
24558
  }
24559
+ setInputHistory((p) => [...p, text]);
24527
24560
  setMessages((p) => [...p, { id: ++nextId, text: `\u276F ${text}` }]);
24528
24561
  setLoading(true);
24529
24562
  setStreaming("");
24563
+ setResponseTime("");
24564
+ const startTime = Date.now();
24530
24565
  try {
24531
24566
  const response = await engine.handleAIMessage(text);
24532
24567
  if (response) setMessages((p) => [...p, { id: ++nextId, text: response }]);
@@ -24535,6 +24570,9 @@ function ChatApp({ engine }) {
24535
24570
  } finally {
24536
24571
  setLoading(false);
24537
24572
  setStreaming("");
24573
+ const elapsed = Date.now() - startTime;
24574
+ const timeStr = elapsed < 1e3 ? `${elapsed}ms` : elapsed < 6e4 ? `${(elapsed / 1e3).toFixed(1)}s` : `${Math.floor(elapsed / 6e4)}m ${Math.round(elapsed % 6e4 / 1e3)}s`;
24575
+ setResponseTime(timeStr);
24538
24576
  engine.updateStatus();
24539
24577
  }
24540
24578
  }, [engine]);
@@ -24594,7 +24632,7 @@ function ChatApp({ engine }) {
24594
24632
  ] })
24595
24633
  ] })
24596
24634
  ] }) : null,
24597
- /* @__PURE__ */ jsx2(Static, { items: messages, children: (msg) => /* @__PURE__ */ jsx2(Box2, { paddingX: 1, marginBottom: msg.text.startsWith("\u276F") ? 0 : 1, flexDirection: "column", children: msg.text.startsWith("\u276F") ? /* @__PURE__ */ jsxs2(Text2, { children: [
24635
+ messages.map((msg) => /* @__PURE__ */ jsx2(Box2, { paddingX: 1, marginBottom: msg.text.startsWith("\u276F") ? 0 : 1, flexDirection: "column", children: msg.text.startsWith("\u276F") ? /* @__PURE__ */ jsxs2(Text2, { children: [
24598
24636
  /* @__PURE__ */ jsx2(Text2, { color: "cyan", bold: true, children: "\u276F" }),
24599
24637
  /* @__PURE__ */ jsx2(Text2, { bold: true, children: msg.text.slice(1) })
24600
24638
  ] }) : msg.text.includes("\u23BF") && msg.text.includes("Write") ? /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
@@ -24603,7 +24641,7 @@ function ChatApp({ engine }) {
24603
24641
  ] }) : msg.text.includes("\u23BF") && msg.text.includes("\u2717") ? /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
24604
24642
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: msg.text.split("\n")[0] }),
24605
24643
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "red", color: "white", children: msg.text.split("\n").slice(1).join("\n") })
24606
- ] }) : msg.text.includes("\u23BF") ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, wrap: "wrap", children: msg.text }) : msg.dim ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, wrap: "wrap", children: msg.text }) : /* @__PURE__ */ jsx2(Markdown, { children: msg.text }) }, msg.id) }),
24644
+ ] }) : msg.text.includes("\u23BF") ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, wrap: "wrap", children: msg.text }) : msg.dim ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, wrap: "wrap", children: msg.text }) : /* @__PURE__ */ jsx2(Markdown, { children: msg.text }) }, msg.id)),
24607
24645
  showModelPicker ? /* @__PURE__ */ jsx2(
24608
24646
  ModelSelector,
24609
24647
  {
@@ -24619,15 +24657,20 @@ function ChatApp({ engine }) {
24619
24657
  },
24620
24658
  onCancel: () => setShowModelPicker(false)
24621
24659
  }
24622
- ) : loading ? /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", paddingX: 1, children: streaming ? /* @__PURE__ */ jsx2(Text2, { wrap: "wrap", children: streaming }) : /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
24660
+ ) : loading ? /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", paddingX: 1, children: streaming ? /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
24661
+ /* @__PURE__ */ jsx2(Text2, { wrap: "wrap", children: streaming }),
24662
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\n esc to cancel" })
24663
+ ] }) : /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
24623
24664
  /* @__PURE__ */ jsx2(InkSpinner, { type: "dots" }),
24624
- " Thinking"
24665
+ " Thinking ",
24666
+ /* @__PURE__ */ jsx2(Text2, { color: "gray", children: "esc to cancel" })
24625
24667
  ] }) }) : /* @__PURE__ */ jsx2(
24626
24668
  InputArea,
24627
24669
  {
24628
24670
  onSubmit: handleSubmit,
24629
24671
  placeholder: "Message RobinPath...",
24630
- statusText: status
24672
+ statusText: responseTime ? `${status} \xB7 ${responseTime}` : status,
24673
+ history: inputHistory
24631
24674
  }
24632
24675
  )
24633
24676
  ] });
@@ -24643,6 +24686,7 @@ var ReplEngine = class {
24643
24686
  conversationMessages;
24644
24687
  cliContext;
24645
24688
  ui = null;
24689
+ abortController = null;
24646
24690
  constructor(resumeSessionId, opts) {
24647
24691
  this.config = readAiConfig();
24648
24692
  this.autoAccept = opts.autoAccept || false;
@@ -24689,6 +24733,12 @@ var ReplEngine = class {
24689
24733
  if (this.usage.cost > 0) parts.push(`$${this.usage.cost.toFixed(4)}`);
24690
24734
  this.ui?.setStatus(parts.join(" \xB7 "));
24691
24735
  }
24736
+ cancel() {
24737
+ if (this.abortController) {
24738
+ this.abortController.abort();
24739
+ this.abortController = null;
24740
+ }
24741
+ }
24692
24742
  exit() {
24693
24743
  if (this.conversationMessages.length > 1) saveSession(this.sessionId, this.sessionName, this.conversationMessages, this.usage);
24694
24744
  process.exit(0);
@@ -24700,7 +24750,8 @@ var ReplEngine = class {
24700
24750
  }
24701
24751
  if (text === "/clear") {
24702
24752
  this.conversationMessages.length = 0;
24703
- return "\u2713 Conversation cleared.";
24753
+ this.ui?.clearMessages();
24754
+ return "";
24704
24755
  }
24705
24756
  if (text === "/compact") {
24706
24757
  if (this.conversationMessages.length > 12) {
@@ -24790,7 +24841,12 @@ Type / to see available commands.`;
24790
24841
  const activeModel = readAiConfig().model || this.model;
24791
24842
  const activeKey = readAiConfig().apiKey || this.apiKey;
24792
24843
  const activeProvider = this.resolveProvider(activeKey);
24844
+ this.abortController = new AbortController();
24793
24845
  for (let loop = 0; loop < 5; loop++) {
24846
+ if (this.abortController?.signal.aborted) {
24847
+ finalResponse = "(cancelled)";
24848
+ break;
24849
+ }
24794
24850
  let fullText = "";
24795
24851
  let lastUpdate = 0;
24796
24852
  const result = await fetchBrainStream(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinpath/cli",
3
- "version": "2.8.0",
3
+ "version": "3.0.0",
4
4
  "description": "AI-powered scripting CLI — automate anything from your terminal",
5
5
  "type": "module",
6
6
  "license": "MIT",