nexrall-code 0.5.175 → 0.5.177

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/index.js +624 -60
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -110527,6 +110527,7 @@ var require_client2 = __commonJS({
110527
110527
  Object.defineProperty(exports2, "__esModule", { value: true });
110528
110528
  exports2.McpClient = void 0;
110529
110529
  exports2.flattenResourceContents = flattenResourceContents;
110530
+ exports2.flattenPromptMessages = flattenPromptMessages;
110530
110531
  var child_process_1 = __require("child_process");
110531
110532
  function flattenResourceContents(result, maxChars = 1e5) {
110532
110533
  const contents = result?.contents ?? [];
@@ -110539,6 +110540,31 @@ var require_client2 = __commonJS({
110539
110540
  }).filter(Boolean);
110540
110541
  const text = parts.join("\n");
110541
110542
  return text.length > maxChars ? text.slice(0, maxChars) + `
110543
+ \u2026 [truncated, ${text.length - maxChars} more characters]` : text;
110544
+ }
110545
+ function flattenPromptMessages(result, maxChars = 1e5) {
110546
+ const messages = result?.messages ?? [];
110547
+ const parts = messages.map((m2) => {
110548
+ const content = m2?.content;
110549
+ const items = Array.isArray(content) ? content : content ? [content] : [];
110550
+ return items.map((c) => {
110551
+ const item = c;
110552
+ if (item?.type === "text" && typeof item.text === "string")
110553
+ return item.text;
110554
+ if (item?.type === "image")
110555
+ return `[image prompt content (${item.mimeType ?? "unknown type"}) not shown]`;
110556
+ if (item?.type === "audio")
110557
+ return `[audio prompt content (${item.mimeType ?? "unknown type"}) not shown]`;
110558
+ if (item?.type === "resource") {
110559
+ if (typeof item.resource?.text === "string")
110560
+ return item.resource.text;
110561
+ return `[resource prompt content (${item.resource?.uri ?? "unknown uri"}) not shown]`;
110562
+ }
110563
+ return "";
110564
+ }).filter(Boolean).join("\n");
110565
+ }).filter(Boolean);
110566
+ const text = parts.join("\n\n");
110567
+ return text.length > maxChars ? text.slice(0, maxChars) + `
110542
110568
  \u2026 [truncated, ${text.length - maxChars} more characters]` : text;
110543
110569
  }
110544
110570
  var McpClient = class {
@@ -110599,6 +110625,20 @@ var require_client2 = __commonJS({
110599
110625
  async readResource(uri) {
110600
110626
  return flattenResourceContents(await this._request("resources/read", { uri }));
110601
110627
  }
110628
+ async listPrompts() {
110629
+ try {
110630
+ const res = await this._request("prompts/list", {});
110631
+ return Array.isArray(res?.prompts) ? res.prompts : [];
110632
+ } catch {
110633
+ return [];
110634
+ }
110635
+ }
110636
+ async getPrompt(name, args) {
110637
+ const params = { name };
110638
+ if (Object.keys(args).length)
110639
+ params.arguments = args;
110640
+ return flattenPromptMessages(await this._request("prompts/get", params));
110641
+ }
110602
110642
  async callTool(name, args) {
110603
110643
  const result = await this._request("tools/call", { name, arguments: args });
110604
110644
  if (!result)
@@ -110726,6 +110766,20 @@ var require_httpClient = __commonJS({
110726
110766
  async readResource(uri) {
110727
110767
  return (0, client_1.flattenResourceContents)(await this._rpc("resources/read", { uri }));
110728
110768
  }
110769
+ async listPrompts() {
110770
+ try {
110771
+ const res = await this._rpc("prompts/list", {});
110772
+ return Array.isArray(res?.prompts) ? res.prompts : [];
110773
+ } catch {
110774
+ return [];
110775
+ }
110776
+ }
110777
+ async getPrompt(name, args) {
110778
+ const params = { name };
110779
+ if (Object.keys(args).length)
110780
+ params.arguments = args;
110781
+ return (0, client_1.flattenPromptMessages)(await this._rpc("prompts/get", params));
110782
+ }
110729
110783
  async callTool(name, args) {
110730
110784
  const result = await this._rpc("tools/call", { name, arguments: args });
110731
110785
  if (!result)
@@ -110872,6 +110926,20 @@ var require_sseClient = __commonJS({
110872
110926
  async readResource(uri) {
110873
110927
  return (0, client_1.flattenResourceContents)(await this._rpc("resources/read", { uri }));
110874
110928
  }
110929
+ async listPrompts() {
110930
+ try {
110931
+ const res = await this._rpc("prompts/list", {});
110932
+ return Array.isArray(res?.prompts) ? res.prompts : [];
110933
+ } catch {
110934
+ return [];
110935
+ }
110936
+ }
110937
+ async getPrompt(name, args) {
110938
+ const params = { name };
110939
+ if (Object.keys(args).length)
110940
+ params.arguments = args;
110941
+ return (0, client_1.flattenPromptMessages)(await this._rpc("prompts/get", params));
110942
+ }
110875
110943
  async callTool(name, args) {
110876
110944
  const result = await this._rpc("tools/call", { name, arguments: args });
110877
110945
  if (!result)
@@ -111216,6 +111284,7 @@ var require_manager = __commonJS({
111216
111284
  constructor() {
111217
111285
  this._clients = /* @__PURE__ */ new Map();
111218
111286
  this._toolMap = /* @__PURE__ */ new Map();
111287
+ this._promptCache = /* @__PURE__ */ new Map();
111219
111288
  this._configs = /* @__PURE__ */ new Map();
111220
111289
  this._errors = /* @__PURE__ */ new Map();
111221
111290
  this._needsAuth = /* @__PURE__ */ new Map();
@@ -111383,6 +111452,75 @@ var require_manager = __commonJS({
111383
111452
  clearTimeout(timer);
111384
111453
  }
111385
111454
  }
111455
+ /**
111456
+ * Prompt metadata for one connected server. Fetched once per connection and
111457
+ * cached — including an empty list (server has no prompts capability), so the
111458
+ * `/` menu does not re-ask a server on every keystroke; reconnecting clears
111459
+ * the entry. Returns [] for a server that is not connected.
111460
+ */
111461
+ async promptsFor(server) {
111462
+ const cached = this._promptCache.get(server);
111463
+ if (cached)
111464
+ return cached;
111465
+ const client = this._clients.get(server);
111466
+ if (!client)
111467
+ return [];
111468
+ const list = await client.listPrompts();
111469
+ this._promptCache.set(server, list);
111470
+ return list;
111471
+ }
111472
+ /** Prompts across connected, enabled servers, tagged with the server they came from. */
111473
+ async listPrompts(server) {
111474
+ const out = [];
111475
+ for (const name of this._clients.keys()) {
111476
+ if (server && name !== server)
111477
+ continue;
111478
+ for (const p of await this.promptsFor(name))
111479
+ out.push({ ...p, server: name });
111480
+ }
111481
+ return out;
111482
+ }
111483
+ /**
111484
+ * Expand one prompt to text. Positional values map, in order, onto the
111485
+ * arguments the server declared in prompts/list — the same positional form
111486
+ * Claude Code accepts (`/mcp__server__prompt first second`). Validation runs
111487
+ * here, before the request, so mistakes read as sentences instead of raw
111488
+ * JSON-RPC errors; the request itself is bounded by the same 60s timeout the
111489
+ * resource reader uses.
111490
+ */
111491
+ async getPrompt(server, name, values = []) {
111492
+ const client = this._clients.get(server);
111493
+ if (!client)
111494
+ throw new Error(`No connected MCP server named "${server}". Connected: ${[...this._clients.keys()].join(", ") || "(none)"}`);
111495
+ const list = await this.promptsFor(server);
111496
+ const meta = list.find((p) => p.name === name);
111497
+ if (!meta) {
111498
+ throw new Error(`No MCP prompt named "${name}" on server "${server}"${list.length ? ` (it offers: ${list.map((p) => p.name).join(", ")})` : ""}.`);
111499
+ }
111500
+ const declared = meta.arguments ?? [];
111501
+ if (values.length > declared.length) {
111502
+ throw new Error(`MCP prompt "${server}:${name}" takes ${declared.length} argument(s)${declared.length ? ` (${declared.map((a) => a.name).join(", ")})` : ""} \u2014 got ${values.length}.`);
111503
+ }
111504
+ const args = {};
111505
+ declared.forEach((a, i2) => {
111506
+ const v = values[i2];
111507
+ if (v !== void 0 && v !== "")
111508
+ args[a.name] = v;
111509
+ });
111510
+ const missing = declared.filter((a) => a.required && args[a.name] === void 0);
111511
+ if (missing.length)
111512
+ throw new Error(`MCP prompt "${server}:${name}" is missing required argument(s): ${missing.map((a) => a.name).join(", ")}.`);
111513
+ let timer;
111514
+ const timeout = new Promise((_2, rej) => {
111515
+ timer = setTimeout(() => rej(new Error(`MCP prompt ${server}:${name} timed out after 60s`)), 6e4);
111516
+ });
111517
+ try {
111518
+ return await Promise.race([client.getPrompt(name, args), timeout]);
111519
+ } finally {
111520
+ if (timer)
111521
+ clearTimeout(timer);
111522
+ }
111523
+ }
111386
111524
  /** True if this tool name belongs to an MCP server. */
111387
111525
  isMcpTool(name) {
111388
111526
  return this._toolMap.has(name);
@@ -111493,6 +111631,7 @@ var require_manager = __commonJS({
111493
111631
  if (this._toolMap.get(key) === name)
111494
111632
  this._toolMap.delete(key);
111495
111633
  }
111634
+ this._promptCache.delete(name);
111496
111635
  this.stats.reset();
111497
111636
  }
111498
111637
  // ─── Config file persistence (for the management UI) ──────────────────────────
@@ -141804,8 +141943,8 @@ var require_strip = __commonJS({
141804
141943
  var require_src4 = __commonJS({
141805
141944
  "../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js"(exports2, module2) {
141806
141945
  "use strict";
141807
- var ESC3 = "\x1B";
141808
- var CSI2 = `${ESC3}[`;
141946
+ var ESC4 = "\x1B";
141947
+ var CSI2 = `${ESC4}[`;
141809
141948
  var beep2 = "\x07";
141810
141949
  var cursor = {
141811
141950
  to(x2, y) {
@@ -141834,8 +141973,8 @@ var require_src4 = __commonJS({
141834
141973
  left: `${CSI2}G`,
141835
141974
  hide: `${CSI2}?25l`,
141836
141975
  show: `${CSI2}?25h`,
141837
- save: `${ESC3}7`,
141838
- restore: `${ESC3}8`
141976
+ save: `${ESC4}7`,
141977
+ restore: `${ESC4}8`
141839
141978
  };
141840
141979
  var scroll = {
141841
141980
  up: (count = 1) => `${CSI2}S`.repeat(count),
@@ -157427,7 +157566,9 @@ function reserveBlockRows(previous, showing) {
157427
157566
  function drainBlockRows(previous, printedRows) {
157428
157567
  return Math.max(0, previous - Math.max(0, printedRows));
157429
157568
  }
157430
- var LIVE_BLOCK_MAX_ROWS = 5;
157569
+ function replayReserveRows(slack, liveRows, pendingRows = 0) {
157570
+ return Math.max(Math.max(0, liveRows), Math.max(0, slack) - Math.max(0, pendingRows));
157571
+ }
157431
157572
  function fillerRowCount(rowsAlreadyPrinted, footerTextValue = "", columns = process.stdout.columns ?? 80, rows = process.stdout.rows, reservedRows = 0, headroom = 2) {
157432
157573
  if (!rows)
157433
157574
  return 0;
@@ -166669,6 +166810,208 @@ function askForTrust(workDir, signals) {
166669
166810
  });
166670
166811
  }
166671
166812
 
166813
+ // src/ui/inputReports.ts
166814
+ var ESC3 = "\x1B";
166815
+ var BEL3 = "\x07";
166816
+ var REPORT_DEADLINE_MS = 120;
166817
+ var OSC_CAP = 4096;
166818
+ function newInputReportState() {
166819
+ return { pending: "", oscSkipLeft: 0 };
166820
+ }
166821
+ function filterInput(state, chunk, opts = {}) {
166822
+ const s2 = state.pending + chunk;
166823
+ state.pending = "";
166824
+ let out = "";
166825
+ let i2 = 0;
166826
+ if (state.oscSkipLeft > 0) {
166827
+ let j = i2;
166828
+ let terminated = false;
166829
+ while (j < s2.length) {
166830
+ if (s2[j] === BEL3) {
166831
+ terminated = true;
166832
+ j += 1;
166833
+ break;
166834
+ }
166835
+ if (s2[j] === ESC3 && s2[j + 1] === "\\") {
166836
+ terminated = true;
166837
+ j += 2;
166838
+ break;
166839
+ }
166840
+ if (s2[j] === ESC3 && j === s2.length - 1)
166841
+ break;
166842
+ j += 1;
166843
+ }
166844
+ const split = !terminated && j < s2.length && s2[j] === ESC3;
166845
+ if (terminated)
166846
+ state.oscSkipLeft = 0;
166847
+ else
166848
+ state.oscSkipLeft = Math.max(0, state.oscSkipLeft - (j - i2));
166849
+ if (split) {
166850
+ state.pending = s2.slice(j);
166851
+ return out;
166852
+ }
166853
+ i2 = j;
166854
+ }
166855
+ while (i2 < s2.length) {
166856
+ if (s2[i2] !== ESC3) {
166857
+ out += s2[i2];
166858
+ i2 += 1;
166859
+ continue;
166860
+ }
166861
+ if (i2 === s2.length - 1) {
166862
+ out += ESC3;
166863
+ i2 += 1;
166864
+ continue;
166865
+ }
166866
+ const next = s2[i2 + 1];
166867
+ if (next === "]") {
166868
+ const end = oscEnd(s2, i2 + 2);
166869
+ if (end >= 0) {
166870
+ i2 = end;
166871
+ continue;
166872
+ }
166873
+ if (s2.length - (i2 + 2) > OSC_CAP) {
166874
+ state.oscSkipLeft = OSC_CAP;
166875
+ i2 = s2.length;
166876
+ continue;
166877
+ }
166878
+ state.pending = s2.slice(i2);
166879
+ break;
166880
+ }
166881
+ if (next === "[") {
166882
+ const r2 = scanCsi(s2, i2, opts);
166883
+ if (r2.kind === "hold") {
166884
+ state.pending = s2.slice(i2);
166885
+ break;
166886
+ }
166887
+ if (r2.kind === "pass")
166888
+ out += s2.slice(i2, r2.end);
166889
+ i2 = r2.end;
166890
+ continue;
166891
+ }
166892
+ out += ESC3 + next;
166893
+ i2 += 2;
166894
+ }
166895
+ return out;
166896
+ }
166897
+ function releasePendingOnDeadline(state, _opts = {}) {
166898
+ const held = state.pending;
166899
+ state.pending = "";
166900
+ if (held === "")
166901
+ return "";
166902
+ if (held.startsWith(ESC3 + "]"))
166903
+ return "";
166904
+ if (held.startsWith(ESC3 + "[")) {
166905
+ const rest = held.slice(2);
166906
+ if (rest.startsWith("M") || rest.startsWith("<"))
166907
+ return "";
166908
+ return ESC3;
166909
+ }
166910
+ return "";
166911
+ }
166912
+ function scanCsi(s2, start, opts) {
166913
+ let j = start + 2;
166914
+ while (j < s2.length) {
166915
+ const c = s2.charCodeAt(j);
166916
+ if (c >= 64 && c <= 126)
166917
+ break;
166918
+ if (c >= 48 && c <= 63) {
166919
+ j += 1;
166920
+ continue;
166921
+ }
166922
+ if (c >= 32 && c <= 47) {
166923
+ j += 1;
166924
+ continue;
166925
+ }
166926
+ return { kind: "drop", end: start + 2 };
166927
+ }
166928
+ if (j >= s2.length)
166929
+ return { kind: "hold" };
166930
+ const final = s2[j];
166931
+ const body = s2.slice(start + 2, j);
166932
+ const seqEnd = j + 1;
166933
+ if (final === "M" && body === "") {
166934
+ if (s2.length < seqEnd + 3)
166935
+ return { kind: "hold" };
166936
+ return opts.passMouse ? { kind: "pass", end: seqEnd + 3 } : { kind: "drop", end: seqEnd + 3 };
166937
+ }
166938
+ if (body.startsWith("<")) {
166939
+ return opts.passMouse ? { kind: "pass", end: seqEnd } : { kind: "drop", end: seqEnd };
166940
+ }
166941
+ if (/^[?>=!]/.test(body))
166942
+ return { kind: "drop", end: seqEnd };
166943
+ if (body === "" && (final === "I" || final === "O"))
166944
+ return { kind: "drop", end: seqEnd };
166945
+ if (final === "R" && /^\d+;\d+$/.test(body))
166946
+ return { kind: "drop", end: seqEnd };
166947
+ return { kind: "pass", end: seqEnd };
166948
+ }
166949
+ function oscEnd(s2, from) {
166950
+ for (let i2 = from; i2 < s2.length; i2 += 1) {
166951
+ if (s2[i2] === BEL3)
166952
+ return i2 + 1;
166953
+ if (s2[i2] === ESC3 && s2[i2 + 1] === "\\")
166954
+ return i2 + 2;
166955
+ }
166956
+ return -1;
166957
+ }
166958
+ var mousePassthrough = () => false;
166959
+ var installed = false;
166960
+ function setMousePassthrough(fn) {
166961
+ mousePassthrough = fn;
166962
+ }
166963
+ function installInputReportFilter(stream = process.stdin) {
166964
+ const isDefault = stream === process.stdin;
166965
+ if (isDefault && installed)
166966
+ return () => {
166967
+ };
166968
+ if (isDefault)
166969
+ installed = true;
166970
+ const stdin = stream;
166971
+ const origRead = stdin.read.bind(stdin);
166972
+ const state = newInputReportState();
166973
+ let outbox = "";
166974
+ let timer = null;
166975
+ const clearTimer = () => {
166976
+ if (timer) {
166977
+ clearTimeout(timer);
166978
+ timer = null;
166979
+ }
166980
+ };
166981
+ const onDeadline = () => {
166982
+ timer = null;
166983
+ outbox += releasePendingOnDeadline(state, { passMouse: mousePassthrough() });
166984
+ stdin.emit("readable");
166985
+ };
166986
+ stdin.read = function patchedRead(...args) {
166987
+ if (args.length > 0)
166988
+ return origRead(...args);
166989
+ let chunk;
166990
+ while ((chunk = origRead()) !== null && chunk !== void 0) {
166991
+ const s2 = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
166992
+ outbox += filterInput(state, s2, { passMouse: mousePassthrough() });
166993
+ }
166994
+ if (state.pending !== "") {
166995
+ clearTimer();
166996
+ timer = setTimeout(onDeadline, REPORT_DEADLINE_MS);
166997
+ timer.unref?.();
166998
+ } else {
166999
+ clearTimer();
167000
+ }
167001
+ if (outbox === "")
167002
+ return null;
167003
+ const out = outbox;
167004
+ outbox = "";
167005
+ return out;
167006
+ };
167007
+ return () => {
167008
+ clearTimer();
167009
+ stdin.read = origRead;
167010
+ if (isDefault)
167011
+ installed = false;
167012
+ };
167013
+ }
167014
+
166672
167015
  // src/ui/inkTerminal.tsx
166673
167016
  var import_react36 = __toESM(require_react(), 1);
166674
167017
 
@@ -166906,6 +167249,32 @@ function skillEntries(skills, builtins = BUILTIN_SLASH_COMMANDS) {
166906
167249
  }
166907
167250
  return out;
166908
167251
  }
167252
+ function promptEntries(prompts2, builtins = BUILTIN_SLASH_COMMANDS) {
167253
+ const taken = /* @__PURE__ */ new Set();
167254
+ for (const b of builtins) {
167255
+ taken.add(b.name);
167256
+ for (const a of b.aliases ?? [])
167257
+ taken.add(a);
167258
+ }
167259
+ const out = [];
167260
+ for (const p of prompts2) {
167261
+ const name = `${p.server}:${p.name}`;
167262
+ if (taken.has(name))
167263
+ continue;
167264
+ taken.add(name);
167265
+ const args = p.arguments ?? [];
167266
+ const description = (p.description ?? "").replace(/\s+/g, " ").trim() || `MCP prompt from ${p.server}`;
167267
+ out.push({
167268
+ name,
167269
+ description,
167270
+ argHint: args.length ? args.map((a) => a.required ? `<${a.name}>` : `[${a.name}]`).join(" ") : void 0,
167271
+ requiresArg: args.some((a) => a.required) || void 0,
167272
+ kind: "mcp",
167273
+ source: p.server
167274
+ });
167275
+ }
167276
+ return out;
167277
+ }
166909
167278
  function matchScore(query, name, aliases, description) {
166910
167279
  if (!query)
166911
167280
  return 0;
@@ -166946,7 +167315,7 @@ function slashQuery(line, cursor) {
166946
167315
  return null;
166947
167316
  if (line.includes("\n"))
166948
167317
  return null;
166949
- const m2 = /^\/([\w-]*)$/.exec(line);
167318
+ const m2 = /^\/([\w:-]*)$/.exec(line);
166950
167319
  if (!m2)
166951
167320
  return null;
166952
167321
  if (cursor < 1)
@@ -167756,7 +168125,7 @@ function describeOpen(spec, target, cwd2) {
167756
168125
  // src/ui/fileMention.ts
167757
168126
  import * as fs26 from "fs";
167758
168127
  import * as path26 from "path";
167759
- import { execFileSync as execFileSync4 } from "child_process";
168128
+ import { execFile, execFileSync as execFileSync4 } from "child_process";
167760
168129
 
167761
168130
  // src/ui/contextFiles.ts
167762
168131
  import * as fs25 from "fs";
@@ -167971,6 +168340,9 @@ var IGNORED_DIRS = /* @__PURE__ */ new Set([
167971
168340
  ]);
167972
168341
  var MAX_INDEXED = 5e4;
167973
168342
  function listProjectFiles(cwd2) {
168343
+ return listProjectFilesFrom(cwd2).files;
168344
+ }
168345
+ function listProjectFilesFrom(cwd2) {
167974
168346
  let files = null;
167975
168347
  try {
167976
168348
  const out = execFileSync4("git", ["-C", cwd2, "ls-files", "-co", "--exclude-standard", "-z"], {
@@ -167982,34 +168354,41 @@ function listProjectFiles(cwd2) {
167982
168354
  files = [...new Set(out.split("\0").filter(Boolean))];
167983
168355
  } catch {
167984
168356
  }
168357
+ const source2 = files ? "git" : "walk";
167985
168358
  if (!files)
167986
168359
  files = walk(cwd2);
167987
- return files.filter((f3) => !/\s/.test(f3)).slice(0, MAX_INDEXED);
168360
+ return { files: files.filter((f3) => !/\s/.test(f3)).slice(0, MAX_INDEXED), source: source2 };
167988
168361
  }
167989
- function walk(root) {
167990
- const out = [];
167991
- const visit = (dir, depth) => {
167992
- if (out.length >= MAX_INDEXED || depth > 8)
167993
- return;
168362
+ function* walkEntries(root) {
168363
+ const queue = [{ dir: root, depth: 0 }];
168364
+ for (let i2 = 0; i2 < queue.length; i2++) {
168365
+ const { dir, depth } = queue[i2];
168366
+ if (depth > 8)
168367
+ continue;
167994
168368
  let entries;
167995
168369
  try {
167996
168370
  entries = fs26.readdirSync(dir, { withFileTypes: true });
167997
168371
  } catch {
167998
- return;
168372
+ continue;
167999
168373
  }
168000
168374
  for (const e2 of entries) {
168001
- if (out.length >= MAX_INDEXED)
168002
- return;
168003
168375
  const full = path26.join(dir, e2.name);
168004
168376
  if (e2.isDirectory()) {
168005
168377
  if (!IGNORED_DIRS.has(e2.name) && !e2.isSymbolicLink())
168006
- visit(full, depth + 1);
168378
+ queue.push({ dir: full, depth: depth + 1 });
168007
168379
  } else if (e2.isFile()) {
168008
- out.push(path26.relative(root, full).split(path26.sep).join("/"));
168380
+ yield path26.relative(root, full).split(path26.sep).join("/");
168009
168381
  }
168010
168382
  }
168011
- };
168012
- visit(root, 0);
168383
+ }
168384
+ }
168385
+ function walk(root) {
168386
+ const out = [];
168387
+ for (const f3 of walkEntries(root)) {
168388
+ out.push(f3);
168389
+ if (out.length >= MAX_INDEXED)
168390
+ break;
168391
+ }
168013
168392
  return out;
168014
168393
  }
168015
168394
  function buildIndex(files) {
@@ -168021,20 +168400,111 @@ function buildIndex(files) {
168021
168400
  }
168022
168401
  return [...dirs, ...files].sort();
168023
168402
  }
168403
+ var GIT_CACHE_MS = 5e3;
168404
+ var WALK_CACHE_MS = 6e4;
168024
168405
  var cache3 = null;
168025
- var CACHE_MS = 5e3;
168026
168406
  var excludedPatterns = [];
168407
+ var excludedKey = "[]";
168027
168408
  function setExcludedPatterns(patterns) {
168028
168409
  excludedPatterns = [...patterns];
168029
- cache3 = null;
168410
+ excludedKey = JSON.stringify(excludedPatterns);
168411
+ }
168412
+ function derivedIndex(raw) {
168413
+ return buildIndex(raw.filter((f3) => !isExcluded(f3, excludedPatterns)));
168030
168414
  }
168031
168415
  function projectIndex(cwd2, now = Date.now()) {
168032
- if (cache3 && cache3.cwd === cwd2 && now - cache3.at < CACHE_MS)
168416
+ if (cache3 && cache3.cwd === cwd2 && now - cache3.at < cache3.ttl) {
168417
+ if (cache3.patterns !== excludedKey)
168418
+ cache3 = { ...cache3, patterns: excludedKey, index: derivedIndex(cache3.raw) };
168033
168419
  return cache3.index;
168034
- const files = listProjectFiles(cwd2).filter((f3) => !isExcluded(f3, excludedPatterns));
168035
- const index = buildIndex(files);
168036
- cache3 = { cwd: cwd2, at: now, index };
168037
- return index;
168420
+ }
168421
+ const { files, source: source2 } = listProjectFilesFrom(cwd2);
168422
+ cache3 = {
168423
+ cwd: cwd2,
168424
+ at: now,
168425
+ ttl: source2 === "git" ? GIT_CACHE_MS : WALK_CACHE_MS,
168426
+ raw: files,
168427
+ patterns: excludedKey,
168428
+ index: derivedIndex(files)
168429
+ };
168430
+ return cache3.index;
168431
+ }
168432
+ var WALK_SLICE_MS = 8;
168433
+ var indexListener = null;
168434
+ function setMentionIndexListener(cb) {
168435
+ indexListener = cb;
168436
+ }
168437
+ var building = null;
168438
+ function walkInSlices(root, job, done) {
168439
+ const entries = walkEntries(root);
168440
+ const out = [];
168441
+ const step = () => {
168442
+ if (job.cancelled)
168443
+ return;
168444
+ const t0 = Date.now();
168445
+ for (; ; ) {
168446
+ if (out.length >= MAX_INDEXED)
168447
+ return done(out);
168448
+ const next = entries.next();
168449
+ if (next.done)
168450
+ return done(out);
168451
+ out.push(next.value);
168452
+ if (Date.now() - t0 >= WALK_SLICE_MS)
168453
+ break;
168454
+ }
168455
+ setImmediate(step);
168456
+ };
168457
+ setImmediate(step);
168458
+ }
168459
+ function finishBuild(job, files, source2) {
168460
+ if (job.cancelled)
168461
+ return;
168462
+ if (building === job)
168463
+ building = null;
168464
+ const raw = files.filter((f3) => !/\s/.test(f3)).slice(0, MAX_INDEXED);
168465
+ cache3 = {
168466
+ cwd: job.cwd,
168467
+ at: Date.now(),
168468
+ ttl: source2 === "git" ? GIT_CACHE_MS : WALK_CACHE_MS,
168469
+ raw,
168470
+ patterns: excludedKey,
168471
+ index: derivedIndex(raw)
168472
+ };
168473
+ indexListener?.();
168474
+ }
168475
+ function primeMentionIndex(cwd2) {
168476
+ if (cache3 && cache3.cwd === cwd2 && Date.now() - cache3.at < cache3.ttl)
168477
+ return;
168478
+ if (building && building.cwd === cwd2 && !building.cancelled)
168479
+ return;
168480
+ if (building)
168481
+ building.cancelled = true;
168482
+ const job = { cwd: cwd2, cancelled: false };
168483
+ building = job;
168484
+ execFile("git", ["-C", cwd2, "ls-files", "-co", "--exclude-standard", "-z"], {
168485
+ encoding: "utf-8",
168486
+ maxBuffer: 64 * 1024 * 1024,
168487
+ timeout: 5e3
168488
+ }, (err, stdout) => {
168489
+ if (job.cancelled)
168490
+ return;
168491
+ if (!err) {
168492
+ finishBuild(job, [...new Set(stdout.split("\0").filter(Boolean))], "git");
168493
+ return;
168494
+ }
168495
+ walkInSlices(cwd2, job, (files) => finishBuild(job, files, "walk"));
168496
+ });
168497
+ }
168498
+ function mentionIndexForRender(cwd2) {
168499
+ if (!cache3 || cache3.cwd !== cwd2) {
168500
+ primeMentionIndex(cwd2);
168501
+ return [];
168502
+ }
168503
+ if (cache3.patterns !== excludedKey)
168504
+ cache3 = { ...cache3, patterns: excludedKey, index: derivedIndex(cache3.raw) };
168505
+ if (Date.now() - cache3.at >= cache3.ttl)
168506
+ primeMentionIndex(cwd2);
168507
+ return cache3.index;
168038
168508
  }
168039
168509
  function subsequence(hay, needle) {
168040
168510
  let i2 = 0;
@@ -168077,13 +168547,13 @@ function rankMentions(query, index, limit = 200) {
168077
168547
  }
168078
168548
  return index.map((p, i2) => ({ p, i: i2, s: score(p, q) })).filter((x2) => x2.s !== Infinity).sort((a, b) => a.s - b.s || a.p.length - b.p.length || a.i - b.i).slice(0, limit).map((x2) => x2.p);
168079
168549
  }
168080
- function computeMention(line, cursor, index, dismissedFor) {
168550
+ function computeMention(line, cursor, getIndex, dismissedFor) {
168081
168551
  if (dismissedFor !== null && dismissedFor === line)
168082
168552
  return null;
168083
168553
  const at = mentionAt(line, cursor);
168084
168554
  if (!at)
168085
168555
  return null;
168086
- const items = rankMentions(at.query, index);
168556
+ const items = rankMentions(at.query, getIndex());
168087
168557
  return items.length ? { at, items } : null;
168088
168558
  }
168089
168559
  function decideMentionEnter(query, pick) {
@@ -168560,7 +169030,7 @@ function slashMenuView(p) {
168560
169030
  return {
168561
169031
  rows: shown.map((e2, i2) => {
168562
169032
  const label = `/${e2.name}${e2.argHint ? " " + e2.argHint : ""}`;
168563
- const tag = e2.kind === "skill" ? ` (${e2.source === "project" || !e2.source ? "skill" : e2.source + " skill"})` : "";
169033
+ const tag = e2.kind === "mcp" ? " (MCP)" : e2.kind === "skill" ? ` (${e2.source === "project" || !e2.source ? "skill" : e2.source + " skill"})` : "";
168564
169034
  const alias = e2.aliases?.length ? ` (${e2.aliases.map((a) => "/" + a).join(", ")})` : "";
168565
169035
  const seen = e2.recent ? " \xB7 recent" : "";
168566
169036
  return {
@@ -168615,7 +169085,7 @@ function fullscreenView(p) {
168615
169085
  function mentionMenuView(p) {
168616
169086
  if (p.blocked)
168617
169087
  return null;
168618
- const m2 = computeMention(p.line, p.cursorPos, projectIndex(p.root), p.dismissedFor);
169088
+ const m2 = computeMention(p.line, p.cursorPos, () => mentionIndexForRender(p.root), p.dismissedFor);
168619
169089
  if (!m2)
168620
169090
  return null;
168621
169091
  const sel = Math.min(p.sel.query === m2.at.query ? p.sel.idx : 0, m2.items.length - 1);
@@ -168652,13 +169122,6 @@ function decideCtrlC(state) {
168652
169122
  }
168653
169123
 
168654
169124
  // src/ui/inkTerminal.tsx
168655
- function fillerContent(rows) {
168656
- if (rows <= 0)
168657
- return "";
168658
- if (rows === 1)
168659
- return " ";
168660
- return "\n".repeat(rows - 1);
168661
- }
168662
169125
  function isBusySlashCommand(line) {
168663
169126
  return /^\/[a-z][\w-]*(\s|$)/.test(line.trim());
168664
169127
  }
@@ -168811,12 +169274,12 @@ var App2 = ({ onReady }) => {
168811
169274
  const mentionRootRef = (0, import_react36.useRef)(process.cwd());
168812
169275
  const setMentionRoot = (0, import_react36.useCallback)((dir) => {
168813
169276
  mentionRootRef.current = dir;
168814
- setImmediate(() => {
168815
- try {
168816
- projectIndex(dir);
168817
- } catch {
168818
- }
168819
- });
169277
+ primeMentionIndex(dir);
169278
+ }, []);
169279
+ const [, bumpMentionIndex] = (0, import_react36.useState)(0);
169280
+ import_react36.default.useEffect(() => {
169281
+ setMentionIndexListener(() => bumpMentionIndex((n) => n + 1));
169282
+ return () => setMentionIndexListener(null);
168820
169283
  }, []);
168821
169284
  const setSlashEntries = (0, import_react36.useCallback)((entries) => {
168822
169285
  slashEntriesRef.current = entries;
@@ -169259,7 +169722,7 @@ var App2 = ({ onReady }) => {
169259
169722
  }
169260
169723
  }
169261
169724
  }
169262
- const mention = askResolverRef.current || choiceRef.current || searchRef.current || historyRef.current.browsing || busyRef.current ? null : computeMention(lineRef.current, cursorRef.current, projectIndex(mentionRootRef.current), mentionDismissedRef.current);
169725
+ const mention = askResolverRef.current || choiceRef.current || searchRef.current || historyRef.current.browsing || busyRef.current ? null : computeMention(lineRef.current, cursorRef.current, () => mentionIndexForRender(mentionRootRef.current), mentionDismissedRef.current);
169263
169726
  if (mention) {
169264
169727
  const sel = mentionSelRef.current.query === mention.at.query ? mentionSelRef.current.idx : 0;
169265
169728
  const pick = mention.items[Math.min(sel, mention.items.length - 1)];
@@ -169555,19 +170018,8 @@ var App2 = ({ onReady }) => {
169555
170018
  const liveRows = liveRef.current ? rowsOccupied(liveRef.current, columns) : 0;
169556
170019
  const footer2 = footerRef.current ? footerText(footerRef.current) : "";
169557
170020
  const slack = fillerRowCount(printedRows, footer2, columns, void 0, liveRows, 1);
169558
- const seed = Math.min(LIVE_BLOCK_MAX_ROWS, slack);
169559
- liveReserveRef.current = seed;
169560
- const filler = fillerRowCount(
169561
- printedRows,
169562
- footer2,
169563
- columns,
169564
- void 0,
169565
- Math.max(liveRows, seed) + Math.max(0, pendingRows),
169566
- 1
169567
- );
169568
- if (filler <= 0)
169569
- return withoutOldFiller;
169570
- return [...withoutOldFiller, { id: idCounter++, content: fillerContent(filler), isFiller: true }];
170021
+ liveReserveRef.current = replayReserveRows(slack, liveRows, pendingRows);
170022
+ return withoutOldFiller;
169571
170023
  });
169572
170024
  }, []);
169573
170025
  const forceFullRedraw = (0, import_react36.useCallback)(() => {
@@ -169642,6 +170094,9 @@ var App2 = ({ onReady }) => {
169642
170094
  if (fullscreenRef.current)
169643
170095
  process.stdout.write(on ? MOUSE_ON : MOUSE_OFF);
169644
170096
  }, []);
170097
+ import_react36.default.useEffect(() => {
170098
+ setMousePassthrough(() => fullscreenRef.current && mouseRef.current);
170099
+ }, []);
169645
170100
  import_react36.default.useEffect(() => () => {
169646
170101
  if (fullscreenRef.current) {
169647
170102
  fullscreenRef.current = false;
@@ -169998,6 +170453,38 @@ var InkReadlineAdapter = class extends EventEmitter3 {
169998
170453
  }
169999
170454
  };
170000
170455
 
170456
+ // src/ui/mcpPrompt.ts
170457
+ function parseMcpPromptRef(cmd, serverNames) {
170458
+ const bare = cmd.startsWith("/") ? cmd.slice(1) : cmd;
170459
+ if (bare.startsWith("mcp__")) {
170460
+ const rest = bare.slice("mcp__".length);
170461
+ const candidates = serverNames.filter((s2) => rest.startsWith(s2 + "__")).sort((a, b) => b.length - a.length);
170462
+ const server = candidates[0];
170463
+ if (!server)
170464
+ return null;
170465
+ const name = rest.slice(server.length + 2);
170466
+ return name ? { server, name } : null;
170467
+ }
170468
+ const colon = bare.indexOf(":");
170469
+ if (colon > 0) {
170470
+ const server = bare.slice(0, colon);
170471
+ const name = bare.slice(colon + 1);
170472
+ if (name && serverNames.includes(server))
170473
+ return { server, name };
170474
+ }
170475
+ return null;
170476
+ }
170477
+ function splitPromptArgs(arg) {
170478
+ const out = [];
170479
+ const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
170480
+ let m2;
170481
+ while (m2 = re.exec(arg)) {
170482
+ const v = m2[1] ?? m2[2] ?? m2[3];
170483
+ out.push(v);
170484
+ }
170485
+ return out;
170486
+ }
170487
+
170001
170488
  // src/ui/recents.ts
170002
170489
  import fs27 from "node:fs";
170003
170490
  import os17 from "node:os";
@@ -173270,7 +173757,7 @@ function printHelp() {
173270
173757
  ["/skills", "List skills (.nexrall/skills/<name>/SKILL.md or .nexrall/commands/*.md) \u2014 the model can also auto-invoke these"],
173271
173758
  ["/commands", "List your custom commands (.nexrall/commands/*.md)"],
173272
173759
  ["/plugins", "List installed plugins (.nexrall/plugins/)"],
173273
- ["/mcp [name|verb]", "List servers; <name> inspects tools/latency; enable|disable persists, connect|disconnect lasts the session"],
173760
+ ["/mcp [name|verb]", "List servers; <name> inspects tools/latency; enable|disable persists, connect|disconnect lasts the session; prompts lists /server:prompt templates"],
173274
173761
  ["/open <path[:line]>", 'Open a file in your editor (bare /open picks from files this session touched; finds "auth.ts" anywhere)'],
173275
173762
  ["/doctor", "Check Node, sign-in, network, terminal, MCP and storage; shows how to fix each problem"],
173276
173763
  ["/fullscreen", "Draw the session on the terminal's alternate screen: it re-wraps on resize and PgUp/PgDn page through it"],
@@ -173399,6 +173886,7 @@ function printSessions() {
173399
173886
  console.log();
173400
173887
  }
173401
173888
  async function startChatSession(options) {
173889
+ installInputReportFilter();
173402
173890
  if (options.bare)
173403
173891
  setNoDiscovery(true);
173404
173892
  _cliAgentTypes = (options.agents ?? []).map((a) => ({ ...a, source: "programmatic" }));
@@ -173968,13 +174456,32 @@ ${text}` : "");
173968
174456
  console.log(paint.green(` \u2713 Saved to ${saved.scope} memory`) + paint.dim(` \u2014 ${saved.file}`) + (saved.superseded ? paint.dim(" (the older fact moved to Superseded)") : ""));
173969
174457
  }
173970
174458
  };
173971
- const allSlashEntries = () => [...BUILTIN_SLASH_COMMANDS, ...skillEntries((0, import_code_core18.userInvokableSkills)(skills))];
174459
+ let mcpPromptList = [];
174460
+ const allSlashEntries = () => {
174461
+ const base = [...BUILTIN_SLASH_COMMANDS, ...skillEntries((0, import_code_core18.userInvokableSkills)(skills))];
174462
+ return [...base, ...promptEntries(mcpPromptList, base)];
174463
+ };
173972
174464
  let slashRecents = loadRecents();
173973
174465
  const syncSlashMenu = () => {
173974
174466
  if (interactive)
173975
174467
  getInkTerminal().setSlashEntries(orderByRecents(allSlashEntries(), slashRecents));
173976
174468
  };
174469
+ const refreshMcpPrompts = async () => {
174470
+ if (!_mcpManager)
174471
+ return;
174472
+ let list;
174473
+ try {
174474
+ list = await _mcpManager.listPrompts();
174475
+ } catch {
174476
+ return;
174477
+ }
174478
+ if (JSON.stringify(list) === JSON.stringify(mcpPromptList))
174479
+ return;
174480
+ mcpPromptList = list;
174481
+ syncSlashMenu();
174482
+ };
173977
174483
  syncSlashMenu();
174484
+ void mcpStarted.then(() => refreshMcpPrompts());
173978
174485
  if (interactive)
173979
174486
  getInkTerminal().setMentionRoot(workDir);
173980
174487
  const doRewind = (id) => {
@@ -174267,6 +174774,7 @@ ${text}` : "");
174267
174774
  }
174268
174775
  }
174269
174776
  }
174777
+ void refreshMcpPrompts();
174270
174778
  const outcome = {};
174271
174779
  if (error !== void 0)
174272
174780
  outcome.error = error;
@@ -176150,6 +176658,26 @@ ${text}
176150
176658
  rl.prompt();
176151
176659
  return;
176152
176660
  }
176661
+ const promptArg = /^prompts?(?:\s+(\S+))?$/i.exec(arg.trim());
176662
+ if (promptArg) {
176663
+ await refreshMcpPrompts();
176664
+ const rows = promptArg[1] ? mcpPromptList.filter((p) => p.server === promptArg[1]) : mcpPromptList;
176665
+ console.log(paint.bold(" MCP prompts:"));
176666
+ if (!rows.length) {
176667
+ console.log(" " + paint.dim(promptArg[1] ? `No prompts offered by "${promptArg[1]}".` : "No prompts offered by the connected servers."));
176668
+ } else {
176669
+ const width = Math.max(...rows.map((p) => `${p.server}:${p.name}`.length));
176670
+ for (const p of rows) {
176671
+ const args = (p.arguments ?? []).map((a) => a.required ? `<${a.name}>` : `[${a.name}]`).join(" ");
176672
+ console.log(" " + paint.cyan(`/${p.server}:${p.name}`.padEnd(width + 1)) + " " + (args ? paint.yellow(args) + " " : "") + paint.dim((p.description ?? "").replace(/\s+/g, " ").trim() || `MCP prompt from ${p.server}`));
176673
+ }
176674
+ console.log();
176675
+ console.log(" " + paint.dim("Run one: type /server:prompt with its arguments (positional; quotes keep spaces together)."));
176676
+ }
176677
+ console.log();
176678
+ rl.prompt();
176679
+ return;
176680
+ }
176153
176681
  console.log(paint.bold(" MCP servers:"));
176154
176682
  await handleMcp(arg);
176155
176683
  console.log();
@@ -176588,7 +177116,43 @@ ${text}
176588
177116
  return;
176589
177117
  }
176590
177118
  default: {
177119
+ const bare = cmd.slice(1);
177120
+ if (bare.startsWith("mcp__") || bare.includes(":"))
177121
+ await mcpReady();
176591
177122
  const custom = (0, import_code_core18.findSkill)(skills, cmd);
177123
+ const mcpRef = custom && !bare.startsWith("mcp__") ? null : parseMcpPromptRef(bare, _mcpManager?.serverNames ?? []);
177124
+ if (mcpRef && _mcpManager) {
177125
+ let promptText;
177126
+ try {
177127
+ promptText = await _mcpManager.getPrompt(mcpRef.server, mcpRef.name, splitPromptArgs(arg));
177128
+ } catch (err) {
177129
+ console.log(paint.red(` ${err.message}`));
177130
+ rl.prompt();
177131
+ return;
177132
+ }
177133
+ console.log(paint.dim(` Running /${cmd} (MCP prompt from ${mcpRef.server})...`));
177134
+ checkpoints.beginTurn(`/${cmd} ${arg}`.trim(), messages.length);
177135
+ messages.push({ role: "user", content: [{ type: "text", text: promptText }] });
177136
+ rl.pause();
177137
+ abortSignal.aborted = false;
177138
+ agentRunning = true;
177139
+ try {
177140
+ const result = await runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrallMd, agentMode, effortLevel, checkpoints, saveProgress, takePendingInput, worktreeState, peerCtx);
177141
+ messages = result.messages;
177142
+ updateTitle();
177143
+ saveSession2(sessionId, sessionTitle, workDir, messages);
177144
+ } catch (err) {
177145
+ messages = recoverTurn(err, messages);
177146
+ updateTitle();
177147
+ saveSession2(sessionId, sessionTitle || "Untitled", workDir, messages);
177148
+ } finally {
177149
+ agentRunning = false;
177150
+ commitCheckpoint();
177151
+ }
177152
+ rl.resume();
177153
+ rl.prompt();
177154
+ return;
177155
+ }
176592
177156
  if (!custom) {
176593
177157
  console.log(paint.red(` Unknown command: ${cmd}`));
176594
177158
  console.log(paint.dim(" Type /help for built-ins or /skills for custom ones."));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexrall-code",
3
- "version": "0.5.175",
3
+ "version": "0.5.177",
4
4
  "description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
5
5
  "keywords": [
6
6
  "ai",