fullcourtdefense-cli 1.5.1 → 1.5.3

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.
@@ -61,6 +61,7 @@ export declare function installMcpGatewayCommand(args: InstallMcpGatewayArgs, co
61
61
  export interface ProtectAllArgs extends McpGatewayArgs {
62
62
  dryRun?: string;
63
63
  config?: string;
64
+ clients?: string;
64
65
  }
65
66
  export declare function protectAllCommand(args: ProtectAllArgs, config: BotGuardConfig): Promise<void>;
66
67
  export declare function unprotectAllCommand(args: ProtectAllArgs, config: BotGuardConfig): Promise<void>;
@@ -811,7 +811,9 @@ function parseClientList(value) {
811
811
  };
812
812
  const requested = raw === 'all'
813
813
  ? exports.ALL_GATEWAY_CLIENTS.slice()
814
- : raw.split(',').map(part => part.trim()).filter(Boolean);
814
+ // Accept commas OR whitespace: some shells (PowerShell) split a comma list
815
+ // into separate argv tokens that get re-joined with spaces.
816
+ : raw.split(/[\s,]+/).map(part => part.trim()).filter(Boolean);
815
817
  const clients = requested.map(client => aliases[client]);
816
818
  const unknown = requested.filter((part, index) => !clients[index]);
817
819
  if (unknown.length > 0) {
@@ -942,6 +944,24 @@ async function installMcpGatewayCommand(args, config) {
942
944
  console.log('Add --upload to refresh AI Fleet after install.');
943
945
  }
944
946
  }
947
+ /** Map a high-level client to the discovery clientKey(s) its config files use. */
948
+ const AGENT_TO_CLIENT_KEYS = {
949
+ cursor: ['cursor'],
950
+ 'claude-code': ['claude_code'],
951
+ 'claude-desktop': ['claude_desktop'],
952
+ codex: ['codex'],
953
+ 'gemini-cli': ['gemini_cli'],
954
+ windsurf: ['windsurf'],
955
+ vscode: ['vscode'],
956
+ };
957
+ /** Resolve the optional --clients filter into a set of clientKeys, or undefined for "all". */
958
+ function resolveProtectClientKeys(clients) {
959
+ const raw = (clients || '').trim().toLowerCase();
960
+ if (!raw || raw === 'auto' || raw === 'all')
961
+ return undefined; // no filter — process every client
962
+ const selection = parseClientList(clients);
963
+ return new Set(selection.flatMap(client => AGENT_TO_CLIENT_KEYS[client] || []));
964
+ }
945
965
  const CLIENT_KEY_TO_AGENT = {
946
966
  cursor: 'cursor',
947
967
  claude_code: 'claude-code',
@@ -1218,24 +1238,29 @@ function transformCodexToml(file, mode, gatewayConfig, dryRun) {
1218
1238
  }
1219
1239
  return stats;
1220
1240
  }
1221
- function protectAllTargetFiles(extra) {
1241
+ function protectAllTargetFiles(extra, allowedClientKeys) {
1222
1242
  const cwd = process.cwd();
1223
1243
  const seen = new Set();
1244
+ const allow = (clientKey) => !allowedClientKeys || allowedClientKeys.has(clientKey);
1224
1245
  const files = [];
1225
1246
  for (const candidate of (0, discoverPaths_1.candidateConfigPaths)(cwd, extra)) {
1226
1247
  const key = path.resolve(candidate.path).toLowerCase();
1227
1248
  if (seen.has(key))
1228
1249
  continue;
1250
+ if (!allow(candidate.clientKey))
1251
+ continue;
1229
1252
  if (!fs.existsSync(candidate.path))
1230
1253
  continue;
1231
1254
  seen.add(key);
1232
1255
  files.push(candidate);
1233
1256
  }
1234
- for (const target of (0, discoverPaths_1.claudeDesktopInstallTargets)()) {
1235
- const key = path.resolve(target.file).toLowerCase();
1236
- if (target.exists && !seen.has(key)) {
1237
- seen.add(key);
1238
- files.push({ path: target.file, source: target.source, clientKey: 'claude_desktop' });
1257
+ if (allow('claude_desktop')) {
1258
+ for (const target of (0, discoverPaths_1.claudeDesktopInstallTargets)()) {
1259
+ const key = path.resolve(target.file).toLowerCase();
1260
+ if (target.exists && !seen.has(key)) {
1261
+ seen.add(key);
1262
+ files.push({ path: target.file, source: target.source, clientKey: 'claude_desktop' });
1263
+ }
1239
1264
  }
1240
1265
  }
1241
1266
  return files;
@@ -1244,11 +1269,14 @@ async function protectAllCommand(args, config) {
1244
1269
  (0, config_1.requireCliSetup)(config, { shieldId: args.shieldId, shieldKey: args.shieldKey, apiUrl: args.apiUrl }, { requireOrganizationId: false });
1245
1270
  const gatewayConfig = resolveGatewayConfig(args, config);
1246
1271
  const dryRun = args.dryRun === 'true';
1247
- const files = protectAllTargetFiles(args.config);
1272
+ const allowedClientKeys = resolveProtectClientKeys(args.clients);
1273
+ const files = protectAllTargetFiles(args.config, allowedClientKeys);
1248
1274
  console.log('\n\x1b[1m\x1b[36mFullCourtDefense — protect every MCP server in every client\x1b[0m');
1249
1275
  console.log(`\x1b[2mRuntime identity: ${gatewayConfig.developerName} | Shield: ${gatewayConfig.shieldId}${dryRun ? ' | DRY RUN' : ''}\x1b[0m\n`);
1250
1276
  if (files.length === 0) {
1251
- console.log('No MCP client config files found on this machine. Configure an MCP server in any client, then re-run.');
1277
+ console.log(allowedClientKeys
1278
+ ? 'No matching client config files found for the requested --clients. Try without --clients, or pick a client that is installed.'
1279
+ : 'No MCP client config files found on this machine. Configure an MCP server in any client, then re-run.');
1252
1280
  return;
1253
1281
  }
1254
1282
  let totalWrapped = 0;
@@ -1285,7 +1313,8 @@ async function protectAllCommand(args, config) {
1285
1313
  }
1286
1314
  async function unprotectAllCommand(args, config) {
1287
1315
  const dryRun = args.dryRun === 'true';
1288
- const files = protectAllTargetFiles(args.config);
1316
+ const allowedClientKeys = resolveProtectClientKeys(args.clients);
1317
+ const files = protectAllTargetFiles(args.config, allowedClientKeys);
1289
1318
  let gatewayConfig;
1290
1319
  try {
1291
1320
  gatewayConfig = resolveGatewayConfig(args, config);
package/dist/index.js CHANGED
@@ -128,8 +128,11 @@ function printHelp() {
128
128
  (Cursor, Claude Code/Desktop, Codex, Gemini, Windsurf, VS Code)
129
129
  and wrap each through the Shield proxy — no --mcp-command needed.
130
130
  Enforces your org Action Policies on every tool. --dry-run to preview.
131
+ Per-tool: --clients cursor (or claude-code, claude-desktop, codex,
132
+ gemini-cli, windsurf, vscode; comma-separated). Default: all tools.
131
133
  unprotect-all
132
134
  Reverse protect-all: restore every server to its original command.
135
+ Also supports --clients to target one tool, and --dry-run.
133
136
  install-mcp-gateway
134
137
  Install MCP gateway into selected clients (--clients all for every tool).
135
138
  install-cursor-mcp-gateway
@@ -511,6 +514,7 @@ async function main() {
511
514
  ...buildGatewayArgs(),
512
515
  dryRun: flags['dry-run'],
513
516
  config: flags.config,
517
+ clients: flags.clients,
514
518
  };
515
519
  await (0, mcpGateway_1.protectAllCommand)(args, config);
516
520
  break;
@@ -521,6 +525,7 @@ async function main() {
521
525
  ...buildGatewayArgs(),
522
526
  dryRun: flags['dry-run'],
523
527
  config: flags.config,
528
+ clients: flags.clients,
524
529
  };
525
530
  await (0, mcpGateway_1.unprotectAllCommand)(args, config);
526
531
  break;
package/dist/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "1.5.1"
2
+ "version": "1.5.3"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fullcourtdefense-cli",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "Full Court Defense CLI — security scanning for AI agents from your terminal",
5
5
  "main": "dist/index.js",
6
6
  "bin": {