@openeryc/pi-coding-agent 0.75.34 → 0.75.36

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.
@@ -289,27 +289,32 @@ export class InteractiveMode {
289
289
  const modelCommand = slashCommands.find((command) => command.name === "model");
290
290
  if (modelCommand) {
291
291
  modelCommand.getArgumentCompletions = (prefix) => {
292
- // Get available models (scoped or from registry)
293
292
  const models = this.session.scopedModels.length > 0
294
293
  ? this.session.scopedModels.map((s) => s.model)
295
294
  : this.session.modelRegistry.getAvailable();
296
295
  if (models.length === 0)
297
296
  return null;
298
- // Create items with provider/id format
299
- const items = models.map((m) => ({
300
- id: m.id,
301
- provider: m.provider,
302
- label: `${m.provider}/${m.id}`,
303
- }));
304
- // Fuzzy filter by model ID + provider (allows "opus anthropic" to match)
297
+ const items = models.map((m) => ({ id: m.id, provider: m.provider, label: `${m.provider}/${m.id}` }));
305
298
  const filtered = fuzzyFilter(items, prefix, (item) => `${item.id} ${item.provider}`);
306
299
  if (filtered.length === 0)
307
300
  return null;
308
- return filtered.map((item) => ({
309
- value: item.label,
310
- label: item.id,
311
- description: item.provider,
312
- }));
301
+ return filtered.map((item) => ({ value: item.label, label: item.id, description: item.provider }));
302
+ };
303
+ }
304
+ // MCP command: autocomplete server names
305
+ const mcpCommand = slashCommands.find((command) => command.name === "mcp");
306
+ if (mcpCommand) {
307
+ mcpCommand.getArgumentCompletions = (prefix) => {
308
+ const servers = this.settingsManager.getMcpServers();
309
+ if (!servers)
310
+ return null;
311
+ const names = Object.keys(servers);
312
+ if (names.length === 0)
313
+ return null;
314
+ const filtered = fuzzyFilter(names.map((n) => ({ label: n })), prefix, (item) => item.label);
315
+ if (filtered.length === 0)
316
+ return null;
317
+ return filtered.map((item) => ({ value: item.label, label: item.label }));
313
318
  };
314
319
  }
315
320
  // Convert prompt templates to SlashCommand format for autocomplete
@@ -2021,6 +2026,12 @@ export class InteractiveMode {
2021
2026
  this.editor.setText("");
2022
2027
  return;
2023
2028
  }
2029
+ if (text.startsWith("/mcp ")) {
2030
+ const name = text.slice(5).trim();
2031
+ this.handleMcpToggle(name);
2032
+ this.editor.setText("");
2033
+ return;
2034
+ }
2024
2035
  if (text === "/usage") {
2025
2036
  this.editor.setText("");
2026
2037
  await this.handleUsageCommand();
@@ -4397,16 +4408,13 @@ export class InteractiveMode {
4397
4408
  this.chatContainer.addChild(new Text(info, 1, 0));
4398
4409
  this.ui.requestRender();
4399
4410
  }
4400
- handleMcpCommand() {
4411
+ handleMcpCommand(highlightServer) {
4401
4412
  const configuredServers = this.settingsManager.getMcpServers();
4402
4413
  const allTools = this.session.getAllTools();
4403
- // Group MCP tools by server name
4404
4414
  const mcpTools = allTools.filter((t) => t.name.startsWith("mcp_"));
4405
4415
  const toolsByServer = new Map();
4406
4416
  for (const tool of mcpTools) {
4407
- // mcp_<server>_<tool> - server name is everything between the first two underscores
4408
- const prefix = "mcp_";
4409
- const rest = tool.name.slice(prefix.length);
4417
+ const rest = tool.name.slice(4);
4410
4418
  const secondUnderscore = rest.indexOf("_");
4411
4419
  const serverName = secondUnderscore === -1 ? rest : rest.slice(0, secondUnderscore);
4412
4420
  const existing = toolsByServer.get(serverName);
@@ -4423,26 +4431,40 @@ export class InteractiveMode {
4423
4431
  this.ui.requestRender();
4424
4432
  return;
4425
4433
  }
4426
- let info = `${theme.bold("MCP Servers")}\n\n`;
4434
+ let info = `${theme.bold("MCP Servers")}\n`;
4435
+ info += `${theme.fg("dim", "Use /mcp <name> to toggle or view details")}\n\n`;
4436
+ let idx = 0;
4427
4437
  for (const [serverName, config] of Object.entries(configuredServers)) {
4428
4438
  const tools = toolsByServer.get(serverName) ?? [];
4439
+ const disabled = config.enabled === false;
4429
4440
  const connected = tools.length > 0;
4430
- const status = connected ? theme.fg("success", "connected") : theme.fg("warning", "disconnected");
4441
+ let status;
4442
+ if (disabled) {
4443
+ status = theme.fg("muted", "disabled");
4444
+ }
4445
+ else if (connected) {
4446
+ status = theme.fg("success", "connected");
4447
+ }
4448
+ else {
4449
+ status = theme.fg("warning", "disconnected");
4450
+ }
4451
+ const toggleHint = disabled ? "[/mcp " + serverName + " to enable]" : "[/mcp " + serverName + " to disable]";
4431
4452
  const transport = config.url ? (config.transport ?? "sse") : config.command ? "stdio" : "unknown";
4432
- info += `${theme.bold(serverName)} ${status}\n`;
4433
- info += `${theme.fg("dim", ` Transport: ${transport}`)}\n`;
4453
+ const toolCount = tools.length;
4454
+ info += `${theme.bold(++idx + ". " + serverName)} ${status} ${theme.fg("dim", toggleHint)}\n`;
4455
+ info += `${theme.fg("dim", ` Transport: ${transport} | Tools: ${toolCount}`)}\n`;
4434
4456
  if (config.command) {
4435
4457
  const cmd = config.args ? `${config.command} ${config.args.join(" ")}` : config.command;
4436
- info += `${theme.fg("dim", ` Command: ${cmd}`)}\n`;
4458
+ info += `${theme.fg("dim", ` Command: ${cmd}`)}\n`;
4437
4459
  }
4438
4460
  if (config.url) {
4439
- info += `${theme.fg("dim", ` URL: ${config.url}`)}\n`;
4461
+ info += `${theme.fg("dim", ` URL: ${config.url}`)}\n`;
4440
4462
  }
4441
- if (connected) {
4442
- info += `${theme.fg("dim", ` Tools: ${tools.length}`)}\n`;
4463
+ // Show detailed tool list only for highlighted server
4464
+ if (highlightServer === serverName && connected) {
4443
4465
  for (const tool of tools) {
4444
4466
  const desc = tool.description ? ` - ${tool.description.split("\n")[0].slice(0, 80)}` : "";
4445
- info += `${theme.fg("dim", ` ${tool.name}${desc}`)}\n`;
4467
+ info += `${theme.fg("dim", ` ${tool.name}${desc}`)}\n`;
4446
4468
  }
4447
4469
  }
4448
4470
  info += "\n";
@@ -4450,6 +4472,21 @@ export class InteractiveMode {
4450
4472
  this.chatContainer.addChild(new Text(info, 1, 0));
4451
4473
  this.ui.requestRender();
4452
4474
  }
4475
+ async handleMcpToggle(serverName) {
4476
+ const mcpServers = this.settingsManager.getMcpServers();
4477
+ if (!mcpServers || !mcpServers[serverName]) {
4478
+ this.chatContainer.addChild(new Spacer(1));
4479
+ this.chatContainer.addChild(new Text(theme.fg("warning", `MCP server "${serverName}" not found.`), 1, 0));
4480
+ this.ui.requestRender();
4481
+ return;
4482
+ }
4483
+ const currentEnabled = mcpServers[serverName].enabled !== false;
4484
+ this.settingsManager.setMcpServerEnabled(serverName, !currentEnabled);
4485
+ await this.session.reloadMcp();
4486
+ this.chatContainer.addChild(new Spacer(1));
4487
+ this.chatContainer.addChild(new Text(`${theme.bold(serverName)} ${theme.fg(currentEnabled ? "muted" : "success", currentEnabled ? "disabled" : "enabled")}`, 1, 0));
4488
+ this.handleMcpCommand(serverName);
4489
+ }
4453
4490
  async handleUsageCommand() {
4454
4491
  this.showStatus("Loading usage stats...");
4455
4492
  this.ui.requestRender();