@livx.cc/agentx 0.99.18 → 0.99.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -9894,11 +9894,15 @@ function lastToken(line) {
9894
9894
  const m = line.match(/(\S*)$/);
9895
9895
  return m ? m[1] : "";
9896
9896
  }
9897
+ function atLineStart(line, token) {
9898
+ return line.slice(0, line.length - token.length).trim() === "";
9899
+ }
9897
9900
  function completeLine(line, ctx) {
9898
9901
  const token = lastToken(line);
9899
- if (token.startsWith("/") && line.trimStart() === token) {
9902
+ if (token.startsWith("/")) {
9903
+ const pool = atLineStart(line, token) ? ctx.commands : ctx.agentCommands ?? ctx.commands;
9900
9904
  const want = token.slice(1);
9901
- const hits = rank(ctx.commands.filter((c) => fuzzy(want, c)), want).map((c) => "/" + c);
9905
+ const hits = rank(pool.filter((c) => fuzzy(want, c)), want).map((c) => "/" + c);
9902
9906
  return [hits, token];
9903
9907
  }
9904
9908
  if (line.startsWith("!") && line.length > 1 && ctx.bangHistory?.length) {
@@ -10484,6 +10488,14 @@ var EditorState = class _EditorState {
10484
10488
  for (const [ph, full] of this.pastes) if (out.includes(ph)) out = out.split(ph).join(full);
10485
10489
  return out;
10486
10490
  }
10491
+ /**
10492
+ * A `/cmd` the REPL will DISPATCH — i.e. the line's first word. A slash token elsewhere in the
10493
+ * prompt is prose the model reads, so it completes like an `@path`: no accept-and-run, no
10494
+ * exact-match row. Kept in sync with the REPL's whole-line `/` dispatch via `atLineStart`.
10495
+ */
10496
+ get runnable() {
10497
+ return this.token.startsWith("/") && atLineStart(this.buf.slice(0, this.cursor), this.token);
10498
+ }
10487
10499
  /** Recompute suggestions from the line up to the cursor. */
10488
10500
  refresh() {
10489
10501
  const r = this.suggest(this.buf.slice(0, this.cursor));
@@ -10491,7 +10503,7 @@ var EditorState = class _EditorState {
10491
10503
  this.token = r.token;
10492
10504
  this.describe = r.describe;
10493
10505
  const exact = r.hits.length === 1 && r.hits[0] === r.token;
10494
- this.menuOpen = r.hits.length > 0 && (!exact || r.token.startsWith("/"));
10506
+ this.menuOpen = r.hits.length > 0 && (!exact || this.runnable);
10495
10507
  if (this.sel >= r.hits.length) this.sel = 0;
10496
10508
  }
10497
10509
  // ── Editor undo (Ctrl-_): snapshot before every mutation, pop to restore ──
@@ -10687,13 +10699,22 @@ var EditorState = class _EditorState {
10687
10699
  this.hits = [];
10688
10700
  this.sel = 0;
10689
10701
  }
10690
- /** Replace the trailing token with the highlighted hit; re-suggest (e.g. `@src/` opens its children). */
10702
+ /**
10703
+ * Replace the trailing token with the highlighted hit; re-suggest (e.g. `@src/` opens its children).
10704
+ * A finished hit gets a trailing space so the next word is typed straight away (CC/shell parity).
10705
+ * Two exceptions: a DIRECTORY hit (`@src/`) is a waypoint, not a word — a space there would end the
10706
+ * mention mid-path; and an existing following space isn't doubled. A spaced dir rides the quoted
10707
+ * form (`@"my dir/"`), so the `/` test must look past a trailing quote.
10708
+ */
10691
10709
  accept() {
10692
10710
  if (!this.menuOpen || !this.hits.length) return false;
10693
10711
  const hit = this.hits[this.sel] ?? this.hits[0];
10694
10712
  const start = this.cursor - this.token.length;
10695
- this.buf = this.buf.slice(0, start) + hit + this.buf.slice(this.cursor);
10696
- this.cursor = start + hit.length;
10713
+ const rest = this.buf.slice(this.cursor);
10714
+ const isDir = hit.replace(/"$/, "").endsWith("/");
10715
+ const pad = isDir || rest.startsWith(" ") ? "" : " ";
10716
+ this.buf = this.buf.slice(0, start) + hit + pad + rest;
10717
+ this.cursor = start + hit.length + pad.length;
10697
10718
  this.refresh();
10698
10719
  return true;
10699
10720
  }
@@ -10907,9 +10928,9 @@ function applyKey(s, key, str) {
10907
10928
  case "return":
10908
10929
  case "enter":
10909
10930
  if (s.menuOpen) {
10910
- const isCmd = s.token.startsWith("/");
10931
+ const run = s.runnable;
10911
10932
  s.accept();
10912
- return isCmd ? "submit" : "none";
10933
+ return run ? "submit" : "none";
10913
10934
  }
10914
10935
  if (s.buf.slice(0, s.cursor).endsWith("\\")) {
10915
10936
  s.backspace();
@@ -14751,10 +14772,11 @@ ${task}`;
14751
14772
  return null;
14752
14773
  }
14753
14774
  };
14754
- const commandNames = () => [...Object.keys(builtins).filter((k) => k !== "quit"), ...cmds.map((c) => c.name), ...skills.map((s) => s.name)];
14775
+ const agentCommandNames = () => [...cmds.map((c) => c.name), ...skills.map((s) => s.name)];
14776
+ const commandNames = () => [...Object.keys(builtins).filter((k) => k !== "quit"), ...agentCommandNames()];
14755
14777
  const describe = (hit) => hit.startsWith("/") ? builtins[hit.slice(1)]?.desc ?? cmds.find((c) => c.name === hit.slice(1))?.description ?? skills.find((s) => s.name === hit.slice(1))?.description : void 0;
14756
14778
  const suggest = (lineToCursor) => {
14757
- const [hits, token] = completeLine(lineToCursor, { commands: commandNames(), listDir, bangHistory: history });
14779
+ const [hits, token] = completeLine(lineToCursor, { commands: commandNames(), agentCommands: agentCommandNames(), listDir, bangHistory: history });
14758
14780
  return { hits, token, describe };
14759
14781
  };
14760
14782
  const editor = createLineEditor(process.stderr);