@robinpath/cli 2.9.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 +61 -7
  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.9.0" : "2.9.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;
@@ -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,6 +24526,13 @@ 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,
@@ -24510,7 +24540,8 @@ function ChatApp({ engine }) {
24510
24540
  setStatus,
24511
24541
  setShowModelPicker,
24512
24542
  addMessage: (text, dim) => setMessages((p) => [...p, { id: ++nextId, text, dim }]),
24513
- clearMessages: () => setMessages([])
24543
+ clearMessages: () => setMessages([]),
24544
+ setResponseTime
24514
24545
  };
24515
24546
  engine.updateStatus();
24516
24547
  }, []);
@@ -24525,9 +24556,12 @@ function ChatApp({ engine }) {
24525
24556
  engine.updateStatus();
24526
24557
  return;
24527
24558
  }
24559
+ setInputHistory((p) => [...p, text]);
24528
24560
  setMessages((p) => [...p, { id: ++nextId, text: `\u276F ${text}` }]);
24529
24561
  setLoading(true);
24530
24562
  setStreaming("");
24563
+ setResponseTime("");
24564
+ const startTime = Date.now();
24531
24565
  try {
24532
24566
  const response = await engine.handleAIMessage(text);
24533
24567
  if (response) setMessages((p) => [...p, { id: ++nextId, text: response }]);
@@ -24536,6 +24570,9 @@ function ChatApp({ engine }) {
24536
24570
  } finally {
24537
24571
  setLoading(false);
24538
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);
24539
24576
  engine.updateStatus();
24540
24577
  }
24541
24578
  }, [engine]);
@@ -24620,15 +24657,20 @@ function ChatApp({ engine }) {
24620
24657
  },
24621
24658
  onCancel: () => setShowModelPicker(false)
24622
24659
  }
24623
- ) : 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: [
24624
24664
  /* @__PURE__ */ jsx2(InkSpinner, { type: "dots" }),
24625
- " Thinking"
24665
+ " Thinking ",
24666
+ /* @__PURE__ */ jsx2(Text2, { color: "gray", children: "esc to cancel" })
24626
24667
  ] }) }) : /* @__PURE__ */ jsx2(
24627
24668
  InputArea,
24628
24669
  {
24629
24670
  onSubmit: handleSubmit,
24630
24671
  placeholder: "Message RobinPath...",
24631
- statusText: status
24672
+ statusText: responseTime ? `${status} \xB7 ${responseTime}` : status,
24673
+ history: inputHistory
24632
24674
  }
24633
24675
  )
24634
24676
  ] });
@@ -24644,6 +24686,7 @@ var ReplEngine = class {
24644
24686
  conversationMessages;
24645
24687
  cliContext;
24646
24688
  ui = null;
24689
+ abortController = null;
24647
24690
  constructor(resumeSessionId, opts) {
24648
24691
  this.config = readAiConfig();
24649
24692
  this.autoAccept = opts.autoAccept || false;
@@ -24690,6 +24733,12 @@ var ReplEngine = class {
24690
24733
  if (this.usage.cost > 0) parts.push(`$${this.usage.cost.toFixed(4)}`);
24691
24734
  this.ui?.setStatus(parts.join(" \xB7 "));
24692
24735
  }
24736
+ cancel() {
24737
+ if (this.abortController) {
24738
+ this.abortController.abort();
24739
+ this.abortController = null;
24740
+ }
24741
+ }
24693
24742
  exit() {
24694
24743
  if (this.conversationMessages.length > 1) saveSession(this.sessionId, this.sessionName, this.conversationMessages, this.usage);
24695
24744
  process.exit(0);
@@ -24792,7 +24841,12 @@ Type / to see available commands.`;
24792
24841
  const activeModel = readAiConfig().model || this.model;
24793
24842
  const activeKey = readAiConfig().apiKey || this.apiKey;
24794
24843
  const activeProvider = this.resolveProvider(activeKey);
24844
+ this.abortController = new AbortController();
24795
24845
  for (let loop = 0; loop < 5; loop++) {
24846
+ if (this.abortController?.signal.aborted) {
24847
+ finalResponse = "(cancelled)";
24848
+ break;
24849
+ }
24796
24850
  let fullText = "";
24797
24851
  let lastUpdate = 0;
24798
24852
  const result = await fetchBrainStream(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinpath/cli",
3
- "version": "2.9.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",