@f5-sales-demo/xcsh 21.43.1 → 21.43.4

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5-sales-demo/xcsh",
4
- "version": "21.43.1",
4
+ "version": "21.43.4",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5-sales-demo/xcsh",
7
7
  "author": "Can Boluk",
@@ -64,13 +64,13 @@
64
64
  },
65
65
  "dependencies": {
66
66
  "@agentclientprotocol/sdk": "1.4.0",
67
- "@f5-sales-demo/pi-agent-core": "21.43.1",
68
- "@f5-sales-demo/pi-ai": "21.43.1",
69
- "@f5-sales-demo/pi-natives": "21.43.1",
70
- "@f5-sales-demo/pi-resource-management": "21.43.1",
71
- "@f5-sales-demo/pi-tui": "21.43.1",
72
- "@f5-sales-demo/pi-utils": "21.43.1",
73
- "@f5-sales-demo/xcsh-stats": "21.43.1",
67
+ "@f5-sales-demo/pi-agent-core": "21.43.4",
68
+ "@f5-sales-demo/pi-ai": "21.43.4",
69
+ "@f5-sales-demo/pi-natives": "21.43.4",
70
+ "@f5-sales-demo/pi-resource-management": "21.43.4",
71
+ "@f5-sales-demo/pi-tui": "21.43.4",
72
+ "@f5-sales-demo/pi-utils": "21.43.4",
73
+ "@f5-sales-demo/xcsh-stats": "21.43.4",
74
74
  "@mozilla/readability": "^0.6",
75
75
  "@sinclair/typebox": "0.34.52",
76
76
  "@tobilu/qmd": "2.8.3",
package/src/cli/args.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { type Effort, THINKING_EFFORTS } from "@f5-sales-demo/pi-ai";
5
5
  import { APP_NAME, CONFIG_DIR_NAME, logger } from "@f5-sales-demo/pi-utils";
6
+ import { CliUsageError } from "@f5-sales-demo/pi-utils/cli";
6
7
  import chalk from "chalk";
7
8
  import { parseEffort } from "../thinking";
8
9
  import {
@@ -49,6 +50,7 @@ export interface Args {
49
50
  models?: string[];
50
51
  tools?: string[];
51
52
  noTools?: boolean;
53
+ mcp?: boolean;
52
54
  noMcp?: boolean;
53
55
  noLsp?: boolean;
54
56
  noPty?: boolean;
@@ -159,6 +161,9 @@ const APPLY: Record<LaunchFlagName, (result: Args, value: string | true) => void
159
161
  "no-tools": r => {
160
162
  r.noTools = true;
161
163
  },
164
+ mcp: r => {
165
+ r.mcp = true;
166
+ },
162
167
  "no-mcp": r => {
163
168
  r.noMcp = true;
164
169
  },
@@ -399,6 +404,8 @@ export function parseArgs(args: string[], extensionFlags?: ExtensionFlagRegistry
399
404
  result.unrecognizedFlags.push({ token, name: name ?? token.replace(/^-+/, "") });
400
405
  }
401
406
 
407
+ if (result.mcp && result.noMcp) throw new CliUsageError("--mcp cannot be combined with --no-mcp");
408
+ if (result.mcp && result.noTools) throw new CliUsageError("--mcp cannot be combined with --no-tools");
402
409
  return result;
403
410
  }
404
411
 
@@ -79,6 +79,7 @@ export const LAUNCH_FLAGS = defineFlags({
79
79
  "provider-session-id": { arity: "value", description: "Resume a provider-side session", hidden: true },
80
80
  models: { arity: "value", description: "Comma-separated model patterns for Ctrl+P cycling" },
81
81
  "no-tools": { arity: "boolean", description: "Disable all built-in tools" },
82
+ mcp: { arity: "boolean", description: "Enable MCP servers for this run" },
82
83
  "no-mcp": { arity: "boolean", description: "Disable MCP server discovery and tools" },
83
84
  "no-lsp": { arity: "boolean", description: "Disable LSP tools, formatting, and diagnostics" },
84
85
  "no-pty": { arity: "boolean", description: "Disable PTY-based interactive bash execution" },
@@ -7,6 +7,7 @@
7
7
  import * as os from "node:os";
8
8
  import { createInterface } from "node:readline/promises";
9
9
  import { APP_NAME, getProjectDir } from "@f5-sales-demo/pi-utils";
10
+ import { CliUsageError } from "@f5-sales-demo/pi-utils/cli";
10
11
  import chalk from "chalk";
11
12
  import { preloadPluginRoots, resolveOrDefaultProjectRegistryPath } from "../discovery/helpers";
12
13
  import { discoverAndLoadExtensions } from "../extensibility/extensions";
@@ -294,7 +295,7 @@ export async function reviewAndExecuteIntegrationSetup(handle: IntegrationHandle
294
295
  }
295
296
 
296
297
  async function handleIntegrationSetup(args: string[], flags: { json?: boolean }): Promise<void> {
297
- if (flags.json) throw new Error("plugin setup is human-only and does not accept --json");
298
+ if (flags.json) throw new CliUsageError("plugin setup is human-only and does not accept --json");
298
299
  if (args.length !== 1) throw new Error(`Usage: ${APP_NAME} plugin setup <plugin>`);
299
300
  if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Plugin setup requires an interactive terminal");
300
301
  const handle = selectSetupIntegration(await loadIntegrationHandles(), args[0]);
@@ -93,10 +93,13 @@ interface UiMetadata {
93
93
  condition?: string;
94
94
  }
95
95
 
96
+ type SettingScope = "user";
97
+
96
98
  interface BooleanDef {
97
99
  type: "boolean";
98
100
  default: boolean;
99
101
  ui?: UiMetadata;
102
+ scope?: SettingScope;
100
103
  }
101
104
 
102
105
  interface StringDef {
@@ -1761,6 +1764,13 @@ export const SETTINGS_SCHEMA = {
1761
1764
  },
1762
1765
 
1763
1766
  // MCP
1767
+ "mcp.enabled": {
1768
+ type: "boolean",
1769
+ default: false,
1770
+ scope: "user",
1771
+ ui: { tab: "tools", label: "MCP", description: "Enable MCP servers for new sessions" },
1772
+ },
1773
+
1764
1774
  "mcp.enableProjectConfig": {
1765
1775
  type: "boolean",
1766
1776
  default: true,
@@ -662,10 +662,25 @@ export class Settings {
662
662
  // ─────────────────────────────────────────────────────────────────────────
663
663
 
664
664
  #rebuildMerged(): void {
665
- this.#merged = this.#deepMerge(this.#deepMerge({}, this.#global), this.#project);
665
+ const trustedProject = structuredClone(this.#project);
666
+ for (const [settingPath, definition] of Object.entries(SETTINGS_SCHEMA)) {
667
+ if (!("scope" in definition) || definition.scope !== "user") continue;
668
+ this.#deleteByPath(trustedProject, settingPath.split("."));
669
+ }
670
+ this.#merged = this.#deepMerge(this.#deepMerge({}, this.#global), trustedProject);
666
671
  this.#merged = this.#deepMerge(this.#merged, this.#overrides);
667
672
  }
668
673
 
674
+ #deleteByPath(obj: RawSettings, segments: string[]): void {
675
+ let current = obj;
676
+ for (let i = 0; i < segments.length - 1; i++) {
677
+ const next = current[segments[i]];
678
+ if (!next || typeof next !== "object" || Array.isArray(next)) return;
679
+ current = next as RawSettings;
680
+ }
681
+ Reflect.deleteProperty(current, segments[segments.length - 1]);
682
+ }
683
+
669
684
  #fireAllHooks(): void {
670
685
  for (const key of Object.keys(SETTING_HOOKS) as SettingPath[]) {
671
686
  const hook = SETTING_HOOKS[key];
@@ -50,7 +50,8 @@ export function describeInstallSetupOutcome(
50
50
  const handle = handles.find(
51
51
  candidate => candidate.id === target || candidate.plugin === target || candidate.plugin?.split("@")[0] === target,
52
52
  );
53
- const nextAction = handle ? describeIntegrationSetupNextAction(handle) : `xcsh plugin setup ${target}`;
53
+ const nextTarget = handle?.plugin?.split("@")[0] ?? handle?.id ?? target;
54
+ const nextAction = `/plugin setup ${nextTarget}`;
54
55
  return `${summary}\nnext: ${nextAction}`;
55
56
  }
56
57