nexrall-code 0.5.176 → 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 +619 -39
  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),
@@ -166671,6 +166810,208 @@ function askForTrust(workDir, signals) {
166671
166810
  });
166672
166811
  }
166673
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
+
166674
167015
  // src/ui/inkTerminal.tsx
166675
167016
  var import_react36 = __toESM(require_react(), 1);
166676
167017
 
@@ -166908,6 +167249,32 @@ function skillEntries(skills, builtins = BUILTIN_SLASH_COMMANDS) {
166908
167249
  }
166909
167250
  return out;
166910
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
+ }
166911
167278
  function matchScore(query, name, aliases, description) {
166912
167279
  if (!query)
166913
167280
  return 0;
@@ -166948,7 +167315,7 @@ function slashQuery(line, cursor) {
166948
167315
  return null;
166949
167316
  if (line.includes("\n"))
166950
167317
  return null;
166951
- const m2 = /^\/([\w-]*)$/.exec(line);
167318
+ const m2 = /^\/([\w:-]*)$/.exec(line);
166952
167319
  if (!m2)
166953
167320
  return null;
166954
167321
  if (cursor < 1)
@@ -167758,7 +168125,7 @@ function describeOpen(spec, target, cwd2) {
167758
168125
  // src/ui/fileMention.ts
167759
168126
  import * as fs26 from "fs";
167760
168127
  import * as path26 from "path";
167761
- import { execFileSync as execFileSync4 } from "child_process";
168128
+ import { execFile, execFileSync as execFileSync4 } from "child_process";
167762
168129
 
167763
168130
  // src/ui/contextFiles.ts
167764
168131
  import * as fs25 from "fs";
@@ -167973,6 +168340,9 @@ var IGNORED_DIRS = /* @__PURE__ */ new Set([
167973
168340
  ]);
167974
168341
  var MAX_INDEXED = 5e4;
167975
168342
  function listProjectFiles(cwd2) {
168343
+ return listProjectFilesFrom(cwd2).files;
168344
+ }
168345
+ function listProjectFilesFrom(cwd2) {
167976
168346
  let files = null;
167977
168347
  try {
167978
168348
  const out = execFileSync4("git", ["-C", cwd2, "ls-files", "-co", "--exclude-standard", "-z"], {
@@ -167984,34 +168354,41 @@ function listProjectFiles(cwd2) {
167984
168354
  files = [...new Set(out.split("\0").filter(Boolean))];
167985
168355
  } catch {
167986
168356
  }
168357
+ const source2 = files ? "git" : "walk";
167987
168358
  if (!files)
167988
168359
  files = walk(cwd2);
167989
- 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 };
167990
168361
  }
167991
- function walk(root) {
167992
- const out = [];
167993
- const visit = (dir, depth) => {
167994
- if (out.length >= MAX_INDEXED || depth > 8)
167995
- 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;
167996
168368
  let entries;
167997
168369
  try {
167998
168370
  entries = fs26.readdirSync(dir, { withFileTypes: true });
167999
168371
  } catch {
168000
- return;
168372
+ continue;
168001
168373
  }
168002
168374
  for (const e2 of entries) {
168003
- if (out.length >= MAX_INDEXED)
168004
- return;
168005
168375
  const full = path26.join(dir, e2.name);
168006
168376
  if (e2.isDirectory()) {
168007
168377
  if (!IGNORED_DIRS.has(e2.name) && !e2.isSymbolicLink())
168008
- visit(full, depth + 1);
168378
+ queue.push({ dir: full, depth: depth + 1 });
168009
168379
  } else if (e2.isFile()) {
168010
- out.push(path26.relative(root, full).split(path26.sep).join("/"));
168380
+ yield path26.relative(root, full).split(path26.sep).join("/");
168011
168381
  }
168012
168382
  }
168013
- };
168014
- 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
+ }
168015
168392
  return out;
168016
168393
  }
168017
168394
  function buildIndex(files) {
@@ -168023,20 +168400,111 @@ function buildIndex(files) {
168023
168400
  }
168024
168401
  return [...dirs, ...files].sort();
168025
168402
  }
168403
+ var GIT_CACHE_MS = 5e3;
168404
+ var WALK_CACHE_MS = 6e4;
168026
168405
  var cache3 = null;
168027
- var CACHE_MS = 5e3;
168028
168406
  var excludedPatterns = [];
168407
+ var excludedKey = "[]";
168029
168408
  function setExcludedPatterns(patterns) {
168030
168409
  excludedPatterns = [...patterns];
168031
- cache3 = null;
168410
+ excludedKey = JSON.stringify(excludedPatterns);
168411
+ }
168412
+ function derivedIndex(raw) {
168413
+ return buildIndex(raw.filter((f3) => !isExcluded(f3, excludedPatterns)));
168032
168414
  }
168033
168415
  function projectIndex(cwd2, now = Date.now()) {
168034
- 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) };
168035
168419
  return cache3.index;
168036
- const files = listProjectFiles(cwd2).filter((f3) => !isExcluded(f3, excludedPatterns));
168037
- const index = buildIndex(files);
168038
- cache3 = { cwd: cwd2, at: now, index };
168039
- 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;
168040
168508
  }
168041
168509
  function subsequence(hay, needle) {
168042
168510
  let i2 = 0;
@@ -168079,13 +168547,13 @@ function rankMentions(query, index, limit = 200) {
168079
168547
  }
168080
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);
168081
168549
  }
168082
- function computeMention(line, cursor, index, dismissedFor) {
168550
+ function computeMention(line, cursor, getIndex, dismissedFor) {
168083
168551
  if (dismissedFor !== null && dismissedFor === line)
168084
168552
  return null;
168085
168553
  const at = mentionAt(line, cursor);
168086
168554
  if (!at)
168087
168555
  return null;
168088
- const items = rankMentions(at.query, index);
168556
+ const items = rankMentions(at.query, getIndex());
168089
168557
  return items.length ? { at, items } : null;
168090
168558
  }
168091
168559
  function decideMentionEnter(query, pick) {
@@ -168562,7 +169030,7 @@ function slashMenuView(p) {
168562
169030
  return {
168563
169031
  rows: shown.map((e2, i2) => {
168564
169032
  const label = `/${e2.name}${e2.argHint ? " " + e2.argHint : ""}`;
168565
- 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"})` : "";
168566
169034
  const alias = e2.aliases?.length ? ` (${e2.aliases.map((a) => "/" + a).join(", ")})` : "";
168567
169035
  const seen = e2.recent ? " \xB7 recent" : "";
168568
169036
  return {
@@ -168617,7 +169085,7 @@ function fullscreenView(p) {
168617
169085
  function mentionMenuView(p) {
168618
169086
  if (p.blocked)
168619
169087
  return null;
168620
- 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);
168621
169089
  if (!m2)
168622
169090
  return null;
168623
169091
  const sel = Math.min(p.sel.query === m2.at.query ? p.sel.idx : 0, m2.items.length - 1);
@@ -168806,12 +169274,12 @@ var App2 = ({ onReady }) => {
168806
169274
  const mentionRootRef = (0, import_react36.useRef)(process.cwd());
168807
169275
  const setMentionRoot = (0, import_react36.useCallback)((dir) => {
168808
169276
  mentionRootRef.current = dir;
168809
- setImmediate(() => {
168810
- try {
168811
- projectIndex(dir);
168812
- } catch {
168813
- }
168814
- });
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);
168815
169283
  }, []);
168816
169284
  const setSlashEntries = (0, import_react36.useCallback)((entries) => {
168817
169285
  slashEntriesRef.current = entries;
@@ -169254,7 +169722,7 @@ var App2 = ({ onReady }) => {
169254
169722
  }
169255
169723
  }
169256
169724
  }
169257
- 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);
169258
169726
  if (mention) {
169259
169727
  const sel = mentionSelRef.current.query === mention.at.query ? mentionSelRef.current.idx : 0;
169260
169728
  const pick = mention.items[Math.min(sel, mention.items.length - 1)];
@@ -169626,6 +170094,9 @@ var App2 = ({ onReady }) => {
169626
170094
  if (fullscreenRef.current)
169627
170095
  process.stdout.write(on ? MOUSE_ON : MOUSE_OFF);
169628
170096
  }, []);
170097
+ import_react36.default.useEffect(() => {
170098
+ setMousePassthrough(() => fullscreenRef.current && mouseRef.current);
170099
+ }, []);
169629
170100
  import_react36.default.useEffect(() => () => {
169630
170101
  if (fullscreenRef.current) {
169631
170102
  fullscreenRef.current = false;
@@ -169982,6 +170453,38 @@ var InkReadlineAdapter = class extends EventEmitter3 {
169982
170453
  }
169983
170454
  };
169984
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
+
169985
170488
  // src/ui/recents.ts
169986
170489
  import fs27 from "node:fs";
169987
170490
  import os17 from "node:os";
@@ -173254,7 +173757,7 @@ function printHelp() {
173254
173757
  ["/skills", "List skills (.nexrall/skills/<name>/SKILL.md or .nexrall/commands/*.md) \u2014 the model can also auto-invoke these"],
173255
173758
  ["/commands", "List your custom commands (.nexrall/commands/*.md)"],
173256
173759
  ["/plugins", "List installed plugins (.nexrall/plugins/)"],
173257
- ["/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"],
173258
173761
  ["/open <path[:line]>", 'Open a file in your editor (bare /open picks from files this session touched; finds "auth.ts" anywhere)'],
173259
173762
  ["/doctor", "Check Node, sign-in, network, terminal, MCP and storage; shows how to fix each problem"],
173260
173763
  ["/fullscreen", "Draw the session on the terminal's alternate screen: it re-wraps on resize and PgUp/PgDn page through it"],
@@ -173383,6 +173886,7 @@ function printSessions() {
173383
173886
  console.log();
173384
173887
  }
173385
173888
  async function startChatSession(options) {
173889
+ installInputReportFilter();
173386
173890
  if (options.bare)
173387
173891
  setNoDiscovery(true);
173388
173892
  _cliAgentTypes = (options.agents ?? []).map((a) => ({ ...a, source: "programmatic" }));
@@ -173952,13 +174456,32 @@ ${text}` : "");
173952
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)") : ""));
173953
174457
  }
173954
174458
  };
173955
- 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
+ };
173956
174464
  let slashRecents = loadRecents();
173957
174465
  const syncSlashMenu = () => {
173958
174466
  if (interactive)
173959
174467
  getInkTerminal().setSlashEntries(orderByRecents(allSlashEntries(), slashRecents));
173960
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
+ };
173961
174483
  syncSlashMenu();
174484
+ void mcpStarted.then(() => refreshMcpPrompts());
173962
174485
  if (interactive)
173963
174486
  getInkTerminal().setMentionRoot(workDir);
173964
174487
  const doRewind = (id) => {
@@ -174251,6 +174774,7 @@ ${text}` : "");
174251
174774
  }
174252
174775
  }
174253
174776
  }
174777
+ void refreshMcpPrompts();
174254
174778
  const outcome = {};
174255
174779
  if (error !== void 0)
174256
174780
  outcome.error = error;
@@ -176134,6 +176658,26 @@ ${text}
176134
176658
  rl.prompt();
176135
176659
  return;
176136
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
+ }
176137
176681
  console.log(paint.bold(" MCP servers:"));
176138
176682
  await handleMcp(arg);
176139
176683
  console.log();
@@ -176572,7 +177116,43 @@ ${text}
176572
177116
  return;
176573
177117
  }
176574
177118
  default: {
177119
+ const bare = cmd.slice(1);
177120
+ if (bare.startsWith("mcp__") || bare.includes(":"))
177121
+ await mcpReady();
176575
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
+ }
176576
177156
  if (!custom) {
176577
177157
  console.log(paint.red(` Unknown command: ${cmd}`));
176578
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.176",
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",